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

Dear Cadabra developers and users,

I would like to construct a "scalar product" of tensors of the form:

met:X x Y ->X{a}*Y{a}

but I can't find a way to implement it. When acting on scalar quantities, it works fine as follows:

{a, b, c, d, e, f, g, h, i, j, k, l, m, n ,p, q, r,s,t,u,v,w,x,y,z#}::Indices(T, position=free, parent=double); Expmet:=met{X??}{Y??}->X??*Y??; Exp:=met{V}{W}; substitute(_, Expmet);

and the output is VW as expected.

Now, if I want X and Y to be vectors, then the naive guess

Expmet:=met{X??}{Y??}->{X??}_{a}*{Y??}_{a};

doesn't work, the output being (VW)_{aa}.

I tried several variations but none of them worked so far.

Is there a way to implement this kind of operators for tensors?

Thank you already for any input!

in General questions by

1 Answer

+1 vote

Adding indices to object wildcards is not supported because there are very few cases where that actually makes much sense. The problem is that, if your rule had worked, it would also match

 met{ A_{b} }{ B_{b} }
 met{ A_{b c d} }{ B_{c} }

and so on. You then almost always want to have control over where the extra $a$ index would need to be added (at the beginning of the set? at the end? in the middle?) and the notation which you wanted to use does not leave any way to specify that location.

So instead, you will need to make a rule which does not take an arbitrary object, but something which has the index structure spelled out. If you had in mind just to act on symbols $V$ and $W$, the rule

Expmet:= met{X?}{Y?} -> X?_{a} Y?_{a};

would work. This will apply to your met{V}{W} case, but will not apply to any of the cases at the top of this reply. You could, however, write e.g.

Expmet2:= met{ X?_{b} }{ Y?_{b} } -> X?_{b a} Y?_{a b};

or similar. That rule would allow you to do

{a,b,c,d}::Indices;
ex:= met{ A_{c} }{ B_{c} };
exmet:= met{ X?_{b} }{ Y?_{b} } -> X?_{b a} Y?_{a b} ;
substitute(ex, exmet);

Hope the logic is clear.

So TL;DR: object patterns (patterns with '??' attached) are very brute force hammers, not always suitable when name patterns (patterns with just '?') will do.

(In addition, your example triggered a parsing bug that led to the indices being put on the product, not on the individual tensors, but that's a different story).

by (76.6k points)

Thank for your answer! Indeed the expression

Expmet:= met{ X?_{a} }{ Y?_{b} } -> X?_{a} Y?_{a};

does just what I wanted. I'm still a bit confused about the underlying logic though.

More specifically, I created a separate function :

Expstar:=star{f?}{X?_{b}}_{a}->f?*X?_{a};

that takes one scalar and one vector and returns a vector.

However, it seems that the output of this function is not recognised by the previous function met.

More precisely, the output of

Expmet:= met{ X?_{a} }{ Y?_{b} } -> X?_{a} Y?_{a}; Expstar:=star{f?}{X?_{b}}_{a}->f?*X?_{a}; Exp:=met{star{g}{V_{b}}_{a}}{W_{c}}; substitute(_, Expmet); substitute(_, Expstar); substitute(_, Expmet);

is

met(g V_{a} , W_{c})

where I expected gV_{a}W_{a}. So it seems that the routine Expmet fails to recognise both star{g}{V_{b}}_{a} and g V_{a}as proper vector inputs.

Is there a way to circumvent this?

Thank you for your help!

Well, yes,

A?_{a}

means 'any text string with a single sub-script index of the type of $a$'. The expression

g V_{a}

is not of that form, because it is a product of two factors. Ditto for the other one.

If you want to be able to automatically take factors out of met, you may want to consider if it makes sense to declare met as a Derivative. You can then do

{a,b,c,d}::Indices;
met{#}::Derivative;
{A, B_{c}}::Depends(met{#});
ex:= met{A}{ g B_{c} };
unwrap(ex);

to give

g met{A}{B_{c}}

although it does not print very nicely at the moment.

Thank you for your reply! I will try something along these lines.

...