Skip to content

Commit dcc8c83

Browse files
committed
adding corolla-related methods to free pre-Lie algebras
1 parent e2e0f8d commit dcc8c83

File tree

1 file changed

+272
-0
lines changed

1 file changed

+272
-0
lines changed

src/sage/combinat/free_prelie_algebra.py

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
# the License, or (at your option) any later version.
1616
# https://www.gnu.org/licenses/
1717
# ****************************************************************************
18+
from copy import copy
19+
from itertools import product
1820

1921
from sage.categories.magmatic_algebras import MagmaticAlgebras
2022
from sage.categories.lie_algebras import LieAlgebras
@@ -26,6 +28,7 @@
2628
from sage.categories.functor import Functor
2729

2830
from sage.combinat.free_module import CombinatorialFreeModule
31+
from sage.combinat.integer_vector import IntegerVectors
2932
from sage.combinat.words.alphabet import Alphabet
3033
from sage.combinat.rooted_tree import (RootedTrees, RootedTree,
3134
LabelledRootedTrees,
@@ -34,6 +37,7 @@
3437

3538
from sage.misc.lazy_attribute import lazy_attribute
3639
from sage.misc.cachefunc import cached_method
40+
from sage.functions.other import factorial
3741

3842
from sage.sets.family import Family
3943
from sage.structure.coerce_exceptions import CoercionException
@@ -530,6 +534,138 @@ def nap_product(self):
530534
codomain=self),
531535
position=1)
532536

