Welcome to Cadabra Q&A, where you can ask questions and receive answers from other members of the community.
+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.

in General questions by (1.1k points)

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():
                used_indices.add(str(index))
    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:
                free['sub'].add(str(index.ex()))
            else:
                free['up'].add(str(index.ex()))
        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   
    if not found:
        used_indices.add(uind)
        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 Answer

+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 (76.4k 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.

...