Lazy Series#

Coefficients of lazy series are computed on demand. They have infinite precision, although equality can only be decided in special cases.

AUTHORS:

  • Kwankyu Lee (2019-02-24): initial version

  • Tejasvi Chebrolu, Martin Rubey, Travis Scrimshaw (2021-08): refactored and expanded functionality

EXAMPLES:

Laurent series over the integer ring are particularly useful as generating functions for sequences arising in combinatorics.

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
L.<z> = LazyLaurentSeriesRing(ZZ)

The generating function of the Fibonacci sequence is:

sage: f = 1 / (1 - z - z^2)
sage: f
1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7)
f = 1 / (1 - z - z^2)
f

In principle, we can now compute any coefficient of f:

sage: f.coefficient(100)
573147844013817084101
f.coefficient(100)

Which coefficients are actually computed depends on the type of implementation. For the sparse implementation, only the coefficients which are needed are computed.

sage: s = L(lambda n: n, valuation=0); s
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: s.coefficient(10)
10
sage: s._coeff_stream._cache
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 10: 10}
s = L(lambda n: n, valuation=0); s
s.coefficient(10)
s._coeff_stream._cache

Using the dense implementation, all coefficients up to the required coefficient are computed.

sage: L.<x> = LazyLaurentSeriesRing(ZZ, sparse=False)
sage: s = L(lambda n: n, valuation=0); s
x + 2*x^2 + 3*x^3 + 4*x^4 + 5*x^5 + 6*x^6 + O(x^7)
sage: s.coefficient(10)
10
sage: s._coeff_stream._cache
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
L.<x> = LazyLaurentSeriesRing(ZZ, sparse=False)
s = L(lambda n: n, valuation=0); s
s.coefficient(10)
s._coeff_stream._cache

We can do arithmetic with lazy power series:

sage: f
1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7)
sage: f^-1
1 - z - z^2 + O(z^7)
sage: f + f^-1
2 + z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7)
sage: g = (f + f^-1)*(f - f^-1); g
4*z + 6*z^2 + 8*z^3 + 19*z^4 + 38*z^5 + 71*z^6 + O(z^7)
f
f^-1
f + f^-1
g = (f + f^-1)*(f - f^-1); g

We call lazy power series whose coefficients are known to be eventually constant ‘exact’. In some cases, computations with such series are much faster. Moreover, these are the series where equality can be decided. For example:

sage: L.<z> = LazyPowerSeriesRing(ZZ)
sage: f = 1 + 2*z^2 / (1 - z)
sage: f - 2 / (1 - z) + 1 + 2*z
0
L.<z> = LazyPowerSeriesRing(ZZ)
f = 1 + 2*z^2 / (1 - z)
f - 2 / (1 - z) + 1 + 2*z

However, multivariate Taylor series are actually represented as streams of multivariate polynomials. Therefore, the only exact series in this case are polynomials:

sage: L.<x,y> = LazyPowerSeriesRing(ZZ)
sage: 1 / (1-x)
1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + O(x,y)^7
L.<x,y> = LazyPowerSeriesRing(ZZ)
1 / (1-x)

A similar statement is true for lazy symmetric functions:

sage: h = SymmetricFunctions(QQ).h()                                                # needs sage.combinat
sage: L = LazySymmetricFunctions(h)                                                 # needs sage.combinat
sage: 1 / (1-L(h[1]))                                                               # needs sage.combinat
h[] + h[1] + (h[1,1]) + (h[1,1,1]) + (h[1,1,1,1]) + (h[1,1,1,1,1]) + (h[1,1,1,1,1,1]) + O^7
h = SymmetricFunctions(QQ).h()                                                # needs sage.combinat
L = LazySymmetricFunctions(h)                                                 # needs sage.combinat
1 / (1-L(h[1]))                                                               # needs sage.combinat

We can change the base ring:

sage: h = g.change_ring(QQ)
sage: h.parent()                                                                    # needs sage.combinat
Lazy Laurent Series Ring in z over Rational Field
sage: h                                                                             # needs sage.combinat
4*z + 6*z^2 + 8*z^3 + 19*z^4 + 38*z^5 + 71*z^6 + 130*z^7 + O(z^8)
sage: hinv = h^-1; hinv                                                             # needs sage.combinat
1/4*z^-1 - 3/8 + 1/16*z - 17/32*z^2 + 5/64*z^3 - 29/128*z^4 + 165/256*z^5 + O(z^6)
sage: hinv.valuation()                                                              # needs sage.combinat
-1
h = g.change_ring(QQ)
h.parent()                                                                    # needs sage.combinat
h                                                                             # needs sage.combinat
hinv = h^-1; hinv                                                             # needs sage.combinat
hinv.valuation()                                                              # needs sage.combinat
class sage.rings.lazy_series.LazyCauchyProductSeries(parent, coeff_stream)#

Bases: LazyModuleElement

A class for series where multiplication is the Cauchy product.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: f = 1 / (1 - z)
sage: f
1 + z + z^2 + O(z^3)
sage: f * (1 - z)
1

sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
sage: f = 1 / (1 - z)
sage: f
1 + z + z^2 + O(z^3)
L.<z> = LazyLaurentSeriesRing(ZZ)
f = 1 / (1 - z)
f
f * (1 - z)
L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
f = 1 / (1 - z)
f
exp()#

Return the exponential series of self.

We use the identity

exp(s)=1+sexp(s).

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: exp(z)
1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7)
sage: exp(z + z^2)
1 + z + 3/2*z^2 + 7/6*z^3 + 25/24*z^4 + 27/40*z^5 + 331/720*z^6 + O(z^7)
sage: exp(0)                                                                # needs sage.symbolic
1
sage: exp(1 + z)
Traceback (most recent call last):
...
ValueError: can only compose with a positive valuation series

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: exp(x+y)[4].factor()
(1/24) * (x + y)^4
sage: exp(x/(1-y)).polynomial(3)
1/6*x^3 + x^2*y + x*y^2 + 1/2*x^2 + x*y + x + 1
L.<z> = LazyLaurentSeriesRing(QQ)
exp(z)
exp(z + z^2)
exp(0)                                                                # needs sage.symbolic
exp(1 + z)
L.<x,y> = LazyPowerSeriesRing(QQ)
exp(x+y)[4].factor()
exp(x/(1-y)).polynomial(3)
log()#

Return the series for the natural logarithm of self.

We use the identity

log(s)=s/s.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: log(1/(1-z))
z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8)

sage: L.<x, y> = LazyPowerSeriesRing(QQ)
sage: log((1 + x/(1-y))).polynomial(3)
1/3*x^3 - x^2*y + x*y^2 - 1/2*x^2 + x*y + x
L.<z> = LazyLaurentSeriesRing(QQ)
log(1/(1-z))
L.<x, y> = LazyPowerSeriesRing(QQ)
log((1 + x/(1-y))).polynomial(3)
valuation()#

Return the valuation of self.

This method determines the valuation of the series by looking for a nonzero coefficient. Hence if the series happens to be zero, then it may run forever.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: s = 1/(1 - z) - 1/(1 - 2*z)
sage: s.valuation()
1
sage: t = z - z
sage: t.valuation()
+Infinity
sage: M = L(lambda n: n^2, 0)
sage: M.valuation()
1
sage: (M - M).valuation()
+Infinity
L.<z> = LazyLaurentSeriesRing(ZZ)
s = 1/(1 - z) - 1/(1 - 2*z)
s.valuation()
t = z - z
t.valuation()
M = L(lambda n: n^2, 0)
M.valuation()
(M - M).valuation()
class sage.rings.lazy_series.LazyCompletionGradedAlgebraElement(parent, coeff_stream)#

Bases: LazyCauchyProductSeries

An element of a completion of a graded algebra that is computed lazily.

class sage.rings.lazy_series.LazyDirichletSeries(parent, coeff_stream)#

Bases: LazyModuleElement

A Dirichlet series where the coefficients are computed lazily.

EXAMPLES:

sage: L = LazyDirichletSeriesRing(ZZ, "z")
sage: f = L(constant=1)^2
sage: f                                                                         # needs sage.symbolic
1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z))
sage: f.coefficient(100) == number_of_divisors(100)                             # needs sage.libs.pari
True
L = LazyDirichletSeriesRing(ZZ, "z")
f = L(constant=1)^2
f                                                                         # needs sage.symbolic
f.coefficient(100) == number_of_divisors(100)                             # needs sage.libs.pari

Lazy Dirichlet series is picklable:

sage: g = loads(dumps(f))
sage: g                                                                         # needs sage.symbolic
1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z))
sage: g == f
True
g = loads(dumps(f))
g                                                                         # needs sage.symbolic
g == f
is_unit()#

Return whether this element is a unit in the ring.

EXAMPLES:

sage: D = LazyDirichletSeriesRing(ZZ, "s")
sage: D([0, 2]).is_unit()
False

sage: D([-1, 2]).is_unit()
True

sage: D([3, 2]).is_unit()
False

sage: D = LazyDirichletSeriesRing(QQ, "s")
sage: D([3, 2]).is_unit()
True
D = LazyDirichletSeriesRing(ZZ, "s")
D([0, 2]).is_unit()
D([-1, 2]).is_unit()
D([3, 2]).is_unit()
D = LazyDirichletSeriesRing(QQ, "s")
D([3, 2]).is_unit()
valuation()#

Return the valuation of self.

This method determines the valuation of the series by looking for a nonzero coefficient. Hence if the series happens to be zero, then it may run forever.

EXAMPLES:

sage: L = LazyDirichletSeriesRing(ZZ, "z")
sage: mu = L(moebius); mu.valuation()                                       # needs sage.libs.pari
0
sage: (mu - mu).valuation()                                                 # needs sage.libs.pari
+Infinity
sage: g = L(constant=1, valuation=2)
sage: g.valuation()                                                         # needs sage.symbolic
log(2)
sage: (g*g).valuation()                                                     # needs sage.symbolic
2*log(2)
L = LazyDirichletSeriesRing(ZZ, "z")
mu = L(moebius); mu.valuation()                                       # needs sage.libs.pari
(mu - mu).valuation()                                                 # needs sage.libs.pari
g = L(constant=1, valuation=2)
g.valuation()                                                         # needs sage.symbolic
(g*g).valuation()                                                     # needs sage.symbolic
class sage.rings.lazy_series.LazyLaurentSeries(parent, coeff_stream)#

Bases: LazyCauchyProductSeries

A Laurent series where the coefficients are computed lazily.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
L.<z> = LazyLaurentSeriesRing(ZZ)

We can build a series from a function and specify if the series eventually takes a constant value:

sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3)
sage: f
-3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + O(z^6)
sage: f[-2]
-2
sage: f[10]
-1
sage: f[-5]
0

sage: f = L(lambda i: i, valuation=-3)
sage: f
-3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + O(z^4)
sage: f[20]
20
f = L(lambda i: i, valuation=-3, constant=-1, degree=3)
f
f[-2]
f[10]
f[-5]
f = L(lambda i: i, valuation=-3)
f
f[20]

Anything that converts into a polynomial can be input, where we can also specify the valuation or if the series eventually takes a constant value:

sage: L([-5,2,0,5])
-5 + 2*z + 5*z^3
sage: L([-5,2,0,5], constant=6)
-5 + 2*z + 5*z^3 + 6*z^4 + 6*z^5 + 6*z^6 + O(z^7)
sage: L([-5,2,0,5], degree=6, constant=6)
-5 + 2*z + 5*z^3 + 6*z^6 + 6*z^7 + 6*z^8 + O(z^9)
sage: L([-5,2,0,5], valuation=-2, degree=3, constant=6)
-5*z^-2 + 2*z^-1 + 5*z + 6*z^3 + 6*z^4 + 6*z^5 + O(z^6)
sage: L([-5,2,0,5], valuation=5)
-5*z^5 + 2*z^6 + 5*z^8
sage: L({-2:9, 3:4}, constant=2, degree=5)
9*z^-2 + 4*z^3 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8)
L([-5,2,0,5])
L([-5,2,0,5], constant=6)
L([-5,2,0,5], degree=6, constant=6)
L([-5,2,0,5], valuation=-2, degree=3, constant=6)
L([-5,2,0,5], valuation=5)
L({-2:9, 3:4}, constant=2, degree=5)

We can also perform arithmetic:

sage: f = 1 / (1 - z - z^2)
sage: f
1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7)
sage: f.coefficient(100)
573147844013817084101
sage: f = (z^-2 - 1 + 2*z) / (z^-1 - z + 3*z^2)
sage: f
z^-1 - z^2 - z^4 + 3*z^5 + O(z^6)
f = 1 / (1 - z - z^2)
f
f.coefficient(100)
f = (z^-2 - 1 + 2*z) / (z^-1 - z + 3*z^2)
f

However, we may not always be able to know when a result is exactly a polynomial:

sage: f * (z^-1 - z + 3*z^2)
z^-2 - 1 + 2*z + O(z^5)
f * (z^-1 - z + 3*z^2)
approximate_series(prec, name=None)#

Return the Laurent series with absolute precision prec approximated from this series.

INPUT:

  • prec – an integer

  • name – name of the variable; if it is None, the name of the variable of the series is used

OUTPUT: a Laurent series with absolute precision prec

EXAMPLES:

sage: L = LazyLaurentSeriesRing(ZZ, 'z')
sage: z = L.gen()
sage: f = (z - 2*z^3)^5/(1 - 2*z)
sage: f
z^5 + 2*z^6 - 6*z^7 - 12*z^8 + 16*z^9 + 32*z^10 - 16*z^11 + O(z^12)
sage: g = f.approximate_series(10)
sage: g
z^5 + 2*z^6 - 6*z^7 - 12*z^8 + 16*z^9 + O(z^10)
sage: g.parent()
Power Series Ring in z over Integer Ring
sage: h = (f^-1).approximate_series(3)
sage: h
z^-5 - 2*z^-4 + 10*z^-3 - 20*z^-2 + 60*z^-1 - 120 + 280*z - 560*z^2 + O(z^3)
sage: h.parent()
Laurent Series Ring in z over Integer Ring
L = LazyLaurentSeriesRing(ZZ, 'z')
z = L.gen()
f = (z - 2*z^3)^5/(1 - 2*z)
f
g = f.approximate_series(10)
g
g.parent()
h = (f^-1).approximate_series(3)
h
h.parent()
compose(g)#

Return the composition of self with g.

Given two Laurent series f and g over the same base ring, the composition (fg)(z)=f(g(z)) is defined if and only if:

  • g=0 and val(f)0,

  • g is non-zero and f has only finitely many non-zero coefficients,

  • g is non-zero and val(g)>0.

