# Performance improvements by using Activate and Inactivate

TensorContract[TensorProduct[A, B], {{2, 5}, {4, 6}}]


with

Activate @ TensorContract[Inactive[TensorProduct][A, B], {{2, 5}, {4, 6}}]


where e.g. for a minimal example:

n = 10;
A = RandomReal[1, {n, n, n, n}];
B = RandomReal[1, {n, n}];


Using this example, the version with Inactivate/Activate is about 30 times faster (according to RepeatedTiming) and uses about 200 times less memory (according to MaxMemoryUsed).

Obviously Mathematica uses some special algorithm to contract the two tensors without actually constructing the whole tensor product.

Now my questions is:

When does using Activate and Inactivate improve performance as drastically as above? How could I've known that using Activate and Inactivate lets Mathematica use more powerful tools? I'm looking for examples, heuristics or hidden Documentation.

• Everywhere where deeper evaluations are heavy but will not affect the result. Activate@Length@{Inactive[Pause][5]} – Kuba Sep 8 '16 at 9:56
• Thanks @Kuba, that seems a good heuristic although it fails for e.g. Activate@Part[Inactive[RandomReal][{0,1},10^9],1;;10] where I would've expected only the first 10 elements to be generated. – AndreasP Sep 8 '16 at 10:03
• Maybe I should improve the wording but Part[Inactive[RandomReal][{0, 1}, 10^9], 1 ;; 10] doesn't make sense while Length@{Inactive[Pause][5]} does. – Kuba Sep 8 '16 at 10:15
• @kuba, my assumption was that Part[Inactive[RandomReal[{0,1},10^9],1;;10] create the "promise of a list" and then just take the first 10 elements and actually evaluate them, similar to lazy behaviour in e.g. haskell. If you have a moment I would appreciate a short answer with a few examples if you can think of any. – AndreasP Sep 9 '16 at 7:39
• I see, I'm afraid that concept doesn't exist in WL but something similar happens for Datasets querying: 85363 – Kuba Sep 9 '16 at 7:47