Skip to content

Commit

Permalink
Trac #32367: Replace Lazy Power Series in species directory
Browse files Browse the repository at this point in the history
In this ticket we finalize the implementation of lazy series, and
replace the old lazy series framework.

URL: https://trac.sagemath.org/32367
Reported by: gh-tejasvicsr1
Ticket author(s): Tejasvi Chebrolu, Martin Rubey, Travis Scrimshaw
Reviewer(s): Martin Rubey, Travis Scrimshaw
  • Loading branch information
Release Manager committed Oct 9, 2022
2 parents 00ebfa9 + 4fc981b commit 6b198bd
Show file tree
Hide file tree
Showing 31 changed files with 1,316 additions and 4,107 deletions.
3 changes: 0 additions & 3 deletions src/doc/en/reference/combinat/module_list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,8 @@ Comprehensive Module List
sage/combinat/species/permutation_species
sage/combinat/species/product_species
sage/combinat/species/recursive_species
sage/combinat/species/series
sage/combinat/species/series_order
sage/combinat/species/set_species
sage/combinat/species/species
sage/combinat/species/stream
sage/combinat/species/structure
sage/combinat/species/subset_species
sage/combinat/species/sum_species
Expand Down
16 changes: 5 additions & 11 deletions src/sage/categories/highest_weight_crystals.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,9 @@ def q_dimension(self, q=None, prec=None, use_product=False):
1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6
+ 9*q^7 + 13*q^8 + 16*q^9 + O(q^10)
sage: qdim = C.q_dimension(); qdim
1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6
+ 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + O(x^11)
sage: qdim.compute_coefficients(15)
sage: qdim
1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6
+ 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + 27*q^11
+ 36*q^12 + 44*q^13 + 57*q^14 + 70*q^15 + O(x^16)
1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + O(q^7)
sage: qdim[:16]
[1, 1, 2, 2, 4, 5, 7, 9, 13, 16, 22, 27, 36, 44, 57, 70]
"""
from sage.rings.integer_ring import ZZ
WLR = self.weight_lattice_realization()
Expand Down Expand Up @@ -375,22 +370,21 @@ def iter_by_deg(gens):
elif prec is None:
# If we're here, we may not be a finite crystal.
# In fact, we're probably infinite.
from sage.combinat.species.series import LazyPowerSeriesRing
from sage.rings.lazy_series_ring import LazyPowerSeriesRing
if q is None:
P = LazyPowerSeriesRing(ZZ, names='q')
else:
P = q.parent()
if not isinstance(P, LazyPowerSeriesRing):
raise TypeError("the parent of q must be a lazy power series ring")
ret = P(iter_by_deg(mg))
ret.compute_coefficients(10)
return ret

from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic
if q is None:
q = PowerSeriesRing(ZZ, 'q', default_prec=prec).gen(0)
P = q.parent()
ret = P.sum(c * q**deg for deg,c in enumerate(iter_by_deg(mg)))
ret = P.sum(c * q**deg for deg, c in enumerate(iter_by_deg(mg)))
if ret.degree() == max_deg and isinstance(P, PowerSeriesRing_generic):
ret = P(ret, prec)
return ret
Expand Down
16 changes: 13 additions & 3 deletions src/sage/categories/sets_with_grading.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,21 @@ def generating_series(self):
Non negative integers
sage: N.generating_series()
1/(-z + 1)
sage: Permutations().generating_series()
1 + z + 2*z^2 + 6*z^3 + 24*z^4 + 120*z^5 + 720*z^6 + O(z^7)
.. TODO::
- Very likely, this should always return a lazy power series.
"""
from sage.combinat.species.series import LazyPowerSeriesRing
from sage.sets.non_negative_integers import NonNegativeIntegers
from sage.rings.lazy_series_ring import LazyPowerSeriesRing
from sage.rings.integer_ring import ZZ
R = LazyPowerSeriesRing(ZZ)
R(self.graded_component(grade).cardinality() for grade in self.grading_set())
if isinstance(self.grading_set(), NonNegativeIntegers):
R = LazyPowerSeriesRing(ZZ, names="z")
return R(lambda n: self.graded_component(n).cardinality())
raise NotImplementedError