INPUT:

  • g – other series

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: f = z^2 + 1 + z
sage: f(0)
1
sage: f(L(0))
1
sage: f(f)
3 + 3*z + 4*z^2 + 2*z^3 + z^4
sage: g = z^-3/(1-2*z); g
z^-3 + 2*z^-2 + 4*z^-1 + 8 + 16*z + 32*z^2 + 64*z^3 + O(z^4)
sage: f(g)
z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z)
sage: g^2 + 1 + g
z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z)
sage: f(int(2))
7

sage: f = z^-2 + z + 4*z^3
sage: f(f)
4*z^-6 + 12*z^-3 + z^-2 + 48*z^-1 + 12 + O(z)
sage: f^-2 + f + 4*f^3
4*z^-6 + 12*z^-3 + z^-2 + 48*z^-1 + 12 + O(z)
sage: f(g)
4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + O(z^-2)
sage: g^-2 + g + 4*g^3
4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + O(z^-2)

sage: f = z^-3 + z^-2 + 1 / (1 + z^2); f
z^-3 + z^-2 + 1 - z^2 + O(z^4)
sage: g = z^3 / (1 + z - z^3); g
z^3 - z^4 + z^5 - z^7 + 2*z^8 - 2*z^9 + O(z^10)
sage: f(g)
z^-9 + 3*z^-8 + 3*z^-7 - z^-6 - 4*z^-5 - 2*z^-4 + z^-3 + O(z^-2)
sage: g^-3 + g^-2 + 1 / (1 + g^2)
z^-9 + 3*z^-8 + 3*z^-7 - z^-6 - 4*z^-5 - 2*z^-4 + z^-3 + O(z^-2)

sage: f = z^-3
sage: g = z^-2 + z^-1
sage: g^(-3)
z^6 - 3*z^7 + 6*z^8 - 10*z^9 + 15*z^10 - 21*z^11 + 28*z^12 + O(z^13)
sage: f(g)
z^6 - 3*z^7 + 6*z^8 - 10*z^9 + 15*z^10 - 21*z^11 + 28*z^12 + O(z^13)

sage: f = z^2 + z^3
sage: g = z^-3 + z^-2
sage: f^-3 + f^-2
z^-6 - 3*z^-5 + 7*z^-4 - 12*z^-3 + 18*z^-2 - 25*z^-1 + 33 + O(z)
sage: g(f)
z^-6 - 3*z^-5 + 7*z^-4 - 12*z^-3 + 18*z^-2 - 25*z^-1 + 33 + O(z)
sage: g^2 + g^3
z^-9 + 3*z^-8 + 3*z^-7 + 2*z^-6 + 2*z^-5 + z^-4
sage: f(g)
z^-9 + 3*z^-8 + 3*z^-7 + 2*z^-6 + 2*z^-5 + z^-4

sage: f = L(lambda n: n, valuation=0); f
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: f(z^2)
z^2 + 2*z^4 + 3*z^6 + 4*z^8 + O(z^9)

sage: f = L(lambda n: n, valuation=-2); f
-2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5)
sage: f3 = f(z^3); f3
-2*z^-6 - z^-3 + O(z)
sage: [f3[i] for i in range(-6,13)]
[-2, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4]
L.<z> = LazyLaurentSeriesRing(QQ)
f = z^2 + 1 + z
f(0)
f(L(0))
f(f)
g = z^-3/(1-2*z); g
f(g)
g^2 + 1 + g
f(int(2))
f = z^-2 + z + 4*z^3
f(f)
f^-2 + f + 4*f^3
f(g)
g^-2 + g + 4*g^3
f = z^-3 + z^-2 + 1 / (1 + z^2); f
g = z^3 / (1 + z - z^3); g
f(g)
g^-3 + g^-2 + 1 / (1 + g^2)
f = z^-3
g = z^-2 + z^-1
g^(-3)
f(g)
f = z^2 + z^3
g = z^-3 + z^-2
f^-3 + f^-2
g(f)
g^2 + g^3
f(g)
f = L(lambda n: n, valuation=0); f
f(z^2)
f = L(lambda n: n, valuation=-2); f
f3 = f(z^3); f3
[f3[i] for i in range(-6,13)]

We compose a Laurent polynomial with a generic element:

sage: R.<x> = QQ[]
sage: f = z^2 + 1 + z^-1
sage: g = x^2 + x + 3
sage: f(g)
(x^6 + 3*x^5 + 12*x^4 + 19*x^3 + 37*x^2 + 28*x + 31)/(x^2 + x + 3)
sage: f(g) == g^2 + 1 + g^-1
True
R.<x> = QQ[]
f = z^2 + 1 + z^-1
g = x^2 + x + 3
f(g)
f(g) == g^2 + 1 + g^-1

We compose with another lazy Laurent series:

sage: LS.<y> = LazyLaurentSeriesRing(QQ)
sage: f = z^2 + 1 + z^-1
sage: fy = f(y); fy
y^-1 + 1 + y^2
sage: fy.parent() is LS
True
sage: g = y - y
sage: f(g)
Traceback (most recent call last):
...
ZeroDivisionError: the valuation of the series must be nonnegative

sage: g = 1 - y
sage: f(g)
3 - y + 2*y^2 + y^3 + y^4 + y^5 + O(y^6)
sage: g^2 + 1 + g^-1
3 - y + 2*y^2 + y^3 + y^4 + y^5 + O(y^6)

sage: f = L(lambda n: n, valuation=0); f
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: f(0)
0
sage: f(y)
y + 2*y^2 + 3*y^3 + 4*y^4 + 5*y^5 + 6*y^6 + 7*y^7 + O(y^8)
sage: fp = f(y - y)
sage: fp == 0
True
sage: fp.parent() is LS
True

sage: f = z^2 + 3 + z
sage: f(y - y)
3
LS.<y> = LazyLaurentSeriesRing(QQ)
f = z^2 + 1 + z^-1
fy = f(y); fy
fy.parent() is LS
g = y - y
f(g)
g = 1 - y
f(g)
g^2 + 1 + g^-1
f = L(lambda n: n, valuation=0); f
f(0)
f(y)
fp = f(y - y)
fp == 0
fp.parent() is LS
f = z^2 + 3 + z
f(y - y)

With both of them sparse:

sage: L.<z> = LazyLaurentSeriesRing(QQ, sparse=True)
sage: LS.<y> = LazyLaurentSeriesRing(QQ, sparse=True)
sage: f = L(lambda n: 1, valuation=0); f
1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7)
sage: f(y^2)
1 + y^2 + y^4 + y^6 + O(y^7)

sage: fp = f - 1 + z^-2; fp
z^-2 + z + z^2 + z^3 + z^4 + O(z^5)
sage: fpy = fp(y^2); fpy
y^-4 + y^2 + O(y^3)
sage: fpy.parent() is LS
True
sage: [fpy[i] for i in range(-4,11)]
[1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]

sage: g = LS(valuation=2, constant=1); g
y^2 + y^3 + y^4 + O(y^5)
sage: fg = f(g); fg
1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + O(y^7)
sage: 1 + g + g^2 + g^3 + g^4 + g^5 + g^6
1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + O(y^7)

sage: h = LS(lambda n: 1 if n % 2 else 0, valuation=2); h
y^3 + y^5 + y^7 + O(y^9)
sage: fgh = fg(h); fgh
1 + y^6 + O(y^7)
sage: [fgh[i] for i in range(0, 15)]
[1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 3, 3, 6, 6, 13]
sage: t = 1 + h^2 + h^3 + 2*h^4 + 3*h^5 + 5*h^6
sage: [t[i] for i in range(0, 15)]
[1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 3, 3, 6, 6, 13]
L.<z> = LazyLaurentSeriesRing(QQ, sparse=True)
LS.<y> = LazyLaurentSeriesRing(QQ, sparse=True)
f = L(lambda n: 1, valuation=0); f
f(y^2)
fp = f - 1 + z^-2; fp
fpy = fp(y^2); fpy
fpy.parent() is LS
[fpy[i] for i in range(-4,11)]
g = LS(valuation=2, constant=1); g
fg = f(g); fg
1 + g + g^2 + g^3 + g^4 + g^5 + g^6
h = LS(lambda n: 1 if n % 2 else 0, valuation=2); h
fgh = fg(h); fgh
[fgh[i] for i in range(0, 15)]
t = 1 + h^2 + h^3 + 2*h^4 + 3*h^5 + 5*h^6
[t[i] for i in range(0, 15)]

We look at mixing the sparse and the dense:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: f = L(lambda n: 1, valuation=0); f
1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7)
sage: g = LS(lambda n: 1, valuation=1); g
y + y^2 + y^3 + y^4 + y^5 + y^6 + y^7 + O(y^8)
sage: f(g)
1 + y + 2*y^2 + 4*y^3 + 8*y^4 + 16*y^5 + 32*y^6 + O(y^7)

sage: f = z^-2 + 1 + z
sage: g = 1/(y*(1-y)); g
y^-1 + 1 + y + O(y^2)
sage: f(g)
y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + y^6 + y^7 + O(y^8)
sage: g^-2 + 1 + g == f(g)
True

sage: f = z^-3 + z^-2 + 1
sage: g = 1/(y^2*(1-y)); g
y^-2 + y^-1 + 1 + O(y)
sage: f(g)
1 + y^4 - 2*y^5 + 2*y^6 - 3*y^7 + 3*y^8 - y^9
sage: g^-3 + g^-2 + 1 == f(g)
True
sage: z(y)
y
L.<z> = LazyLaurentSeriesRing(QQ)
f = L(lambda n: 1, valuation=0); f
g = LS(lambda n: 1, valuation=1); g
f(g)
f = z^-2 + 1 + z
g = 1/(y*(1-y)); g
f(g)
g^-2 + 1 + g == f(g)
f = z^-3 + z^-2 + 1
g = 1/(y^2*(1-y)); g
f(g)
g^-3 + g^-2 + 1 == f(g)
z(y)

We look at cases where the composition does not exist. g=0 and val(f)<0:

sage: g = L(0)
sage: f = z^-1 + z^-2
sage: f.valuation() < 0
True
sage: f(g)
Traceback (most recent call last):
...
ZeroDivisionError: the valuation of the series must be nonnegative
g = L(0)
f = z^-1 + z^-2
f.valuation() < 0
f(g)

g0 and val(g)0 and f has infinitely many non-zero coefficients:

sage: g = z^-1 + z^-2
sage: g.valuation() <= 0
True
sage: f = L(lambda n: n, valuation=0)
sage: f(g)
Traceback (most recent call last):
...
ValueError: can only compose with a positive valuation series

sage: f = L(lambda n: n, valuation=1)
sage: f(1 + z)
Traceback (most recent call last):
...
ValueError: can only compose with a positive valuation series
g = z^-1 + z^-2
g.valuation() <= 0
f = L(lambda n: n, valuation=0)
f(g)
f = L(lambda n: n, valuation=1)
f(1 + z)

We compose the exponential with a Dirichlet series:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: e = L(lambda n: 1/factorial(n), 0)
sage: D = LazyDirichletSeriesRing(QQ, "s")
sage: g = D(constant=1)-1
sage: g                                                                     # needs sage.symbolic
1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s))

sage: e(g)[0:10]
[0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2]

sage: sum(g^k/factorial(k) for k in range(10))[0:10]
[0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2]

sage: g = D([0,1,0,1,1,2])
sage: g                                                                     # needs sage.symbolic
1/(2^s) + 1/(4^s) + 1/(5^s) + 2/6^s
sage: e(g)[0:10]
[0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0]
sage: sum(g^k/factorial(k) for k in range(10))[0:10]
[0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0]

sage: e(D([1,0,1]))
Traceback (most recent call last):
...
ValueError: can only compose with a positive valuation series

sage: e5 = L(e, degree=5)
sage: e5
1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4
sage: e5(g)                                                                 # needs sage.symbolic
1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s))
sage: sum(e5[k] * g^k for k in range(5))                                    # needs sage.symbolic
1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s))
L.<z> = LazyLaurentSeriesRing(QQ)
e = L(lambda n: 1/factorial(n), 0)
D = LazyDirichletSeriesRing(QQ, "s")
g = D(constant=1)-1
g                                                                     # needs sage.symbolic
e(g)[0:10]
sum(g^k/factorial(k) for k in range(10))[0:10]
g = D([0,1,0,1,1,2])
g                                                                     # needs sage.symbolic
e(g)[0:10]
sum(g^k/factorial(k) for k in range(10))[0:10]
e(D([1,0,1]))
e5 = L(e, degree=5)
e5
e5(g)                                                                 # needs sage.symbolic
sum(e5[k] * g^k for k in range(5))                                    # needs sage.symbolic

The output parent is always the common parent between the base ring of f and the parent of g or extended to the corresponding lazy series:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: R.<x> = ZZ[]
sage: parent(z(x))
Univariate Polynomial Ring in x over Rational Field
sage: parent(z(R.zero()))
Univariate Polynomial Ring in x over Rational Field
sage: parent(z(0))
Rational Field
sage: f = 1 / (1 - z)
sage: f(x)
1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + O(x^7)
sage: three = L(3)(x^2); three
3
sage: parent(three)
Univariate Polynomial Ring in x over Rational Field
L.<z> = LazyLaurentSeriesRing(QQ)
R.<x> = ZZ[]
parent(z(x))
parent(z(R.zero()))
parent(z(0))
f = 1 / (1 - z)
f(x)
three = L(3)(x^2); three
parent(three)

Consistency check when g is an uninitialized series between a polynomial f as both a polynomial and a lazy series:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: f = 1 + z
sage: g = L.undefined(valuation=0)
sage: f(g) == f.polynomial()(g)
True
L.<z> = LazyLaurentSeriesRing(QQ)
f = 1 + z
g = L.undefined(valuation=0)
f(g) == f.polynomial()(g)
compositional_inverse()#

Return the compositional inverse of self.

Given a Laurent series f, the compositional inverse is a Laurent series g over the same base ring, such that (fg)(z)=f(g(z))=z.

The compositional inverse exists if and only if:

  • val(f)=1, or

  • f=a+bz with a,b0, or

  • f=a/z with a0.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: (2*z).revert()
1/2*z
sage: (2/z).revert()
2*z^-1
sage: (z-z^2).revert()
z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8)

sage: s = L(degree=1, constant=-1)
sage: s.revert()
-z - z^2 - z^3 + O(z^4)

sage: s = L(degree=1, constant=1)
sage: s.revert()
z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8)
L.<z> = LazyLaurentSeriesRing(QQ)
(2*z).revert()
(2/z).revert()
(z-z^2).revert()
s = L(degree=1, constant=-1)
s.revert()
s = L(degree=1, constant=1)
s.revert()

Warning

For series not known to be eventually constant (e.g., being defined by a function) with approximate valuation 1 (but not necessarily its true valuation), this assumes that this is the actual valuation:

sage: f = L(lambda n: n if n > 2 else 0, valuation=1)
sage: f.revert()
<repr(... failed: ValueError: inverse does not exist>
f = L(lambda n: n if n > 2 else 0, valuation=1)
f.revert()
derivative(*args)#

Return the derivative of the Laurent series.

Multiple variables and iteration counts may be supplied; see the documentation of sage.calculus.functional.derivative() function for details.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: z.derivative()
1
sage: (1+z+z^2).derivative(3)
0
sage: (1/z).derivative()
-z^-2
sage: (1/(1-z)).derivative(z)
1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7)
L.<z> = LazyLaurentSeriesRing(ZZ)
z.derivative()
(1+z+z^2).derivative(3)
(1/z).derivative()
(1/(1-z)).derivative(z)
is_unit()#

Return whether this element is a unit in the ring.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: (2*z).is_unit()
False

sage: (1 + 2*z).is_unit()
True

sage: (1 + 2*z^-1).is_unit()
False

sage: (z^3 + 4 - z^-2).is_unit()
True
L.<z> = LazyLaurentSeriesRing(ZZ)
(2*z).is_unit()
(1 + 2*z).is_unit()
(1 + 2*z^-1).is_unit()
(z^3 + 4 - z^-2).is_unit()
polynomial(degree=None, name=None)#

Return self as a Laurent polynomial if self is actually so.

INPUT:

  • degreeNone or an integer

  • name – name of the variable; if it is None, the name of the variable of the series is used

OUTPUT:

A Laurent polynomial if the valuation of the series is negative or a polynomial otherwise.

If degree is not None, the terms of the series of degree greater than degree are first truncated. If degree is None and the series is not a polynomial or a Laurent polynomial, a ValueError is raised.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: f = L([1,0,0,2,0,0,0,3], valuation=5); f
z^5 + 2*z^8 + 3*z^12
sage: f.polynomial()
3*z^12 + 2*z^8 + z^5
L.<z> = LazyLaurentSeriesRing(ZZ)
f = L([1,0,0,2,0,0,0,3], valuation=5); f
f.polynomial()
revert()#

Return the compositional inverse of self.

Given a Laurent series f, the compositional inverse is a Laurent series g over the same base ring, such that (fg)(z)=f(g(z))=z.

The compositional inverse exists if and only if:

  • val(f)=1, or

  • f=a+bz with a,b0, or

  • f=a/z with a0.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: (2*z).revert()
1/2*z
sage: (2/z).revert()
2*z^-1
sage: (z-z^2).revert()
z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8)

sage: s = L(degree=1, constant=-1)
sage: s.revert()
-z - z^2 - z^3 + O(z^4)

sage: s = L(degree=1, constant=1)
sage: s.revert()
z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8)
L.<z> = LazyLaurentSeriesRing(QQ)
(2*z).revert()
(2/z).revert()
(z-z^2).revert()
s = L(degree=1, constant=-1)
s.revert()
s = L(degree=1, constant=1)
s.revert()

Warning

For series not known to be eventually constant (e.g., being defined by a function) with approximate valuation 1 (but not necessarily its true valuation), this assumes that this is the actual valuation:

sage: f = L(lambda n: n if n > 2 else 0, valuation=1)
sage: f.revert()
<repr(... failed: ValueError: inverse does not exist>
f = L(lambda n: n if n > 2 else 0, valuation=1)
f.revert()
class sage.rings.lazy_series.LazyModuleElement(parent, coeff_stream)#

Bases: Element

A lazy sequence with a module structure given by term-wise addition and scalar multiplication.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: M = L(lambda n: n, valuation=0)
sage: N = L(lambda n: 1, valuation=0)
sage: M[0:10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: N[0:10]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
L.<z> = LazyLaurentSeriesRing(ZZ)
M = L(lambda n: n, valuation=0)
N = L(lambda n: 1, valuation=0)
M[0:10]
N[0:10]

Two sequences can be added:

sage: O = M + N
sage: O[0:10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
O = M + N
O[0:10]

Two sequences can be subtracted:

sage: P = M - N
sage: P[0:10]
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
P = M - N
P[0:10]

A sequence can be multiplied by a scalar:

sage: Q = 2 * M
sage: Q[0:10]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Q = 2 * M
Q[0:10]

The negation of a sequence can also be found:

sage: R = -M
sage: R[0:10]
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
R = -M
R[0:10]
arccos()#

Return the arccosine of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(RR)
sage: arccos(z)                                                             # needs sage.symbolic
1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2
 - 0.166666666666667*z^3 + 0.000000000000000*z^4
 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7)

sage: L.<z> = LazyLaurentSeriesRing(SR)                                     # needs sage.symbolic
sage: arccos(z/(1-z))                                                       # needs sage.symbolic
1/2*pi - z - z^2 - 7/6*z^3 - 3/2*z^4 - 83/40*z^5 - 73/24*z^6 + O(z^7)

sage: L.<x,y> = LazyPowerSeriesRing(SR)                                     # needs sage.symbolic
sage: arccos(x/(1-y))                                                       # needs sage.symbolic
1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3)
 + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7
L.<z> = LazyLaurentSeriesRing(RR)
arccos(z)                                                             # needs sage.symbolic
L.<z> = LazyLaurentSeriesRing(SR)                                     # needs sage.symbolic
arccos(z/(1-z))                                                       # needs sage.symbolic
L.<x,y> = LazyPowerSeriesRing(SR)                                     # needs sage.symbolic
arccos(x/(1-y))                                                       # needs sage.symbolic
arccot()#

Return the arctangent of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(RR)
sage: arccot(z)                                                             # needs sage.symbolic
1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2
 + 0.333333333333333*z^3 + 0.000000000000000*z^4
 - 0.200000000000000*z^5 + O(1.00000000000000*z^7)

sage: L.<z> = LazyLaurentSeriesRing(SR)                                     # needs sage.symbolic
sage: arccot(z/(1-z))                                                       # needs sage.symbolic
1/2*pi - z - z^2 - 2/3*z^3 + 4/5*z^5 + 4/3*z^6 + O(z^7)

sage: L.<x,y> = LazyPowerSeriesRing(SR)                                     # needs sage.symbolic
sage: acot(x/(1-y))                                                         # needs sage.symbolic
1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3)
 + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7
L.<z> = LazyLaurentSeriesRing(RR)
arccot(z)                                                             # needs sage.symbolic
L.<z> = LazyLaurentSeriesRing(SR)                                     # needs sage.symbolic
arccot(z/(1-z))                                                       # needs sage.symbolic
L.<x,y> = LazyPowerSeriesRing(SR)                                     # needs sage.symbolic
acot(x/(1-y))                                                         # needs sage.symbolic
arcsin()#

Return the arcsine of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: arcsin(z)
z + 1/6*z^3 + 3/40*z^5 + 5/112*z^7 + O(z^8)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: asin(x/(1-y))
x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3)
 + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5)
 + (5/112*x^7+9/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8
L.<z> = LazyLaurentSeriesRing(QQ)
arcsin(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
asin(x/(1-y))
arcsinh()#

Return the inverse of the hyperbolic sine of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: asinh(z)
z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8)
L.<z> = LazyLaurentSeriesRing(QQ)
asinh(z)

arcsinh is an alias:

sage: arcsinh(z)
z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: asinh(x/(1-y))
x + x*y + (-1/6*x^3+x*y^2) + (-1/2*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4)
 + (3/8*x^5*y-5/3*x^3*y^3+x*y^5) + (-5/112*x^7+9/8*x^5*y^2-5/2*x^3*y^4+x*y^6) + O(x,y)^8
arcsinh(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
asinh(x/(1-y))
arctan()#

Return the arctangent of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: arctan(z)
z - 1/3*z^3 + 1/5*z^5 - 1/7*z^7 + O(z^8)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: atan(x/(1-y))
x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (1/5*x^5-2*x^3*y^2+x*y^4)
 + (x^5*y-10/3*x^3*y^3+x*y^5) + (-1/7*x^7+3*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8
L.<z> = LazyLaurentSeriesRing(QQ)
arctan(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
atan(x/(1-y))
arctanh()#

Return the inverse of the hyperbolic tangent of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: atanh(z)
z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8)
L.<z> = LazyLaurentSeriesRing(QQ)
atanh(z)

arctanh is an alias:

sage: arctanh(z)
z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8)

sage: L.<x, y> = LazyPowerSeriesRing(QQ)
sage: atanh(x/(1-y))
x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4)
 + (x^5*y+10/3*x^3*y^3+x*y^5) + (1/7*x^7+3*x^5*y^2+5*x^3*y^4+x*y^6) + O(x,y)^8
arctanh(z)
L.<x, y> = LazyPowerSeriesRing(QQ)
atanh(x/(1-y))
change_ring(ring)#

Return self with coefficients converted to elements of ring.

INPUT:

  • ring – a ring

EXAMPLES:

Dense Implementation:

sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=False)
sage: s = 2 + z
sage: t = s.change_ring(QQ)
sage: t^-1
1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7)
sage: M = L(lambda n: n, valuation=0); M
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: N = M.change_ring(QQ)
sage: N.parent()
Lazy Laurent Series Ring in z over Rational Field
sage: M.parent()
Lazy Laurent Series Ring in z over Integer Ring
L.<z> = LazyLaurentSeriesRing(ZZ, sparse=False)
s = 2 + z
t = s.change_ring(QQ)
t^-1
M = L(lambda n: n, valuation=0); M
N = M.change_ring(QQ)
N.parent()
M.parent()

Sparse Implementation:

sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
sage: M = L(lambda n: n, valuation=0); M
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: M.parent()
Lazy Laurent Series Ring in z over Integer Ring
sage: N = M.change_ring(QQ)
sage: N.parent()
Lazy Laurent Series Ring in z over Rational Field
sage: M^-1
z^-1 - 2 + z + O(z^6)
L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
M = L(lambda n: n, valuation=0); M
M.parent()
N = M.change_ring(QQ)
N.parent()
M^-1

A Dirichlet series example:

sage: L = LazyDirichletSeriesRing(ZZ, 'z')
sage: s = L(constant=2)
sage: t = s.change_ring(QQ)
sage: t.parent()
Lazy Dirichlet Series Ring in z over Rational Field
sage: it = t^-1
sage: it                                                                    # needs sage.symbolic
1/2 - 1/2/2^z - 1/2/3^z - 1/2/5^z + 1/2/6^z - 1/2/7^z + O(1/(8^z))
L = LazyDirichletSeriesRing(ZZ, 'z')
s = L(constant=2)
t = s.change_ring(QQ)
t.parent()
it = t^-1
it                                                                    # needs sage.symbolic

A Taylor series example:

sage: L.<z> = LazyPowerSeriesRing(ZZ)
sage: s = 2 + z
sage: t = s.change_ring(QQ)
sage: t^-1
1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7)
sage: t.parent()
Lazy Taylor Series Ring in z over Rational Field
L.<z> = LazyPowerSeriesRing(ZZ)
s = 2 + z
t = s.change_ring(QQ)
t^-1
t.parent()
coefficient(n)#

Return the homogeneous degree n part of the series.

INPUT:

  • n – integer; the degree

For a series f, the slice f[start:stop] produces the following:

  • if start and stop are integers, return the list of terms with given degrees

  • if start is None, return the list of terms beginning with the valuation

  • if stop is None, return a lazy_list_generic instead.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: f = z / (1 - 2*z^3)
sage: [f[n] for n in range(20)]
[0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64]
sage: f[0:20]
[0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64]
sage: f[:20]
[1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64]
sage: f[::3]
lazy list [1, 2, 4, ...]

sage: M = L(lambda n: n, valuation=0)
sage: [M[n] for n in range(20)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
sage: M = L(lambda n: n, valuation=0)
sage: [M[n] for n in range(20)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
L.<z> = LazyLaurentSeriesRing(ZZ)
f = z / (1 - 2*z^3)
[f[n] for n in range(20)]
f[0:20]
f[:20]
f[::3]
M = L(lambda n: n, valuation=0)
[M[n] for n in range(20)]
L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
M = L(lambda n: n, valuation=0)
[M[n] for n in range(20)]

Similarly for multivariate series:

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: sin(x*y)[:11]
[x*y, 0, 0, 0, -1/6*x^3*y^3, 0, 0, 0, 1/120*x^5*y^5]
sage: sin(x*y)[2::4]
lazy list [x*y, -1/6*x^3*y^3, 1/120*x^5*y^5, ...]
L.<x,y> = LazyPowerSeriesRing(QQ)
sin(x*y)[:11]
sin(x*y)[2::4]

Similarly for Dirichlet series:

sage: L = LazyDirichletSeriesRing(ZZ, "z")
sage: L(lambda n: n)[1:11]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
L = LazyDirichletSeriesRing(ZZ, "z")
L(lambda n: n)[1:11]
coefficients(n=None)#

Return the first n non-zero coefficients of self.

INPUT:

  • n – (optional) the number of non-zero coefficients to return

If the series has fewer than n non-zero coefficients, only these are returned.

If n is None, a lazy_list_generic with all non-zero coefficients is returned instead.

Warning

If there are fewer than n non-zero coefficients, but this cannot be detected, this method will not return.

EXAMPLES:

sage: L.<x> = LazyPowerSeriesRing(QQ)
sage: f = L([1,2,3])
sage: f.coefficients(5)
doctest:...: DeprecationWarning: the method coefficients now only returns the non-zero coefficients. Use __getitem__ instead.
See https://github.com/sagemath/sage/issues/32367 for details.
[1, 2, 3]

sage: f = sin(x)
sage: f.coefficients(5)
[1, -1/6, 1/120, -1/5040, 1/362880]

sage: L.<x, y> = LazyPowerSeriesRing(QQ)
sage: f = sin(x^2+y^2)
sage: f.coefficients(5)
[1, 1, -1/6, -1/2, -1/2]

sage: f.coefficients()
lazy list [1, 1, -1/6, ...]

sage: L.<x> = LazyPowerSeriesRing(GF(2))
sage: f = L(lambda n: n)
sage: f.coefficients(5)
[1, 1, 1, 1, 1]
L.<x> = LazyPowerSeriesRing(QQ)
f = L([1,2,3])
f.coefficients(5)
f = sin(x)
f.coefficients(5)
L.<x, y> = LazyPowerSeriesRing(QQ)
f = sin(x^2+y^2)
f.coefficients(5)
f.coefficients()
L.<x> = LazyPowerSeriesRing(GF(2))
f = L(lambda n: n)
f.coefficients(5)
cos()#

Return the cosine of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: cos(z)
1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: cos(x/(1-y)).polynomial(4)
1/24*x^4 - 3/2*x^2*y^2 - x^2*y - 1/2*x^2 + 1
L.<z> = LazyLaurentSeriesRing(QQ)
cos(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
cos(x/(1-y)).polynomial(4)
cosh()#

Return the hyperbolic cosine of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: cosh(z)
1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: cosh(x/(1-y))
1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3)
 + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7
L.<z> = LazyLaurentSeriesRing(QQ)
cosh(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
cosh(x/(1-y))
cot()#

Return the cotangent of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: cot(z)
z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6)

sage: L.<x> = LazyLaurentSeriesRing(QQ)
sage: cot(x/(1-x)).polynomial(4)
x^-1 - 1 - 1/3*x - 1/3*x^2 - 16/45*x^3 - 2/5*x^4
L.<z> = LazyLaurentSeriesRing(QQ)
cot(z)
L.<x> = LazyLaurentSeriesRing(QQ)
cot(x/(1-x)).polynomial(4)
coth()#

Return the hyperbolic cotangent of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: coth(z)                                                               # needs sage.libs.flint
z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6)

sage: coth(z + z^2)                                                         # needs sage.libs.flint
z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6)
L.<z> = LazyLaurentSeriesRing(QQ)
coth(z)                                                               # needs sage.libs.flint
coth(z + z^2)                                                         # needs sage.libs.flint
csc()#

