Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding corolla-related methods to free pre-Lie algebras #36913

Merged
merged 2 commits into from
Dec 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 269 additions & 0 deletions src/sage/combinat/free_prelie_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# the License, or (at your option) any later version.
# https://www.gnu.org/licenses/
# ****************************************************************************
from itertools import product

from sage.categories.magmatic_algebras import MagmaticAlgebras
from sage.categories.lie_algebras import LieAlgebras
Expand All @@ -26,6 +27,7 @@
from sage.categories.functor import Functor

from sage.combinat.free_module import CombinatorialFreeModule
from sage.combinat.integer_vector import IntegerVectors
from sage.combinat.words.alphabet import Alphabet
from sage.combinat.rooted_tree import (RootedTrees, RootedTree,
LabelledRootedTrees,
Expand All @@ -34,6 +36,7 @@

from sage.misc.lazy_attribute import lazy_attribute
from sage.misc.cachefunc import cached_method
from sage.functions.other import factorial

from sage.sets.family import Family
from sage.structure.coerce_exceptions import CoercionException
Expand Down Expand Up @@ -530,6 +533,135 @@ def nap_product(self):
codomain=self),
position=1)

def corolla(self, x, y, n, N):
"""
Return the corolla obtained with ``x`` as root and ``y`` as leaves.

INPUT:

- ``x``, ``y`` -- two elements
- ``n`` -- integer; width of the corolla
- ``N`` -- integer; truncation order (up to order ``N`` included)

OUTPUT:

the sum over all possible ways to graft ``n`` copies of ``y``
on top of ``x`` (with at most ``N`` vertices in total)

This operation can be defined by induction starting from the
pre-Lie product.

EXAMPLES::

sage: A = algebras.FreePreLie(QQ)
sage: a = A.gen(0)
sage: b = A.corolla(a,a,1,4); b
B[[[]]]
sage: A.corolla(b,b,2,7)
B[[[[[]], [[]]]]] + 2*B[[[[]], [[[]]]]] + B[[[], [[]], [[]]]]

sage: A = algebras.FreePreLie(QQ, 'o')
sage: a = A.gen(0)
sage: b = A.corolla(a,a,1,4)

sage: A = algebras.FreePreLie(QQ,'ab')
sage: a, b = A.gens()
sage: A.corolla(a,b,1,4)
B[a[b[]]]
sage: A.corolla(b,a,3,4)
B[b[a[], a[], a[]]]

sage: A.corolla(a+b,a+b,2,4)
B[a[a[], a[]]] + 2*B[a[a[], b[]]] + B[a[b[], b[]]] + B[b[a[], a[]]] +
2*B[b[a[], b[]]] + B[b[b[], b[]]]

TESTS::

sage: A = algebras.FreePreLie(QQ,'ab')
sage: a, b = A.gens()
sage: A.corolla(a,A.zero(),2,2)
0
"""
if not x or not y:
return self.zero()

basering = self.base_ring()
vx = x.valuation()
vy = y.valuation()
min_deg = vy * n + vx
if min_deg > N:
return self.zero()

try:
self.gen(0).support()[0].label()
labels = True
except AttributeError:
labels = False

deg_x = x.maximal_degree()
deg_y = y.maximal_degree()
max_x = min(deg_x, N - n * vy)
max_y = min(deg_y, N - vx - (n - 1) * vy)
xx = x.truncate(max_x + 1)
yy = y.truncate(max_y + 1)

y_homog = {i: list(yy.homogeneous_component(i))
for i in range(vy, max_y + 1)}
resu = self.zero()
for k in range(min_deg, N + 1): # total degree of (x ; y, y, y, y)
for mx, coef_x in xx:
dx = mx.node_number()
step = self.zero()
for pi in IntegerVectors(k - dx, n, min_part=vy, max_part=max_y):
for ly in product(*[y_homog[part] for part in pi]):
coef_y = basering.prod(mc[1] for mc in ly)
arbres_y = [mc[0] for mc in ly]
step += coef_y * self.sum(self(t)
for t in corolla_gen(mx, arbres_y, labels))
resu += coef_x * step
return resu

def group_product(self, x, y, n, N=10):
r"""
Return the truncated group product of ``x`` and ``y``.

This is a weighted sum of all corollas with up to ``n`` leaves, with
``x`` as root and ``y`` as leaves.

The result is computed up to order ``N`` (included).

When considered with infinitely many terms and infinite precision,
this is an analogue of the Baker-Campbell-Hausdorff formula: it
defines an associative product on the completed free pre-Lie algebra.

INPUT:

- ``x``, ``y`` -- two elements
- ``n`` -- integer; the maximal width of corollas
- ``N`` -- integer (default: 10); truncation order

EXAMPLES:

In the free pre-Lie algebra with one generator::

sage: PL = algebras.FreePreLie(QQ)
sage: a = PL.gen(0)
sage: PL.group_product(a, a, 3, 3)
B[[]] + B[[[]]] + 1/2*B[[[], []]]

In the free pre-Lie algebra with several generators::

sage: PL = algebras.FreePreLie(QQ,'@O')
sage: a, b = PL.gens()
sage: PL.group_product(a, b, 3, 3)
B[@[]] + B[@[O[]]] + 1/2*B[@[O[], O[]]]
sage: PL.group_product(a, b, 3, 10)
B[@[]] + B[@[O[]]] + 1/2*B[@[O[], O[]]] + 1/6*B[@[O[], O[], O[]]]
"""
br = self.base_ring()
return x + self.sum(self.corolla(x, y, i, N) * ~br(factorial(i))
for i in range(1, n + 1))

