Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 1d559cc

Browse files
committedAug 29, 2022
improve composing Taylor series, start making plethysm more general
1 parent 07ca029 commit 1d559cc

File tree

2 files changed

+152
-47
lines changed

2 files changed

+152
-47
lines changed
 

Diff for: ‎src/sage/combinat/sf/sfa.py

+8
Original file line numberDiff line numberDiff line change
@@ -3093,6 +3093,14 @@ def plethysm(self, x, include=None, exclude=None):
30933093
sage: r - f(g, include=[])
30943094
(a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2]
30953095
3096+
Check that we can compute the plethysm with a constant::
3097+
3098+
sage: p[2,2,1](2)
3099+
8
3100+
3101+
sage: p[2,2,1](a1)
3102+
a1^5
3103+
30963104
.. TODO::
30973105
30983106
The implementation of plethysm in

Diff for: ‎src/sage/rings/lazy_series.py

+144-47
Original file line numberDiff line numberDiff line change
@@ -2706,7 +2706,7 @@ def __call__(self, g, *, check=True):
27062706
r"""
27072707
Return the composition of ``self`` with ``g``.
27082708
2709-
Given two Laurent Series `f` and `g` over the same base ring, the
2709+
Given two Laurent series `f` and `g` over the same base ring, the
27102710
composition `(f \circ g)(z) = f(g(z))` is defined if and only if:
27112711
27122712
- `g = 0` and `val(f) >= 0`,
@@ -2907,7 +2907,7 @@ def __call__(self, g, *, check=True):
29072907
ZeroDivisionError: the valuation of the series must be nonnegative
29082908
29092909
`g \neq 0` and `val(g) \leq 0` and `f` has infinitely many
2910-
non-zero coefficients`::
2910+
non-zero coefficients::
29112911
29122912
sage: g = z^-1 + z^-2
29132913
sage: g.valuation() <= 0
@@ -3110,8 +3110,8 @@ def revert(self):
31103110
r"""
31113111
Return the compositional inverse of ``self``.
31123112
3113-
Given a Laurent Series `f`. the compositional inverse is a
3114-
Laurent Series `g` over the same base ring, such that
3113+
Given a Laurent series `f`, the compositional inverse is a
3114+
Laurent series `g` over the same base ring, such that
31153115
`(f \circ g)(z) = f(g(z)) = z`.
31163116
31173117
The compositional inverse exists if and only if:
@@ -3343,10 +3343,10 @@ def polynomial(self, degree=None, name=None):
33433343
A Laurent polynomial if the valuation of the series is negative or
33443344
a polynomial otherwise.
33453345
3346-
If ``degree`` is not ``None``, the terms of the series of degree
3347-
greater than ``degree`` are truncated first. If ``degree`` is ``None``
3348-
and the series is not a polynomial or a Laurent polynomial, a
3349-
``ValueError`` is raised.
3346+
If ``degree`` is not ``None``, the terms of the series of
3347+
degree greater than ``degree`` are first truncated. If
3348+
``degree`` is ``None`` and the series is not a polynomial or
3349+
a Laurent polynomial, a ``ValueError`` is raised.
33503350
33513351
EXAMPLES::
33523352
@@ -3387,6 +3387,7 @@ def polynomial(self, degree=None, name=None):
33873387
33883388
sage: L.zero().polynomial()
33893389
0
3390+
33903391
"""
33913392
S = self.parent()
33923393

@@ -3481,12 +3482,21 @@ def __call__(self, *g, check=True):
34813482
The arity of ``self`` must be equal to the number of
34823483
arguments provided.
34833484
3484-
Given two Taylor Series `f` and `g` over the same base ring, the
3485-
composition `(f \circ g)(z) = f(g(z))` is defined if and only if:
3485+
Given a Taylor series `f` of arity `n` and a tuple of Taylor
3486+
series `g = (g_1,\dots, g_n)` over the same base ring, the
3487+
composition `f \circ g` is defined if and only if for each
3488+
`1\leq k\leq n`:
34863489
3487-
- `g = 0` and `val(f) >= 0`,
3488-
- `g` is non-zero and `f` has only finitely many non-zero coefficients,
3489-
- `g` is non-zero and `val(g) > 0`.
3490+
- `g_i` is zero, or
3491+
- setting all variables except the `i`th in `f` to zero
3492+
yields a polynomial, or
3493+
- `val(g_i) > 0`.
3494+
3495+
If `f` is a univariate 'exact' series, we can check whether
3496+
`f` is a actually a polynomial. However, if `f` is a
3497+
multivariate series, we have no way to test whether setting
3498+
all but one variable of `f` to zero yields a polynomial,
3499+
except if `f` itself is 'exact' and therefore a polynomial.
34903500
34913501
INPUT:
34923502
@@ -3615,17 +3625,54 @@ def __call__(self, *g, check=True):
36153625
sage: gp.define(z / f(gp))
36163626
sage: gp
36173627
z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8)
3628+
3629+
Check that composing the zero series with anything yields zero::
3630+
3631+
sage: T.<x,y> = LazyTaylorSeriesRing(QQ)
3632+
sage: M.<a, b> = LazyTaylorSeriesRing(QQ)
3633+
sage: T(0)(1/(1-a), a+b)
3634+
0
3635+
3636+
Check that composing `f` with zero series yields the constant term of `f`::
3637+
3638+
sage: T(3/(1-x-2*y))(0, 0)
3639+
3
3640+
3641+
Check that we can compose a polynomial with anything::
3642+
3643+
sage: T(1-x-2*y + x*y^2)(1, 3)
3644+
3
3645+
3646+
sage: T(1-x-2*y + x*y^2)(1 + a, 3)
3647+
3 + 8*a
3648+
3649+
sage: T(1-x-2*y + x*y^2)(1/(1-a), 3)
3650+
3 + 8*a + 8*a^2 + 8*a^3 + 8*a^4 + 8*a^5 + 8*a^6 + O(a,b)^7
3651+
36183652
"""
3619-
if len(g) != len(self.parent().variable_names()):
3653+
fP = parent(self)
3654+
if len(g) != fP._arity:
36203655
raise ValueError("arity of must be equal to the number of arguments provided")
36213656

