# How to multiply two tensor with arbitrary ranks, on one index only (like GR)?

I am writing a function which take two tensors with the same dimensions but with arbitrary ranks and multiplies them over one index, just like this example from GR:

See, I couldn't use Table since I don't know the ranks r, which may be very large for me to explicitly write all configurations. If all inputs had the same ranks, this would be a simple sum inside table, with r ranges:

Please let me know if you know a clever way of doing this, for example by using TensorProduct, Inner, Outer, etc.

• Maybe this package can be useful: xact.es May 30, 2016 at 21:49
• Mattiav27, I know about this package, but I like to have a self-contained code. May 31, 2016 at 7:21
• Using the answer, I got it to work for that example. Can you explain the process of index shifting please? Is it switching the last index with the one we are summing over? I think other people would like to see your explanation if you add it to above answer of yours. Thanks! – Milad P. 6 hours ago May 31, 2016 at 7:21

From the docs of Inner:

Inner[f,Subscript[list, 1],Subscript[list, 2],g,n] contracts index n of the first tensor with the first index of the second tensor.

This means that you can leave the first tensor argument as-is, and specify which of its indices you want to contract in the fifth argument of Inner, but then you have to Transpose the second tensor so that the index to contract is the first.

So in your case you could either do

v1 = Inner[Times, g, Transpose[T], Plus, 2]


Then if the parts of g are g[[j, m]] and the parts of T are T[[i, m, k]] the parts of v1 will be

v1[[j, i, k]]


Or you can do

v2 = Inner[Times, T, Transpose[g], 2]


Such that we have

v1[[i, k, j]]


In general, if we want to contract index number n1 of tensor t1 with index number n2 of tensor t2, we may use the code

tensorContract[t1_, t2_, n1_, n2_] :=
With[{t2transpose = Transpose[t2, ReplacePart[Range[ArrayDepth[t2]], 1 -> n2, n2 -> 1]]},
Inner[Times, t1, t2transpose, Plus, n1]
]


If the indices of t1 were

{i[1], i[2], ..., i[n1-1], i[n1], i[n1+1], ..., i[r1]}


and the indices of t2 were

{j[1], j[2], ..., j[n2-1], j[n2], j[n2+1], ... j[r2]}


then the indices of the answer produced by the above function will be

{i[1], ..., i[n1-1], i[n1+1], ..., i[r1], j[1], ..., j[n2-1], j[n2+1], ..., j[r2]}

• Don't I need to take a final transpose of Inner[...]? May 30, 2016 at 22:04
• And why do you have g first and T second? Doesn't 2 specify the index for the FIRST list, not the second one? May 30, 2016 at 22:06
• In your post it seems that m, the index to contract, is the second index of both g and T, no? So that will be correct no matter the order. I have included both orders, g, T and T, g in my post... And I'm showing how the indices come out if we do it both ways. If you want the indices of the result in any specific order, e.g. [[k, i, j]], you can of course Transpose in the end if you like. May 30, 2016 at 22:21
• Thank you, I got it to work for that example. Can you explain the process of index shifting please? Is it switching the last index with the one we are summing over? I think other people would like to see your explanation if you add it to above answer of yours. Thanks! May 31, 2016 at 1:06
• Thank you very much! Very helpful. I'll definitely mention you in the GR package I'm writing. May 31, 2016 at 19:13