Return the cosecant of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: csc(z)
z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6)

sage: L.<x> = LazyLaurentSeriesRing(QQ)
sage: csc(x/(1-x)).polynomial(4)
x^-1 - 1 + 1/6*x + 1/6*x^2 + 67/360*x^3 + 9/40*x^4
L.<z> = LazyLaurentSeriesRing(QQ)
csc(z)
L.<x> = LazyLaurentSeriesRing(QQ)
csc(x/(1-x)).polynomial(4)
csch()#

Return the hyperbolic cosecant of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: csch(z)                                                               # needs sage.libs.flint
z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6)

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: csch(z/(1-z))                                                         # needs sage.libs.flint
z^-1 - 1 - 1/6*z - 1/6*z^2 - 53/360*z^3 - 13/120*z^4 - 787/15120*z^5 + O(z^6)
L.<z> = LazyLaurentSeriesRing(QQ)
csch(z)                                                               # needs sage.libs.flint
L.<z> = LazyLaurentSeriesRing(QQ)
csch(z/(1-z))                                                         # needs sage.libs.flint
define(s)#

Define an equation by self = s.

INPUT:

  • s – a lazy series

EXAMPLES:

We begin by constructing the Catalan numbers:

sage: L.<z> = LazyPowerSeriesRing(ZZ)
sage: C = L.undefined()
sage: C.define(1 + z*C^2)
sage: C
1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7)
sage: binomial(2000, 1000) / C[1000]                                        # needs sage.symbolic
1001
L.<z> = LazyPowerSeriesRing(ZZ)
C = L.undefined()
C.define(1 + z*C^2)
C
binomial(2000, 1000) / C[1000]                                        # needs sage.symbolic

The Catalan numbers but with a valuation 1:

sage: B = L.undefined(valuation=1)
sage: B.define(z + B^2)
sage: B
z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8)
B = L.undefined(valuation=1)
B.define(z + B^2)
B

We can define multiple series that are linked:

sage: s = L.undefined()
sage: t = L.undefined()
sage: s.define(1 + z*t^3)
sage: t.define(1 + z*s^2)
sage: s[0:9]
[1, 1, 3, 9, 34, 132, 546, 2327, 10191]
sage: t[0:9]
[1, 1, 2, 7, 24, 95, 386, 1641, 7150]
s = L.undefined()
t = L.undefined()
s.define(1 + z*t^3)
t.define(1 + z*s^2)
s[0:9]
t[0:9]

A bigger example:

sage: L.<z> = LazyPowerSeriesRing(ZZ)
sage: A = L.undefined(valuation=5)
sage: B = L.undefined()
sage: C = L.undefined(valuation=2)
sage: A.define(z^5 + B^2)
sage: B.define(z^5 + C^2)
sage: C.define(z^2 + C^2 + A^2)
sage: A[0:15]
[0, 0, 0, 0, 0, 1, 0, 0, 1, 2, 5, 4, 14, 10, 48]
sage: B[0:15]
[0, 0, 0, 0, 1, 1, 2, 0, 5, 0, 14, 0, 44, 0, 138]
sage: C[0:15]
[0, 0, 1, 0, 1, 0, 2, 0, 5, 0, 15, 0, 44, 2, 142]
L.<z> = LazyPowerSeriesRing(ZZ)
A = L.undefined(valuation=5)
B = L.undefined()
C = L.undefined(valuation=2)
A.define(z^5 + B^2)
B.define(z^5 + C^2)
C.define(z^2 + C^2 + A^2)
A[0:15]
B[0:15]
C[0:15]

Counting binary trees:

sage: L.<z> = LazyPowerSeriesRing(QQ)
sage: s = L.undefined(valuation=1)
sage: s.define(z + (s^2+s(z^2))/2)
sage: s[0:9]
[0, 1, 1, 1, 2, 3, 6, 11, 23]
L.<z> = LazyPowerSeriesRing(QQ)
s = L.undefined(valuation=1)
s.define(z + (s^2+s(z^2))/2)
s[0:9]

The q-Catalan numbers:

sage: R.<q> = ZZ[]
sage: L.<z> = LazyLaurentSeriesRing(R)
sage: s = L.undefined(valuation=0)
sage: s.define(1+z*s*s(q*z))
sage: s
1 + z + (q + 1)*z^2 + (q^3 + q^2 + 2*q + 1)*z^3
 + (q^6 + q^5 + 2*q^4 + 3*q^3 + 3*q^2 + 3*q + 1)*z^4
 + (q^10 + q^9 + 2*q^8 + 3*q^7 + 5*q^6 + 5*q^5 + 7*q^4 + 7*q^3 + 6*q^2 + 4*q + 1)*z^5
 + (q^15 + q^14 + 2*q^13 + 3*q^12 + 5*q^11 + 7*q^10 + 9*q^9 + 11*q^8
    + 14*q^7 + 16*q^6 + 16*q^5 + 17*q^4 + 14*q^3 + 10*q^2 + 5*q + 1)*z^6 + O(z^7)
R.<q> = ZZ[]
L.<z> = LazyLaurentSeriesRing(R)
s = L.undefined(valuation=0)
s.define(1+z*s*s(q*z))
s

We count unlabeled ordered trees by total number of nodes and number of internal nodes:

sage: R.<q> = QQ[]
sage: Q.<z> = LazyPowerSeriesRing(R)
sage: leaf = z
sage: internal_node = q * z
sage: L = Q(constant=1, degree=1)
sage: T = Q.undefined(valuation=1)
sage: T.define(leaf + internal_node * L(T))
sage: T[0:6]
[0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q]
R.<q> = QQ[]
Q.<z> = LazyPowerSeriesRing(R)
leaf = z
internal_node = q * z
L = Q(constant=1, degree=1)
T = Q.undefined(valuation=1)
T.define(leaf + internal_node * L(T))
T[0:6]

Similarly for Dirichlet series:

sage: L = LazyDirichletSeriesRing(ZZ, "z")
sage: g = L(constant=1, valuation=2)
sage: F = L.undefined()
sage: F.define(1 + g*F)
sage: F[:16]
[1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3]
sage: oeis(_)                                                       # optional - internet
0: A002033: Number of perfect partitions of n.
1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n.
...

sage: F = L.undefined()
sage: F.define(1 + g*F*F)
sage: F[:16]
[1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5]
L = LazyDirichletSeriesRing(ZZ, "z")
g = L(constant=1, valuation=2)
F = L.undefined()
F.define(1 + g*F)
F[:16]
oeis(_)                                                       # optional - internet
F = L.undefined()
F.define(1 + g*F*F)
F[:16]

We can compute the Frobenius character of unlabeled trees:

sage: # needs sage.combinat
sage: m = SymmetricFunctions(QQ).m()
sage: s = SymmetricFunctions(QQ).s()
sage: L = LazySymmetricFunctions(m)
sage: E = L(lambda n: s[n], valuation=0)
sage: X = L(s[1])
sage: A = L.undefined()
sage: A.define(X*E(A))
sage: A[:6]
[m[1],
 2*m[1, 1] + m[2],
 9*m[1, 1, 1] + 5*m[2, 1] + 2*m[3],
 64*m[1, 1, 1, 1] + 34*m[2, 1, 1] + 18*m[2, 2] + 13*m[3, 1] + 4*m[4],
 625*m[1, 1, 1, 1, 1] + 326*m[2, 1, 1, 1] + 171*m[2, 2, 1] + 119*m[3, 1, 1] + 63*m[3, 2] + 35*m[4, 1] + 9*m[5]]
# needs sage.combinat
m = SymmetricFunctions(QQ).m()
s = SymmetricFunctions(QQ).s()
L = LazySymmetricFunctions(m)
E = L(lambda n: s[n], valuation=0)
X = L(s[1])
A = L.undefined()
A.define(X*E(A))
A[:6]
euler()#

Return the Euler function evaluated at self.

The Euler function is defined as

ϕ(z)=(z;z)=n=0(1)nq(3n2n)/2.

EXAMPLES:

sage: L.<q> = LazyLaurentSeriesRing(ZZ)
sage: phi = L.euler()
sage: (q + q^2).euler() - phi(q + q^2)
O(q^7)
L.<q> = LazyLaurentSeriesRing(ZZ)
phi = L.euler()
(q + q^2).euler() - phi(q + q^2)
exp()#

Return the exponential series of self.

EXAMPLES:

sage: L = LazyDirichletSeriesRing(QQ, "s")
sage: Z = L(constant=1, valuation=2)
sage: exp(Z)                                                                # needs sage.symbolic
1 + 1/(2^s) + 1/(3^s) + 3/2/4^s + 1/(5^s) + 2/6^s + 1/(7^s) + O(1/(8^s))
L = LazyDirichletSeriesRing(QQ, "s")
Z = L(constant=1, valuation=2)
exp(Z)                                                                # needs sage.symbolic
hypergeometric(a, b)#

Return the pFq-hypergeometric function pFq where (p,q) is the parameterization of self.

INPUT:

  • a – the first parameter of the hypergeometric function

  • b – the second parameter of the hypergeometric function

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: z.hypergeometric([1, 1], [1])
1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7)
sage: z.hypergeometric([], []) - exp(z)
O(z^7)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: (x+y).hypergeometric([1, 1], [1]).polynomial(4)
x^4 + 4*x^3*y + 6*x^2*y^2 + 4*x*y^3 + y^4 + x^3 + 3*x^2*y
 + 3*x*y^2 + y^3 + x^2 + 2*x*y + y^2 + x + y + 1
