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