+1 vote

If my expression represents some sum, I can get each term in a loop like

for element in ex.top().terms():

but if expression is equality i need to use something else. I know about cdb.core.manip package, but I would like to be able to access the expression tree itself without changing it.

Well... Now, I think, my question became more complicated. I am writing a covariant derivative function that exposes derivatives from the inside out, but for now it doesn't work for equalities and products of derivatives, like \nabla{c}{\nabla{a}{\nabla{d}{p}}\nabla{b}{p}} . That is the main function which i'm calling:

def expand_nabla(ex):
for element in ex.top().terms():
count = 0
used_indices = set()
for nabla in ex[r'\nabla']:
count += 1
if count == 0:
pass
else:
for n in ex:
for index in n.indices():
element1, used_indices = nabla_calculation(element, used_indices, count)
element.replace(element1)
return ex

If the term contains nabla, it calls another function:

def nabla_calculation(ex, used_indices, count):
ex = ex.ex()
new := 0;
for element in ex.top().terms():
local_count = 0
for nabla in element[r'\nabla']:
local_count += 1
if local_count == 0:
new += element.ex()
elif count == 1:
new, used_indices = (one_nabla(ex, used_indices))
count -= 1
else:
for nabla in ex[r'\nabla']:
for arg1 in nabla.args():
arg2, used_indices = nabla_calculation(arg1, used_indices, count - 1)
index = nabla.indices().__next__()
t := \nabla_{@(index)}{@[arg2]};
display(t)
new = Ex(str(nabla.multiplier)) *  t
nabla1, used_indices = one_nabla(new, used_indices)
new = Ex(str(nabla.multiplier)) * nabla1
nabla.replace(new)
return ex, used_indices

which already calls a function that calculates one derivative:

def one_nabla(ex, used_indices):
t3, used_indices = select_index(used_indices)
free = dict()
free['sub'] = set()
free['up'] = set()
for nabla in ex[r'\nabla']:
nabla.name=r'\partial'
dindex = nabla.indices().__next__()
for arg in nabla.args():
ret:=0;
for index in arg.free_indices():
if index.parent_rel==sub:
else:
for key in free.keys():
for index in free[key]:
ind = Ex(index)
if key == 'sub':
t1:= -\Gamma^{@[t3]}_{@(dindex) @[ind]};
else:
t1:=  \Gamma^{@[ind]}_{@(dindex) @[t3]};
t2:= @[arg];
for term_index in arg.free_indices():
if str(term_index.ex()) == index:
if term_index.parent_rel==sub:
t2[term_index]:= _{@[t3]};
else:
t2[term_index]:= ^{@[t3]};
ret += Ex(str(nabla.multiplier)) * t1 * t2
nabla += ret
break
break
return ex, used_indices

here uses a small function to select a free index to sum over it

def select_index(used_indices):
indeces = r'z y x w v u t s r q o n m l k j i h g f e d c b a'.split()
for uind in indeces:
found = False
for qind in used_indices:
if qind == uind:
found = True
break
index = uind
break
return Ex(index), used_indices

I know the code is not very good, but I would appreciate any help to improve it

+1 vote

You could wrap this in an outer loop which iterates over the two sides of the equality, e.g.

ex:=  A+B = C
for sides in ex.top().children():
for element in sides.terms():
element.multiplier *= 2

which turns ex into

2A + 2B = 2C

If you only wanted to e.g. touch the right-hand side, do something like

ch = ex.top().children()
next(ch)
next(ch)
for element in ch.terms():
element.multiplier *= 2
by (71.6k points)

Thank you! Apparently, I still have to somehow learn how to separate nested derivatives and products of derivatives in order to correctly construct a recursion for them.