# Revision history [back]

If i correctly understood the cyclic differential, the following pedestrian code should do the job...

def delta(f, i):
"""Implement $d_i$ on elements f of a free algebra with N generators.
Here, we expect that i is among 0, 1, ... , N-1.

Below, there is a commented print.
For the test non-commutative polynomial f from

F.<a,b,c> = FreeAlgebra(QQ)
f = a^3*b^2*a*c*b + 3*a*b^3*c - 7*a^3

it delivers:

Derivating monomial a^3*b^2*a*c*b
(alias [(a, 3), (b, 2), (a, 1), (c, 1), (b, 1)] as a list)
with coefficient 1.

Derivating monomial a*b^3*c
(alias [(a, 1), (b, 3), (c, 1)] as a list)
with coefficient 3.

Derivating monomial a^3
(alias [(a, 3)] as a list)
with coefficient -7.

Hope this explains the implementation now...
"""
F = f.parent()
N = len(F.gens())
if i not in range(N):
return F(0)

v = f.parent().gens()[i]    # and we cyclically differentiate w.r.t. v

monomials = []    # so far, and we append monomials from derivations
for mon, mon_coeff in f:
# print('Derivating monomial {}\n(alias {} as a list)\nwith coefficient {}.\n'
#       .format(mon, list(mon), mon_coeff))
mon_list = list(mon)
L = len(mon_list)    # there are L entries in this list
for j in range(L):
if mon_list[j][0] == v:
p = mon_list[j][1] * v^(mon_list[j][1] - 1) \
* prod([mon_list[(j + k) % L][0] ^ mon_list[(j + k) % L][1]
for k in range(1, L)])

monomials.append(mon_coeff*p)
return sum(monomials)


Test:

F.<a,b,c> = FreeAlgebra(QQ)
f = a^3*b^2*a*c*b + 3*a*b^3*c - 7*a^3
print(f'f = {f}')
print(f'delta0 f = {delta(f, 0)}')
print(f'delta1 f = {delta(f, 1)}')
print(f'delta2 f = {delta(f, 2)}')


This delivers:

f = -7*a^3 + 3*a*b^3*c + a^3*b^2*a*c*b
delta0 f = -21*a^2 + 3*b^3*c + 3*a^2*b^2*a*c*b + c*b*a^3*b^2
delta1 f = 9*b^2*c*a + a^3*b^2*a*c + 2*b*a*c*b*a^3
delta2 f = 3*a*b^3 + b*a^3*b^2*a


If i correctly understood the cyclic differential, the following pedestrian code should do the job...

def delta(f, i):
"""Implement $d_i$ on elements f of a free algebra with N generators.
Here, we expect that i is among 0, 1, ... , N-1.

Below, there is a commented print.
For the test non-commutative polynomial f from

F.<a,b,c> = FreeAlgebra(QQ)
f = a^3*b^2*a*c*b + 3*a*b^3*c - 7*a^3

it delivers:

Derivating monomial a^3*b^2*a*c*b
(alias [(a, 3), (b, 2), (a, 1), (c, 1), (b, 1)] as a list)
with coefficient 1.

Derivating monomial a*b^3*c
(alias [(a, 1), (b, 3), (c, 1)] as a list)
with coefficient 3.

Derivating monomial a^3
(alias [(a, 3)] as a list)
with coefficient -7.

Hope this explains the implementation now...
"""
F = f.parent()
N = len(F.gens())
if i not in range(N):
return F(0)

v = f.parent().gens()[i] F.gens()[i]    # and we cyclically differentiate w.r.t. v

monomials = []    # so far, and we append monomials from derivations
for mon, mon_coeff in f:
# print('Derivating monomial {}\n(alias {} as a list)\nwith coefficient {}.\n'
#       .format(mon, list(mon), mon_coeff))
mon_list = list(mon)
L = len(mon_list)    # there are L entries in this list
for j in range(L):
if mon_list[j][0] == v:
p = mon_list[j][1] * v^(mon_list[j][1] - 1) \
* prod([mon_list[(j + k) % L][0] ^ mon_list[(j + k) % L][1]
for k in range(1, L)])

monomials.append(mon_coeff*p)
return sum(monomials)


Test:

F.<a,b,c> = FreeAlgebra(QQ)
f = a^3*b^2*a*c*b + 3*a*b^3*c - 7*a^3
print(f'f = {f}')
print(f'delta0 f = {delta(f, 0)}')
print(f'delta1 f = {delta(f, 1)}')
print(f'delta2 f = {delta(f, 2)}')


This delivers:

f = -7*a^3 + 3*a*b^3*c + a^3*b^2*a*c*b
delta0 f = -21*a^2 + 3*b^3*c + 3*a^2*b^2*a*c*b + c*b*a^3*b^2
delta1 f = 9*b^2*c*a + a^3*b^2*a*c + 2*b*a*c*b*a^3
delta2 f = 3*a*b^3 + b*a^3*b^2*a