Welcome to Cadabra Q&A, where you can ask questions and receive answers from other members of the community.
0 votes

Hi Folks,

I'd like to use Cadabra2 to do the hard work of tensor gymnastics before passing the results onto Python/sympy to generate C code. Suppose I have this code

{a,b,c}::Indices(position=fixed,values={x,y,z}).
{x,y,z}::Coordinate.
ex := A_{a} A_{b};
rl := {A_{x}=Ax,A_{y}=Ay,A_{z}=Az};
evaluate(ex,rl,rhsonly=True);

This produces a Cadabra expression with two indices. How can I create an object that I can pass to the codegen tools of sympy? I'd be happy with a way to pass individual components of "ex" to sympy (and run a loop over all components). Even better would be a way to construct a sympy matrix that contains all 9 components of "ex".

Cheers, Leo

in General questions by (1.8k points)

3 Answers

0 votes
 
Best answer

You can get access to the individual elements of a \components node (which is what your ex contains; print(tree(ex)) shows the internal representation) by doing something like

lst=[]
for i in range( len(ex[2]) ):
    lst.append( str(ex[2][i][1]) )
print(lst)

This produces

['Ax**2', 'Ax*Ay', 'Ax*Az', 'Ax*Ay', ...]

in other words, lst is a list of strings, one for each component in your original ex. You can feed that to sympy or do other things with it. If you strip off the str(...) in the example above, your list will contain Cadabra Ex objects instead.

This is obviously still not ideal, but we're working on a better method.

by (83.0k points)
selected by

Thanks Kasper, that worked perfectly. I had been fiddling with various combinations of ex and square brackets but gave up as I could only get pieces of the expression. Now I see that the trick is to use .append. Very nice.

0 votes

Dear Leo,

it is not a loop over all components but it works fine if someone has to select a specific evaluated component to make manipulations with Sympy:

{a,b,c}::Indices(position=fixed,values={x,y,z}).
{x,y,z}::Coordinate.

rl := {A_{x}=Ax,A_{y}=Ay,A_{z}=Az}:
CompSel:={xx^{x x}=1,xy^{x y}=1,xz^{x z}=1,yx^{y x}=1,yy^{y y}=1,yz^{y z}=1,zx^{z x}=1,zy^{z y}=1,zz^{z z}=1}:

ex := T_{a b}=A_{a} A_{b};
evaluate(ex,rl);

yz_Comp:=T_{a b} yz^{a b}:
substitute(_,ex)
evaluate(_,CompSel)

yz_Comp=sympy.expand(yz_Comp);

I hope it can be useful,

Mattia

by (410 points)

Hi Mattia, Thanks for that. It's a neat solution. I'll add it to my collection of neat Cadabra/Python tricks. Cheers, Leo

0 votes

The version on github now makes this substantially easier; with

{a,b,c}::Indices(position=fixed,values={x,y,z}).
{x,y,z}::Coordinate.
ex := A_{a} A_{b};
evaluate(ex);

you get

□_{ab}
    {x, x} = A_{x}**2
    {x, y} = A_{x}*A_{y}
    {x, z} = A_{x}*A_{z}
    {y, x} = A_{x}*A_{y}
    {y, y} = A_{y}**2
    {y, z} = A_{y}*A_{z}
    {z, x} = A_{x}*A_{z}
    {z, y} = A_{y}*A_{z}
    {z, z} = A_{z}**2
by (83.0k points)
...