# TODO:
# * asymptotic behavior: we need an object for asymptotic behavior and
Expand Down
16 changes: 5 additions & 11 deletions src/sage/combinat/species/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@
- :ref:`section-examples-catalan`
- :ref:`section-generic-species`
Lazy Power Series
-----------------
- :ref:`sage.combinat.species.stream`
- :ref:`sage.combinat.species.series_order`
- :ref:`sage.combinat.species.series`
- :ref:`sage.combinat.species.generating_series`
Basic Species
-------------
Expand Down Expand Up @@ -52,6 +44,8 @@
from sage.misc.namespace_package import install_doc
install_doc(__package__, __doc__)

from .series import LazyPowerSeriesRing
from .recursive_species import CombinatorialSpecies
from . import library as species
from sage.misc.lazy_import import lazy_import
lazy_import("sage.combinat.species.recursive_species", "CombinatorialSpecies")
lazy_import("sage.combinat.species", "library", as_="species")
del lazy_import

28 changes: 14 additions & 14 deletions src/sage/combinat/species/characteristic_species.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,15 @@ def __init__(self, n, min=None, max=None, weight=None):
[1]
sage: X.structures([1,2]).list()
[]
sage: X.generating_series().coefficients(4)
sage: X.generating_series()[0:4]
[0, 1, 0, 0]
sage: X.isotype_generating_series().coefficients(4)
sage: X.isotype_generating_series()[0:4]
[0, 1, 0, 0]
sage: X.cycle_index_series().coefficients(4)
sage: X.cycle_index_series()[0:4]
[0, p[1], 0, 0]
sage: F = species.CharacteristicSpecies(3)
sage: c = F.generating_series().coefficients(4)
sage: c = F.generating_series()[0:4]
sage: F._check()
True
sage: F == loads(dumps(F))
Expand Down Expand Up @@ -163,7 +163,7 @@ def _gs_term(self, base_ring):
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: F.generating_series().coefficients(5)
sage: F.generating_series()[0:5]
[0, 0, 1/2, 0, 0]
sage: F.generating_series().count(2)
1
Expand All @@ -187,7 +187,7 @@ def _itgs_term(self, base_ring):
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: F.isotype_generating_series().coefficients(5)
sage: F.isotype_generating_series()[0:5]
[0, 0, 1, 0, 0]
Here we test out weighting each structure by q.
Expand All @@ -196,7 +196,7 @@ def _itgs_term(self, base_ring):
sage: R.<q> = ZZ[]
sage: Fq = species.CharacteristicSpecies(2, weight=q)
sage: Fq.isotype_generating_series().coefficients(5)
sage: Fq.isotype_generating_series()[0:5]
[0, 0, q, 0, 0]
"""
return base_ring(self._weight)
Expand All @@ -207,7 +207,7 @@ def _cis_term(self, base_ring):
sage: F = species.CharacteristicSpecies(2)
sage: g = F.cycle_index_series()
sage: g.coefficients(5)
sage: g[0:5]
[0, 0, 1/2*p[1, 1] + 1/2*p[2], 0, 0]
"""
cis = SetSpecies(weight=self._weight).cycle_index_series(base_ring)
Expand Down Expand Up @@ -248,11 +248,11 @@ def __init__(self, min=None, max=None, weight=None):
[{}]
sage: X.structures([1,2]).list()
[]
sage: X.generating_series().coefficients(4)
sage: X.generating_series()[0:4]
[1, 0, 0, 0]
sage: X.isotype_generating_series().coefficients(4)
sage: X.isotype_generating_series()[0:4]
[1, 0, 0, 0]
sage: X.cycle_index_series().coefficients(4)
sage: X.cycle_index_series()[0:4]
[p[], 0, 0, 0]
TESTS::
Expand Down Expand Up @@ -290,11 +290,11 @@ def __init__(self, min=None, max=None, weight=None):
[1]
sage: X.structures([1,2]).list()
[]
sage: X.generating_series().coefficients(4)
sage: X.generating_series()[0:4]
[0, 1, 0, 0]
sage: X.isotype_generating_series().coefficients(4)
sage: X.isotype_generating_series()[0:4]
[0, 1, 0, 0]
sage: X.cycle_index_series().coefficients(4)
sage: X.cycle_index_series()[0:4]
[0, p[1], 0, 0]
TESTS::
Expand Down
22 changes: 8 additions & 14 deletions src/sage/combinat/species/composition_species.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def transport(self, perm):
f, gs = self._list
pi = self._partition.transport(perm)
f = f.change_labels(pi._list)
g = [g.change_labels(part) for g, part in zip(gs, pi)] # BUG HERE ?
_ = [g.change_labels(part) for g, part in zip(gs, pi)] # TODO: BUG HERE ?
return self.__class__(self, self._labels, pi, f, gs)

