### Navigation

- index
- modules |
- next |
- previous |
- Combinatorics »
- Combinatorial Species »

# Generating Series

This file makes a number of extensions to lazy power series by endowing them with some semantic content for how they’re to be interpreted.

This code is based on the work of Ralf Hemmecke and Martin Rubey’s Aldor-Combinat, which can be found at http://www.risc.uni-linz.ac.at/people/hemmecke/aldor/combinat/index.html. In particular, the relevant section for this file can be found at http://www.risc.uni-linz.ac.at/people/hemmecke/AldorCombinat/combinatse10.html. One notable difference is that we use power-sum symmetric functions as the coefficients of our cycle index series.

TESTS:

    sage: from sage.combinat.species.stream import Stream, _integers_from
    sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
    sage: p = SymmetricFunctions(QQ).power()
    sage: CIS = CycleIndexSeriesRing(QQ)

    sage: geo1 = CIS((p([1])^i  for i in _integers_from(0)))
    sage: geo2 = CIS((p([2])^i  for i in _integers_from(0)))
    sage: s = geo1 * geo2
    sage: s[0]
    p[]
    sage: s[1]
    p[1] + p[2]
    sage: s[2]
    p[1, 1] + p[2, 1] + p[2, 2]
    sage: s[3]
    p[1, 1, 1] + p[2, 1, 1] + p[2, 2, 1] + p[2, 2, 2]

Whereas the coefficients of the above test are homogeneous with respect to total degree, the following test groups with respect to weighted degree where each variable x_i has weight i.

    sage: def g():
    ....:     for i in _integers_from(0):
    ....:         yield p([2])^i
    ....:         yield p(0)
    sage: geo1 = CIS((p([1])^i  for i in _integers_from(0)))
    sage: geo2 = CIS(g())
    sage: s = geo1 * geo2
    sage: s[0]
    p[]
    sage: s[1]
    p[1]
    sage: s[2]
    p[1, 1] + p[2]
    sage: s[3]
    p[1, 1, 1] + p[2, 1]
    sage: s[4]
    p[1, 1, 1, 1] + p[2, 1, 1] + p[2, 2]

