Commits (1)
......@@ -15,11 +15,10 @@ Characteristic Species
#
# http://www.gnu.org/licenses/
#*****************************************************************************
from species import GenericCombinatorialSpecies
from species import GenericCombinatorialSpecies, SpeciesTermStream
from generating_series import factorial_stream
from structure import GenericSpeciesStructure
from set_species import SetSpecies
from sage.misc.cachefunc import cached_function
from sage.structure.unique_representation import UniqueRepresentation
class CharacteristicSpeciesStructure(GenericSpeciesStructure):
......@@ -157,18 +156,6 @@ class CharacteristicSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
_isotypes = _structures
def _gs_term(self, base_ring):
"""
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: F.generating_series().coefficients(5)
[0, 0, 1/2, 0, 0]
sage: F.generating_series().count(2)
1
"""
return base_ring(self._weight)/base_ring(factorial_stream[self._n])
def _order(self):
"""
Returns the order of the generating series.
......@@ -181,36 +168,52 @@ class CharacteristicSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
"""
return self._n
def _itgs_term(self, base_ring):
"""
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: F.isotype_generating_series().coefficients(5)
[0, 0, 1, 0, 0]
Here we test out weighting each structure by q.
::
sage: R.<q> = ZZ[]
sage: Fq = species.CharacteristicSpecies(2, weight=q)
sage: Fq.isotype_generating_series().coefficients(5)
[0, 0, q, 0, 0]
"""
return base_ring(self._weight)
def _cis_term(self, base_ring):
"""
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: g = F.cycle_index_series()
sage: g.coefficients(5)
[0, 0, 1/2*p[1, 1] + 1/2*p[2], 0, 0]
"""
cis = SetSpecies(weight=self._weight).cycle_index_series(base_ring)
return cis.coefficient(self._n)
class GeneratingSeriesStream(SpeciesTermStream):
def value(self, base_ring, weight):
"""
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: F.generating_series().coefficients(5)
[0, 0, 1/2, 0, 0]
sage: F.generating_series().count(2)
1
"""
return base_ring(weight)/factorial_stream[self._n]
class IsotypeGeneratingSeriesStream(SpeciesTermStream):
def value(self, base_ring, weight):
"""
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: F.isotype_generating_series().coefficients(5)
[0, 0, 1, 0, 0]
Here we test out weighting each structure by q.
::
sage: R.<q> = ZZ[]
sage: Fq = species.CharacteristicSpecies(2, weight=q)
sage: Fq.isotype_generating_series().coefficients(5)
[0, 0, q, 0, 0]
"""
return base_ring(weight)
class CycleIndexSeriesStream(SpeciesTermStream):
def value(self, base_ring, weight):
"""
EXAMPLES::
sage: F = species.CharacteristicSpecies(2)
sage: g = F.cycle_index_series()
sage: g.coefficients(5)
[0, 0, 1/2*p[1, 1] + 1/2*p[2], 0, 0]
"""
cis = SetSpecies(weight=weight).cycle_index_series(base_ring.base_ring())
return cis.coefficient(self._n)
def _equation(self, var_mapping):
"""
......
"""
Combinatorial Logarithm
This file provides the cycle index series for the virtual species `\Omega`,
the 'combinatorial logarithm', defined to be the compositional inverse of
the species `E^{+}` of nonempty sets:
.. MATH::
\Omega \circ E^{+} = E^{+} \circ \Omega = X.
.. warning::
This module is now deprecated. Please use
:meth:`sage.combinat.species.generating_series.CycleIndexSeriesRing.exponential`
instead of :func:`CombinatorialLogarithmSeries`.
AUTHORS:
- Andrew Gainer-Dewar (2013): initial version
"""
#*****************************************************************************
# Copyright (C) 2013 Andrew Gainer-Dewar <andrew.gainer.dewar@gmail.com>
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
from sage.combinat.species.generating_series import CycleIndexSeriesRing, LogarithmCycleIndexSeries
from sage.rings.all import QQ
from sage.misc.cachefunc import cached_function
from sage.misc.superseded import deprecation
@cached_function
def CombinatorialLogarithmSeries(R=QQ):
r"""
Return the cycle index series of the virtual species `\Omega`, the compositional inverse
of the species `E^{+}` of nonempty sets.
The notion of virtual species is treated thoroughly in [BLL]_. The specific algorithm used
here to compute the cycle index of `\Omega` is found in [Labelle]_.
EXAMPLES:
The virtual species `\Omega` is 'properly virtual', in the sense that its cycle index
has negative coefficients::
sage: from sage.combinat.species.combinatorial_logarithm import CombinatorialLogarithmSeries
sage: CombinatorialLogarithmSeries().coefficients(4)
doctest:...: DeprecationWarning: CombinatorialLogarithmSeries is deprecated, use CycleIndexSeriesRing(R).logarithm_series() or CycleIndexSeries().logarithm() instead
See http://trac.sagemath.org/14846 for details.
[0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]]
Its defining property is that `\Omega \circ E^{+} = E^{+} \circ \Omega = X` (that is, that
composition with `E^{+}` in both directions yields the multiplicative identity `X`)::
sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series()
sage: CombinatorialLogarithmSeries().compose(Eplus).coefficients(4)
[0, p[1], 0, 0]
"""
deprecation(14846, "CombinatorialLogarithmSeries is deprecated, use CycleIndexSeriesRing(R).logarithm_series() or CycleIndexSeries().logarithm() instead")
return LogarithmCycleIndexSeries(R)
......@@ -15,12 +15,11 @@ Cycle Species
#
# http://www.gnu.org/licenses/
#*****************************************************************************
from species import GenericCombinatorialSpecies
from species import GenericCombinatorialSpecies, SpeciesSeriesStream
from series import SeriesStreamFromList
from structure import GenericSpeciesStructure
from generating_series import _integers_from
from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.all import ZZ, divisors, euler_phi
from sage.misc.cachefunc import cached_function
from sage.combinat.species.misc import accept_size
class CycleSpeciesStructure(GenericSpeciesStructure):
......@@ -58,7 +57,7 @@ class CycleSpeciesStructure(GenericSpeciesStructure):
sage: a.permutation_group_element()
(1,2,3)
"""
from sage.groups.all import PermutationGroupElement, SymmetricGroup
from sage.groups.all import PermutationGroupElement
return PermutationGroupElement(tuple(self._list))
def transport(self, perm):
......@@ -180,30 +179,6 @@ class CycleSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
if len(labels) != 0:
yield structure_class(self, labels, range(1, len(labels)+1))
def _gs_iterator(self, base_ring):
r"""
The generating series for cyclic permutations is
`-\log(1-x) = \sum_{n=1}^\infty x^n/n`.
EXAMPLES::
sage: P = species.CycleSpecies()
sage: g = P.generating_series()
sage: g.coefficients(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)
[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
def _order(self):
"""
Returns the order of the generating series.
......@@ -216,70 +191,92 @@ class CycleSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
"""
return 1
def _itgs_list(self, base_ring):
"""
The isomorphism type generating series for cyclic permutations is
given by `x/(1-x)`.
class GeneratingSeriesStream(SpeciesSeriesStream):
def compute(self, n):
r"""
The generating series for cyclic permutations is
`-\log(1-x) = \sum_{n=1}^\infty x^n/n`.
EXAMPLES::
EXAMPLES::
sage: P = species.CycleSpecies()
sage: g = P.isotype_generating_series()
sage: g.coefficients(5)
[0, 1, 1, 1, 1]
sage: P = species.CycleSpecies()
sage: g = P.generating_series()
sage: g.coefficients(10)
[0, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9]
TESTS::
TESTS::
sage: P = species.CycleSpecies()
sage: g = P.isotype_generating_series(RR)
sage: g.coefficients(3)
[0.000000000000000, 1.00000000000000, 1.00000000000000]
"""
return [base_ring(0), self._weight*base_ring(1)]
sage: P = species.CycleSpecies()
sage: g = P.generating_series(RR)
sage: g.coefficients(3)
[0.000000000000000, 1.00000000000000, 0.500000000000000]
"""
if n == 0:
return self._zero
else:
return self._base_ring(self._weight) / n
def _cis_iterator(self, base_ring):
r"""
The cycle index series of the species of cyclic permutations is
given by
class IsotypeGeneratingSeriesStream(SeriesStreamFromList, SpeciesSeriesStream):
def list(self):
"""
The isomorphism type generating series for cyclic permutations is
given by `x/(1-x)`.
.. math::
EXAMPLES::
-\sum_{k=1}^\infty \phi(k)/k * log(1 - x_k)
sage: P = species.CycleSpecies()
sage: g = P.isotype_generating_series()
sage: g.coefficients(5)
[0, 1, 1, 1, 1]
TESTS::
which is equal to
sage: P = species.CycleSpecies()
sage: g = P.isotype_generating_series(RR)
sage: g.coefficients(3)
[0.000000000000000, 1.00000000000000, 1.00000000000000]
"""
return [self._zero, self._weight*self._base_ring(1)]
.. math::
class CycleIndexSeriesStream(SpeciesSeriesStream):
def compute(self, n):
r"""
The cycle index series of the species of cyclic permutations is
given by
\sum_{n=1}^\infty \frac{1}{n} * \sum_{k|n} \phi(k) * x_k^{n/k}
.. math::
.
-\sum_{k=1}^\infty \phi(k)/k * log(1 - x_k)
EXAMPLES::
sage: P = species.CycleSpecies()
sage: cis = P.cycle_index_series()
sage: cis.coefficients(7)
[0,
p[1],
1/2*p[1, 1] + 1/2*p[2],
1/3*p[1, 1, 1] + 2/3*p[3],
1/4*p[1, 1, 1, 1] + 1/4*p[2, 2] + 1/2*p[4],
1/5*p[1, 1, 1, 1, 1] + 4/5*p[5],
1/6*p[1, 1, 1, 1, 1, 1] + 1/6*p[2, 2, 2] + 1/3*p[3, 3] + 1/3*p[6]]
"""
from sage.combinat.sf.sf import SymmetricFunctions
p = SymmetricFunctions(base_ring).power()
which is equal to
.. math::
\sum_{n=1}^\infty \frac{1}{n} * \sum_{k|n} \phi(k) * x_k^{n/k}
.
EXAMPLES::
zero = base_ring(0)
sage: P = species.CycleSpecies()
sage: cis = P.cycle_index_series()
sage: cis.coefficients(7)
[0,
p[1],
1/2*p[1, 1] + 1/2*p[2],
1/3*p[1, 1, 1] + 2/3*p[3],
1/4*p[1, 1, 1, 1] + 1/4*p[2, 2] + 1/2*p[4],
1/5*p[1, 1, 1, 1, 1] + 4/5*p[5],
1/6*p[1, 1, 1, 1, 1, 1] + 1/6*p[2, 2, 2] + 1/3*p[3, 3] + 1/3*p[6]]
"""
if n == 0:
return self._zero
yield zero
for n in _integers_from(1):
res = zero
res = self._zero
for k in divisors(n):
res += euler_phi(k)*p([k])**(n//k)
res /= n
yield self._weight*res
res += euler_phi(k)*self._base_ring([k])**(n//k)
return self._weight * res / n
#Backward compatibility
CycleSpecies_class = CycleSpecies
......@@ -16,7 +16,6 @@ Empty Species
# http://www.gnu.org/licenses/
#*****************************************************************************
from species import GenericCombinatorialSpecies
from sage.misc.cachefunc import cached_function
from series_order import inf
from sage.structure.unique_representation import UniqueRepresentation
......
......@@ -17,13 +17,12 @@ Functorial composition species
#*****************************************************************************
from species import GenericCombinatorialSpecies
from structure import GenericSpeciesStructure
from sage.misc.cachefunc import cached_function
from sage.structure.unique_representation import UniqueRepresentation
class FunctorialCompositionStructure(GenericSpeciesStructure):
pass
class FunctorialCompositionSpecies(GenericCombinatorialSpecies):
class FunctorialCompositionSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
def __init__(self, F, G, min=None, max=None, weight=None):
"""
Returns the functorial composition of two species.
......
......@@ -15,11 +15,10 @@ Linear-order Species
#
# http://www.gnu.org/licenses/
#*****************************************************************************
from species import GenericCombinatorialSpecies
from species import GenericCombinatorialSpecies, SpeciesSeriesStream
from series import SeriesStreamFromList
from structure import GenericSpeciesStructure
from generating_series import _integers_from
from sage.structure.unique_representation import UniqueRepresentation
from sage.misc.cachefunc import cached_function
from sage.combinat.species.misc import accept_size
class LinearOrderSpeciesStructure(GenericSpeciesStructure):
......@@ -123,48 +122,48 @@ class LinearOrderSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
"""
yield structure_class(self, labels, range(1, len(labels)+1))
def _gs_list(self, base_ring):
r"""
The generating series for the species of linear orders is
`\frac{1}{1-x}`.
EXAMPLES::
sage: L = species.LinearOrderSpecies()
sage: g = L.generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [base_ring(1)]
def _itgs_list(self, base_ring):
r"""
The isomorphism type generating series is given by
`\frac{1}{1-x}`.
EXAMPLES::
sage: L = species.LinearOrderSpecies()
sage: g = L.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [base_ring(1)]
def _cis_iterator(self, base_ring):
"""
EXAMPLES::
sage: L = species.LinearOrderSpecies()
sage: g = L.cycle_index_series()
sage: g.coefficients(5)
[p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]]
"""
from sage.combinat.sf.sf import SymmetricFunctions
p = SymmetricFunctions(base_ring).power()
for n in _integers_from(0):
yield p([1]*n)
class GeneratingSeriesStream(SeriesStreamFromList, SpeciesSeriesStream):
def list(self):
r"""
The generating series for the species of linear orders is
`\frac{1}{1-x}`.
EXAMPLES::
sage: L = species.LinearOrderSpecies()
sage: g = L.generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [self._base_ring(1)]
class IsotypeGeneratingSeriesStream(SeriesStreamFromList, SpeciesSeriesStream):
def list(self):
r"""
The isomorphism type generating series is given by
`\frac{1}{1-x}`.
EXAMPLES::
sage: L = species.LinearOrderSpecies()
sage: g = L.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [self._base_ring(1)]
class CycleIndexSeriesStream(SpeciesSeriesStream):
def compute(self, n):
"""
EXAMPLES::
sage: L = species.LinearOrderSpecies()
sage: g = L.cycle_index_series()
sage: g.coefficients(5)
[p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]]
"""
return self._base_ring([1]*n)
#Backward compatibility
LinearOrderSpecies_class = LinearOrderSpecies
"""
(New) Streams
This code provides a new implementation of the streams found at
:mod:`sage.combinat.species.stream`.
"""
#*****************************************************************************
# Copyright (C) 2013 Mike Hansen <mhansen@gmail.com>,
#
# Distributed under the terms of the GNU General Public License (GPL)
#
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# The full text of the GPL is available at:
#
# http://www.gnu.org/licenses/
#*****************************************************************************
from sage.structure.sage_object import SageObject
from sage.misc.misc import is_iterator
from sage.misc.abstract_method import abstract_method
def check_constant_decorator(func):
"""
A method decorator for ``__getitem__`` which checks is the stream
is (eventually) constant before computing the $n$-th
coefficient.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream, check_constant_decorator
sage: s = Stream()
sage: def foo(self, n):
....: return self.compute(n)
sage: import types
sage: s.foo = types.MethodType(check_constant_decorator(foo), s)
sage: s.set_constant(1, 3)
sage: s.compute(5)
Traceback (most recent call last):
...
NotImplementedError: <abstract method compute at ...>
sage: s.foo(5)
3
"""
from sage.misc.all import sage_wraps
@sage_wraps(func)
def wrapper(self, n):
if self._constant is not False or self.is_constant():
if self._constant is False:
self.set_constant(self.get_constant_position(),
self.get_constant())
pos, value = self._constant
if n >= pos:
return value
return func(self, n)
return wrapper
class Stream(SageObject):
"""
A base class for streams.
This class is typically subclassed.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: class NNStream(Stream):
....: def compute(self, n):
....: return n
sage: s = NNStream()
sage: [s[i] for i in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
def __init__(self):
"""
TESTS::
sage: from sage.combinat.species.new_stream import Stream
sage: class NNStream(Stream):
....: def compute(self, n):
....: pass
....: def __setitem__(self, n, value):
....: pass
sage: import __main__; __main__.NNStream = NNStream # fakes NNStream being defined in a Python module
sage: s = NNStream()
sage: s.is_constant()
False
Pickling fails because equality is not implemented::
sage: TestSuite(s).run()
Failure in _test_pickling:
...
AssertionError: <class '__main__.NNStream'> != <class '__main__.NNStream'>
------------------------------------------------------------
The following tests failed: _test_pickling
"""
self._constant = False
@abstract_method
def compute(self, n):
"""
Compute the $n$-th coefficient of this stream. This should
be overridden by subclasses.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: s = Stream()
sage: s.compute(2)
Traceback (most recent call last):
...
NotImplementedError: <abstract method compute at ...>
"""
@abstract_method
def __setitem__(self, n, value):
"""
Sets the $n$-th coefficient of this stream to ``value``.
This should be overridden by subclasses.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: s = Stream()
sage: s[0] = 2
Traceback (most recent call last):
...
NotImplementedError: <abstract method __setitem__ at ...>
"""
@check_constant_decorator
def __getitem__(self, n):
"""
Return the $n$-th coefficient of this stream.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: class MyStream(Stream):
....: def compute(self, n):
....: return n
sage: s = MyStream()
sage: s[10]
10
"""
return self.compute(n)
def is_constant(self):
"""
Return True if this stream is eventually constant.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: s = Stream()
sage: s.is_constant()
False
sage: s.set_constant(2, 4)
sage: s.is_constant()
True
"""
return self._constant is not False
def set_constant(self, n, value):
"""
Set this stream to be eventually constant at coefficient
``n`` with value ``value``.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: s = Stream()
sage: s.set_constant(0, 2)
sage: s.get_constant()
2
sage: s.get_constant_position()
0
sage: s[3]
2
"""
self._constant = (n, value)
def get_constant(self):
"""
Return the constant value if this stream is constant.
Precondition: Assume that the stream is constant.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: s = Stream()
sage: s.set_constant(0, 2)
sage: s.get_constant()
2
"""
assert self._constant is not False
return self._constant[1]
def get_constant_position(self):
"""
Return the position where this stream is constant.
Precondition: Assume that this stream is constant.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: s = Stream()
sage: s.set_constant(1, 2)
sage: s.get_constant_position()
1
"""
assert self._constant is not False
return self._constant[0]
def __iter__(self):
"""
Return an iterator for this stream.
EXAMPLES::
sage: from sage.combinat.species.new_stream import Stream
sage: s = Stream()
sage: s.set_constant(0, 2)
sage: it = iter(s)
sage: [it.next() for i in range(5)]
[2, 2, 2, 2, 2]
"""
i = 0
while True:
try:
yield self[i]
except IndexError:
break
i += 1
raise StopIteration
class ListCachedStream(Stream):
"""
A stream whose computed values are cached in a list.
Additionally, when the $n$-th coefficient is requested, it guarantees that
all the coefficients up to $n$ have been computed.
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromFunction, ListCachedStream
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: isinstance(s, ListCachedStream)
True
sage: s[5]
8
sage: s._cache
[1, 1, 2, 3, 5, 8]
"""
def __init__(self, **kwds):
"""
TESTS::
sage: from sage.combinat.species.new_stream import StreamFromFunction, ListCachedStream
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: isinstance(s, ListCachedStream)
True
sage: s[5]
8
sage: s._cache
[1, 1, 2, 3, 5, 8]
Pickling fails because we can not pickle a lambda::
sage: TestSuite(s).run()
Failure in _test_pickling:
...
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed
------------------------------------------------------------
The following tests failed: _test_pickling
"""
self._cache = []
super(ListCachedStream, self).__init__(**kwds)
def __setitem__(self, n, value):
"""
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromFunction, ListCachedStream
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: isinstance(s, ListCachedStream)
True
sage: s[1]
1
sage: s[0] = 2
sage: s[0]
2
sage: s[10]
123
sage: s[15] = 100
sage: s[15]
100
"""
pos = len(self._cache)
while n >= pos:
self[pos]
pos += 1
self._cache[n] = value
def length_of_cache(self):
"""
Return the number of coefficients that have been computed so
far.
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromFunction, ListCachedStream
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: isinstance(s, ListCachedStream)
True
sage: s[5]
8
sage: s.length_of_cache()
6
"""
return len(self._cache)
__len__ = length_of_cache
@check_constant_decorator
def __getitem__(self, n):
"""
Return the $n$-th coefficient of this stream, checking the
cache before trying to compute the value.
This method guarantees that all of the coefficients up to $n$
have been computed first.
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromFunction, ListCachedStream
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: isinstance(s, ListCachedStream)
True
sage: s[5]
8
sage: s._cache
[1, 1, 2, 3, 5, 8]
We check to see that values are indeed returned from the cache
if already computed::
sage: def foo(self, n):
....: raise NotImplementedError
sage: s.compute = foo
sage: s[2]
2
"""
pos = len(self._cache)
while pos <= n:
value = self.compute(pos)
self._cache.append(value)
pos += 1
return self._cache[n]
class StreamFromIterator(ListCachedStream):
"""
A `ListCachedStream` initialized by an iterator
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromIterator
sage: s = StreamFromIterator(iterator=NN)
sage: s[0]
0
sage: s[10]
10
"""
def __init__(self, iterator=None, **kwds):
"""
TESTS::
sage: from sage.combinat.species.new_stream import StreamFromIterator
sage: s = StreamFromIterator(iterator=NN)
sage: s[0]
0
sage: s[10]
10
Pickling fails because we can not pickle a generator::
sage: TestSuite(s).run()
Failure in _test_pickling:
...
PicklingError: Can't pickle <type 'generator'>: attribute lookup __builtin__.generator failed
------------------------------------------------------------
The following tests failed: _test_pickling
"""
self._it = iterator if is_iterator(iterator) else iter(iterator)
super(StreamFromIterator, self).__init__(**kwds)
def compute(self, n):
"""
EXAMPLES:
We test to make sure that iterator which finish iterating are
constant for the rest of the values::
sage: from sage.combinat.species.new_stream import StreamFromIterator
sage: s = StreamFromIterator(iter([1,2,3]))
sage: s[0]
1
sage: s.is_constant()
False
sage: s[2], s[10] # indirect doctest
(3, 3)
sage: s.is_constant()
True
"""
# ListCachedStream verifies that compute will be called with n in order
assert n == len(self._cache), "compute called out of order"
try:
return self._it.next()
except StopIteration:
value = self._cache[-1]
self.set_constant(len(self._cache) - 1, value)
return value
class StreamFromFunction(ListCachedStream):
"""
A `ListCachedStream` initialized by a function of $n$ which
return the $n$-th coefficient.
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromFunction
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: s[0]
1
sage: s[1]
1
sage: s[2]
2
sage: s[10]
89
"""
def __init__(self, func=None, **kwds):
"""
TESTS::
sage: from sage.combinat.species.new_stream import StreamFromFunction
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: s[0]
1
sage: s[1]
1
sage: s[2]
2
sage: s[10]
89
Pickling fails because we can not pickle a lambda::
sage: TestSuite(s).run()
Failure in _test_pickling:
...
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed
------------------------------------------------------------
The following tests failed: _test_pickling
"""
self._func = func
super(StreamFromFunction, self).__init__(**kwds)
def compute(self, n):
"""
.. note::
This should not be called directly. Instead, you should
use :meth:`__getitem__`.
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromFunction
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = StreamFromFunction(h)
sage: s.compute(0)
1
sage: s.compute(2)
Traceback (most recent call last):
...
AssertionError: compute called out of order
"""
# ListCachedStream verifies that compute will be called with n in order
assert n == len(self._cache), "compute called out of order"
return self._func(self._cache)
class StreamFromList(ListCachedStream):
"""
A `ListCachedStream` initialized by a list.
EXAMPLES::
sage: from sage.combinat.species.new_stream import StreamFromList
sage: s = StreamFromList([1,2,3])
sage: s[0]
1
sage: s[5]
3
"""
def __init__(self, list=None, **kwds):
"""
TESTS::
sage: from sage.combinat.species.new_stream import StreamFromList
sage: s = StreamFromList([1,2,3])
sage: s[0]
1
sage: s[5]
3
:meth`compute` does not need to be implemented for this kind of stream.
Pickling fails because equality is not implemented::
sage: TestSuite(s).run()
Failure in _test_not_implemented_methods:
...
AssertionError: Not implemented method: compute
------------------------------------------------------------
Failure in _test_pickling:
...
AssertionError: <class 'sage.combinat.species.new_stream.StreamFromList'> != <class 'sage.combinat.species.new_stream.StreamFromList'>
------------------------------------------------------------
The following tests failed: _test_not_implemented_methods, _test_pickling
"""
super(StreamFromList, self).__init__(**kwds)
if list is None:
list = self.list()
if len(list) < 0:
raise ValueError("list cannot be empty")
self._cache = list[:]
self.set_constant(len(list) - 1, list[-1])
def OldStreamBehavior(x=None, const=None):
"""
A function which emulates the behavior of
:func:`sage.combinat.species.stream.Stream` using
:class:`sage.combinat.species.new_stream.Stream`.
EXAMPLES::
sage: from sage.combinat.species.new_stream import OldStreamBehavior
sage: s = OldStreamBehavior(const=3)
sage: [s[i] for i in range(5)]
[3, 3, 3, 3, 3]
sage: s = OldStreamBehavior([1,2,3])
sage: [s[i] for i in range(5)]
[1, 2, 3, 3, 3]
sage: s = OldStreamBehavior(iter([1,2,3]))
sage: [s[i] for i in range(5)]
[1, 2, 3, 3, 3]
sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2]
sage: s = OldStreamBehavior(h)
sage: [s[i] for i in range(10)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
sage: s = OldStreamBehavior(4)
sage: [s[i] for i in range(5)]
[4, 0, 0, 0, 0]
"""
import types
if const is not None:
s = Stream()
s.set_constant(0, const)
return s
elif isinstance(x, list):
return StreamFromList(x)
elif hasattr(x, '__iter__'):
return StreamFromIterator(iter(x))
elif isinstance(x, (types.FunctionType, types.LambdaType)):
return StreamFromFunction(x)
else:
return StreamFromIterator(iter([x,0]))
......@@ -16,14 +16,14 @@ Partition Species
# http://www.gnu.org/licenses/
#*****************************************************************************
from species import GenericCombinatorialSpecies
from generating_series import _integers_from, factorial_stream
from species import GenericCombinatorialSpecies, SpeciesSeriesStream
from generating_series import factorial_stream
from subset_species import SubsetSpeciesStructure
from set_species import SetSpecies
from structure import GenericSpeciesStructure
from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.all import ZZ
from sage.misc.cachefunc import cached_function
from sage.sets.all import PositiveIntegers
from sage.combinat.species.misc import accept_size
from functools import reduce
......@@ -123,7 +123,7 @@ class PartitionSpeciesStructure(GenericSpeciesStructure):
return PartitionSpeciesStructure(self.parent(), labels, [block.change_labels(labels) for block in self._list])
class PartitionSpecies(GenericCombinatorialSpecies):
class PartitionSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
@staticmethod
@accept_size
def __classcall__(cls, *args, **kwds):
......@@ -223,34 +223,34 @@ class PartitionSpecies(GenericCombinatorialSpecies):
breaks = [sum(p[:i]) for i in range(len(p)+1)]
return structure_class(self, labels, [range(breaks[i]+1, breaks[i+1]+1) for i in range(len(p))])
def _gs_iterator(self, base_ring):
r"""
EXAMPLES::
sage: P = species.PartitionSpecies()
sage: g = P.generating_series()
sage: g.coefficients(5)
[1, 1, 1, 5/6, 5/8]
"""
from sage.combinat.combinat import bell_number
for n in _integers_from(0):
yield self._weight*base_ring(bell_number(n)/factorial_stream[n])
def _itgs_iterator(self, base_ring):
r"""
The isomorphism type generating series is given by
`\frac{1}{1-x}`.
EXAMPLES::
sage: P = species.PartitionSpecies()
sage: g = P.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30]
"""
from sage.combinat.partitions import number_of_partitions
for n in _integers_from(0):
yield self._weight*base_ring(number_of_partitions(n))
class GeneratingSeriesStream(SpeciesSeriesStream):
def compute(self, n):
r"""
EXAMPLES::
sage: P = species.PartitionSpecies()
sage: g = P.generating_series()
sage: g.coefficients(5)
[1, 1, 1, 5/6, 5/8]
"""
from sage.combinat.combinat import bell_number
return self._weight*self._base_ring(bell_number(n)/factorial_stream[n])
class IsotypeGeneratingSeriesStream(SpeciesSeriesStream):
def compute(self, n):
r"""
The isomorphism type generating series is given by
`\frac{1}{1-x}`.
EXAMPLES::
sage: P = species.PartitionSpecies()
sage: g = P.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30]
"""
from sage.combinat.partitions import number_of_partitions
return self._weight * self._base_ring(number_of_partitions(n))
def _cis(self, series_ring, base_ring):
r"""
......@@ -260,8 +260,6 @@ class PartitionSpecies(GenericCombinatorialSpecies):
exp \sum_{n \ge 1} \frac{1}{n} \left( exp \left( \sum_{k \ge 1} \frac{x_{kn}}{k} \right) -1 \right).
EXAMPLES::
sage: P = species.PartitionSpecies()
......@@ -273,6 +271,7 @@ class PartitionSpecies(GenericCombinatorialSpecies):
5/6*p[1, 1, 1] + 3/2*p[2, 1] + 2/3*p[3],
5/8*p[1, 1, 1, 1] + 7/4*p[2, 1, 1] + 7/8*p[2, 2] + p[3, 1] + 3/4*p[4]]
"""
PP = PositiveIntegers()
ciset = SetSpecies().cycle_index_series(base_ring)
res = ciset.composition(ciset - 1)
if self.is_weighted():
......
......@@ -15,13 +15,12 @@ Permutation species
#
# http://www.gnu.org/licenses/
#*****************************************************************************
from species import GenericCombinatorialSpecies
from species import GenericCombinatorialSpecies, SpeciesSeriesStream
from series import SeriesStreamFromList
from structure import GenericSpeciesStructure
from generating_series import _integers_from
from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.all import ZZ
from sage.misc.cachefunc import cached_function
from sage.combinat.permutation import Permutation, Permutations
from sage.combinat.partition import Partitions
from sage.combinat.species.misc import accept_size
class PermutationSpeciesStructure(GenericSpeciesStructure):
......@@ -55,7 +54,6 @@ class PermutationSpeciesStructure(GenericSpeciesStructure):
sage: a.permutation_group_element()
(2,3)
"""
from sage.groups.all import PermutationGroupElement
return Permutation(self._list).to_permutation_group_element()
def transport(self, perm):
......@@ -162,7 +160,6 @@ class PermutationSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
sage: P.isotypes([1,2,3]).list()
[[2, 3, 1], [2, 1, 3], [1, 2, 3]]
"""
from sage.combinat.partition import Partitions
if labels == []:
yield structure_class(self, labels, [])
return
......@@ -186,83 +183,59 @@ class PermutationSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
return structure_class(self, labels, perm)
def _gs_list(self, base_ring):
r"""
The generating series for the species of linear orders is
`\frac{1}{1-x}`.
class GeneratingSeriesStream(SeriesStreamFromList, SpeciesSeriesStream):
def list(self):
r"""
The generating series for the species of linear orders is
`\frac{1}{1-x}`.
EXAMPLES::
sage: P = species.PermutationSpecies()
sage: g = P.generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [base_ring(1)]
def _itgs_iterator(self, base_ring):
r"""
The isomorphism type generating series is given by
`\frac{1}{1-x}`.
EXAMPLES::
sage: P = species.PermutationSpecies()
sage: g = P.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30]
"""
from sage.combinat.partitions import number_of_partitions
for n in _integers_from(0):
yield base_ring(number_of_partitions(n))
EXAMPLES::
sage: P = species.PermutationSpecies()
sage: g = P.generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [self._base_ring(1)]
def _cis(self, series_ring, base_ring):
r"""
The cycle index series for the species of permutations is given by
class IsotypeGeneratingSeriesStream(SpeciesSeriesStream):
def compute(self, n):
r"""
The isomorphism type generating series is given by
`\frac{1}{1-x}`.
.. math::
EXAMPLES::
\prod{n=1}^\infty \frac{1}{1-x_n}.
sage: P = species.PermutationSpecies()
sage: g = P.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30]
"""
from sage.combinat.partitions import number_of_partitions
return self._base_ring(number_of_partitions(n))
class CycleIndexSeriesStream(SpeciesSeriesStream):
def compute(self, n):
r"""
The cycle index series for the species of permutations is given by
EXAMPLES::
sage: P = species.PermutationSpecies()
sage: g = P.cycle_index_series()
sage: g.coefficients(5)
[p[],
p[1],
p[1, 1] + p[2],
p[1, 1, 1] + p[2, 1] + p[3],
p[1, 1, 1, 1] + p[2, 1, 1] + p[2, 2] + p[3, 1] + p[4]]
"""
CIS = series_ring
return CIS.product_generator( CIS(self._cis_gen(base_ring, i)) for i in _integers_from(ZZ(1)) )
def _cis_gen(self, base_ring, n):
"""
EXAMPLES::
sage: P = species.PermutationSpecies()
sage: g = P._cis_gen(QQ, 2)
sage: [next(g) for i in range(10)]
[p[], 0, p[2], 0, p[2, 2], 0, p[2, 2, 2], 0, p[2, 2, 2, 2], 0]
"""
from sage.combinat.sf.sf import SymmetricFunctions
p = SymmetricFunctions(base_ring).power()
.. math::
pn = p([n])
\prod{n=1}^\infty \frac{1}{1-x_n}.
n = n - 1
yield p(1)
EXAMPLES::
for k in _integers_from(1):
for i in range(n):
yield base_ring(0)
yield pn**k
sage: P = species.PermutationSpecies()
sage: g = P.cycle_index_series()
sage: g.coefficients(5)
[p[],
p[1],
p[1, 1] + p[2],
p[1, 1, 1] + p[2, 1] + p[3],
p[1, 1, 1, 1] + p[2, 1, 1] + p[2, 2] + p[3, 1] + p[4]]
"""
return self._base_ring.sum_of_monomials(Partitions(n))
#Backward compatibility
PermutationSpecies_class = PermutationSpecies
......@@ -18,7 +18,6 @@ Sum species
from species import GenericCombinatorialSpecies
from structure import GenericSpeciesStructure
from subset_species import SubsetSpecies
from sage.misc.cachefunc import cached_function
from sage.structure.unique_representation import UniqueRepresentation
class ProductSpeciesStructure(GenericSpeciesStructure):
......@@ -165,12 +164,11 @@ class ProductSpeciesStructure(GenericSpeciesStructure):
sage: [a.transport(g) for g in a.automorphism_group()]
[{2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}]
"""
from sage.groups.all import PermutationGroupElement, PermutationGroup, SymmetricGroup
from sage.groups.all import PermutationGroupElement, PermutationGroup
from sage.misc.misc import uniq
from sage.combinat.species.misc import change_support
left, right = self._list
n = len(self._labels)
#Get the supports for each of the sides
l_support = self._subset._list
......
......@@ -209,7 +209,7 @@ class CombinatorialSpecies(GenericCombinatorialSpecies):
sage: F = CombinatorialSpecies()
sage: F.generating_series()
Uninitialized lazy power series
O(1)
"""
if base_ring not in self._generating_series:
self._generating_series[base_ring] = series_ring()
......@@ -226,7 +226,7 @@ class CombinatorialSpecies(GenericCombinatorialSpecies):
sage: F = CombinatorialSpecies()
sage: F.isotype_generating_series()
Uninitialized lazy power series
O(1)
"""
if base_ring not in self._isotype_generating_series:
self._isotype_generating_series[base_ring] = series_ring()
......@@ -243,7 +243,7 @@ class CombinatorialSpecies(GenericCombinatorialSpecies):
sage: F = CombinatorialSpecies()
sage: F.cycle_index_series()
Uninitialized lazy power series
O(1)
"""
if base_ring not in self._cycle_index_series:
self._cycle_index_series[base_ring] = series_ring()
......
This diff is collapsed.
This diff is collapsed.
......@@ -15,12 +15,14 @@ Set Species
#
# http://www.gnu.org/licenses/
#*****************************************************************************
from species import GenericCombinatorialSpecies
from generating_series import factorial_stream, _integers_from
from species import GenericCombinatorialSpecies, SpeciesSeriesStream
from generating_series import factorial_stream
from series import SeriesStreamFromList
from sage.combinat.species.structure import GenericSpeciesStructure
from sage.misc.cachefunc import cached_function
from sage.combinat.species.misc import accept_size
from sage.combinat.sf.sf import SymmetricFunctions
from sage.structure.unique_representation import UniqueRepresentation
from sage.sets.all import PositiveIntegers
class SetSpeciesStructure(GenericSpeciesStructure):
def __repr__(self):
......@@ -128,38 +130,51 @@ class SetSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
_isotypes = _structures
def _gs_iterator(self, base_ring):
r"""
The generating series for the species of sets is given by
`e^x`.
EXAMPLES::
sage: S = species.SetSpecies()
sage: g = S.generating_series()
sage: g.coefficients(10)
[1, 1, 1/2, 1/6, 1/24, 1/120, 1/720, 1/5040, 1/40320, 1/362880]
sage: [g.count(i) for i in range(10)]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
def _order(self):
"""
for n in _integers_from(0):
yield base_ring(self._weight/factorial_stream[n])
def _itgs_list(self, base_ring):
r"""
The isomorphism type generating series for the species of sets is
`\frac{1}{1-x}`.
Returns the order of the species.
EXAMPLES::
sage: S = species.SetSpecies()
sage: g = S.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
sage: [g.count(i) for i in range(10)]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [base_ring(self._weight)]
sage: S._order()
0
"""
return 0
class GeneratingSeriesStream(SpeciesSeriesStream):
def compute(self, n):
r"""
The generating series for the species of sets is given by
`e^x`.
EXAMPLES::
sage: S = species.SetSpecies()
sage: g = S.generating_series()
sage: g.coefficients(10)
[1, 1, 1/2, 1/6, 1/24, 1/120, 1/720, 1/5040, 1/40320, 1/362880]
sage: [g.count(i) for i in range(10)]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return self._base_ring(self._weight) / factorial_stream[n]
class IsotypeGeneratingSeriesStream(SeriesStreamFromList, SpeciesSeriesStream):
def list(self):
r"""
The isomorphism type generating series for the species of sets is
`\frac{1}{1-x}`.
EXAMPLES::
sage: S = species.SetSpecies()
sage: g = S.isotype_generating_series()
sage: g.coefficients(10)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
sage: [g.count(i) for i in range(10)]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
"""
return [self._base_ring(self._weight)]
def _cis(self, series_ring, base_ring):
r"""
......@@ -177,12 +192,9 @@ class SetSpecies(GenericCombinatorialSpecies, UniqueRepresentation):
1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3],
1/24*p[1, 1, 1, 1] + 1/4*p[2, 1, 1] + 1/8*p[2, 2] + 1/3*p[3, 1] + 1/4*p[4]]
"""
from generating_series import ExponentialCycleIndexSeries
res = ExponentialCycleIndexSeries(base_ring)
res = series_ring.exponential()
if self.is_weighted():
res *= self._weight
return res
......
......@@ -50,7 +50,9 @@ three internal nodes.
#
# http://www.gnu.org/licenses/
#*****************************************************************************
from generating_series import OrdinaryGeneratingSeriesRing, ExponentialGeneratingSeriesRing, CycleIndexSeriesRing
from generating_series import (OrdinaryGeneratingSeriesRing, ExponentialGeneratingSeriesRing,
CycleIndexSeriesRing)
from series import SeriesStream, TermStream
from sage.rings.all import QQ
from sage.structure.sage_object import SageObject
from sage.misc.cachefunc import cached_method
......@@ -58,6 +60,55 @@ from sage.combinat.species.misc import accept_size
from sage.combinat.species.structure import StructuresWrapper, IsotypesWrapper
from functools import reduce
class SpeciesSeriesStream(SeriesStream):
def __init__(self, weight=None, species=None, **kwds):
"""
A SeriesStream which knows about the weight of the species as
well as its order.
EXAMPLES::
sage: from sage.combinat.species.species import SpeciesSeriesStream
sage: S = species.SetSpecies(min=2)
sage: s = SpeciesSeriesStream(weight=S.weight(), species=S, base_ring=QQ)
"""
assert species is not None
self._species = species