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

Commit a80d67f

Browse files
committed
added convolution product based on code from Amy Pang
1 parent 6913b18 commit a80d67f

File tree

3 files changed

+265
-129
lines changed

3 files changed

+265
-129
lines changed

src/sage/categories/bialgebras.py

+180-64
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
from sage.categories.category_types import Category_over_base_ring
1313
from sage.categories.all import Algebras, Coalgebras
14+
from sage.categories.tensor import tensor
15+
from sage.functions.other import floor, ceil
16+
from sage.rings.integer import Integer
1417

1518
class Bialgebras(Category_over_base_ring):
1619
"""
@@ -61,76 +64,189 @@ class ParentMethods:
6164

6265
class ElementMethods:
6366

64-
def convolution_product(h,a,b):
65-
r"""
66-
input: h - an element of a Hopf algebra H
67-
a,b - linear maps from H to H
68-
output: [a*b](h)
67+
def adams_operator(self, n):
6968
"""
70-
H = h.parent()
71-
out = 0
72-
for (bimonom,coef) in h.coproduct():
73-
out += coef*a(H(bimonom[0]))*b(H(bimonom[1]))
74-
return out
69+
Compute the n-th convolution power of the identity morphism `Id` on self.
70+
71+
INPUT:
72+
73+
- ``n`` -- a nonnegative integer.
74+
75+
OUTPUT:
76+
77+
- the element of self.parent() corresponding to `Id^{*n}(self)`.
78+
79+
.. SEEALSO::
80+
81+
:mod:`sage.categories.hopf_algebras.ElementMethods.convolution_product`
82+
:mod:`sage.categories.hopf_algebras.ElementMethods.convolution_product`
83+
84+
(In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.)
85+
86+
REFERENCES:
87+
88+
.. [AL2015] The characteristic polynomial of the Adams operators on graded connected Hopf algebras.
89+
Marcelo Aguiar and Aaron Lauve.
90+
Algebra Number Theory, v.9, 2015, n.3, 2015.
91+
92+
.. TODO::
93+
94+
Move to hopf_algebras.py (i.e., remove dependency on modules_with_basis methods).
95+
96+
TESTS::
97+
98+
sage: h = SymmetricFunctions(QQ).h()
99+
sage: h[5].adams_operator(2)
100+
2*h[3, 2] + 2*h[4, 1] + 2*h[5]
101+
sage: h[5].plethysm(2*h[1])
102+
2*h[3, 2] + 2*h[4, 1] + 2*h[5]
103+
sage: h([]).adams_operator(0), h([]).adams_operator(1)
104+
(h[], h[])
105+
sage: h[3,2].adams_operator(0), h[3,2].adams_operator(1)
106+
(0, h[3, 2])
107+
108+
sage: S = NonCommutativeSymmetricFunctions(QQ).S()
109+
sage: S[4].adams_operator(5)
110+
5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4]
111+
112+
sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m()
113+
sage: m[[1,3],[2]].adams_operator(-2)
114+
3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}}
75115
76-
def convolution_power(h, L, n):
77-
r"""
78-
input: h - an element of a Hopf algebra H
79-
L - linear map from H to H
80-
n - the convolution power to which to take 'L'
81-
output: [L^*n](h)
82116
"""
83-
from sage.categories.tensor import tensor
84-
H = h.parent()
85-
def n_fold_coproduct(h, n):
86-
H = h.parent()
87-
if n == 0:
88-
return H(h.counit())
89-
elif n == 1:
90-
return h
91-
elif n == 2:
92-
return h.coproduct()
93-
else:
94-
# apply some kind of multilinear recursion
95-
Hn = tensor([H]*n) # or: tensor([H for i in range(n)])
96-
terms = []
97-
hh = n_fold_coproduct(h, n-1)
98-
for (monom,cof) in hh:
99-
h0 = H(monom[0]).coproduct()
100-
terms += [(tuple((h00, h01) + monom[1:]), cof0 * cof) for ((h00, h01), cof0) in h0]
101-
return Hn.sum_of_terms(terms)
102-
hhh = n_fold_coproduct(h,n)
103-
out = H.zero()
104-
for term in hhh:
105-
out += H.prod(L(H(t)) for t in term[0]) * term[1]
106-
return out
107-
108-
def hopf_power(h,n=2):
109-
r"""
110-
Input:
111-
h - an element of a Hopf algebra H
112-
n - the convolution power of the identity morphism to use
113-
Output:
114-
the nth convolution power of the identity morphism, applied to h., i.e., [id^*n](h)
115-
116-
Remark: for historical reasons (see saga of Frobenius-Schur indicators), the second power deserves special attention.
117-
we use '2' as the default value for 'n'
117+
if n < 0:
118+
raise ValueError("cannot take less than 0 coproduct iterations: %s < 0" % str(n))
119+
return self.convolution_product([lambda x: x] * n)
120+
121+
def convolution_product(self, *maplist):
122+
"""
123+
Given a maplist `(R, S, ..., T)` of length `n`, compute the action of their convolution product on ``self.``
124+
125+
MATH::
126+
127+
(R*S*\cdots *T)(h) = \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h)
128+
129+
where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`,
130+
with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`;
131+
and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu`
132+
(the ordinary product). See [Sw1969]_.
133+
134+
(In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.)
135+
136+
REFERENCES:
137+
138+
.. [KMN2012] On the trace of the antipode and higher indicators.
139+
Yevgenia Kashina and Susan Montgomery and Richard Ng.
140+
Israel J. Math., v.188, 2012.
141+
142+
.. [Sw1969] Hopf algebras.
143+
Moss Sweedler.
144+
W.A. Benjamin, Math Lec Note Ser., 1969.
145+
146+
.. TODO::
147+
148+
Remove dependency on modules_with_basis methods.
149+
150+
TESTS::
151+
152+
sage: Id = lambda x: x
153+
sage: Antipode = lambda x: x.antipode()
154+
155+
sage: h = SymmetricFunctions(QQ).h()
156+
sage: h[5].convolution_product([Id,Id])
157+
2*h[3, 2] + 2*h[4, 1] + 2*h[5]
158+
sage: h([]).convolution_product([Id,Antipode])
159+
h[]
160+
sage: h[3,2].convolution_product([Id,Antipode])
161+
0
162+
163+
sage: S = NonCommutativeSymmetricFunctions(QQ).S()
164+
sage: S[4].convolution_product([Id]*5)
165+
5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4]
166+
167+
sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m()
168+
sage: m[[1,3],[2]].convolution_product([Antipode,Antipode])
169+
3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}}
170+
171+
sage: m[[]].convolution_product([]), m[[1,3],[2]].convolution_product([])
172+
(m{}, 0)
173+
174+
sage: x = GroupAlgebra(SymmetricGroup(7),QQ).an_element(); x
175+
() + 3*(1,2) + 3*(1,2,3,4,5,6,7)
176+
sage: x.convolution_product([Id, Antipode, Antipode, Antipode])
177+
4*() + 3*(1,6,4,2,7,5,3)
178+
118179
"""
119-
H = h.parent()
120-
def Id(x):
121-
return x
122-
def S(x):
123-
return x.antipode()
124-
125-
if n<0:
126-
L = S
180+
# be flexible on how the maps are entered...
181+
if len(maplist)==1 and isinstance(maplist[0], (list,tuple)):
182+
T = tuple(maplist[0])
183+
else:
184+
T = maplist
185+
186+
H = self.parent()
187+
n = len(T)
188+
if n == 0:
189+
return H.one() * self.counit()
190+
elif n == 1:
191+
return T[0](self)
127192
else:
128-
L = Id
193+
# We apply the maps T_i and products concurrently with coproducts, as this
194+
# seems to be faster than applying a composition of maps, e.g., (H.nfold_product) * tensor(T) * (H.nfold_coproduct).
195+
196+
i = 0
197+
out = tensor((H.one(), self))
198+
dom = tensor((H, H))
129199