36223657
# Find a good parent for the result
36233658
from sage.structure.element import get_coercion_model
36243659
cm = get_coercion_model()
36253660
P = cm.common_parent(self.base_ring(), *[parent(h) for h in g])
36263661

3627-
# f has finite length
3628-
if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant:
3662+
# f = 0
3663+
if isinstance(self._coeff_stream, Stream_zero):
3664+
return P.zero()
3665+
3666+
# g = (0, ..., 0)
3667+
if all((not isinstance(h, LazyModuleElement) and not h)
3668+
or (isinstance(h, LazyModuleElement)
3669+
and isinstance(h._coeff_stream, Stream_zero))
3670+
for h in g):
3671+
return P(self[0])
3672+
3673+
# f has finite length and f != 0
3674+
if (isinstance(self._coeff_stream, Stream_exact)
3675+
and not self._coeff_stream._constant):
36293676
# constant polynomial
36303677
poly = self.polynomial()
36313678
if poly.is_constant():
@@ -3640,7 +3687,6 @@ def __call__(self, *g, check=True):
36403687
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate
36413688
from sage.rings.lazy_series_ring import LazySeriesRing
36423689
if not isinstance(P, LazySeriesRing):
3643-
fP = parent(self)
36443690
if fP._laurent_poly_ring.has_coerce_map_from(P):
36453691
S = fP._laurent_poly_ring
36463692
P = fP
@@ -3708,8 +3754,8 @@ def revert(self):
37083754
r"""
37093755
Return the compositional inverse of ``self``.
37103756
3711-
Given a Taylor Series `f`. the compositional inverse is a
3712-
Laurent Series `g` over the same base ring, such that
3757+
Given a Taylor series `f`, the compositional inverse is a
3758+
Laurent series `g` over the same base ring, such that
37133759
`(f \circ g)(z) = f(g(z)) = z`.
37143760
37153761
The compositional inverse exists if and only if:
@@ -3932,9 +3978,10 @@ def polynomial(self, degree=None, names=None):
39323978
39333979
OUTPUT:
39343980
3935-
If ``degree`` is not ``None``, the terms of the series of degree greater
3936-
than ``degree`` are truncated first. If ``degree`` is ``None`` and the
3937-
series is not a polynomial polynomial, a ``ValueError`` is raised.
3981+
If ``degree`` is not ``None``, the terms of the series of
3982+
degree greater than ``degree`` are first truncated. If
3983+
``degree`` is ``None`` and the series is not a polynomial
3984+
polynomial, a ``ValueError`` is raised.
39383985
39393986
EXAMPLES::
39403987
@@ -3966,6 +4013,7 @@ def polynomial(self, degree=None, names=None):
39664013
sage: f = z-z^2
39674014
sage: f.polynomial()
39684015
-z^2 + z
4016+
39694017
"""
39704018
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
39714019
S = self.parent()
@@ -4077,24 +4125,35 @@ class LazySymmetricFunction(LazyCompletionGradedAlgebraElement):
40774125
sage: s = SymmetricFunctions(ZZ).s()
40784126
sage: L = LazySymmetricFunctions(s)
40794127
"""
4080-
def __call__(self, *args, check=True):
4128+
def __call__(self, *g, check=True):
40814129
r"""
4082-
Return the composition of ``self`` with ``args``.
4130+
Return the composition of ``self`` with ``g``.
40834131
40844132
The arity of ``self`` must be equal to the number of
40854133
arguments provided.
40864134
4087-
Given two lazy symmetric functions `f` and `g` over the same
4088-
base ring, the composition (or plethysm) `(f \circ g)` is
4089-
defined if and only if:
4090-
4091-
- `g = 0`,
4092-
- `g` is non-zero and `f` has only finitely many non-zero coefficients,
4093-
- `g` is non-zero and `val(g) > 0`.
4135+
Given a lazy symmetric function `f` of arity `n` and a tuple
4136+
of lazy symmetric functions `g = (g_1,\dots, g_n)` over the
4137+
same base ring, the composition (or plethysm) `(f \circ g)`
4138+
is defined if and only if for each `1\leq k\leq n`:
4139+
4140+
- `g_i = 0`, or
4141+
- setting all alphabets except the `i`th in `f` to zero
4142+
yields a symmetric function with only finitely many
4143+
non-zero coefficients, or
4144+
- `val(g) > 0`.
4145+
4146+
If `f` is a univariate 'exact' lazy symmetric function, we
4147+
can check whether `f` has only finitely many non-zero
4148+
coefficients. However, if `f` has larger arity, we have no
4149+
way to test whether setting all but one alphabets of `f` to
4150+
zero yields a polynomial, except if `f` itself is 'exact' and
4151+
therefore a symmetric function with only finitely many
4152+
non-zero coefficients.
40944153
40954154
INPUT:
40964155
4097-
- ``args`` -- other (lazy) symmetric functions
4156+
- ``g`` -- other (lazy) symmetric functions
40984157
40994158
.. TODO::
41004159
@@ -4176,28 +4235,64 @@ def __call__(self, *args, check=True):
41764235
Traceback (most recent call last):
41774236
...
41784237
ValueError: can only compose with a positive valuation series
4238+
4239+
Check that composing the zero series with anything yields
4240+
zero in the correct parent::
4241+
4242+
sage: e = SymmetricFunctions(QQ).e()
4243+
sage: h = SymmetricFunctions(QQ).h()
4244+
sage: s = SymmetricFunctions(QQ).s()
4245+
sage: p = SymmetricFunctions(QQ).p()
4246+
sage: L = LazySymmetricFunctions(tensor([e, h]))
4247+
sage: r = (L(0)(s[1], p[1])); r
4248+
0
4249+
sage: r.parent()
4250+
Symmetric Functions over Rational Field in the Schur basis
4251+
4252+
Check that composing `f` with zero series yields the constant term of `f`::
4253+
4254+
sage: f = 3*L(tensor([s[1], s[1]]))
4255+
sage: f(0, 0)
4256+
0
4257+
sage: (3+f)(0, 0)
4258+
3
41794259
"""
4180-
if len(args) != self.parent()._arity:
4260+
fP = parent(self)
4261+
if len(g) != fP._arity:
41814262
raise ValueError("arity must be equal to the number of arguments provided")
4263+
4264+
# we actually do not need this
41824265
from sage.combinat.sf.sfa import is_SymmetricFunction
4183-
if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) or not g for g in args):
4184-
raise ValueError("all arguments must be (possibly lazy) symmetric functions")
4266+
# if not all(isinstance(h, LazySymmetricFunction)
4267+
# or is_SymmetricFunction(h) or not h for h in g):
4268+
# raise ValueError("all arguments must be (possibly lazy) symmetric functions")
41854269

4186-
if isinstance(self._coeff_stream, Stream_zero):
4187-
return self
4270+
# Find a good parent for the result
4271+
from sage.structure.element import get_coercion_model
4272+
cm = get_coercion_model()
4273+
P = cm.common_parent(self.base_ring(), *[parent(h) for h in g])
41884274

4189-
if len(args) == 1:
4190-
g = args[0]
4191-
P = g.parent()
4275+
# f = 0
4276+
if isinstance(self._coeff_stream, Stream_zero):
4277+
return P.zero()
41924278

4193-
# Handle other types of 0s
4194-
if not isinstance(g, LazySymmetricFunction) and not g:
4195-
return P(self[0].leading_coefficient())
4279+
# g = (0, ..., 0)
4280+
if all((not isinstance(h, LazyModuleElement) and not h)
4281+
or (isinstance(h, LazyModuleElement)
4282+
and isinstance(h._coeff_stream, Stream_zero))
4283+
for h in g):
4284+
f = self[0]
4285+
# FIXME: TypeError: unable to convert 0 to a rational
4286+
if f:
4287+
return P(f.leading_coefficient())
4288+
return P.zero()
41964289

4290+
if len(g) == 1:
4291+
g = g[0]
41974292
if (isinstance(self._coeff_stream, Stream_exact)
41984293
and not self._coeff_stream._constant):
41994294
f = self.symmetric_function()
4200-
if is_SymmetricFunction(g):
4295+
if not isinstance(g, LazySymmetricFunction):
42014296
return f(g)
42024297
# g must be a LazySymmetricFunction
42034298
if (isinstance(g._coeff_stream, Stream_exact)
@@ -4422,9 +4517,10 @@ def symmetric_function(self, degree=None):
44224517
44234518
OUTPUT:
44244519
4425-
If ``degree`` is not ``None``, the terms of the series of degree greater
4426-
than ``degree`` are truncated first. If ``degree`` is ``None`` and the
4427-
series is not a polynomial polynomial, a ``ValueError`` is raised.
4520+
If ``degree`` is not ``None``, the terms of the series of
4521+
degree greater than ``degree`` are first truncated. If
4522+
``degree`` is ``None`` and the series is not a polynomial
4523+
polynomial, a ``ValueError`` is raised.
44284524
44294525
EXAMPLES::
44304526
@@ -4459,6 +4555,7 @@ def symmetric_function(self, degree=None):
44594555
0
44604556
sage: f4.symmetric_function(0)
44614557
s[]
4558+
44624559
"""
44634560
S = self.parent()
44644561
R = S._laurent_poly_ring

0 commit comments

Comments
 (0)
This repository has been archived.