L.<z> = LazyLaurentSeriesRing(QQ)
z.hypergeometric([1, 1], [1])
z.hypergeometric([], []) - exp(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
(x+y).hypergeometric([1, 1], [1]).polynomial(4)
is_nonzero(proof=False)#

Return True if self is known to be nonzero.

INPUT:

  • proof – (default: False) if True, this will also return an index such that self has a nonzero coefficient

Warning

If the stream is exactly zero, this will run forever.

EXAMPLES:

A series that it not known to be nonzero with no halting precision:

sage: L.<z> = LazyLaurentSeriesRing(GF(2))
sage: f = L(lambda n: 0, valuation=0)
sage: f.is_nonzero()
False
sage: bool(f)
True
sage: g = L(lambda n: 0 if n < 50 else 1, valuation=2)
sage: g.is_nonzero()
False
sage: g[60]
1
sage: g.is_nonzero()
True
L.<z> = LazyLaurentSeriesRing(GF(2))
f = L(lambda n: 0, valuation=0)
f.is_nonzero()
bool(f)
g = L(lambda n: 0 if n < 50 else 1, valuation=2)
g.is_nonzero()
g[60]
g.is_nonzero()

With finite halting precision, it can be considered to be indistinguishable from zero until possibly enough coefficients are computed:

sage: L.options.halting_precision = 20
sage: f = L(lambda n: 0, valuation=0)
sage: f.is_zero()
True

sage: g = L(lambda n: 0 if n < 50 else 1, valuation=2)
sage: g.is_nonzero()  # checks up to degree 22 = 2 + 20
False
sage: g.is_nonzero()  # checks up to degree 42 = 22 + 20
False
sage: g.is_nonzero()  # checks up to degree 62 = 42 + 20
True
sage: L.options._reset()
L.options.halting_precision = 20
f = L(lambda n: 0, valuation=0)
f.is_zero()
g = L(lambda n: 0 if n < 50 else 1, valuation=2)
g.is_nonzero()  # checks up to degree 22 = 2 + 20
g.is_nonzero()  # checks up to degree 42 = 22 + 20
g.is_nonzero()  # checks up to degree 62 = 42 + 20
L.options._reset()

With a proof:

sage: L.<z> = LazyLaurentSeriesRing(GF(5))
sage: g = L(lambda n: 5 if n < 50 else 1, valuation=2)
sage: g.is_nonzero(proof=True)
(True, 50)

sage: L.zero().is_nonzero(proof=True)
(False, None)
L.<z> = LazyLaurentSeriesRing(GF(5))
g = L(lambda n: 5 if n < 50 else 1, valuation=2)
g.is_nonzero(proof=True)
L.zero().is_nonzero(proof=True)
is_trivial_zero()#

Return whether self is known to be trivially zero.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: f = L(lambda n: 0, valuation=2)
sage: f.is_trivial_zero()
False

sage: L.zero().is_trivial_zero()
True
L.<z> = LazyLaurentSeriesRing(ZZ)
f = L(lambda n: 0, valuation=2)
f.is_trivial_zero()
L.zero().is_trivial_zero()
lift_to_precision(absprec=None)#

Return another element of the same parent with absolute precision at least absprec, congruent to this element modulo the precision of this element.

Since the precision of a lazy series is infinity, this method returns the series itself, and the argument is ignored.

EXAMPLES:

sage: P.<t> = PowerSeriesRing(QQ, default_prec=2)
sage: R.<z> = LazyPowerSeriesRing(P)
sage: f = R(lambda n: 1/(1-t)^n)
sage: f
1 + ((1+t+O(t^2))*z) + ((1+2*t+O(t^2))*z^2)
  + ((1+3*t+O(t^2))*z^3)
  + ((1+4*t+O(t^2))*z^4)
  + ((1+5*t+O(t^2))*z^5)
  + ((1+6*t+O(t^2))*z^6) + O(z^7)
sage: f.lift_to_precision()
1 + ((1+t+O(t^2))*z) + ((1+2*t+O(t^2))*z^2)
  + ((1+3*t+O(t^2))*z^3)
  + ((1+4*t+O(t^2))*z^4)
  + ((1+5*t+O(t^2))*z^5)
  + ((1+6*t+O(t^2))*z^6) + O(z^7)
P.<t> = PowerSeriesRing(QQ, default_prec=2)
R.<z> = LazyPowerSeriesRing(P)
f = R(lambda n: 1/(1-t)^n)
f
f.lift_to_precision()
log()#

Return the series for the natural logarithm of self.

EXAMPLES:

sage: L = LazyDirichletSeriesRing(QQ, "s")
sage: Z = L(constant=1)
sage: log(Z)                                                                # needs sage.symbolic
1/(2^s) + 1/(3^s) + 1/2/4^s + 1/(5^s) + 1/(7^s) + O(1/(8^s))
L = LazyDirichletSeriesRing(QQ, "s")
Z = L(constant=1)
log(Z)                                                                # needs sage.symbolic
map_coefficients(f)#

Return the series with f applied to each nonzero coefficient of self.

INPUT:

  • func – function that takes in a coefficient and returns a new coefficient

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: m = L(lambda n: n, valuation=0); m
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: m.map_coefficients(lambda c: c + 1)
2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + 8*z^7 + O(z^8)
L.<z> = LazyLaurentSeriesRing(ZZ)
m = L(lambda n: n, valuation=0); m
m.map_coefficients(lambda c: c + 1)

Similarly for Dirichlet series:

sage: L = LazyDirichletSeriesRing(ZZ, "z")
sage: s = L(lambda n: n-1)
sage: s                                                                     # needs sage.symbolic
1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + O(1/(8^z))
sage: ms = s.map_coefficients(lambda c: c + 1)                              # needs sage.symbolic
sage: ms                                                                    # needs sage.symbolic
2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + 8/8^z + O(1/(9^z))
L = LazyDirichletSeriesRing(ZZ, "z")
s = L(lambda n: n-1)
s                                                                     # needs sage.symbolic
ms = s.map_coefficients(lambda c: c + 1)                              # needs sage.symbolic
ms                                                                    # needs sage.symbolic

Similarly for multivariate power series:

sage: L.<x, y> = LazyPowerSeriesRing(QQ)
sage: f = 1/(1-(x+y)); f
1 + (x+y) + (x^2+2*x*y+y^2) + (x^3+3*x^2*y+3*x*y^2+y^3)
 + (x^4+4*x^3*y+6*x^2*y^2+4*x*y^3+y^4)
 + (x^5+5*x^4*y+10*x^3*y^2+10*x^2*y^3+5*x*y^4+y^5)
 + (x^6+6*x^5*y+15*x^4*y^2+20*x^3*y^3+15*x^2*y^4+6*x*y^5+y^6)
 + O(x,y)^7
sage: f.map_coefficients(lambda c: c^2)
1 + (x+y) + (x^2+4*x*y+y^2) + (x^3+9*x^2*y+9*x*y^2+y^3)
 + (x^4+16*x^3*y+36*x^2*y^2+16*x*y^3+y^4)
 + (x^5+25*x^4*y+100*x^3*y^2+100*x^2*y^3+25*x*y^4+y^5)
 + (x^6+36*x^5*y+225*x^4*y^2+400*x^3*y^3+225*x^2*y^4+36*x*y^5+y^6)
 + O(x,y)^7
L.<x, y> = LazyPowerSeriesRing(QQ)
f = 1/(1-(x+y)); f
f.map_coefficients(lambda c: c^2)

Similarly for lazy symmetric functions:

sage: # needs sage.combinat
sage: p = SymmetricFunctions(QQ).p()
sage: L = LazySymmetricFunctions(p)
sage: f = 1/(1-2*L(p[1])); f
p[] + 2*p[1] + (4*p[1,1]) + (8*p[1,1,1]) + (16*p[1,1,1,1])
 + (32*p[1,1,1,1,1]) + (64*p[1,1,1,1,1,1]) + O^7
sage: f.map_coefficients(lambda c: log(c, 2))
p[1] + (2*p[1,1]) + (3*p[1,1,1]) + (4*p[1,1,1,1])
 + (5*p[1,1,1,1,1]) + (6*p[1,1,1,1,1,1]) + O^7
# needs sage.combinat
p = SymmetricFunctions(QQ).p()
L = LazySymmetricFunctions(p)
f = 1/(1-2*L(p[1])); f
f.map_coefficients(lambda c: log(c, 2))
prec()#

Return the precision of the series, which is infinity.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: f = 1/(1 - z)
sage: f.prec()
+Infinity
L.<z> = LazyLaurentSeriesRing(ZZ)
f = 1/(1 - z)
f.prec()
q_pochhammer(q=None)#

Return the infinite q-Pochhammer symbol (a;q), where a is self.

This is also one version of the quantum dilogarithm or the q-Exponential function.

INPUT:

  • q – (default: qQ(q)) the parameter q

EXAMPLES:

sage: q = ZZ['q'].fraction_field().gen()
sage: L.<z> = LazyLaurentSeriesRing(q.parent())
sage: qp = L.q_pochhammer(q)
sage: (z + z^2).q_pochhammer(q) - qp(z + z^2)
O(z^7)
q = ZZ['q'].fraction_field().gen()
L.<z> = LazyLaurentSeriesRing(q.parent())
qp = L.q_pochhammer(q)
(z + z^2).q_pochhammer(q) - qp(z + z^2)
sec()#

Return the secant of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: sec(z)
1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: sec(x/(1-y)).polynomial(4)
5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1
L.<z> = LazyLaurentSeriesRing(QQ)
sec(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
sec(x/(1-y)).polynomial(4)
sech()#

Return the hyperbolic secant of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: sech(z)                                                               # needs sage.libs.flint
1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7)

sage: L.<x, y> = LazyPowerSeriesRing(QQ)
sage: sech(x/(1-y))                                                         # needs sage.libs.flint
1 + (-1/2*x^2) + (-x^2*y) + (5/24*x^4-3/2*x^2*y^2) + (5/6*x^4*y-2*x^2*y^3)
 + (-61/720*x^6+25/12*x^4*y^2-5/2*x^2*y^4) + O(x,y)^7
L.<z> = LazyLaurentSeriesRing(QQ)
sech(z)                                                               # needs sage.libs.flint
L.<x, y> = LazyPowerSeriesRing(QQ)
sech(x/(1-y))                                                         # needs sage.libs.flint
set(s)#

Define an equation by self = s.

INPUT:

  • s – a lazy series

EXAMPLES:

We begin by constructing the Catalan numbers:

sage: L.<z> = LazyPowerSeriesRing(ZZ)
sage: C = L.undefined()
sage: C.define(1 + z*C^2)
sage: C
1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7)
sage: binomial(2000, 1000) / C[1000]                                        # needs sage.symbolic
1001
L.<z> = LazyPowerSeriesRing(ZZ)
C = L.undefined()
C.define(1 + z*C^2)
C
binomial(2000, 1000) / C[1000]                                        # needs sage.symbolic

The Catalan numbers but with a valuation 1:

sage: B = L.undefined(valuation=1)
sage: B.define(z + B^2)
sage: B
z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8)
B = L.undefined(valuation=1)
B.define(z + B^2)
B

We can define multiple series that are linked:

sage: s = L.undefined()
sage: t = L.undefined()
sage: s.define(1 + z*t^3)
sage: t.define(1 + z*s^2)
sage: s[0:9]
[1, 1, 3, 9, 34, 132, 546, 2327, 10191]
sage: t[0:9]
[1, 1, 2, 7, 24, 95, 386, 1641, 7150]
s = L.undefined()
t = L.undefined()
s.define(1 + z*t^3)
t.define(1 + z*s^2)
s[0:9]
t[0:9]

A bigger example:

sage: L.<z> = LazyPowerSeriesRing(ZZ)
sage: A = L.undefined(valuation=5)
sage: B = L.undefined()
sage: C = L.undefined(valuation=2)
sage: A.define(z^5 + B^2)
sage: B.define(z^5 + C^2)
sage: C.define(z^2 + C^2 + A^2)
sage: A[0:15]
[0, 0, 0, 0, 0, 1, 0, 0, 1, 2, 5, 4, 14, 10, 48]
sage: B[0:15]
[0, 0, 0, 0, 1, 1, 2, 0, 5, 0, 14, 0, 44, 0, 138]
sage: C[0:15]
[0, 0, 1, 0, 1, 0, 2, 0, 5, 0, 15, 0, 44, 2, 142]
L.<z> = LazyPowerSeriesRing(ZZ)
A = L.undefined(valuation=5)
B = L.undefined()
C = L.undefined(valuation=2)
A.define(z^5 + B^2)
B.define(z^5 + C^2)
C.define(z^2 + C^2 + A^2)
A[0:15]
B[0:15]
C[0:15]

Counting binary trees:

sage: L.<z> = LazyPowerSeriesRing(QQ)
sage: s = L.undefined(valuation=1)
sage: s.define(z + (s^2+s(z^2))/2)
sage: s[0:9]
[0, 1, 1, 1, 2, 3, 6, 11, 23]
L.<z> = LazyPowerSeriesRing(QQ)
s = L.undefined(valuation=1)
s.define(z + (s^2+s(z^2))/2)
s[0:9]

The q-Catalan numbers:

sage: R.<q> = ZZ[]
sage: L.<z> = LazyLaurentSeriesRing(R)
sage: s = L.undefined(valuation=0)
sage: s.define(1+z*s*s(q*z))
sage: s
1 + z + (q + 1)*z^2 + (q^3 + q^2 + 2*q + 1)*z^3
 + (q^6 + q^5 + 2*q^4 + 3*q^3 + 3*q^2 + 3*q + 1)*z^4
 + (q^10 + q^9 + 2*q^8 + 3*q^7 + 5*q^6 + 5*q^5 + 7*q^4 + 7*q^3 + 6*q^2 + 4*q + 1)*z^5
 + (q^15 + q^14 + 2*q^13 + 3*q^12 + 5*q^11 + 7*q^10 + 9*q^9 + 11*q^8
    + 14*q^7 + 16*q^6 + 16*q^5 + 17*q^4 + 14*q^3 + 10*q^2 + 5*q + 1)*z^6 + O(z^7)
R.<q> = ZZ[]
L.<z> = LazyLaurentSeriesRing(R)
s = L.undefined(valuation=0)
s.define(1+z*s*s(q*z))
s

We count unlabeled ordered trees by total number of nodes and number of internal nodes:

sage: R.<q> = QQ[]
sage: Q.<z> = LazyPowerSeriesRing(R)
sage: leaf = z
sage: internal_node = q * z
sage: L = Q(constant=1, degree=1)
sage: T = Q.undefined(valuation=1)
sage: T.define(leaf + internal_node * L(T))
sage: T[0:6]
[0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q]
R.<q> = QQ[]
Q.<z> = LazyPowerSeriesRing(R)
leaf = z
internal_node = q * z
L = Q(constant=1, degree=1)
T = Q.undefined(valuation=1)
T.define(leaf + internal_node * L(T))
T[0:6]

Similarly for Dirichlet series:

sage: L = LazyDirichletSeriesRing(ZZ, "z")
sage: g = L(constant=1, valuation=2)
sage: F = L.undefined()
sage: F.define(1 + g*F)
sage: F[:16]
[1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3]
sage: oeis(_)                                                       # optional - internet
0: A002033: Number of perfect partitions of n.
1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n.
...

sage: F = L.undefined()
sage: F.define(1 + g*F*F)
sage: F[:16]
[1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5]
L = LazyDirichletSeriesRing(ZZ, "z")
g = L(constant=1, valuation=2)
F = L.undefined()
F.define(1 + g*F)
F[:16]
oeis(_)                                                       # optional - internet
F = L.undefined()
F.define(1 + g*F*F)
F[:16]

We can compute the Frobenius character of unlabeled trees:

sage: # needs sage.combinat
sage: m = SymmetricFunctions(QQ).m()
sage: s = SymmetricFunctions(QQ).s()
sage: L = LazySymmetricFunctions(m)
sage: E = L(lambda n: s[n], valuation=0)
sage: X = L(s[1])
sage: A = L.undefined()
sage: A.define(X*E(A))
sage: A[:6]
[m[1],
 2*m[1, 1] + m[2],
 9*m[1, 1, 1] + 5*m[2, 1] + 2*m[3],
 64*m[1, 1, 1, 1] + 34*m[2, 1, 1] + 18*m[2, 2] + 13*m[3, 1] + 4*m[4],
 625*m[1, 1, 1, 1, 1] + 326*m[2, 1, 1, 1] + 171*m[2, 2, 1] + 119*m[3, 1, 1] + 63*m[3, 2] + 35*m[4, 1] + 9*m[5]]
# needs sage.combinat
m = SymmetricFunctions(QQ).m()
s = SymmetricFunctions(QQ).s()
L = LazySymmetricFunctions(m)
E = L(lambda n: s[n], valuation=0)
X = L(s[1])
A = L.undefined()
A.define(X*E(A))
A[:6]
shift(n)#

Return self with the indices shifted by n.

For example, a Laurent series is multiplied by the power zn, where z is the variable of self. For series with a fixed minimal valuation (e.g., power series), this removes any terms that are less than the minimal valuation.

INPUT:

  • n – the amount to shift

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: f = 1 / (1 + 2*z)
sage: f
1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7)
sage: f.shift(3)
z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10)
sage: f << -3  # shorthand
z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4)
sage: g = z^-3 + 3 + z^2
sage: g.shift(5)
z^2 + 3*z^5 + z^7
sage: L([2,0,3], valuation=2, degree=7, constant=1) << -2
2 + 3*z^2 + z^5 + z^6 + z^7 + O(z^8)

sage: D = LazyDirichletSeriesRing(QQ, 't')
sage: f = D([0,1,2])
sage: f                                                                     # needs sage.symbolic
1/(2^t) + 2/3^t
sage: sf = f.shift(3)
sage: sf                                                                    # needs sage.symbolic
1/(5^t) + 2/6^t
L.<z> = LazyLaurentSeriesRing(ZZ)
f = 1 / (1 + 2*z)
f
f.shift(3)
f << -3  # shorthand
g = z^-3 + 3 + z^2
g.shift(5)
L([2,0,3], valuation=2, degree=7, constant=1) << -2
D = LazyDirichletSeriesRing(QQ, 't')
f = D([0,1,2])
f                                                                     # needs sage.symbolic
sf = f.shift(3)
sf                                                                    # needs sage.symbolic

Examples with power series (where the minimal valuation is 0):

sage: L.<x> = LazyPowerSeriesRing(QQ)
sage: f = 1 / (1 - x)
sage: f.shift(2)
x^2 + x^3 + x^4 + O(x^5)
sage: g = f.shift(-1); g
1 + x + x^2 + O(x^3)
sage: f == g
True
sage: g[-1]
0
sage: h = L(lambda n: 1)
sage: LazyPowerSeriesRing.options.halting_precision(20)  # verify up to degree 20
sage: f == h
True
sage: h == f
True
sage: h.shift(-1) == h
True
sage: LazyPowerSeriesRing.options._reset()

