# Mathematica does not respect tensor order?

I'm trying to verify an identity involving symmetric traceless tensors over the reals. What I tried was:

In[11]:= $Assumptions = d \[Element] Matrices[{3, 3}, Reals, Symmetric[{1, 2}]] Out[11]= d \[Element] Matrices[{3, 3}, Reals, Symmetric[{1, 2}]] In[24]:= dd = d - Tr[d] IdentityMatrix[3]/3 Out[24]= {{d - Tr[d]/3, d, d}, {d, d - Tr[d]/3, d}, {d, d,d - Tr[d]/3}}  I think the output in 24 is assuming that d is now a scalar. That gets me into trouble later when I tried to compute outer products of dd and use TensorReduce. For example lh = TensorReduce[TensorContract[dd\[TensorProduct]dd, {{1, 3}, {2, 4}}]] TensorDimensions::fscl: Nonscalar expression d encountered as an argument of numeric function Power. >> TensorDimensions::inhom: Inhomogeneous dimensions in sum d-Tr[d]/3. >>  Why is this not working, and what is the right way to do computations on traceless matrices? Sune • – Jens Apr 11 '14 at 15:10 ## 2 Answers Issue The main issue here is you can't add symbolic tensors with explicit tensors. In your example, d is a symbolic tensor, but IdentityMatrix[3] is an explicit tensor. Note what happens when you add them: $Assumptions = Element[d, Matrices[{3, 3}, Reals, Symmetric[{1,2}]]];

d + IdentityMatrix[3]


{{1 + d, d, d}, {d, 1 + d, d}, {d, d, 1 + d}}

The Listable attribute of Plus causes d to be added to all of the matrix elements of IdentityMatrix[3].

Symbolic identity matrix

Instead of using the explicit tensor IdentityMatrix[3], you can use either IdentityMatrix[n] or Inactive[IdentityMatrix][3]. For example:

d + IdentityMatrix[n]
d + Inactive[IdentityMatrix][3]


d + IdentityMatrix[n]

d + Inactive[IdentityMatrix][3]

In both cases no explicit matrix is generated. Now, for your example, it is better to use Inactive[IdentityMatrix][3] so that dimensions match up. If you had used Element[d, Matrices[{n, n}]] instead, you could use IdentityMatrix[n]. So:

dd = d - Tr[d] Inactive[IdentityMatrix][3]/3;

TensorReduce @ TensorContract[TensorProduct[dd, dd], {{1, 3}, {2, 4}}]


TensorContract[TensorProduct[d, d], {{1, 3}, {2, 4}}] - 2/3 TensorContract[ TensorProduct[d, Inactive[IdentityMatrix][3]], {{1, 3}, {2, 4}}] Tr[ d] + 1/9 TensorContract[ TensorProduct[Inactive[IdentityMatrix][ 3], Inactive[IdentityMatrix][3]], {{1, 3}, {2, 4}}] Tr[d]^2

Unfortunately, at the present time, TensorReduce doesn't know what to do with these "symbolic" identity tensors. Therefore, we will need to help things along.

SymbolicTensorsIdentityTensor

One possibility is to make use of the internal symbol SymbolicTensorsIdentityTensor. When a single such symbol is involved in a tensor contraction, then TensorContract will properly simplify the tensor product. Here is an example:

tensor = TensorContract[TensorProduct[d, Inactive[IdentityMatrix][3]], {{1, 3}, {2, 4}}];
tensor /. Inactive[IdentityMatrix] -> SymbolicTensorsIdentityTensor


TensorContract[d, {{1, 2}}]

On the other hand, if the TensorProduct contains a "symbolic" identity tensor (i.e., Inactive[IdentityMatrix][3] or IdentityMatrix[n]) that is not contracted, then TensorContract produces an error:

tensor = TensorContract[TensorProduct[d, Inactive[IdentityMatrix][3], d], {{1, 5}}];
tensor /. Inactive[IdentityMatrix] -> SymbolicTensorsIdentityTensor


Part::pkspec1: The expression {SymbolicTensorsSymbolicTensorsDumpi} cannot be used as a part specification.

...

where I've suppressed most of the output. Similarly, if the TensorProduct contains multiple "symbolic" identity tensors, even if they are all contracted, TensorContract still produces an error:

tensor = TensorContract[TensorProduct[Inactive[IdentityMatrix][3], Inactive[IdentityMatrix][3]], {{1, 4}, {2, 3}}];
tensor /. Inactive[IdentityMatrix] -> SymbolicTensorsIdentityTensor


Part::partw: Part {2,3} of {3[1,1],2[1,2]} does not exist.

...

So, what is needed is a method to find "symbolic" identity tensors that are being contracted, and one at a time, replace those tensors with SymbolicTensorsIdentityTensor.

IdentityReduce

Update - The paclet now lives on GitHub, and can be installed using:

PacletInstall[
"TensorSimplify",
"Site" -> "http://raw.githubusercontent.com/carlwoll/TensorSimplify/master"
]