def change_labels(self, labels):
Expand Down Expand Up @@ -105,7 +105,7 @@ def __init__(self, F, G, min=None, max=None, weight=None):
sage: E = species.SetSpecies()
sage: C = species.CycleSpecies()
sage: S = E(C)
sage: S.generating_series().coefficients(5)
sage: S.generating_series()[:5]
[1, 1, 1, 1, 1]
sage: E(C) is S
True
Expand All @@ -114,7 +114,7 @@ def __init__(self, F, G, min=None, max=None, weight=None):
sage: E = species.SetSpecies(); C = species.CycleSpecies()
sage: L = E(C)
sage: c = L.generating_series().coefficients(3)
sage: c = L.generating_series()[:3]
sage: L._check() #False due to isomorphism types not being implemented
False
sage: L == loads(dumps(L))
Expand Down Expand Up @@ -193,7 +193,7 @@ def _gs(self, series_ring, base_ring):
sage: E = species.SetSpecies(); C = species.CycleSpecies()
sage: L = E(C)
sage: L.generating_series().coefficients(5)
sage: L.generating_series()[:5]
[1, 1, 1, 1, 1]
"""
return self._F.generating_series(base_ring)(self._G.generating_series(base_ring))
Expand All @@ -204,7 +204,7 @@ def _itgs(self, series_ring, base_ring):
sage: E = species.SetSpecies(); C = species.CycleSpecies()
sage: L = E(C)
sage: L.isotype_generating_series().coefficients(10)
sage: L.isotype_generating_series()[:10]
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30]
"""
cis = self.cycle_index_series(base_ring)
Expand All @@ -216,7 +216,7 @@ def _cis(self, series_ring, base_ring):
sage: E = species.SetSpecies(); C = species.CycleSpecies()
sage: L = E(C)
sage: L.cycle_index_series().coefficients(5)
sage: L.cycle_index_series()[:5]
[p[],
p[1],
p[1, 1] + p[2],
Expand All @@ -233,7 +233,7 @@ def _cis(self, series_ring, base_ring):
sage: E = species.SetSpecies()
sage: C = species.CycleSpecies(weight=t)
sage: S = E(C)
sage: S.isotype_generating_series().coefficients(5) #indirect
sage: S.isotype_generating_series()[:5] #indirect
[1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t]
We do the same thing with set partitions weighted by the number of
Expand All @@ -245,17 +245,11 @@ def _cis(self, series_ring, base_ring):
sage: E = species.SetSpecies()
sage: E_t = species.SetSpecies(min=1,weight=t)
sage: Par = E(E_t)
sage: Par.isotype_generating_series().coefficients(5)
sage: Par.isotype_generating_series()[:5]
[1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t]
"""
f_cis = self._F.cycle_index_series(base_ring)
g_cis = self._G.cycle_index_series(base_ring)

#If G is a weighted species, then we can't use the default
#algorithm for the composition of the cycle index series
#since we must raise the weighting to the power.
if self._G.is_weighted():
return f_cis.weighted_composition(self._G)
return f_cis(g_cis)

def weight_ring(self):
Expand Down
47 changes: 23 additions & 24 deletions src/sage/combinat/species/cycle_species.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@

from .species import GenericCombinatorialSpecies
from .structure import GenericSpeciesStructure
from .generating_series import _integers_from
from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.integer_ring import ZZ
from sage.arith.all import divisors, euler_phi
from sage.combinat.species.misc import accept_size

Expand Down Expand Up @@ -142,7 +140,7 @@ def __init__(self, min=None, max=None, weight=None):
True
sage: P = species.CycleSpecies()
sage: c = P.generating_series().coefficients(3)
sage: c = P.generating_series()[:3]
sage: P._check()
True
sage: P == loads(dumps(P))
Expand Down Expand Up @@ -177,7 +175,7 @@ def _isotypes(self, structure_class, labels):
if len(labels) != 0:
yield structure_class(self, labels, range(1, len(labels)+1))

def _gs_iterator(self, base_ring):
def _gs_callable(self, base_ring, n):
r"""
The generating series for cyclic permutations is
`-\log(1-x) = \sum_{n=1}^\infty x^n/n`.
Expand All @@ -186,20 +184,19 @@ def _gs_iterator(self, base_ring):
sage: P = species.CycleSpecies()
sage: g = P.generating_series()
sage: g.coefficients(10)
sage: g[0:10]
[0, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9]
TESTS::
sage: P = species.CycleSpecies()
sage: g = P.generating_series(RR)
sage: g.coefficients(3)
sage: g[0:3]
[0.000000000000000, 1.00000000000000, 0.500000000000000]
"""
one = base_ring(1)
yield base_ring(0)
for n in _integers_from(ZZ(1)):
yield self._weight*one/n
if n:
return self._weight * base_ring.one() / n
return base_ring.zero()

def _order(self):
"""
Expand All @@ -213,7 +210,7 @@ def _order(self):
"""
return 1

def _itgs_list(self, base_ring):
def _itgs_list(self, base_ring, n):
"""
The isomorphism type generating series for cyclic permutations is
given by `x/(1-x)`.
Expand All @@ -222,19 +219,21 @@ def _itgs_list(self, base_ring):
sage: P = species.CycleSpecies()
sage: g = P.isotype_generating_series()
sage: g.coefficients(5)
sage: g[0:5]
[0, 1, 1, 1, 1]
TESTS::
sage: P = species.CycleSpecies()
sage: g = P.isotype_generating_series(RR)
sage: g.coefficients(3)
sage: g[0:3]
[0.000000000000000, 1.00000000000000, 1.00000000000000]
"""
return [base_ring(0), self._weight*base_ring(1)]
if n:
return self._weight * base_ring.one()
return base_ring.zero()

def _cis_iterator(self, base_ring):
def _cis_callable(self, base_ring, n):
r"""
The cycle index series of the species of cyclic permutations is
given by
Expand All @@ -256,7 +255,7 @@ def _cis_iterator(self, base_ring):
sage: P = species.CycleSpecies()
sage: cis = P.cycle_index_series()
sage: cis.coefficients(7)
sage: cis[0:7]
[0,
p[1],
1/2*p[1, 1] + 1/2*p[2],
Expand All @@ -268,15 +267,15 @@ def _cis_iterator(self, base_ring):
from sage.combinat.sf.sf import SymmetricFunctions
p = SymmetricFunctions(base_ring).power()

zero = base_ring(0)
zero = base_ring.zero()

yield zero
for n in _integers_from(1):
res = zero
for k in divisors(n):
res += euler_phi(k)*p([k])**(n//k)
res /= n
yield self._weight*res
if not n:
return zero
res = zero
for k in divisors(n):
res += euler_phi(k)*p([k])**(n//k)
res /= n
return self._weight * res

#Backward compatibility
CycleSpecies_class = CycleSpecies

0 comments on commit 6b198bd

Please sign in to comment.