class `sage.combinat.species.generating_series.``CycleIndexSeries`(A, stream=None, order=None, aorder=None, aorder_changed=True, is_initialized=False, name=None)

  Bases: `sage.combinat.species.series.LazyPowerSeries`

  EXAMPLES:

      sage: L = LazyPowerSeriesRing(QQ)
      sage: f = L()
      sage: loads(dumps(f))
      Uninitialized lazy power series

  `arithmetic_product`(g, check_input=True)

    Return the arithmetic product of `self` with `g`.

    For species \(M\) and \(N\) such that \(M[\varnothing] = N[\varnothing] = \varnothing\), their arithmetic product is the species \(M \boxdot N\) of “\(M\)-assemblies of cloned \(N\)-structures”. This operation is defined and several examples are given in [MM].

    The cycle index series for \(M \boxdot N\) can be computed in terms of the component series \(Z_M\) and \(Z_N\), as implemented in this method.

    INPUT:

    - `g` – a cycle index series having the same parent as `self`.
    - `check_input` – (default: `True`) a Boolean which, when set to `False`, will cause input checks to be skipped.

    OUTPUT:

    The arithmetic product of `self` with `g`. This is a cycle index series defined in terms of `self` and `g` such that if `self` and `g` are the cycle index series of two species \(M\) and \(N\), their arithmetic product is the cycle index series of the species \(M \boxdot N\).

    EXAMPLES:

    For \(C\) the species of (oriented) cycles and \(L_{+}\) the species of nonempty linear orders, \(C \boxdot L_{+}\) corresponds to the species of “regular octopuses”; a \((C \boxdot L_{+})\)-structure is a cycle of some length, each of whose elements is an ordered list of a length which is consistent for all the lists in the structure.

        sage: C = species.CycleSpecies().cycle_index_series()
        sage: Lplus = species.LinearOrderSpecies(min=1).cycle_index_series()
        sage: RegularOctopuses = C.arithmetic_product(Lplus)
        sage: RegOctSpeciesSeq = RegularOctopuses.generating_series().counts(8)
        sage: RegOctSpeciesSeq
        [0, 1, 3, 8, 42, 144, 1440, 5760]

    It is shown in [MM] that the exponential generating function for regular octopuses satisfies \((C \boxdot L_{+}) (x) = \sum_{n \geq 1} \sigma (n) (n - 1)! \frac{x^{n}}{n!}\) (where \(\sigma (n)\) is the sum of the divisors of \(n\)).

        sage: RegOctDirectSeq = [0] + [sum(divisors(i))*factorial(i-1) for i in range(1,8)]
        sage: RegOctDirectSeq == RegOctSpeciesSeq
        True

    AUTHORS:

    - Andrew Gainer-Dewar (2013)

    REFERENCES:

    [MM] | (1, 2) M. Maia and M. Mendez. “On the arithmetic product of combinatorial species”. Discrete Mathematics, vol. 308, issue 23, 2008, pp. 5407-5427. Arxiv math/0503436v2.

  `coefficient_cycle_type`(t)

    Returns the coefficient of a cycle type t.

    EXAMPLES:

        sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
        sage: p = SymmetricFunctions(QQ).power()
        sage: CIS = CycleIndexSeriesRing(p)
        sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])])
        sage: f.coefficient_cycle_type([1])
        1
        sage: f.coefficient_cycle_type([1,1])
        2
        sage: f.coefficient_cycle_type([2,1])
        3

  `compositional_inverse`()

    Return the compositional inverse of `self` if possible.

    (Specifically, if `self` is of the form \(0 + p_{1} + \dots\).)

    The compositional inverse is the inverse with respect to plethystic substitution. This is the operation on cycle index series which corresponds to substitution, a.k.a. partitional composition, on the level of species. See Section 2.2 of [BLL] for a definition of this operation.

    EXAMPLES:

        sage: Eplus = species.SetSpecies(min=1).cycle_index_series()
        sage: Eplus(Eplus.compositional_inverse()).coefficients(8)
        [0, p[1], 0, 0, 0, 0, 0, 0]

    TESTS:

        sage: Eplus = species.SetSpecies(min=2).cycle_index_series()
        sage: Eplus.compositional_inverse()
        Traceback (most recent call last):
        ...
        ValueError: not an invertible series

    ALGORITHM:

    Let \(F\) be a species satisfying \(F = 0 + X + F_2 + F_3 + \dots\) for \(X\) the species of singletons. (Equivalently, \(\lvert F[\varnothing] \rvert = 0\) and \(\lvert F[\{1\}] \rvert = 1\).) Then there exists a (virtual) species \(G\) satisfying \(F \circ G = G \circ F = X\).

    It follows that \((F - X) \circ G = F \circ G - X \circ G = X - G\). Rearranging, we obtain the recursive equation \(G = X - (F - X) \circ G\), which can be solved using iterative methods.

    Warning

    This algorithm is functional but can be very slow. Use with caution!

    See also

    The compositional inverse \(\Omega\) of the species \(E_{+}\) of nonempty sets can be handled much more efficiently using specialized methods. These are implemented in `CombinatorialLogarithmSeries`.

    AUTHORS:

    - Andrew Gainer-Dewar
  `count`(t)

    Returns the number of structures corresponding to a certain cycle type.

    EXAMPLES:

        sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
        sage: p = SymmetricFunctions(QQ).power()
        sage: CIS = CycleIndexSeriesRing(p)
        sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])])
        sage: f.count([1])
        1
        sage: f.count([1,1])
        4
        sage: f.count([2,1])
        6

  `expand_as_sf`(n, alphabet='x')

    Returns the expansion of a cycle index series as a symmetric function in `n` variables.

    Specifically, this returns a `LazyPowerSeries` whose ith term is obtained by calling `expand()` on the ith term of `self`.

    This relies on the (standard) interpretation of a cycle index series as a symmetric function in the power sum basis.

    INPUT:

    - `self` – a cycle index series
    - `n` – a positive integer
    - `alphabet` – a variable for the expansion (default: \(x\))

    EXAMPLES:

        sage: from sage.combinat.species.set_species import SetSpecies
        sage: SetSpecies().cycle_index_series().expand_as_sf(2).coefficients(4)
        [1, x0 + x1, x0^2 + x0*x1 + x1^2, x0^3 + x0^2*x1 + x0*x1^2 + x1^3]

  `functorial_composition`(g)

    Returns the functorial composition of self and g.

    If \(F\) and \(G\) are species, their functorial composition is the species \(F \Box G\) obtained by setting \((F \Box G) [A] = F[ G[A] ]\). In other words, an \((F \Box G)\)-structure on a set \(A\) of labels is an \(F\)-structure whose labels are the set of all \(G\)-structures on \(A\).

    It can be shown (as in section 2.2 of [BLL]) that there is a corresponding operation on cycle indices:

    \[Z_{F} \Box Z_{G} = \sum_{n \geq 0} \frac{1}{n!} \sum_{\sigma \in \mathfrak{S}_{n}} \operatorname{fix} F[ (G[\sigma])_{1}, (G[\sigma])_{2}, \dots ] \, p_{1}^{\sigma_{1}} p_{2}^{\sigma_{2}} \dots.\]

    This method implements that operation on cycle index series.

    EXAMPLES:

    The species \(G\) of simple graphs can be expressed in terms of a functorial composition: \(G = \mathfrak{p} \Box \mathfrak{p}_{2}\), where \(\mathfrak{p}\) is the `SubsetSpecies`. This is how it is implemented in `SimpleGraphSpecies()`:

        sage: S = species.SimpleGraphSpecies()
        sage: S.cycle_index_series().coefficients(5)
        [p[],
         p[1],
         p[1, 1] + p[2],
         4/3*p[1, 1, 1] + 2*p[2, 1] + 2/3*p[3],
         8/3*p[1, 1, 1, 1] + 4*p[2, 1, 1] + 2*p[2, 2] + 4/3*p[3, 1] + p[4]]

  `generating_series`()

    EXAMPLES:

        sage: P = species.PartitionSpecies()
        sage: cis = P.cycle_index_series()
        sage: f = cis.generating_series()
        sage: f.coefficients(5)
        [1, 1, 1, 5/6, 5/8]

  `isotype_generating_series`()

    EXAMPLES:

        sage: P = species.PermutationSpecies()
        sage: cis = P.cycle_index_series()
        sage: f = cis.isotype_generating_series()
        sage: f.coefficients(10)
        [1, 1, 2, 3, 5, 7, 11, 15, 22, 30]

  `stretch`(k)

    Returns the stretch of a cycle index series by a positive integer \(k\).

    If

    \[f = \sum_{n=0}^{\infty} f_n(x_1, x_2, \ldots, x_n),\]

    then the stretch \(g\) of \(f\) by \(k\) is

    \[g = \sum_{n=0}^{\infty} f_n(x_k, x_{2k}, \ldots, x_{nk}).\]

    EXAMPLES:

        sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
        sage: p = SymmetricFunctions(QQ).power()
        sage: CIS = CycleIndexSeriesRing(p)
        sage: f = CIS([p([1])])
        sage: f.stretch(3).coefficients(10)
        [p[3], 0, 0, p[3], 0, 0, p[3], 0, 0, p[3]]

  `weighted_composition`(y_species)

    Returns the composition of this cycle index series with the cycle index series of y_species where y_species is a weighted species.

    Note that this is basically the same algorithm as composition except we can not use the optimization that the powering of cycle index series commutes with ‘stretching’.

    EXAMPLES:

        sage: E = species.SetSpecies(); C = species.CycleSpecies()
        sage: E_cis = E.cycle_index_series()
        sage: E_cis.weighted_composition(C).coefficients(4)
        [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]]
        sage: E(C).cycle_index_series().coefficients(4)
        [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]]