sage: fp = L([3,3,3], constant=1)
sage: fp.shift(2)
3*x^2 + 3*x^3 + 3*x^4 + x^5 + x^6 + x^7 + O(x^8)
sage: fp.shift(-2)
3 + x + x^2 + x^3 + O(x^4)
sage: fp.shift(-7)
1 + x + x^2 + O(x^3)
sage: fp.shift(-5) == g
True
L.<x> = LazyPowerSeriesRing(QQ)
f = 1 / (1 - x)
f.shift(2)
g = f.shift(-1); g
f == g
g[-1]
h = L(lambda n: 1)
LazyPowerSeriesRing.options.halting_precision(20)  # verify up to degree 20
f == h
h == f
h.shift(-1) == h
LazyPowerSeriesRing.options._reset()
fp = L([3,3,3], constant=1)
fp.shift(2)
fp.shift(-2)
fp.shift(-7)
fp.shift(-5) == g

We compare the shifting with converting to the fraction field (see also github issue #35293):

sage: M = L.fraction_field()
sage: f = L([1,2,3,4]); f
1 + 2*x + 3*x^2 + 4*x^3
sage: f.shift(-3)
4
sage: M(f).shift(-3)
x^-3 + 2*x^-2 + 3*x^-1 + 4
M = L.fraction_field()
f = L([1,2,3,4]); f
f.shift(-3)
M(f).shift(-3)

An example with a more general function:

sage: fun = lambda n: 1 if ZZ(n).is_power_of(2) else 0
sage: f = L(fun); f
x + x^2 + x^4 + O(x^7)
sage: fs = f.shift(-4)
sage: fs
1 + x^4 + O(x^7)
sage: fs.shift(4)
x^4 + x^8 + O(x^11)
sage: M(f).shift(-4)
x^-3 + x^-2 + 1 + O(x^4)
fun = lambda n: 1 if ZZ(n).is_power_of(2) else 0
f = L(fun); f
fs = f.shift(-4)
fs
fs.shift(4)
M(f).shift(-4)
sin()#

Return the sine of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: sin(z)
z - 1/6*z^3 + 1/120*z^5 - 1/5040*z^7 + O(z^8)

sage: sin(1 + z)
Traceback (most recent call last):
...
ValueError: can only compose with a positive valuation series

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: sin(x/(1-y)).polynomial(3)
-1/6*x^3 + x*y^2 + x*y + x
L.<z> = LazyLaurentSeriesRing(QQ)
sin(z)
sin(1 + z)
L.<x,y> = LazyPowerSeriesRing(QQ)
sin(x/(1-y)).polynomial(3)
sinh()#

Return the hyperbolic sine of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: sinh(z)
z + 1/6*z^3 + 1/120*z^5 + 1/5040*z^7 + O(z^8)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: sinh(x/(1-y))
x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3)
 + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5)
 + (1/5040*x^7+1/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8
L.<z> = LazyLaurentSeriesRing(QQ)
sinh(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
sinh(x/(1-y))
sqrt()#

Return self^(1/2).

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: sqrt(1+z)
1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: sqrt(1+x/(1-y))
1 + 1/2*x + (-1/8*x^2+1/2*x*y) + (1/16*x^3-1/4*x^2*y+1/2*x*y^2)
 + (-5/128*x^4+3/16*x^3*y-3/8*x^2*y^2+1/2*x*y^3)
 + (7/256*x^5-5/32*x^4*y+3/8*x^3*y^2-1/2*x^2*y^3+1/2*x*y^4)
 + (-21/1024*x^6+35/256*x^5*y-25/64*x^4*y^2+5/8*x^3*y^3-5/8*x^2*y^4+1/2*x*y^5)
 + O(x,y)^7
L.<z> = LazyLaurentSeriesRing(QQ)
sqrt(1+z)
L.<x,y> = LazyPowerSeriesRing(QQ)
sqrt(1+x/(1-y))

This also works for Dirichlet series:

sage: # needs sage.symbolic
sage: D = LazyDirichletSeriesRing(SR, "s")
sage: Z = D(constant=1)
sage: f = sqrt(Z);  f
1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s))
sage: f*f - Z
O(1/(8^s))
# needs sage.symbolic
D = LazyDirichletSeriesRing(SR, "s")
Z = D(constant=1)
f = sqrt(Z);  f
f*f - Z
tan()#

Return the tangent of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: tan(z)
z + 1/3*z^3 + 2/15*z^5 + 17/315*z^7 + O(z^8)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: tan(x/(1-y)).polynomial(5)
2/15*x^5 + 2*x^3*y^2 + x*y^4 + x^3*y + x*y^3 + 1/3*x^3 + x*y^2 + x*y + x
L.<z> = LazyLaurentSeriesRing(QQ)
tan(z)
L.<x,y> = LazyPowerSeriesRing(QQ)
tan(x/(1-y)).polynomial(5)
tanh()#

Return the hyperbolic tangent of self.

EXAMPLES:

sage: L.<z> = LazyLaurentSeriesRing(QQ)
sage: tanh(z)                                                               # needs sage.libs.flint
z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8)

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: tanh(x/(1-y))                                                         # needs sage.libs.flint
x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5-2*x^3*y^2+x*y^4)
 + (2/3*x^5*y-10/3*x^3*y^3+x*y^5) + (-17/315*x^7+2*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8
L.<z> = LazyLaurentSeriesRing(QQ)
tanh(z)                                                               # needs sage.libs.flint
L.<x,y> = LazyPowerSeriesRing(QQ)
tanh(x/(1-y))                                                         # needs sage.libs.flint
truncate(d)#

Return the series obtained by removing all terms of degree at least d.

INPUT:

  • d – integer; the degree from which the series is truncated

EXAMPLES:

Dense implementation:

sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=False)
sage: alpha = 1/(1-z)
sage: alpha
1 + z + z^2 + O(z^3)
sage: beta = alpha.truncate(5)
sage: beta
1 + z + z^2 + z^3 + z^4
sage: alpha - beta
z^5 + z^6 + z^7 + O(z^8)
sage: M = L(lambda n: n, valuation=0); M
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: M.truncate(4)
z + 2*z^2 + 3*z^3
L.<z> = LazyLaurentSeriesRing(ZZ, sparse=False)
alpha = 1/(1-z)
alpha
beta = alpha.truncate(5)
beta
alpha - beta
M = L(lambda n: n, valuation=0); M
M.truncate(4)

Sparse Implementation:

sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
sage: M = L(lambda n: n, valuation=0); M
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7)
sage: M.truncate(4)
z + 2*z^2 + 3*z^3
L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
M = L(lambda n: n, valuation=0); M
M.truncate(4)

Series which are known to be exact can also be truncated:

sage: M = z + z^2 + z^3 + z^4
sage: M.truncate(4)
z + z^2 + z^3
M = z + z^2 + z^3 + z^4
M.truncate(4)
class sage.rings.lazy_series.LazyPowerSeries(parent, coeff_stream)#

Bases: LazyCauchyProductSeries

A Taylor series where the coefficients are computed lazily.

EXAMPLES:

sage: L.<x, y> = LazyPowerSeriesRing(ZZ)
sage: f = 1 / (1 - x^2 + y^3); f
1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7
sage: P.<x, y> = PowerSeriesRing(ZZ, default_prec=101)
sage: g = 1 / (1 - x^2 + y^3); f[100] - g[100]
0
L.<x, y> = LazyPowerSeriesRing(ZZ)
f = 1 / (1 - x^2 + y^3); f
P.<x, y> = PowerSeriesRing(ZZ, default_prec=101)
g = 1 / (1 - x^2 + y^3); f[100] - g[100]

Lazy Taylor series is picklable:

sage: g = loads(dumps(f))
sage: g
1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7
sage: g == f
True
g = loads(dumps(f))
g
g == f
compose(*g)#

Return the composition of self with g.

The arity of self must be equal to the number of arguments provided.

Given a Taylor series f of arity n and a tuple of Taylor series g=(g1,,gn) over the same base ring, the composition fg is defined if and only if for each 1in:

  • gi is zero, or

  • setting all variables except the i-th in f to zero yields a polynomial, or

  • val(gi)>0.

If f is a univariate ‘exact’ series, we can check whether f is a actually a polynomial. However, if f is a multivariate series, we have no way to test whether setting all but one variable of f to zero yields a polynomial, except if f itself is ‘exact’ and therefore a polynomial.

INPUT:

  • g – other series, all can be coerced into the same parent

EXAMPLES:

sage: L.<x, y, z> = LazyPowerSeriesRing(QQ)
sage: M.<a, b> = LazyPowerSeriesRing(ZZ)
sage: g1 = 1 / (1 - x)
sage: g2 = x + y^2
sage: p = a^2 + b + 1
sage: p(g1, g2) - g1^2 - g2 - 1
O(x,y,z)^7
L.<x, y, z> = LazyPowerSeriesRing(QQ)
M.<a, b> = LazyPowerSeriesRing(ZZ)
g1 = 1 / (1 - x)
g2 = x + y^2
p = a^2 + b + 1
p(g1, g2) - g1^2 - g2 - 1

The number of mappings from a set with m elements to a set with n elements:

sage: M.<a> = LazyPowerSeriesRing(QQ)
sage: Ea = M(lambda n: 1/factorial(n))
sage: Ex = L(lambda n: 1/factorial(n)*x^n)
sage: Ea(Ex*y)[5]
1/24*x^4*y + 2/3*x^3*y^2 + 3/4*x^2*y^3 + 1/6*x*y^4 + 1/120*y^5
M.<a> = LazyPowerSeriesRing(QQ)
Ea = M(lambda n: 1/factorial(n))
Ex = L(lambda n: 1/factorial(n)*x^n)
Ea(Ex*y)[5]

So, there are 3!2!2/3=8 mappings from a three element set to a two element set.

We perform the composition with a lazy Laurent series:

sage: N.<w> = LazyLaurentSeriesRing(QQ)
sage: f1 = 1 / (1 - w)
sage: f2 = cot(w / (1 - w))
sage: p(f1, f2)
w^-1 + 1 + 5/3*w + 8/3*w^2 + 164/45*w^3 + 23/5*w^4 + 5227/945*w^5 + O(w^6)
N.<w> = LazyLaurentSeriesRing(QQ)
f1 = 1 / (1 - w)
f2 = cot(w / (1 - w))
p(f1, f2)

We perform the composition with a lazy Dirichlet series:

sage: # needs sage.symbolic
sage: D = LazyDirichletSeriesRing(QQ, "s")
sage: g = D(constant=1)-1
sage: g
1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s))
sage: f = 1 / (1 - x - y*z); f
1 + x + (x^2+y*z) + (x^3+2*x*y*z) + (x^4+3*x^2*y*z+y^2*z^2)
 + (x^5+4*x^3*y*z+3*x*y^2*z^2)
 + (x^6+5*x^4*y*z+6*x^2*y^2*z^2+y^3*z^3)
 + O(x,y,z)^7
sage: fog = f(g, g, g)
sage: fog
1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + O(1/(7^s))
sage: fg = 1 / (1 - g - g*g)
sage: fg
1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + 1/(7^s) + O(1/(8^s))
sage: fog - fg
O(1/(8^s))

sage: f = 1 / (1 - 2*a)
sage: f(g)                                                                  # needs sage.symbolic
1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s))
sage: 1 / (1 - 2*g)                                                         # needs sage.symbolic
1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s))
# needs sage.symbolic
D = LazyDirichletSeriesRing(QQ, "s")
g = D(constant=1)-1
g
f = 1 / (1 - x - y*z); f
fog = f(g, g, g)
fog
fg = 1 / (1 - g - g*g)
fg
fog - fg
f = 1 / (1 - 2*a)
f(g)                                                                  # needs sage.symbolic
1 / (1 - 2*g)                                                         # needs sage.symbolic

The output parent is always the common parent between the base ring of f and the parent of g or extended to the corresponding lazy series:

sage: T.<x,y> = LazyPowerSeriesRing(QQ)
sage: R.<a,b,c> = ZZ[]
sage: S.<v> = R[]
sage: L.<z> = LaurentPolynomialRing(ZZ)
sage: parent(x(a, b))
Multivariate Polynomial Ring in a, b, c over Rational Field
sage: parent(x(CC(2), a))
Multivariate Polynomial Ring in a, b, c over Complex Field with 53 bits of precision
sage: parent(x(0, 0))
Rational Field
sage: f = 1 / (1 - x - y); f
1 + (x+y) + (x^2+2*x*y+y^2) + (x^3+3*x^2*y+3*x*y^2+y^3)
 + (x^4+4*x^3*y+6*x^2*y^2+4*x*y^3+y^4)
 + (x^5+5*x^4*y+10*x^3*y^2+10*x^2*y^3+5*x*y^4+y^5)
 + (x^6+6*x^5*y+15*x^4*y^2+20*x^3*y^3+15*x^2*y^4+6*x*y^5+y^6)
 + O(x,y)^7
sage: f(a^2, b*c)
1 + (a^2+b*c) + (a^4+2*a^2*b*c+b^2*c^2) + (a^6+3*a^4*b*c+3*a^2*b^2*c^2+b^3*c^3) + O(a,b,c)^7
sage: f(v, v^2)
1 + v + 2*v^2 + 3*v^3 + 5*v^4 + 8*v^5 + 13*v^6 + O(v^7)
sage: f(z, z^2 + z)
1 + 2*z + 5*z^2 + 12*z^3 + 29*z^4 + 70*z^5 + 169*z^6 + O(z^7)
sage: three = T(3)(a^2, b); three
3
sage: parent(three)
Multivariate Polynomial Ring in a, b, c over Rational Field
T.<x,y> = LazyPowerSeriesRing(QQ)
R.<a,b,c> = ZZ[]
S.<v> = R[]
L.<z> = LaurentPolynomialRing(ZZ)
parent(x(a, b))
parent(x(CC(2), a))
parent(x(0, 0))
f = 1 / (1 - x - y); f
f(a^2, b*c)
f(v, v^2)
f(z, z^2 + z)
three = T(3)(a^2, b); three
parent(three)
compositional_inverse()#

Return the compositional inverse of self.

Given a Taylor series f in one variable, the compositional inverse is a power series g over the same base ring, such that (fg)(z)=f(g(z))=z.

The compositional inverse exists if and only if:

  • val(f)=1, or

  • f=a+bz with a,b0.

EXAMPLES:

sage: L.<z> = LazyPowerSeriesRing(QQ)
sage: (2*z).revert()
1/2*z
sage: (z-z^2).revert()
z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8)

sage: s = L(degree=1, constant=-1)
sage: s.revert()
-z - z^2 - z^3 + O(z^4)

sage: s = L(degree=1, constant=1)
sage: s.revert()
z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8)
L.<z> = LazyPowerSeriesRing(QQ)
(2*z).revert()
(z-z^2).revert()
s = L(degree=1, constant=-1)
s.revert()
s = L(degree=1, constant=1)
s.revert()

Warning

For series not known to be eventually constant (e.g., being defined by a function) with approximate valuation 1 (but not necessarily its true valuation), this assumes that this is the actual valuation:

sage: f = L(lambda n: n if n > 2 else 0)
sage: f.revert()
<repr(... failed: ValueError: generator already executing>
f = L(lambda n: n if n > 2 else 0)
f.revert()
compute_coefficients(i)#

Computes all the coefficients of self up to i.

This method is deprecated, it has no effect anymore.

derivative(*args)#

Return the derivative of the Taylor series.

Multiple variables and iteration counts may be supplied; see the documentation of sage.calculus.functional.derivative() function for details.

EXAMPLES:

sage: T.<z> = LazyPowerSeriesRing(ZZ)
sage: z.derivative()
1
sage: (1+z+z^2).derivative(3)
0
sage: (1/(1-z)).derivative()
1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7)

sage: R.<q> = QQ[]
sage: L.<x, y> = LazyPowerSeriesRing(R)
sage: f = 1/(1-q*x+y); f
1 + (q*x-y) + (q^2*x^2+(-2*q)*x*y+y^2)
 + (q^3*x^3+(-3*q^2)*x^2*y+3*q*x*y^2-y^3)
 + (q^4*x^4+(-4*q^3)*x^3*y+6*q^2*x^2*y^2+(-4*q)*x*y^3+y^4)
 + (q^5*x^5+(-5*q^4)*x^4*y+10*q^3*x^3*y^2+(-10*q^2)*x^2*y^3+5*q*x*y^4-y^5)
 + (q^6*x^6+(-6*q^5)*x^5*y+15*q^4*x^4*y^2+(-20*q^3)*x^3*y^3+15*q^2*x^2*y^4+(-6*q)*x*y^5+y^6)
 + O(x,y)^7
sage: f.derivative(q)
x + (2*q*x^2+(-2)*x*y) + (3*q^2*x^3+(-6*q)*x^2*y+3*x*y^2)
 + (4*q^3*x^4+(-12*q^2)*x^3*y+12*q*x^2*y^2+(-4)*x*y^3)
 + (5*q^4*x^5+(-20*q^3)*x^4*y+30*q^2*x^3*y^2+(-20*q)*x^2*y^3+5*x*y^4)
 + (6*q^5*x^6+(-30*q^4)*x^5*y+60*q^3*x^4*y^2+(-60*q^2)*x^3*y^3+30*q*x^2*y^4+(-6)*x*y^5)
 + O(x,y)^7
T.<z> = LazyPowerSeriesRing(ZZ)
z.derivative()
(1+z+z^2).derivative(3)
(1/(1-z)).derivative()
R.<q> = QQ[]
L.<x, y> = LazyPowerSeriesRing(R)
f = 1/(1-q*x+y); f
f.derivative(q)
exponential()#

Return the exponential series of self.

This method is deprecated, use exp() instead.

is_unit()#

Return whether this element is a unit in the ring.

EXAMPLES:

sage: L.<z> = LazyPowerSeriesRing(ZZ)
sage: (2*z).is_unit()
False

sage: (1 + 2*z).is_unit()
True

sage: (3 + 2*z).is_unit()
False

sage: L.<x,y> = LazyPowerSeriesRing(ZZ)
sage: (-1 + 2*x + 3*x*y).is_unit()
True
L.<z> = LazyPowerSeriesRing(ZZ)
(2*z).is_unit()
(1 + 2*z).is_unit()
(3 + 2*z).is_unit()
L.<x,y> = LazyPowerSeriesRing(ZZ)
(-1 + 2*x + 3*x*y).is_unit()
polynomial(degree=None, names=None)#

Return self as a polynomial if self is actually so.

INPUT:

  • degreeNone or an integer

  • names – names of the variables; if it is None, the name of the variables of the series is used

OUTPUT:

If degree is not None, the terms of the series of degree greater than degree are first truncated. If degree is None and the series is not a polynomial polynomial, a ValueError is raised.

EXAMPLES:

sage: L.<x,y> = LazyPowerSeriesRing(ZZ)
sage: f = x^2 + y*x - x + 2; f
2 + (-x) + (x^2+x*y)
sage: f.polynomial()
x^2 + x*y - x + 2
L.<x,y> = LazyPowerSeriesRing(ZZ)
f = x^2 + y*x - x + 2; f
f.polynomial()
revert()#

Return the compositional inverse of self.

Given a Taylor series f in one variable, the compositional inverse is a power series g over the same base ring, such that (fg)(z)=f(g(z))=z.

The compositional inverse exists if and only if:

  • val(f)=1, or

  • f=a+bz with a,b0.

EXAMPLES:

sage: L.<z> = LazyPowerSeriesRing(QQ)
sage: (2*z).revert()
1/2*z
sage: (z-z^2).revert()
z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8)

sage: s = L(degree=1, constant=-1)
sage: s.revert()
-z - z^2 - z^3 + O(z^4)

sage: s = L(degree=1, constant=1)
sage: s.revert()
z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8)
L.<z> = LazyPowerSeriesRing(QQ)
(2*z).revert()
(z-z^2).revert()
s = L(degree=1, constant=-1)
s.revert()
s = L(degree=1, constant=1)
s.revert()

Warning

For series not known to be eventually constant (e.g., being defined by a function) with approximate valuation 1 (but not necessarily its true valuation), this assumes that this is the actual valuation:

sage: f = L(lambda n: n if n > 2 else 0)
sage: f.revert()
<repr(... failed: ValueError: generator already executing>
f = L(lambda n: n if n > 2 else 0)
f.revert()
class sage.rings.lazy_series.LazyPowerSeries_gcd_mixin#

Bases: object

A lazy power series that also implements the GCD algorithm.

gcd(other)#

Return the greatest common divisor of self and other.

EXAMPLES:

sage: L.<x> = LazyPowerSeriesRing(QQ)
sage: a = 16*x^5 / (1 - 5*x)
sage: b = (22*x^2 + x^8) / (1 - 4*x^2)
sage: a.gcd(b)
x^2
L.<x> = LazyPowerSeriesRing(QQ)
a = 16*x^5 / (1 - 5*x)
b = (22*x^2 + x^8) / (1 - 4*x^2)
a.gcd(b)
xgcd(f)#

Return the extended gcd of self and f.

OUTPUT:

A triple (g, s, t) such that g is the gcd of self and f, and s and t are cofactors satisfying the Bezout identity

g=sself+tf.

EXAMPLES:

sage: L.<x> = LazyPowerSeriesRing(QQ)
sage: a = 16*x^5 / (1 - 2*x)
sage: b = (22*x^3 + x^8) / (1 - 3*x^2)
sage: g, s, t = a.xgcd(b)
sage: g
x^3
sage: s
1/22 - 41/242*x^2 - 8/121*x^3 + 120/1331*x^4 + 1205/5324*x^5 + 316/14641*x^6 + O(x^7)
sage: t
1/22 - 41/242*x^2 - 8/121*x^3 + 120/1331*x^4 + 1205/5324*x^5 + 316/14641*x^6 + O(x^7)

sage: LazyPowerSeriesRing.options.halting_precision(20)  # verify up to degree 20

sage: g == s * a + t * b
True

sage: a = 16*x^5 / (1 - 2*x)
sage: b = (-16*x^5 + x^8) / (1 - 3*x^2)
sage: g, s, t = a.xgcd(b)
sage: g
x^5
sage: s
1/16 - 1/16*x - 3/16*x^2 + 1/8*x^3 - 17/256*x^4 + 9/128*x^5 + 1/128*x^6 + O(x^7)
sage: t
1/16*x - 1/16*x^2 - 3/16*x^3 + 1/8*x^4 - 17/256*x^5 + 9/128*x^6 + 1/128*x^7 + O(x^8)
sage: g == s * a + t * b
True

sage: # needs sage.rings.finite_rings
sage: L.<x> = LazyPowerSeriesRing(GF(2))
sage: a = L(lambda n: n % 2, valuation=3); a
x^3 + x^5 + x^7 + x^9 + O(x^10)
sage: b = L(lambda n: binomial(n,2) % 2, valuation=3); b
x^3 + x^6 + x^7 + O(x^10)
sage: g, s, t = a.xgcd(b)
sage: g
x^3
sage: s
1 + x + x^3 + x^4 + x^5 + O(x^7)
sage: t
x + x^2 + x^4 + x^5 + x^6 + O(x^8)
sage: g == s * a + t * b
True

sage: LazyPowerSeriesRing.options._reset()  # reset the options
L.<x> = LazyPowerSeriesRing(QQ)
a = 16*x^5 / (1 - 2*x)
b = (22*x^3 + x^8) / (1 - 3*x^2)
g, s, t = a.xgcd(b)
g
s
t
LazyPowerSeriesRing.options.halting_precision(20)  # verify up to degree 20
g == s * a + t * b
a = 16*x^5 / (1 - 2*x)
b = (-16*x^5 + x^8) / (1 - 3*x^2)
g, s, t = a.xgcd(b)
g
s
t
g == s * a + t * b
# needs sage.rings.finite_rings
L.<x> = LazyPowerSeriesRing(GF(2))
a = L(lambda n: n % 2, valuation=3); a
b = L(lambda n: binomial(n,2) % 2, valuation=3); b
g, s, t = a.xgcd(b)
g
s
t
g == s * a + t * b
LazyPowerSeriesRing.options._reset()  # reset the options
class sage.rings.lazy_series.LazySymmetricFunction(parent, coeff_stream)#

Bases: LazyCompletionGradedAlgebraElement

A symmetric function where each degree is computed lazily.

EXAMPLES:

sage: s = SymmetricFunctions(ZZ).s()                                            # needs sage.modules
sage: L = LazySymmetricFunctions(s)                                             # needs sage.modules
s = SymmetricFunctions(ZZ).s()                                            # needs sage.modules
L = LazySymmetricFunctions(s)                                             # needs sage.modules
arithmetic_product(*args)#

Return the arithmetic product of self with g.

The arithmetic product is a binary operation on the ring of symmetric functions which is bilinear in its two arguments and satisfies

pλpμ=i1,j1plcm(λi,μj)gcd(λi,μj)

for any two partitions λ=(λ1,λ2,λ3,) and μ=(μ1,μ2,μ3,) (where pν denotes the power-sum symmetric function indexed by the partition ν, and pi denotes the i-th power-sum symmetric function). This is enough to define the arithmetic product if the base ring is torsion-free as a Z-module; for all other cases the arithmetic product is uniquely determined by requiring it to be functorial in the base ring. See http://mathoverflow.net/questions/138148/ for a discussion of this arithmetic product.

Warning

The operation fg was originally defined only for symmetric functions f and g without constant term. We extend this definition using the convention that the least common multiple of any integer with 0 is 0.

If f and g are two symmetric functions which are homogeneous of degrees a and b, respectively, then fg is homogeneous of degree ab.

The arithmetic product is commutative and associative and has unity e1=p1=h1.

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

INPUT:

  • g – a cycle index series having the same parent as self

OUTPUT:

The arithmetic product of self with g.

EXAMPLES:

For C the species of (oriented) cycles and L+ the species of nonempty linear orders, CL+ corresponds to the species of “regular octopuses”; a (CL+)-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: R.<q> = QQ[]
sage: p = SymmetricFunctions(R).p()                                         # needs sage.modules
sage: m = SymmetricFunctions(R).m()                                         # needs sage.modules
sage: L = LazySymmetricFunctions(m)                                         # needs sage.modules

sage: # needs sage.modules
sage: C = species.CycleSpecies().cycle_index_series()
sage: c = L(lambda n: C[n])
sage: Lplus = L(lambda n: p([1]*n), valuation=1)
sage: r = c.arithmetic_product(Lplus); r                                    # needs sage.libs.pari
m[1] + (3*m[1,1]+2*m[2])
 + (8*m[1,1,1]+4*m[2,1]+2*m[3])
 + (42*m[1,1,1,1]+21*m[2,1,1]+12*m[2,2]+7*m[3,1]+3*m[4])
 + (144*m[1,1,1,1,1]+72*m[2,1,1,1]+36*m[2,2,1]+24*m[3,1,1]+12*m[3,2]+6*m[4,1]+2*m[5])
 + ...
 + O^7
R.<q> = QQ[]
p = SymmetricFunctions(R).p()                                         # needs sage.modules
m = SymmetricFunctions(R).m()                                         # needs sage.modules
L = LazySymmetricFunctions(m)                                         # needs sage.modules
# needs sage.modules
C = species.CycleSpecies().cycle_index_series()
c = L(lambda n: C[n])
Lplus = L(lambda n: p([1]*n), valuation=1)
r = c.arithmetic_product(Lplus); r                                    # needs sage.libs.pari

In particular, the number of regular octopuses is:

sage: [r[n].coefficient([1]*n) for n in range(8)]                           # needs sage.libs.pari sage.modules
[0, 1, 3, 8, 42, 144, 1440, 5760]
[r[n].coefficient([1]*n) for n in range(8)]                           # needs sage.libs.pari sage.modules

It is shown in [MM2008] that the exponential generating function for regular octopuses satisfies (CL+)(x)=n1σ(n)(n1)!xnn! (where σ(n) is the sum of the divisors of n).

sage: [sum(divisors(i))*factorial(i-1) for i in range(1,8)]                 # needs sage.modules
[1, 3, 8, 42, 144, 1440, 5760]
[sum(divisors(i))*factorial(i-1) for i in range(1,8)]                 # needs sage.modules

AUTHORS:

  • Andrew Gainer-Dewar (2013)

REFERENCES:

compositional_inverse()#

Return the compositional inverse of self.

Given a symmetric function f, the compositional inverse is a symmetric function g over the same base ring, such that fg=p1. Thus, it is the inverse with respect to plethystic substitution.

The compositional inverse exists if and only if:

  • val(f)=1, or

  • f=a+bp1 with a,b0.

EXAMPLES:

sage: # needs sage.modules
sage: h = SymmetricFunctions(QQ).h()
sage: L = LazySymmetricFunctions(h)
sage: f = L(lambda n: h[n]) - 1
sage: f(f.revert())
h[1] + O^8
# needs sage.modules
h = SymmetricFunctions(QQ).h()
L = LazySymmetricFunctions(h)
f = L(lambda n: h[n]) - 1
f(f.revert())

ALGORITHM:

Let F be a symmetric function with valuation 1, i.e., whose constant term vanishes and whose degree one term equals bp1. Then

(Fbp1)G=FGbp1G=p1bG,

and therefore G=(p1(Fbp1)G)/b, which allows recursive computation of G.

See also

The compositional inverse Ω of the symmetric function h1+h2+ can be handled much more efficiently using specialized methods. See LogarithmCycleIndexSeries()

AUTHORS:

  • Andrew Gainer-Dewar

  • Martin Rubey

derivative_with_respect_to_p1(n=1)#

Return the symmetric function obtained by taking the derivative of self with respect to the power-sum symmetric function p1 when the expansion of self in the power-sum basis is considered as a polynomial in pk’s (with k1).

This is the same as skewing self by the first power-sum symmetric function p1.

INPUT:

  • n – (default: 1) nonnegative integer which determines which power of the derivative is taken

EXAMPLES:

The species E of sets satisfies the relationship E=E:

sage: # needs sage.modules
sage: h = SymmetricFunctions(QQ).h()
sage: T = LazySymmetricFunctions(h)
sage: E = T(lambda n: h[n])
sage: E - E.derivative_with_respect_to_p1()
O^6
# needs sage.modules
h = SymmetricFunctions(QQ).h()
T = LazySymmetricFunctions(h)
E = T(lambda n: h[n])
E - E.derivative_with_respect_to_p1()

The species C of cyclic orderings and the species L of linear orderings satisfy the relationship C=L:

sage: # needs sage.modules
sage: p = SymmetricFunctions(QQ).p()
sage: C = T(lambda n: (sum(euler_phi(k)*p([k])**(n//k)
....:                      for k in divisors(n))/n if n > 0 else 0))
sage: L = T(lambda n: p([1]*n))
sage: L - C.derivative_with_respect_to_p1()                                 # needs sage.libs.pari
O^6
# needs sage.modules
p = SymmetricFunctions(QQ).p()
C = T(lambda n: (sum(euler_phi(k)*p([k])**(n//k)
                     for k in divisors(n))/n if n > 0 else 0))
L = T(lambda n: p([1]*n))
L - C.derivative_with_respect_to_p1()                                 # needs sage.libs.pari
functorial_composition(*args)#

Return the functorial composition of self and g.

Let X be a finite set of cardinality m. For a group action of the symmetric group g:SnSX and a (possibly virtual) representation of the symmetric group on X, f:SXGL(V), the functorial composition is the (virtual) representation of the symmetric group fg:SnGL(V) given by σf(g(σ)).

This is more naturally phrased in the language of combinatorial species. Let F and G be species, then their functorial composition is the species FG with (FG)[A]=F[G[A]]. In other words, an (FG)-structure on a set A of labels is an F-structure whose labels are the set of all G-structures on A.

The Frobenius character (or cycle index series) of FG can be computed as follows, see section 2.2 of [BLL1998]):

n01n!σSnfixF[(G[σ])1,(G[σ])2,]p1σ1p2σ2.

Warning

The operation fg only makes sense when g corresponds to a permutation representation, i.e., a group action.

EXAMPLES:

The species G of simple graphs can be expressed in terms of a functorial composition: G=pp2, where p is the SubsetSpecies.:

sage: # needs sage.modules
sage: R.<q> = QQ[]
sage: h = SymmetricFunctions(R).h()
sage: m = SymmetricFunctions(R).m()
sage: L = LazySymmetricFunctions(m)
sage: P = L(lambda n: sum(q^k*h[n-k]*h[k] for k in range(n+1)))
sage: P2 = L(lambda n: h[2]*h[n-2], valuation=2)
sage: P.functorial_composition(P2)[:4]                                      # needs sage.libs.pari
[m[],
 m[1],
 (q+1)*m[1, 1] + (q+1)*m[2],
 (q^3+3*q^2+3*q+1)*m[1, 1, 1] + (q^3+2*q^2+2*q+1)*m[2, 1] + (q^3+q^2+q+1)*m[3]]
# needs sage.modules
R.<q> = QQ[]
h = SymmetricFunctions(R).h()
m = SymmetricFunctions(R).m()
L = LazySymmetricFunctions(m)
P = L(lambda n: sum(q^k*h[n-k]*h[k] for k in range(n+1)))
P2 = L(lambda n: h[2]*h[n-2], valuation=2)
P.functorial_composition(P2)[:4]                                      # needs sage.libs.pari

For example, there are:

sage: P.functorial_composition(P2)[4].coefficient([4])[3]                   # needs sage.libs.pari sage.modules
3
P.functorial_composition(P2)[4].coefficient([4])[3]                   # needs sage.libs.pari sage.modules

unlabelled graphs on 4 vertices and 3 edges, and:

sage: P.functorial_composition(P2)[4].coefficient([2,2])[3]                 # needs sage.libs.pari sage.modules
8
P.functorial_composition(P2)[4].coefficient([2,2])[3]                 # needs sage.libs.pari sage.modules

labellings of their vertices with two 1’s and two 2’s.

The symmetric function h1nhn is the neutral element with respect to functorial composition:

sage: # needs sage.modules
sage: p = SymmetricFunctions(QQ).p()
sage: h = SymmetricFunctions(QQ).h()
sage: e = SymmetricFunctions(QQ).e()
sage: L = LazySymmetricFunctions(h)
sage: H = L(lambda n: h[n])
sage: Ep = p[1]*H.derivative_with_respect_to_p1(); Ep
h[1] + (h[1,1]) + (h[2,1]) + (h[3,1]) + (h[4,1]) + (h[5,1]) + O^7
sage: f = L(lambda n: h[n-n//2, n//2])
sage: f - Ep.functorial_composition(f)                                      # needs sage.libs.pari
O^7
# needs sage.modules
p = SymmetricFunctions(QQ).p()
h = SymmetricFunctions(QQ).h()
e = SymmetricFunctions(QQ).e()
L = LazySymmetricFunctions(h)
H = L(lambda n: h[n])
Ep = p[1]*H.derivative_with_respect_to_p1(); Ep
f = L(lambda n: h[n-n//2, n//2])
f - Ep.functorial_composition(f)                                      # needs sage.libs.pari

The symmetric function nhn is a left absorbing element:

sage: # needs sage.modules
sage: H.functorial_composition(f) - H
O^7
# needs sage.modules
H.functorial_composition(f) - H

The functorial composition distributes over the sum:

sage: # needs sage.modules
sage: F1 = L(lambda n: h[n])
sage: F2 = L(lambda n: e[n])
sage: f1 = F1.functorial_composition(f)
sage: f2 = F2.functorial_composition(f)
sage: (F1 + F2).functorial_composition(f) - f1 - f2         # long time
O^7
# needs sage.modules
F1 = L(lambda n: h[n])
F2 = L(lambda n: e[n])
f1 = F1.functorial_composition(f)
f2 = F2.functorial_composition(f)
(F1 + F2).functorial_composition(f) - f1 - f2         # long time
is_unit()#

Return whether this element is a unit in the ring.

EXAMPLES:

sage: # needs sage.modules
sage: m = SymmetricFunctions(ZZ).m()
sage: L = LazySymmetricFunctions(m)
sage: L(2*m[1]).is_unit()
False
sage: L(-1 + 2*m[1]).is_unit()
True
sage: L(2 + m[1]).is_unit()
False
sage: m = SymmetricFunctions(QQ).m()
sage: L = LazySymmetricFunctions(m)
sage: L(2 + 3*m[1]).is_unit()
True
# needs sage.modules
m = SymmetricFunctions(ZZ).m()
L = LazySymmetricFunctions(m)
L(2*m[1]).is_unit()
L(-1 + 2*m[1]).is_unit()
L(2 + m[1]).is_unit()
m = SymmetricFunctions(QQ).m()
L = LazySymmetricFunctions(m)
L(2 + 3*m[1]).is_unit()
plethysm(*args)#

Return the composition of self with g.

The arity of self must be equal to the number of arguments provided.

Given a lazy symmetric function f of arity n and a tuple of lazy symmetric functions g=(g1,,gn) over the same base ring, the composition (or plethysm) (fg) is defined if and only if for each 1in:

  • gi=0, or

  • setting all alphabets except the i-th in f to zero yields a symmetric function with only finitely many non-zero coefficients, or

  • val(g)>0.

If f is a univariate ‘exact’ lazy symmetric function, we can check whether f has only finitely many non-zero coefficients. However, if f has larger arity, we have no way to test whether setting all but one alphabets of f to zero yields a polynomial, except if f itself is ‘exact’ and therefore a symmetric function with only finitely many non-zero coefficients.

INPUT:

  • g – other (lazy) symmetric functions

Todo

Allow specification of degree one elements.

EXAMPLES:

sage: # needs sage.modules
sage: P.<q> = QQ[]
sage: s = SymmetricFunctions(P).s()
sage: L = LazySymmetricFunctions(s)
sage: f = s[2]
sage: g = s[3]
sage: L(f)(L(g)) - L(f(g))
0
sage: f = s[2] + s[2,1]
sage: g = s[1] + s[2,2]
sage: L(f)(L(g)) - L(f(g))
0
sage: L(f)(g) - L(f(g))
0
sage: f = s[2] + s[2,1]
sage: g = s[1] + s[2,2]
sage: L(f)(L(q*g)) - L(f(q*g))
0
# needs sage.modules
P.<q> = QQ[]
s = SymmetricFunctions(P).s()
L = LazySymmetricFunctions(s)
f = s[2]
g = s[3]
L(f)(L(g)) - L(f(g))
f = s[2] + s[2,1]
g = s[1] + s[2,2]
L(f)(L(g)) - L(f(g))
L(f)(g) - L(f(g))
f = s[2] + s[2,1]
g = s[1] + s[2,2]
L(f)(L(q*g)) - L(f(q*g))

The Frobenius character of the permutation action on set partitions is a plethysm:

sage: # needs sage.modules
sage: s = SymmetricFunctions(QQ).s()
sage: S = LazySymmetricFunctions(s)
sage: E1 = S(lambda n: s[n], valuation=1)
sage: E = 1 + E1
sage: P = E(E1)
sage: P[:5]
[s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]]
# needs sage.modules
s = SymmetricFunctions(QQ).s()
S = LazySymmetricFunctions(s)
E1 = S(lambda n: s[n], valuation=1)
E = 1 + E1
P = E(E1)
P[:5]

The plethysm with a tensor product is also implemented:

sage: # needs sage.modules
sage: s = SymmetricFunctions(QQ).s()
sage: X = tensor([s[1],s[[]]])
sage: Y = tensor([s[[]],s[1]])
sage: S = LazySymmetricFunctions(s)
sage: S2 = LazySymmetricFunctions(tensor([s, s]))
sage: A = S(s[1,1,1])
sage: B = S2(X+Y)
sage: A(B)                                                                  # needs lrcalc_python
(s[]#s[1,1,1]+s[1]#s[1,1]+s[1,1]#s[1]+s[1,1,1]#s[])

sage: H = S(lambda n: s[n])                                                 # needs sage.modules
sage: H(S2(X*Y))                                                            # needs lrcalc_python sage.modules
(s[]#s[]) + (s[1]#s[1]) + (s[1,1]#s[1,1]+s[2]#s[2])
 + (s[1,1,1]#s[1,1,1]+s[2,1]#s[2,1]+s[3]#s[3]) + O^7
sage: H(S2(X+Y))                                                            # needs sage.modules
(s[]#s[]) + (s[]#s[1]+s[1]#s[]) + (s[]#s[2]+s[1]#s[1]+s[2]#s[])
 + (s[]#s[3]+s[1]#s[2]+s[2]#s[1]+s[3]#s[])
 + (s[]#s[4]+s[1]#s[3]+s[2]#s[2]+s[3]#s[1]+s[4]#s[])
 + (s[]#s[5]+s[1]#s[4]+s[2]#s[3]+s[3]#s[2]+s[4]#s[1]+s[5]#s[])
 + (s[]#s[6]+s[1]#s[5]+s[2]#s[4]+s[3]#s[3]+s[4]#s[2]+s[5]#s[1]+s[6]#s[])
 + O^7
# needs sage.modules
s = SymmetricFunctions(QQ).s()
X = tensor([s[1],s[[]]])
Y = tensor([s[[]],s[1]])
S = LazySymmetricFunctions(s)
S2 = LazySymmetricFunctions(tensor([s, s]))
A = S(s[1,1,1])
B = S2(X+Y)
A(B)                                                                  # needs lrcalc_python
H = S(lambda n: s[n])                                                 # needs sage.modules
H(S2(X*Y))                                                            # needs lrcalc_python sage.modules
H(S2(X+Y))                                                            # needs sage.modules
plethystic_inverse()#

Return the compositional inverse of self.

Given a symmetric function f, the compositional inverse is a symmetric function g over the same base ring, such that fg=p1. Thus, it is the inverse with respect to plethystic substitution.

The compositional inverse exists if and only if:

  • val(f)=1, or

  • f=a+bp1 with a,b0.

EXAMPLES:

sage: # needs sage.modules
sage: h = SymmetricFunctions(QQ).h()
sage: L = LazySymmetricFunctions(h)
sage: f = L(lambda n: h[n]) - 1
sage: f(f.revert())
h[1] + O^8
# needs sage.modules
h = SymmetricFunctions(QQ).h()
L = LazySymmetricFunctions(h)
f = L(lambda n: h[n]) - 1
f(f.revert())

ALGORITHM:

Let F be a symmetric function with valuation 1, i.e., whose constant term vanishes and whose degree one term equals bp1. Then

(Fbp1)G=FGbp1G=p1bG,

and therefore G=(p1(Fbp1)G)/b, which allows recursive computation of G.

See also

The compositional inverse Ω of the symmetric function h1+h2+ can be handled much more efficiently using specialized methods. See LogarithmCycleIndexSeries()

AUTHORS:

  • Andrew Gainer-Dewar

  • Martin Rubey

revert()#

Return the compositional inverse of self.

Given a symmetric function f, the compositional inverse is a symmetric function g over the same base ring, such that fg=p1. Thus, it is the inverse with respect to plethystic substitution.

The compositional inverse exists if and only if:

  • val(f)=1, or

  • f=a+bp1 with a,b0.

EXAMPLES:

sage: # needs sage.modules
sage: h = SymmetricFunctions(QQ).h()
sage: L = LazySymmetricFunctions(h)
sage: f = L(lambda n: h[n]) - 1
sage: f(f.revert())
h[1] + O^8
# needs sage.modules
h = SymmetricFunctions(QQ).h()
L = LazySymmetricFunctions(h)
f = L(lambda n: h[n]) - 1
f(f.revert())

ALGORITHM:

Let F be a symmetric function with valuation 1, i.e., whose constant term vanishes and whose degree one term equals bp1. Then

(Fbp1)G=FGbp1G=p1bG,

and therefore G=(p1(Fbp1)G)/b, which allows recursive computation of G.

See also

The compositional inverse Ω of the symmetric function h1+h2+ can be handled much more efficiently using specialized methods. See LogarithmCycleIndexSeries()

AUTHORS:

  • Andrew Gainer-Dewar

  • Martin Rubey

symmetric_function(degree=None)#

Return self as a symmetric function if self is actually so.

INPUT:

  • degreeNone or an integer

OUTPUT:

If degree is not None, the terms of the series of degree greater than degree are first truncated. If degree is None and the series is not a polynomial polynomial, a ValueError is raised.

EXAMPLES:

sage: # needs sage.modules
sage: s = SymmetricFunctions(QQ).s()
sage: S = LazySymmetricFunctions(s)
sage: elt = S(s[2])
sage: elt.symmetric_function()
s[2]
# needs sage.modules
s = SymmetricFunctions(QQ).s()
S = LazySymmetricFunctions(s)
elt = S(s[2])
elt.symmetric_function()