Here is a function that does this (soon to be a part of a TensorSimplify package I will be putting on GitHub):

IdentityReduce[expr_] := expr /. TensorContract -> ir

ir[t_TensorProduct, i_] := Module[{indices, imIndices, ids, dummy},
indices = tensorIndices[t];
If[indices === $Failed, Return[TensorContract[t, i]]]; imIndices = Position[ Replace[t, Inactive[IdentityMatrix][n_] -> dummy[n], {1}], IdentityMatrix | dummy, {2} ]; ids = Pick[ imIndices, IntersectingQ[Flatten[i],indices[#]]& /@ imIndices[[All,1]] ]; If[ids==={}, TensorContract[t,i], TensorContract[ReplacePart[t, ids[[1]]->SymbolicTensorsIdentityTensor],i] /. TensorContract->ir ] ] ir[(Inactive[IdentityMatrix] | IdentityMatrix)[n_], {{1,2}}]=n; ir[o_, i_]:=TensorContract[o,i] tensorIndices[Verbatim[TensorProduct][t__]] := With[{r=Accumulate @* Map[TensorRank] @ {1,t}}, If[MatchQ[r, {__Integer}], Association @ Thread @ Rule[ Range@Length[{t}], Range[1+Most[r], Rest[r]] ],$Failed
]
]


Let's try the OP example again:

e = TensorReduce @ TensorContract[TensorProduct[dd, dd], {{1, 3}, {2, 4}}];
IdentityReduce @ e


TensorContract[TensorProduct[d, d], {{1, 3}, {2, 4}}] - 2/3 TensorContract[d, {{1, 2}}] Tr[d] + Tr[d]^2/3

Notice how the symbolic identity tensors have been resolved. One can perform one final step, converting all TensorContract objects to Dot/Tr (if possible) using my FromTensor function:

FromTensor @ IdentityReduce @ e


-(1/3) Tr[d]^2 + Tr[Transpose[d].d]

It is possible to use TensorReduce on this expression, but it produces a result using Tr[MatrixPower[d, 2]] instead of Tr[d.d], so I won't do so.

Assumptions are not used in normal evaluation, but only in certain functions like Simplify. Another, simpler example:

In[1]:= $Assumptions = x \[Element] Reals Out[1]= x \[Element] Reals In[2]:= Conjugate[x] Out[2]= Conjugate[x] In[3]:= Simplify[%] Out[3]= x  You see, during normal evaluation Mathematica doesn't recognize that x is supposed to be real, only during Simplify. You can identify the functions which take $Assumptions into account by the fact that they also accept an option Assumption. On Mathematica 8, using

Select[Names["System*"],Options[Symbol@#,Assumptions]!={}&]


I get the following list:

• ContinuedFractionK
• Convolve
• DifferenceDelta
• DifferenceRootReduce
• DifferentialRootReduce
• DirichletTransform
• DiscreteConvolve
• DiscreteRatio
• DiscreteShift
• Expectation
• ExpectedValue
• ExponentialGeneratingFunction
• FinancialBond
• FourierCoefficient
• FourierCosCoefficient
• FourierCosSeries
• FourierCosTransform
• FourierSequenceTransform
• FourierSeries
• FourierSinCoefficient
• FourierSinSeries
• FourierSinTransform
• FourierTransform
• FourierTrigSeries
• FullSimplify
• FunctionExpand
• GeneratingFunction
• Integrate
• InverseFourierCosTransform
• InverseFourierSequenceTransform
• InverseFourierSinTransform
• InverseFourierTransform
• InverseZTransform
• LaplaceTransform
• Limit
• PiecewiseExpand
• PossibleZeroQ
• PowerExpand
• Probability
• ProbabilityDistribution
• Product
• Refine
• Residue
• Series
• SeriesCoefficient
• Simplify
• Sum
• SumConvergence
• TimeValue
• ToRadicals
• TransformedDistribution
• ZTransform
• To be more precise, $Assumptions only works on functions with Assumptions option :) – xzczd Apr 11 '14 at 12:24 • @xzczd: I already suspected that, but wasn't quite sure, so I didn't include that. But now that you say so, I think it can be safely included. Thank you. – celtschk Apr 11 '14 at 12:26 • Thanks - got it. So perhaps the only way of approaching my problem would be to define SymmetrizedArrays with proper symmetries and then subtract the trace explicitly? – Sooner Apr 12 '14 at 8:34 • I don't have experience with SymmetrizedArray (it's a Mathematica 9 feature, and I only have access to Mathematica 8), so I cannot tell you whether that would be the correct or best approach. The problem here is that Mathematica treats all unbound variables as scalars during evaluation, and there's AFAIK no way to override that behaviour for specific variables. – celtschk Apr 12 '14 at 9:01 • The OP is using M9+, and in M9+ TensorReduce accepts the Assumptions option. So, the OP is correct in assuming that his$Assumptions are used during TensorReduce. – Carl Woll Sep 13 '17 at 17:47