`sage.combinat.species.generating_series.``CycleIndexSeriesRing`(R)

  Returns the ring of cycle index series. Note that is is just a LazyPowerSeriesRing whose elements have some extra methods.

  EXAMPLES:

      sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
      sage: R = CycleIndexSeriesRing(QQ); R
      Cycle Index Series Ring over Symmetric Functions over Rational Field in the powersum basis
      sage: R([1]).coefficients(4)
      [1, 1, 1, 1]

  TESTS: We test to make sure that caching works.

      sage: R is CycleIndexSeriesRing(QQ)
      True

class `sage.combinat.species.generating_series.``CycleIndexSeriesRing_class`(R)

  Bases: `sage.combinat.species.series.LazyPowerSeriesRing`

  EXAMPLES:

      sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
      sage: R = CycleIndexSeriesRing(QQ); R
      Cycle Index Series Ring over Symmetric Functions over Rational Field in the powersum basis
      sage: R == loads(dumps(R))
      True

class `sage.combinat.species.generating_series.``ExponentialGeneratingSeries`(A, stream=None, order=None, aorder=None, aorder_changed=True, is_initialized=False, name=None)

  Bases: `sage.combinat.species.series.LazyPowerSeries`

  EXAMPLES:

      sage: L = LazyPowerSeriesRing(QQ)
      sage: f = L()
      sage: loads(dumps(f))
      Uninitialized lazy power series

  `count`(n)

    Returns the number of structures of size n.

    EXAMPLES:

        sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing
        sage: R = ExponentialGeneratingSeriesRing(QQ)
        sage: f = R([1])
        sage: [f.count(i) for i in range(7)]
        [1, 1, 2, 6, 24, 120, 720]

  `counts`(n)

    Returns the number of structures on a set for size i for i in range(n).

    EXAMPLES:

        sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing
        sage: R = ExponentialGeneratingSeriesRing(QQ)
        sage: f = R(range(20))
        sage: f.counts(5)
        [0, 1, 4, 18, 96]

  `functorial_composition`(y)

    Returns the exponential generating series which is the functorial composition of self with y.

    If \(f = \sum_{n=0}^{\infty} f_n \frac{x^n}{n!}\) and \(g = \sum_{n=0}^{\infty} f_n \frac{x^n}{n!}\), then functorial composition \(f \Box g\) is defined as

    \[f \Box g = \sum_{n=0}^{\infty} f_{g_n} \frac{x^n}{n!}\]

    REFERENCES:

    - Section 2.2 of [BLL].

    EXAMPLES:

        sage: G = species.SimpleGraphSpecies()
        sage: g = G.generating_series()
        sage: g.coefficients(10)
        [1, 1, 1, 4/3, 8/3, 128/15, 2048/45, 131072/315, 2097152/315, 536870912/2835]

