Edit
This is the fastest solution:
Do[TensorContract[TensorProduct[v, w], {2, 5}], {10000}] // Timing // AbsoluteTiming
Do[TensorMultiply[v, w, {{2, 2}}], {10000}] // Timing // AbsoluteTiming
Do[Activate@TensorContract[Inactive[TensorProduct][v, w], {2, 5}], {10000}] // Timing // AbsoluteTiming
Do[DotAt[v, w, 2, 2], {10000}] // Timing // AbsoluteTiming
{5.36688, {5.36012, Null}}
{0.753744, {0.752581, Null}}
{0.57401, {0.573111, Null}}
{0.143519, {0.143405, Null}}
Original answer
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]]]]
DotAt
contracts the index m
of T
with the index n
of U
.
This way, u = TensorContract[TensorProduct[v, w], {2, 5}];
would become u = DotAt[v, w, 2, 2]
. 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.
Dot
as inu2 = Outer[Dot[v[[#1, All, #2]], w[[#3, All, #4]]] &, Range[3], Range[3], Range[3], Range[3]]
. $\endgroup$