Skip to content

Commit e1e7f0d

Browse files
committed
Merge branch 'u/mantepse/implement_derivatives_of_lazy_series' of trac.sagemath.org:sage into t/34473/remove_rings_from_streams
2 parents cae9ee5 + 5666eae commit e1e7f0d

File tree

7 files changed

+1517
-222
lines changed

7 files changed

+1517
-222
lines changed

src/sage/categories/commutative_algebras.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
# http://www.gnu.org/licenses/
1111
#******************************************************************************
1212

13+
from sage.misc.cachefunc import cached_method
1314
from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring
1415
from sage.categories.algebras import Algebras
16+
from sage.categories.commutative_rings import CommutativeRings
17+
from sage.categories.tensor import TensorProductsCategory
1518

1619
class CommutativeAlgebras(CategoryWithAxiom_over_base_ring):
1720
"""
@@ -36,7 +39,7 @@ class CommutativeAlgebras(CategoryWithAxiom_over_base_ring):
3639
True
3740
sage: TestSuite(CommutativeAlgebras(ZZ)).run()
3841
39-
Todo:
42+
.. TODO::
4043
4144
- product ( = Cartesian product)
4245
- coproduct ( = tensor product over base ring)
@@ -58,3 +61,32 @@ def __contains__(self, A):
5861
"""
5962
return super().__contains__(A) or \
6063
(A in Algebras(self.base_ring()) and hasattr(A, "is_commutative") and A.is_commutative())
64+
65+
class TensorProducts(TensorProductsCategory):
66+
"""
67+
The category of commutative algebras constructed by tensor product of commutative algebras.
68+
"""
69+
70+
@cached_method
71+
def extra_super_categories(self):
72+
"""
73+
EXAMPLES::
74+
75+
sage: Algebras(QQ).Commutative().TensorProducts().extra_super_categories()
76+
[Category of commutative rings]
77+
sage: Algebras(QQ).Commutative().TensorProducts().super_categories()
78+
[Category of tensor products of algebras over Rational Field,
79+
Category of commutative algebras over Rational Field]
80+
81+
TESTS::
82+
83+
sage: X = algebras.Shuffle(QQ, 'ab')
84+
sage: Y = algebras.Shuffle(QQ, 'bc')
85+
sage: X in Algebras(QQ).Commutative()
86+
True
87+
sage: T = tensor([X, Y])
88+
sage: T in CommutativeRings()
89+
True
90+
"""
91+
return [CommutativeRings()]
92+

src/sage/combinat/partition.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,19 @@ def __truediv__(self, p):
10571057

10581058
return SkewPartition([self[:], p])
10591059

1060+
def stretch(self, k):
1061+
"""
1062+
Return the partition obtained by multiplying each part with the
1063+
given number.
1064+
1065+
EXAMPLES::
1066+
1067+
sage: p = Partition([4,2,2,1,1])
1068+
sage: p.stretch(3)
1069+
[12, 6, 6, 3, 3]
1070+
"""
1071+
return _Partitions([k * p for p in self])
1072+
10601073
def power(self, k):
10611074
r"""
10621075
Return the cycle type of the `k`-th power of any permutation

src/sage/combinat/sf/powersum.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,8 @@ def frobenius(self, n):
476476
477477
:meth:`~sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.plethysm`
478478
"""
479-
dct = {Partition([n * i for i in lam]): coeff
480-
for (lam, coeff) in self.monomial_coefficients().items()}
479+
dct = {lam.stretch(n): coeff
480+
for lam, coeff in self.monomial_coefficients().items()}
481481
return self.parent()._from_dict(dct)
482482

483483
adams_operation = frobenius

src/sage/combinat/sf/sfa.py