`sage.combinat.species.generating_series.``ExponentialGeneratingSeriesRing`(R)

  Returns the ring of ordinary generating series. Note that is is just a LazyPowerSeriesRing whose elements have some extra methods.

  EXAMPLES:

      sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing
      sage: R = ExponentialGeneratingSeriesRing(QQ); R
      Lazy Power Series Ring over Rational Field
      sage: R([1]).coefficients(4)
      [1, 1, 1, 1]
      sage: R([1]).counts(4)
      [1, 1, 2, 6]

  TESTS: We test to make sure that caching works.

      sage: R is ExponentialGeneratingSeriesRing(QQ)
      True

class `sage.combinat.species.generating_series.``ExponentialGeneratingSeriesRing_class`(R)

  Bases: `sage.combinat.species.series.LazyPowerSeriesRing`

  EXAMPLES:

      sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing
      sage: R = ExponentialGeneratingSeriesRing(QQ)
      sage: R == loads(dumps(R))
      True

class `sage.combinat.species.generating_series.``OrdinaryGeneratingSeries`(A, stream=None, order=None, aorder=None, aorder_changed=True, is_initialized=False, name=None)

  Bases: `sage.combinat.species.series.LazyPowerSeries`

  EXAMPLES:

      sage: L = LazyPowerSeriesRing(QQ)
      sage: f = L()
      sage: loads(dumps(f))
      Uninitialized lazy power series

  `count`(n)

    Returns the number of structures on a set of size n.

    EXAMPLES:

        sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing
        sage: R = OrdinaryGeneratingSeriesRing(QQ)
        sage: f = R(range(20))
        sage: f.count(10)
        10

  `counts`(n)

    Returns the number of structures on a set for size i for i in range(n).

    EXAMPLES:

        sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing
        sage: R = OrdinaryGeneratingSeriesRing(QQ)
        sage: f = R(range(20))
        sage: f.counts(10)
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

`sage.combinat.species.generating_series.``OrdinaryGeneratingSeriesRing`(R)

  Returns the ring of ordinary generating series.

  Note that is is just a LazyPowerSeriesRing whose elements have some extra methods.

  EXAMPLES:

      sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing
      sage: R = OrdinaryGeneratingSeriesRing(QQ); R
      Lazy Power Series Ring over Rational Field
      sage: R([1]).coefficients(4)
      [1, 1, 1, 1]
      sage: R([1]).counts(4)
      [1, 1, 1, 1]

  TESTS: We test to make sure that caching works.

      sage: R is OrdinaryGeneratingSeriesRing(QQ)
      True

class `sage.combinat.species.generating_series.``OrdinaryGeneratingSeriesRing_class`(R)

  Bases: `sage.combinat.species.series.LazyPowerSeriesRing`

  EXAMPLES:

      sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing
      sage: R = OrdinaryGeneratingSeriesRing(QQ)
      sage: R == loads(dumps(R))
      True

`sage.combinat.species.generating_series.``factorial_gen`()

  A generator for the factorials starting at 0.

  EXAMPLES:

      sage: from sage.combinat.species.generating_series import factorial_gen
      sage: g = factorial_gen()
      sage: [g.next() for i in range(5)]
      [1, 1, 2, 6, 24]

### Navigation

- index
- modules |
- next |
- previous |
- Combinatorics »
- Combinatorial Species »