200+
# ALGORITHM:
201+
# `convolve` moves terms of the form x # y to x * T_i(y_1) # y_2, writing Delta(y) in Sweedler notation.
202+
convolve = lambda (x,y): ( ((xy1, y2), c * d) for ((y1, y2), d) in H(y).coproduct() for (xy1, c) in H(x) * T[i](H(y1)) )
203+
while i < n-1:
204+
out = dom.module_morphism(on_basis=lambda t: dom.sum_of_terms(convolve(t)), codomain = dom)(out)
205+
i += 1
206+
207+
# Apply final map `T_n` to last term, `y`, and multiply.
208+
cod = H
209+
out = dom.module_morphism(on_basis=lambda (x,y): H(x) * T[n-1](H(y)), codomain=cod)(out)
210+
211+
return out
212+
213+
def coproduct_iterated(self, n=1):
214+
r"""
215+
Apply `k-1` coproducts to ``self``.
216+
217+
218+
TESTS::
219+
220+
sage: p = SymmetricFunctions(QQ).p()
221+
sage: p[5,2,2].coproduct_iterated()
222+
p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[]
223+
sage: p([]).coproduct_iterated(3)
224+
p[] # p[] # p[] # p[]
225+
226+
sage: S = NonCommutativeSymmetricFunctions(QQ).S()
227+
sage: S[4].coproduct_iterated(0)
228+
S[4]
229+
sage: S[4].coproduct_iterated(2)
230+
S[] # S[] # S[4] + S[] # S[1] # S[3] + S[] # S[2] # S[2] + S[] # S[3] # S[1] + S[] # S[4] # S[] + S[1] # S[] # S[3] + S[1] # S[1] # S[2] + S[1] # S[2] # S[1] + S[1] # S[3] # S[] + S[2] # S[] # S[2] + S[2] # S[1] # S[1] + S[2] # S[2] # S[] + S[3] # S[] # S[1] + S[3] # S[1] # S[] + S[4] # S[] # S[]
231+
232+
sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m()
233+
sage: m[[1,3],[2]].convolution_product([Antipode,Antipode])
234+
3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}}
235+
236+
sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0)
237+
(m{} # m{} # m{} # m{}, m{{1, 3}, {2}})
238+
239+
240+
"""
241+
if n < 0:
242+
raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n))
130243
if n==0:
131-
return H(h.counit())
132-
elif abs(n)==1:
133-
return L(h)
244+
return self
245+
elif n==1:
246+
return self.coproduct()
134247
else:
135-
return h.convolution_power(L,abs(n))
248+
# Use coassociativity of `\Delta` to perform many coproducts simultaneously.
249+
fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2)
250+
def split(a,b): return tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)])
251+
return (self.coproduct()).apply_multilinear_morphism(split)
136252