def _element_constructor_(self, x):
r"""
Convert ``x`` into ``self``.
Expand Down Expand Up @@ -703,6 +835,40 @@ def lift(self):
for x, cf in self.monomial_coefficients(copy=False).items()}
return UEA.element_class(UEA, data)

def valuation(self):
"""
Return the valuation of ``self``.

EXAMPLES::

sage: a = algebras.FreePreLie(QQ).gen(0)
sage: a.valuation()
1
sage: (a*a).valuation()
2

sage: a, b = algebras.FreePreLie(QQ,'ab').gens()
sage: (a+b).valuation()
1
sage: (a*b).valuation()
2
sage: (a*b+a).valuation()
1

TESTS::

sage: z = algebras.FreePreLie(QQ).zero()
sage: z.valuation()
+Infinity
"""
if self == self.parent().zero():
return Infinity
fchapoton marked this conversation as resolved.
Show resolved Hide resolved
i = 0
while True:
i += 1
if self.homogeneous_component(i):
return i


class PreLieFunctor(ConstructionFunctor):
"""
Expand Down Expand Up @@ -872,3 +1038,106 @@ def _repr_(self):
PreLie[x,y,z,t]
"""
return "PreLie[%s]" % ','.join(self.vars)


def tree_from_sortkey(ch, labels=True):
r"""
Transform a list of ``(valence, label)`` into a tree and a remainder.

This is like an inverse of the ``sort_key`` method.

INPUT:

- ``ch`` -- a list of pairs ``(integer, label)``
- ``labels`` -- (default ``True``) whether to use labelled trees

OUTPUT:

a pair ``(tree, remainder of the input)``

EXAMPLES::

sage: from sage.combinat.free_prelie_algebra import tree_from_sortkey
sage: a = algebras.FreePreLie(QQ).gen(0)
sage: t = (a*a*a*a).support()
sage: all(tree_from_sortkey(u.sort_key(), False)[0] == u for u in t)
True

sage: a, b = algebras.FreePreLie(QQ,'ab').gens()
sage: t = (a*b*a*b).support()
sage: all(tree_from_sortkey(u.sort_key())[0] == u for u in t)
True
"""
if labels:
Trees = LabelledRootedTrees()
width, label = ch[0]
else:
Trees = RootedTrees()
width = ch[0]

remainder = ch[1:]
if width == 0:
if labels:
return (Trees([], label), remainder)
return (Trees([]), remainder)

branches = {}
for i in range(width):
tree, remainder = tree_from_sortkey(remainder, labels=labels)
branches[i] = tree

if labels:
return (Trees(branches.values(), label), remainder)
return (Trees(branches.values()), remainder)


def corolla_gen(tx, list_ty, labels=True):
"""
Yield the terms in the corolla with given bottom tree and top trees.

These are the possible terms in the simultaneous grafting of the
top trees on vertices of the bottom tree.

INPUT:

- ``tx`` -- a tree
- ``list_ty`` -- a list of trees

EXAMPLES::

sage: from sage.combinat.free_prelie_algebra import corolla_gen
sage: a = algebras.FreePreLie(QQ).gen(0)
sage: ta = a.support()[0]
sage: list(corolla_gen(ta,[ta],False))
[[[]]]

sage: a, b = algebras.FreePreLie(QQ,'ab').gens()
sage: ta = a.support()[0]
sage: tb = b.support()[0]
sage: ab = (a*b).support()[0]
sage: list(corolla_gen(ta,[tb]))
[a[b[]]]
sage: list(corolla_gen(tb,[ta,ta]))
[b[a[], a[]]]
sage: list(corolla_gen(ab,[ab,ta]))
[a[a[], b[], a[b[]]], a[a[b[]], b[a[]]], a[a[], b[a[b[]]]],
a[b[a[], a[b[]]]]]
"""
n = len(list_ty)
zx = tx.sort_key()
nx = len(zx)
liste_zy = [t.sort_key() for t in list_ty]
for list_pos in product(range(nx), repeat=n):
new_zx = tuple(zx)
data = zip(list_pos, liste_zy)
sorted_data = sorted(data, reverse=True)
for pos_t in sorted_data:
if labels:
idx, lbl = new_zx[pos_t[0]]
new_zx = (new_zx[:pos_t[0]] + ((idx + 1, lbl),) +
pos_t[1] + new_zx[pos_t[0] + 1:])
else:
idx = new_zx[pos_t[0]]
new_zx = (new_zx[:pos_t[0]] + (idx + 1,) +
pos_t[1] + new_zx[pos_t[0] + 1:])
yield tree_from_sortkey(new_zx, labels=labels)[0]
Loading