537+
def corolla(self, x, y, n, N):
538+
"""
539+
Return the corolla obtained with ``x`` as root and ``y`` as leaves.
540+
541+
INPUT:
542+
543+
- ``x``, ``y`` -- two elements
544+
545+
- ``n`` -- an integer, width of the corolla
546+
547+
- ``N`` -- an integer, truncation order (up to order ``N`` included)
548+
549+
OUTPUT:
550+
551+
the sum over all possible ways to graft ``n`` copies of ``y``
552+
on top of ``x`` (with at most ``N`` vertices in total)
553+
554+
This operation can be defined by induction starting from the
555+
pre-Lie product.
556+
557+
EXAMPLES::
558+
559+
sage: A = algebras.FreePreLie(QQ)
560+
sage: a = A.gen(0)
561+
sage: b = A.corolla(a,a,1,4); b
562+
B[[[]]]
563+
sage: A.corolla(b,b,2,7)
564+
B[[[[[]], [[]]]]] + 2*B[[[[]], [[[]]]]] + B[[[], [[]], [[]]]]
565+
566+
sage: A = algebras.FreePreLie(QQ, 'o')
567+
sage: a = A.gen(0)
568+
sage: b = A.corolla(a,a,1,4)
569+
570+
sage: A = algebras.FreePreLie(QQ,'ab')
571+
sage: a, b = A.gens()
572+
sage: A.corolla(a,b,1,4)
573+
B[a[b[]]]
574+
sage: A.corolla(b,a,3,4)
575+
B[b[a[], a[], a[]]]
576+
577+
sage: A.corolla(a+b,a+b,2,4)
578+
B[a[a[], a[]]] + 2*B[a[a[], b[]]] + B[a[b[], b[]]] + B[b[a[], a[]]] +
579+
2*B[b[a[], b[]]] + B[b[b[], b[]]]
580+
"""
581+
basering = self.base_ring()
582+
if x == self.zero() or y == self.zero():
583+
return self.zero()
584+
585+
vx = x.valuation()
586+
vy = y.valuation()
587+
min_deg = vy * n + vx
588+
if min_deg > N:
589+
return self.zero()
590+
591+
try:
592+
self.gen(0).support()[0].label()
593+
labels = True
594+
except AttributeError:
595+
labels = False
596+
597+
deg_x = x.maximal_degree()
598+
deg_y = y.maximal_degree()
599+
max_x = min(deg_x, N - n * vy)
600+
max_y = min(deg_y, N - vx - (n - 1) * vy)
601+
xx = x.truncate(max_x + 1)
602+
yy = y.truncate(max_y + 1)
603+
604+
y_homog = {i: list(yy.homogeneous_component(i))
605+
for i in range(vy, max_y + 1)}
606+
resu = self.zero()
607+
for k in range(min_deg, N + 1): # total degree of (x ; y, y, y, y)
608+
for mx, coef_x in xx:
609+
dx = mx.node_number()
610+
step = self.zero()
611+
for pi in IntegerVectors(k - dx, n, min_part=vy, max_part=max_y):
612+
for ly in product(*[y_homog[part] for part in pi]):
613+
coef_y = basering.prod(mc[1] for mc in ly)
614+
arbres_y = [mc[0] for mc in ly]
615+
step += coef_y * self.sum(self(t)
616+
for t in corolla_gen(mx,
617+
arbres_y,
618+
labels))
619+
resu += coef_x * step
620+
return resu
621+
622+
def group_product(self, x, y, n, N=10):
623+
r"""
624+
Return the truncated group product of ``x`` and ``y``.
625+
626+
This is a weighted sum of all corollas with up to ``n`` leaves, with
627+
``x`` as root and ``y`` as leaves.
628+
629+
The result is computed up to order ``N`` (included).
630+
631+
When considered with infinitely many terms and infinite precision,
632+
this is an analogue of the Baker-Campbell-Hausdorff formula: it
633+
defines an associative product on the free pre-Lie algebra.
634+
635+
INPUT:
636+
637+
- ``x``, ``y`` -- two elements
638+
639+
- ``n`` -- an integer, the maximal width of corollas
640+
641+
- ``N`` -- an integer (optional, default: 10), truncation order
642+
643+
OUTPUT:
644+
645+
an element
646+
647+
EXAMPLES:
648+
649+
In the free pre-Lie algebra with one generator::
650+
651+
sage: PL = algebras.FreePreLie(QQ)
652+
sage: a = PL.gen(0)
653+
sage: PL.group_product(a, a, 3, 3)
654+
B[[]] + B[[[]]] + 1/2*B[[[], []]]
655+
656+
In the free pre-Lie algebra with several generators::
657+
658+
sage: PL = algebras.FreePreLie(QQ,'@O')
659+
sage: a, b = PL.gens()
660+
sage: PL.group_product(a, b, 3, 3)
661+
B[@[]] + B[@[O[]]] + 1/2*B[@[O[], O[]]]
662+
sage: PL.group_product(a, b, 3, 10)
663+
B[@[]] + B[@[O[]]] + 1/2*B[@[O[], O[]]] + 1/6*B[@[O[], O[], O[]]]
664+
"""
665+
br = self.base_ring()
666+
return x + self.sum(self.corolla(x, y, i, N) * ~br(factorial(i))
667+
for i in range(1, n + 1))
668+
533669
def _element_constructor_(self, x):
534670
r"""
535671
Convert ``x`` into ``self``.
@@ -703,6 +839,34 @@ def lift(self):
703839
for x, cf in self.monomial_coefficients(copy=False).items()}
704840
return UEA.element_class(UEA, data)
705841

842+
def valuation(self):
843+
"""
844+
Return the valuation of ``self``.
845+
846+
EXAMPLES::
847+
848+
sage: a = algebras.FreePreLie(QQ).gen(0)
849+
sage: a.valuation()
850+
1
851+
sage: (a*a).valuation()
852+
2
853+
854+
sage: a, b = algebras.FreePreLie(QQ,'ab').gens()
855+
sage: (a+b).valuation()
856+
1
857+
sage: (a*b).valuation()
858+
2
859+
sage: (a*b+a).valuation()
860+
1
861+
"""
862+
if self == self.parent().zero():
863+
return Infinity
864+
i = 0
865+
while True:
866+
i += 1
867+
if self.homogeneous_component(i):
868+
return i
869+
706870

707871
class PreLieFunctor(ConstructionFunctor):
708872
"""
@@ -872,3 +1036,111 @@ def _repr_(self):
8721036
PreLie[x,y,z,t]
8731037
"""
8741038
return "PreLie[%s]" % ','.join(self.vars)
1039+
1040+
1041+
def tree_from_sortkey(ch, labels=True):
1042+
r"""
1043+
Transform a list of (valence, label) into a tree and a remainder.
1044+
1045+
This is like an inverse of the ``sort_key`` method.
1046+
1047+
INPUT:
1048+
1049+
- ``ch`` -- a list of pairs (integer, label))
1050+
1051+
- ``labels`` -- optional (default ``True``)
1052+
whether to use labelled trees
1053+
1054+
OUTPUT:
1055+
1056+
a pair (tree, remainder of the input)
1057+
1058+
EXAMPLES::
1059+
1060+
sage: from sage.combinat.free_prelie_algebra import tree_from_sortkey
1061+
sage: a = algebras.FreePreLie(QQ).gen(0)
1062+
sage: t = (a*a*a*a).support()
1063+
sage: all(tree_from_sortkey(u.sort_key(), False)[0] == u for u in t)
1064+
True
1065+
1066+
sage: a, b = algebras.FreePreLie(QQ,'ab').gens()
1067+
sage: t = (a*b*a*b).support()
1068+
sage: all(tree_from_sortkey(u.sort_key())[0] == u for u in t)
1069+
True
1070+
"""
1071+
if labels:
1072+
Trees = LabelledRootedTrees()
1073+
width, label = ch[0]
1074+
else:
1075+
Trees = RootedTrees()
1076+
width = ch[0]
1077+
1078+
remainder = ch[1:]
1079+
if width == 0:
1080+
if labels:
1081+
return (Trees([], label), remainder)
1082+
return (Trees([]), remainder)
1083+
1084+
branches = {}
1085+
for i in range(width):
1086+
tree, remainder = tree_from_sortkey(remainder, labels=labels)
1087+
branches[i] = tree
1088+
1089+
if labels:
1090+
return (Trees(branches.values(), label), remainder)
1091+
return (Trees(branches.values()), remainder)
1092+
1093+
1094+
def corolla_gen(tx, list_ty, labels=True):
1095+
"""
1096+
Yield the terms in the corolla with given bottom tree and top trees.
1097+
1098+
These are the possible terms in the simultaneous grafting of the
1099+
top trees on vertices of the bottom tree.
1100+
1101+
INPUT:
1102+
1103+
one tree ``tx``, a list of trees ``list_ty``
1104+
1105+
OUTPUT:
1106+
1107+
trees
1108+
1109+
EXAMPLES::
1110+
1111+
sage: from sage.combinat.free_prelie_algebra import corolla_gen
1112+
sage: a = algebras.FreePreLie(QQ).gen(0)
1113+
sage: ta = a.support()[0]
1114+
sage: list(corolla_gen(ta,[ta],False))
1115+
[[[]]]
1116+
1117+
sage: a, b = algebras.FreePreLie(QQ,'ab').gens()
1118+
sage: ta = a.support()[0]
1119+
sage: tb = b.support()[0]
1120+
sage: ab = (a*b).support()[0]
1121+
sage: list(corolla_gen(ta,[tb]))
1122+
[a[b[]]]
1123+
sage: list(corolla_gen(tb,[ta,ta]))
1124+
[b[a[], a[]]]
1125+
sage: list(corolla_gen(ab,[ab,ta]))
1126+
[a[a[], b[], a[b[]]], a[a[b[]], b[a[]]], a[a[], b[a[b[]]]],
1127+
a[b[a[], a[b[]]]]]
1128+
"""
1129+
n = len(list_ty)
1130+
zx = tx.sort_key()
1131+
nx = len(zx)
1132+
liste_zy = [t.sort_key() for t in list_ty]
1133+
for list_pos in product(*[list(range(nx))] * n):
1134+
new_zx = copy(zx)
1135+
data = zip(list_pos, liste_zy)
1136+
sorted_data = sorted(data, reverse=True)
1137+
for pos_t in sorted_data:
1138+
if labels:
1139+
idx, lbl = new_zx[pos_t[0]]
1140+
new_zx = (new_zx[:pos_t[0]] + ((idx + 1, lbl),) +
1141+
pos_t[1] + new_zx[pos_t[0] + 1:])
1142+
else:
1143+
idx = new_zx[pos_t[0]]
1144+
new_zx = (new_zx[:pos_t[0]] + (idx + 1,) +
1145+
pos_t[1] + new_zx[pos_t[0] + 1:])
1146+
yield tree_from_sortkey(new_zx, labels=labels)[0]

0 commit comments

Comments
 (0)