src/sage/categories/hopf_algebras.py

+3-64
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from category import Category
1313
from category_types import Category_over_base_ring
1414
from sage.categories.bialgebras import Bialgebras
15-
from sage.categories.tensor import TensorProductsCategory, tensor
15+
from sage.categories.tensor import TensorProductsCategory # tensor
1616
from sage.categories.realizations import RealizationsCategory
1717
from sage.misc.cachefunc import cached_method
1818
#from sage.misc.lazy_attribute import lazy_attribute
@@ -45,7 +45,7 @@ def super_categories(self):
4545

4646
def dual(self):
4747
"""
48-
Returns the dual category
48+
Return the dual category
4949
5050
EXAMPLES:
5151
@@ -63,7 +63,7 @@ class ElementMethods:
6363

6464
def antipode(self):
6565
"""
66-
Returns the antipode of self.
66+
Return the antipode of self
6767
6868
EXAMPLES::
6969
@@ -86,67 +86,6 @@ def antipode(self):
8686
# This choice should be done consistently with coproduct, ...
8787
# return operator.antipode(self)
8888

89-
def adams_operator(self, k):
90-
"""
91-
92-
Iterate `k` times the coproduct and then the product:
93-
94-
MATH::
95-
96-
\mu^k \circ \Delta^{k}
97-
98-
where `\Delta^k := (\Delta \otimes Id^{k -1 \otimes}) \circ \Delta^{k-1}` with `\Delta^1 = \Delta`,
99-
`\Delta^0 = Id` and `\mu^k := \mu \circ (Id \otimes \mu^{k-1})` with `\mu^1 = \mu`, `\mu^0 = \mu`.
100-
101-
Reference
102-
---------
103-
104-
.. [AL] The characteristic polynomial of the Adams operators on graded connected Hopf algebras
105-
Marcelo Aguiar and Aaron Lauve
106-
http://www.math.cornell.edu/~maguiar/adams.pdf
107-
108-
TESTS::
109-
110-
sage: h = SymmetricFunctions(QQ).h()
111-
sage: h[5].adams_operator(1)
112-
2*h[3, 2] + 2*h[4, 1] + 2*h[5]
113-
sage: h[5].plethysm(2*h[1])
114-
2*h[3, 2] + 2*h[4, 1] + 2*h[5]
115-
116-
sage: S = NonCommutativeSymmetricFunctions(QQ).S()
117-
sage: S[4].adams_operator(4)
118-
5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4]
119-
120-
"""
121-
if k == 0: return self
122-
123-
S = self.parent()
124-
term = self.coproduct()
125-
dom = tensor((S,)*2)
126-
cod = tensor((S,)*3)
127-
for _ in range(k-1):
128-
term = dom.module_morphism(
129-
on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): (a+t[1:], c), S(t[0]).coproduct())),
130-
codomain=cod
131-
)(term)
132-
dom, cod = cod, tensor([S, cod])
133-
134-
for i in range(k-1):
135-
dom = tensor((S,)*(k-i+1))
136-
cod = tensor((S,)*(k-i))
137-
term = dom.module_morphism(
138-
on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): ((a,) + t[:-2], c), S(t[-2]) * S(t[-1]))),
139-
codomain=cod
140-
)(term)
141-
142-
term = tensor((S,S)).module_morphism(
143-
on_basis=lambda t: S(t[0]) * S(t[1]),
144-
codomain=S
145-
)(term)
146-
147-
return term
148-
149-
15089
class ParentMethods:
15190
#def __setup__(self): # Check the conventions for _setup_ or __setup__
15291
# if self.implements("antipode"):

0 commit comments

Comments
 (0)