Lines changed: 183 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3072,6 +3072,31 @@ def plethysm(self, x, include=None, exclude=None):
30723072
sage: sum(s[mu](X)*s[mu.conjugate()](Y) for mu in P5) == sum(m[mu](X)*e[mu](Y) for mu in P5)
30733073
True
30743074
3075+
Sage can also do the plethysm with an element in the completion::
3076+
3077+
sage: L = LazySymmetricFunctions(s)
3078+
sage: f = s[2,1]
3079+
sage: g = L(s[1]) / (1 - L(s[1])); g
3080+
s[1] + (s[1,1]+s[2]) + (s[1,1,1]+2*s[2,1]+s[3])
3081+
+ (s[1,1,1,1]+3*s[2,1,1]+2*s[2,2]+3*s[3,1]+s[4])
3082+
+ (s[1,1,1,1,1]+4*s[2,1,1,1]+5*s[2,2,1]+6*s[3,1,1]+5*s[3,2]+4*s[4,1]+s[5])
3083+
+ ... + O^8
3084+
sage: fog = f(g)
3085+
sage: fog[:8]
3086+
[s[2, 1],
3087+
s[1, 1, 1, 1] + 3*s[2, 1, 1] + 2*s[2, 2] + 3*s[3, 1] + s[4],
3088+
2*s[1, 1, 1, 1, 1] + 8*s[2, 1, 1, 1] + 10*s[2, 2, 1]
3089+
+ 12*s[3, 1, 1] + 10*s[3, 2] + 8*s[4, 1] + 2*s[5],
3090+
3*s[1, 1, 1, 1, 1, 1] + 17*s[2, 1, 1, 1, 1] + 30*s[2, 2, 1, 1]
3091+
+ 16*s[2, 2, 2] + 33*s[3, 1, 1, 1] + 54*s[3, 2, 1] + 16*s[3, 3]
3092+
+ 33*s[4, 1, 1] + 30*s[4, 2] + 17*s[5, 1] + 3*s[6],
3093+
5*s[1, 1, 1, 1, 1, 1, 1] + 30*s[2, 1, 1, 1, 1, 1] + 70*s[2, 2, 1, 1, 1]
3094+
+ 70*s[2, 2, 2, 1] + 75*s[3, 1, 1, 1, 1] + 175*s[3, 2, 1, 1]
3095+
+ 105*s[3, 2, 2] + 105*s[3, 3, 1] + 100*s[4, 1, 1, 1] + 175*s[4, 2, 1]
3096+
+ 70*s[4, 3] + 75*s[5, 1, 1] + 70*s[5, 2] + 30*s[6, 1] + 5*s[7]]
3097+
sage: parent(fog)
3098+
Lazy completion of Symmetric Functions over Rational Field in the Schur basis
3099+
30753100
.. SEEALSO::
30763101
30773102
:meth:`frobenius`
@@ -3080,66 +3105,100 @@ def plethysm(self, x, include=None, exclude=None):
30803105
30813106
sage: (1+p[2]).plethysm(p[2])
30823107
p[] + p[4]
3108+
3109+
Check that degree one elements are treated in the correct way::
3110+
3111+
sage: R.<a1,a2,a11,b1,b21,b111> = QQ[]
3112+
sage: p = SymmetricFunctions(R).p()
3113+
sage: f = a1*p[1] + a2*p[2] + a11*p[1,1]
3114+
sage: g = b1*p[1] + b21*p[2,1] + b111*p[1,1,1]
3115+
sage: r = f(g); r
3116+
a1*b1*p[1] + a11*b1^2*p[1, 1] + a1*b111*p[1, 1, 1]
3117+
+ 2*a11*b1*b111*p[1, 1, 1, 1] + a11*b111^2*p[1, 1, 1, 1, 1, 1]
3118+
+ a2*b1^2*p[2] + a1*b21*p[2, 1] + 2*a11*b1*b21*p[2, 1, 1]
3119+
+ 2*a11*b21*b111*p[2, 1, 1, 1, 1] + a11*b21^2*p[2, 2, 1, 1]
3120+
+ a2*b111^2*p[2, 2, 2] + a2*b21^2*p[4, 2]
3121+
sage: r - f(g, include=[])
3122+
(a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2]
3123+
3124+
Check that we can compute the plethysm with a constant::
3125+
3126+
sage: p[2,2,1](2)
3127+
8*p[]
3128+
3129+
sage: p[2,2,1](int(2))
3130+
8*p[]
3131+
3132+
sage: p[2,2,1](a1)
3133+
a1^5*p[]
3134+
3135+
sage: X = algebras.Shuffle(QQ, 'ab')
3136+
sage: Y = algebras.Shuffle(QQ, 'bc')
3137+
sage: T = tensor([X,Y])
3138+
sage: s = SymmetricFunctions(T).s()
3139+
sage: s(2*T.one())
3140+
(2*B[word:]#B[word:])*s[]
3141+
3142+
.. TODO::
3143+
3144+
The implementation of plethysm in
3145+
:class:`sage.data_structures.stream.Stream_plethysm` seems
3146+
to be faster. This should be investigated.
30833147
"""
30843148
parent = self.parent()
3085-
R = parent.base_ring()
3086-
tHA = HopfAlgebrasWithBasis(R).TensorProducts()
3087-
tensorflag = tHA in x.parent().categories()
3088-
if not (is_SymmetricFunction(x) or tensorflag):
3089-
raise TypeError("only know how to compute plethysms "
3090-
"between symmetric functions or tensors "
3091-
"of symmetric functions")
3092-
p = parent.realization_of().power()
3093-
if self == parent.zero():
3149+
if not self:
30943150
return self
30953151

3096-
# Handle degree one elements
3097-
if include is not None and exclude is not None:
3098-
raise RuntimeError("include and exclude cannot both be specified")
3099-
3100-
try:
3101-
degree_one = [R(g) for g in R.variable_names_recursive()]
3102-
except AttributeError:
3103-
try:
3104-
degree_one = R.gens()
3105-
except NotImplementedError:
3106-
degree_one = []
3107-
3108-
if include:
3109-
degree_one = [R(g) for g in include]
3110-
if exclude:
3111-
degree_one = [g for g in degree_one if g not in exclude]
3152+
R = parent.base_ring()
3153+
tHA = HopfAlgebrasWithBasis(R).TensorProducts()
3154+
from sage.structure.element import parent as get_parent
3155+
Px = get_parent(x)
3156+
tensorflag = Px in tHA
3157+
if not is_SymmetricFunction(x):
3158+
if Px is R: # Handle stuff that is directly in the base ring
3159+
x = parent(x)
3160+
elif (not tensorflag or any(not isinstance(factor, SymmetricFunctionAlgebra_generic)
3161+
for factor in Px._sets)):
3162+
from sage.rings.lazy_series import LazySymmetricFunction
3163+
if isinstance(x, LazySymmetricFunction):
3164+
from sage.rings.lazy_series_ring import LazySymmetricFunctions
3165+
L = LazySymmetricFunctions(parent)
3166+
return L(self)(x)
3167+
3168+
# Try to coerce into a symmetric function
3169+
phi = parent.coerce_map_from(Px)
3170+
if phi is not None:
3171+
x = phi(x)
3172+
elif not tensorflag:
3173+
raise TypeError("only know how to compute plethysms "
3174+
"between symmetric functions or tensors "
3175+
"of symmetric functions")
31123176

3113-
degree_one = [g for g in degree_one if g != R.one()]
3177+
p = parent.realization_of().power()
31143178

3115-
def raise_c(n):
3116-
return lambda c: c.subs(**{str(g): g ** n for g in degree_one})
3179+
degree_one = _variables_recursive(R, include=include, exclude=exclude)
31173180

31183181
if tensorflag:
3119-
tparents = x.parent()._sets
3120-
return tensor([parent]*len(tparents))(sum(d*prod(sum(raise_c(r)(c)
3121-
* tensor([p[r].plethysm(base(la))
3122-
for (base,la) in zip(tparents,trm)])
3123-
for (trm,c) in x)
3124-
for r in mu)
3125-
for (mu, d) in p(self)))
3126-
3127-
# Takes in n, and returns a function which takes in a partition and
3128-
# scales all of the parts of that partition by n
3129-
def scale_part(n):
3130-
return lambda m: m.__class__(m.parent(), [i * n for i in m])
3131-
3132-
# Takes n an symmetric function f, and an n and returns the
3182+
tparents = Px._sets
3183+
s = sum(d * prod(sum(_raise_variables(c, r, degree_one)
3184+
* tensor([p[r].plethysm(base(la))
3185+
for base, la in zip(tparents, trm)])
3186+
for trm, c in x)
3187+
for r in mu)
3188+
for mu, d in p(self))
3189+
return tensor([parent]*len(tparents))(s)
3190+
3191+
# Takes a symmetric function f, and an n and returns the
31333192
# symmetric function with all of its basis partitions scaled
31343193
# by n
31353194
def pn_pleth(f, n):
3136-
return f.map_support(scale_part(n))
3195+
return f.map_support(lambda mu: mu.stretch(n))
31373196

31383197
# Takes in a partition and applies
31393198
p_x = p(x)
31403199

31413200
def f(part):
3142-
return p.prod(pn_pleth(p_x.map_coefficients(raise_c(i)), i)
3201+
return p.prod(pn_pleth(p_x.map_coefficients(lambda c: _raise_variables(c, i, degree_one)), i)
31433202
for i in part)
31443203
return parent(p._apply_module_morphism(p(self), f, codomain=p))
31453204

@@ -4917,9 +4976,7 @@ def frobenius(self, n):
49174976
# then convert back.
49184977
parent = self.parent()
49194978
m = parent.realization_of().monomial()
4920-
from sage.combinat.partition import Partition
4921-
dct = {Partition([n * i for i in lam]): coeff
4922-
for (lam, coeff) in m(self)}
4979+
dct = {lam.stretch(n): coeff for lam, coeff in m(self)}
49234980
result_in_m_basis = m._from_dict(dct)
49244981
return parent(result_in_m_basis)
49254982

@@ -6125,3 +6182,82 @@ def _nonnegative_coefficients(x):
61256182
return all(c >= 0 for c in x.coefficients(sparse=False))
61266183
else:
61276184
return x >= 0
6185+
6186+
def _variables_recursive(R, include=None, exclude=None):
6187+
"""
6188+
Return all variables appearing in the ring ``R``.
6189+
6190+
INPUT:
6191+
6192+
- ``R`` -- a :class:`Ring`
6193+
- ``include``, ``exclude`` (optional, default ``None``) --
6194+
iterables of variables in ``R``
6195+
6196+
OUTPUT:
6197+
6198+
- If ``include`` is specified, only these variables are returned
6199+
as elements of ``R``. Otherwise, all variables in ``R``
6200+
(recursively) with the exception of those in ``exclude`` are
6201+
returned.
6202+
6203+
EXAMPLES::
6204+
6205+
sage: from sage.combinat.sf.sfa import _variables_recursive
6206+
sage: R.<a, b> = QQ[]
6207+
sage: S.<t> = R[]
6208+
sage: _variables_recursive(S)
6209+
[a, b, t]
6210+
6211+
sage: _variables_recursive(S, exclude=[b])
6212+
[a, t]
6213+
6214+
sage: _variables_recursive(S, include=[b])
6215+
[b]
6216+
6217+
TESTS::
6218+
6219+
sage: _variables_recursive(R.fraction_field(), exclude=[b])
6220+
[a]
6221+
6222+
sage: _variables_recursive(S.fraction_field(), exclude=[b]) # known bug
6223+
[a, t]
6224+
"""
6225+
if include is not None and exclude is not None:
6226+
raise RuntimeError("include and exclude cannot both be specified")
6227+
6228+
if include is not None:
6229+
degree_one = [R(g) for g in include]
6230+
else:
6231+
try:
6232+
degree_one = [R(g) for g in R.variable_names_recursive()]
6233+
except AttributeError:
6234+
try:
6235+
degree_one = R.gens()
6236+
except NotImplementedError:
6237+
degree_one = []
6238+
if exclude is not None:
6239+
degree_one = [g for g in degree_one if g not in exclude]
6240+
6241+
return [g for g in degree_one if g != R.one()]
6242+
6243+
def _raise_variables(c, n, variables):
6244+
"""
6245+
Replace the given variables in the ring element ``c`` with their
6246+
``n``-th power.
6247+
6248+
INPUT:
6249+
6250+
- ``c`` -- an element of a ring
6251+
- ``n`` -- the power to raise the given variables to
6252+
- ``variables`` -- the variables to raise
6253+
6254+
EXAMPLES::
6255+
6256+
sage: from sage.combinat.sf.sfa import _raise_variables
6257+
sage: R.<a, b> = QQ[]
6258+
sage: S.<t> = R[]
6259+
sage: _raise_variables(2*a + 3*b*t, 2, [a, t])
6260+
3*b*t^2 + 2*a^2
6261+
6262+
"""
6263+
return c.subs(**{str(g): g ** n for g in variables})

0 commit comments

Comments
 (0)