# Ways to compute inner products of tensors

One way to evaluate the following sums is combining Table and Sum:

$u_{abcd} = \sum_{e=1}^3 v_{aeb}w_{ced}$

$q_{ab} = \sum_{d,e=1}^3 v_{d e a}w_{deb}$

It will look like

v = Table[Times[i, j, k], {i, 3}, {j, 3}, {k, 3}]
w = Table[Times[i+2, j-1, k+1], {i, 3}, {j, 3}, {k, 3}]

u = Table[Sum[v[[a, e, b]] w[[c, e, d]], {e, 3}], {a, 3}, {b, 3}, {c, 3}, {d,  3}]
q = Table[Sum[v[[d, e, a]] w[[d, e, b]], {d, 3}, {e, 3}], {a, 3}, {b, 3}]


Is there a more elegant way to evaluate sums like these?

-
Just replacing the sum with Dot as in u2 = Outer[Dot[v[[#1, All, #2]], w[[#3, All, #4]]] &, Range[3], Range[3], Range[3], Range[3]]. – b.gatessucks Jan 14 '13 at 15:27
@b.gatessucks I'm curious why you didn't post that as an answer. I took the liberty of posting it for you, but I encourage you to post such things yourself in the future. If you wish to post it now, I'll be glad to delete mine. – Mr.Wizard Jan 14 '13 at 15:33
@Mr.Wizard It's not gonna be more helpful in an answer and it's quicker to add a comment. Thanks for taking the time. – b.gatessucks Jan 14 '13 at 15:40
@b.gatessucks actually, it is: comments cannot be Accepted and voting is limited. It takes hardly a moment longer to make an answer than a comment, and you should get the credit for your own answers/ideas. Nevertheless, it's your prerogative. – Mr.Wizard Jan 14 '13 at 15:42
From the tutorial on tensors: "You can think of Inner as performing a "contraction" of the last index of one tensor with the first index of another. If you want to perform contractions across other pairs of indices, you can do so by first transposing the appropriate indices into the first or last position, then applying Inner, and then transposing the result back." For multiple contractions, as in the second example, transpose all involved indexes to the end, Flatten them into a single index, and then perform a contraction. – whuber Jan 14 '13 at 15:58

If we transpose the indices of $v$ and $w$ so that $v'_{abe} = v_{aeb}$ and $w'_{ecd} = w_{ced}$, then we can compute $u = v' \cdot w'$:

u === Transpose[v, {1, 3, 2}] . Transpose[w, {2, 1, 3}]
(* True *)


We can use a similar trick to compute $q$ if we reorder $v_{dea} \to v''_{ade}$, except that this time the $d$ and $e$ indices in $v_{ade}''$ and $w_{deb}$ must treated as if they comprised a single index to be contracted. Flatten can do this for us:

q === Flatten[v, {{3}, {1, 2}}] . Flatten[w, {{1, 2}, {3}}]
(* True *)


For details about the Flatten syntax used here, see Flatten command: matrix as second argument.

-
Much better. I was trying to figure this out myself earlier but failed. Big +1. – Mr.Wizard Jan 15 '13 at 1:49

In Mathematica version 9, you can do these kinds of things much more naturally. Here are the two quantities that you wanted:

u = TensorContract[TensorProduct[v, w], {2, 5}];

q = TensorContract[TensorProduct[v, w], {{1, 4}, {2, 5}}];


The contraction is performed on the tensor product in which the first three indices belong to the factor v and the last three indices label w. Therefore, the indices corresponding to $e$ in your sum for u are in slots {2, 5}, and the two summations for q run over slots {1, 4} (for the variable $d$) and {2,5} (as in v).

-
No love for this answer? If it works it's nice. (I can't test it.) – Mr.Wizard Jan 15 '13 at 6:27
@Mr.Wizard Trust me, it works, it's the best. I consider this to be one of the most important news in ver.9, much more interesting than auto-completion tosh. – Artes Jan 15 '13 at 12:56
@Artes Thanks - and I still haven't gotten used to autocompletion; when it appears and I want to just navigate away by down-arrow, it annoyingly snags the cursor... I guess we have to take the good with the bad. – Jens Jan 15 '13 at 15:01
@Jens Since I've been getting used to autocompletion for 2 months, it seems quite natural and sometimes I lack it when using ver.8. Nevertheless I find it's a toy unlike the new tensor capabilites which are definitely still underestimated. – Artes Jan 17 '13 at 16:21
@Artes I think I'd like it better if autocomplete choices only appeared after pressing a certain special key (like Tab), not immediately while in the middle of a word. I find that intrusive. – Jens Jan 17 '13 at 17:06

Incorporating b.gatessucks's recommendation:

u === Outer[v[[#1, All, #2]].w[[#3, All, #4]] &, ##] & @@ Range@{3, 3, 3, 3}


True

-
How would you calculate q with Outer[] and Dot[]? – sjdh Jan 15 '13 at 10:43

As used in a recent answer recent answer, one can easily define a function which contracts two tensors:

DotAt[T_?TensorQ, U_?TensorQ, m_Integer?Positive, n_Integer?Positive] :=
With[{dimT = Length@Dimensions@T, dimU = Length@Dimensions@U},
Dot[Transpose[T, Insert[Range[dimT - 1], dimT, m]],
Transpose[U, Insert[Range[2, dimU], 1, n]]]]


This way, u = TensorContract[TensorProduct[v, w], {2, 5}]; would become u = DotAt[v, w, 2, 3]. This just shows that Dot and Transpose can be combined to perform all the operations and that it is actually quite easy to implement a form of TensorContract with the syntax that one prefers.

-

Since the question "Efficient tensor product followed by contraction" asking for an efficient solution to this problem has been marked as a duplicate, I find it appropriate to add here an encapsulated version of the answer to that question by @m_goldberg. Note that this works efficiently for the contraction of any number of index pairs. The notation follows Mathematica's TensorContract.

TensorMultiply[ A, B, {{$a_1$,$b_1$},{$a_2$,$b_2$},...} ]

$\hspace{7.5mm}$yields the tensor product of tensors A and B in the pairs {$a_i$,$b_i$} of slots.

TensorMultiply[A_, B_, pairs_] :=
Activate@TensorContract[
Inactive[TensorProduct][A, B], (# + {0, TensorRank[A]}) & /@ pairs];

-