Defining and working with tensorial rules

When working with a rule involving tensors we need to take into account the following :

Dummy indices on the right hand side.

tensor symmetries.

Existence of a metric.

We start a new xTensor session:

<<xAct`xTensor`

$DefInfoQ=False;

$PrePrint=ScreenDollarIndices;

Define manifold, metric & covariant derivatives:

DefConstantSymbol[dim,PrintAs->"d"]

DefManifold[M,dim,IndexRange[a,q]]

DefMetric[-1,metric[-a,-b],CD,PrintAs->"g"]

DefCovD[cd[-a],{"|","D"},Torsion->True]

Rules with dummy indices

DefTensor[A[b],M]

DefTensor[B[-c,-d,-f],M]

Imagine that we want to define a rule involving dummy indices. A first approach would be:

rule=A[b_]->B[d,-d,b];

However, this naive approach would give us incorrect tensor expressions due to dummy index collision:

A[d]/.rule

(A[c]A[-c])(A[f]A[-f])/.rule

Suggestion coming from the WL: use the unique local variables of a Module construct:

rule=A[b_]:>Module[{d},B[d,-d,b]]

The WL represents these local variables by creating  new symbols by appending dollar characters. New dollar symbols are created whenever the rule is invoked. Run the rule below several times and check how the number of dollar variables increase:

$PrePrint=.

A[d]A[-d]A[c]A[-c]A[f]A[-f]/.rule

Names["Global`d$*"]

%//Length

%%%//ScreenDollarIndices

IndexRule and IndexSet

We can avoid building the Module ourselves by using IndexRule or IndexSet: IndexRule is the counterpart of Rule for indexed rules and IndexSet is the counterpart of Set for indexed assignments.

?IndexRule

?IndexSet

Define new tensors:

DefTensor[v[a],M]

DefTensor[F[a,b],M,Antisymmetric[{1,2}]]

Patterns are admitted in the left hand side of the rule:

rule=IndexRule[v[b_],v[a]F[-a,b]]

InputForm[rule]

Now everything works as before:

$PrePrint=ScreenDollarIndices;

v[a]v[b]v[c]v[d]v[e]v[f]/.rule

IndexSet[A[b_],B[d,-d,b]]

A[b]A[c]A[d]A[e]A[f]

IndexSet works by attaching DownValues to the appropriate symbol:

DownValues@A

IndexSet and IndexRule have their delayed counterparts:

?IndexRuleDelayed

?IndexSetDelayed

Check the difference:

A=1000;

B v[a]v[b]v[c]v[d]v[e]v[f]/.IndexRule[A_Symbol v[b_], v[a] F[-a,b]A^2]

B v[a]v[b]v[c]v[d]v[e]v[f]/.IndexRuleDelayed[A_Symbol v[b_],v[a]F[-a,b]A^2]

MakeRule: full control on rules

Tensorial rules are far more complex than what we have discussed so far. In addition to the problem of dummy index clash, we need to take into consideration the existence of symmetries in the tensors which appear in the rules. For example imagine the rule:

rule=F[a_,b_]v[-b_]:>v[a]

This rule does not take into account that the tensor F is antisymmetric:

{F[c,d]v[-d],F[d,c]v[-d]}/.rule

To take into account that the tensor F is antisymmetric, we need to use MakeRule:

rule=MakeRule[{F[a,b]v[-b],v[a]}]

MakeRule adds automatically the necessary pattern indices (unless we ask it not to do so with the appropriate options). The fact that we are working with pattern indices is indicated with the double underscores under the indices.

%//InputForm

Now the rule works as expected:

{F[c,d]v[-d],F[d,c]v[-d]}/.rule

MakeRule is a powerful function with several options:

Options[MakeRule]

PatternIndices->All: pattern indices are constructed for all the indices.

UseSymmetries->True: construct all the possible rules equivalent under index symmetry permutation of the left hand side.

TestIndices->True :adds vector bundle information on the pattern indices.

MetricOn: specifies what set of indices are allowed to change in their character (covariant or contravariant).

ContractMetrics->True: contracts all metrics on the RHS of the rule.

MakeRule: working with metrics

Now we define a rule taking into account the presence of a metric:

rule=MakeRule[{F[-a,-c],PD[-b][F[b,-a]]v[-c]},MetricOn->All]

The rule is now applied for any index configuration:

{F[a,b],F[a,-b],F[-a,b],F[-a,-b]}/.rule

Compare to what happens when we use IndexRule instead of MakeRule:

rule1=IndexRule[F[-a_,-c_],PD[-b][F[b,-a]]v[-c]]

{F[a,b],F[a,-b],F[-a,b],F[-a,-b]}/.rule1

We can eliminate unnecessary metric factors within MakeRule:

rule=MakeRule[{F[-a,-c],PD[-b][F[b,-a]]v[-c]},MetricOn->All,ContractMetrics->True]

{F[a,b],F[a,-b],F[-a,b],F[-a,-b]}/.rule

Examples

For a given tensorial rule, MakeRule is able to compute all the possible rules taking into account the tensor symmetries, the dummy indices and the  presence of a metric. Sometimes this results in quite a number of possible rules:

rule=MakeRule[{F[-a,-b]F[b,c]v[-c],v[-a]},MetricOn->All,ContractMetrics->True]

Length[%]

rule=MakeRule[{F[-a,-b]F[b,-c]F[c,-d]v[d],v[-a]},MetricOn->All,ContractMetrics->True]

%//Length

Riemann tensor expressions (section 9.2 of xTensor documentation file)

Recall that a tensor T admit  two types of symmetries:

Mono-term symmetries:

g·T=±T,  g∈(Subscript[ℤ, 2])×(Subscript[S, n]).

Multi-term symmetries:

s·T=±T,  s∈ℝ(G), where G≡(Subscript[ℤ, 2])×(Subscript[S, n])and ℝ(G) is the group algebra of G.

There is no algorithm at present in xTensor to canonicalize expressions with multi-term symmetries. That is an obstacle in GR when one wants to work with the Riemann tensor, which has a cyclic symmetry. A simple, brute-force, solution is to prepare a number of rules which are only valid for the Riemann tensor. We follow MathTensor's discussion of this point (see MathTensor book, section 3.6). MathTensor implements 48 rules in total, numbered from 1 to 40, some of them having subcases.
16 of those rules are simple consequences of the mono-term symmetries of the Riemann tensor, and hence can be considered already implemented in ToCanonical:

RiemannRule1:

RiemannCD[-a,a,-c,-d]//ToCanonical

RiemannCD[-a,-b,-c,c]//ToCanonical

RiemannRule2:

RiemannCD[-a,-b,a,-d]//ToCanonical

RiemannRule3:

RiemannCD[-a,-b,-c,a]//ToCanonical

RiemannRule4:

RiemannCD[-a,-b,b,-d]//ToCanonical

RiemannRule5:

RiemannCD[-a,-b,-c,b]//ToCanonical

RiemannRule6:

RiemannCD[-a,-b,-c,-d]RicciCD[a,b]//ToCanonical

RiemannCD[-a,-b,-c,-d]RicciCD[c,d]//ToCanonical

RiemannRule31:

CD[-e]@RiemannCD[-a,-b,-c,-d]RicciCD[a,b]//ToCanonical

CD[-e]@RiemannCD[-a,-b,-c,-d]RicciCD[c,d]//ToCanonical

RiemannRule32:

CD[-e]@RiemannCD[-a,-b,-c,-d]CD[-f]@RicciCD[a,b]//ToCanonical

CD[-e]@RiemannCD[-a,-b,-c,-d]CD[-f]@RicciCD[c,d]//ToCanonical

RiemannRule33:

CD[-c]@RicciCD[-a,-b]RiemannCD[a,b,d,e]//ToCanonical

CD[-c]@RicciCD[-a,-b]RiemannCD[d,e,a,b]//ToCanonical

There are 2 more rules which can be obtained from the fact that the Einstein tensor is divergence free:

RiemannRule16:

CD[b][RicciCD[-a,-b]]//RicciToEinstein//ContractMetric

RiemannRule17:

CD[a][RicciCD[-a,-b]]//RicciToEinstein//ContractMetric

The other 32 MathTensor rules are actual consequences of the cyclic symmetry of the Riemann tensor, and therefore must be programmed independently. Using MakeRule we can avoid typing equivalent rules (up to permutations of indices), reducing the number to 17 independent rules in xTensor. We first study 13 MathTensor rules having derivatives of a single curvature tensor on the LHS. They are in fact only 6 independent xTensor rules:
	RuleDivRiemann
	RuleDivGradRicci
	RuleBoxRiemann
	RuleDivGradRiemann
	RuleD4RicciScalar
	RuleD4Ricci

RuleDivRiemann//Length

RuleDivGradRicci//Length

RuleBoxRiemann//Length

RuleDivGradRiemann//Length

RuleD4RicciScalar//Length

RuleD4Ricci//Length

The four MathTensor rules 20-23 are all the same:

RuleDivRiemann=MakeRule[{CD[a]@RiemannCD[-a,-b,-c,-d],-CD[-d]@RicciCD[-b,-c]+CD[-c]@RicciCD[-b,-d]},UseSymmetries->True,MetricOn->All];

RiemannRule20:

CD[a]@RiemannCD[-a,-b,-c,-d]/.RuleDivRiemann

RiemannRule21:

CD[b]@RiemannCD[-a,-b,-c,-d]/.RuleDivRiemann

RiemannRule22:

CD[c]@RiemannCD[-a,-b,-c,-d]/.RuleDivRiemann

RiemannRule23:

CD[d]@RiemannCD[-a,-b,-c,-d]/.RuleDivRiemann

Two rules with second derivatives of Ricci can be combined in a single rule:

RuleDivGradRicci=MakeRule[{CD[b]@CD[-c]@RicciCD[-a,-b],1/2CD[-c]@CD[-a]@RicciScalarCD[]+RicciCD[-m,-a]RicciCD[-c,m]-RicciCD[-m,-n]RiemannCD[-a,n,-c,m]},UseSymmetries->True,MetricOn->All];

RiemannRule18:

CD[b]@CD[-c]@RicciCD[-a,-b]/.RuleDivGradRicci

RiemannRule19:

CD[a]@CD[-c]@RicciCD[-a,-b]/.RuleDivGradRicci

MathTensor Rules 26 to 30 are now two rules in xTensor:

RuleBoxRiemann=MakeRule[{CD[e]@CD[-e]@RiemannCD[-a,-b,-c,-d],
CD[-b]@CD[-d]@RicciCD[-a,-c]-CD[-b]@CD[-c]@RicciCD[-a,-d]-
CD[-a]@CD[-d]@RicciCD[-b,-c]+CD[-a]@CD[-c]@RicciCD[-b,-d]+
RicciCD[-m,-b]RiemannCD[-a,m,-c,-d]-
RicciCD[-m,-a]RiemannCD[-b,m,-c,-d]-
RiemannCD[-m,-n,-c,-d]RiemannCD[-a,m,-b,n]-
RiemannCD[-m,-b,-n,-d]RiemannCD[-a,m,-c,n]+
RiemannCD[-m,-b,-n,-c]RiemannCD[-a,m,-d,n]+RiemannCD[-m,-a,-n,-d]RiemannCD[-b,m,-c,n]-RiemannCD[-m,-a,-n,-c]RiemannCD[-b,m,-d,n]-
RiemannCD[-m,-a,-n,-b]RiemannCD[-c,-d,m,n]},UseSymmetries->True,MetricOn->All];

RuleDivGradRiemann=MakeRule[{CD[a]@CD[-e]@RiemannCD[-a,-b,-c,-d],-CD[-e]@CD[-d]@RicciCD[-b,-c]+CD[-e]@CD[-c]@RicciCD[-b,-d]-RicciCD[-m,-e]RiemannCD[-b,m,-c,-d]+RiemannCD[-m,-n,-c,-d]RiemannCD[-b,m,-e,n]-RiemannCD[-m,-b,-n,-d]RiemannCD[-c,n,-e,m]+RiemannCD[-m,-b,-n,-c]RiemannCD[-d,n,-e,m]},UseSymmetries->True,MetricOn->All];

RiemannRule26:

CD[e]@CD[-e]@RiemannCD[-a,-b,-c,-d]/.RuleBoxRiemann

RiemannRule27:

CD[a]@CD[-e]@RiemannCD[-a,-b,-c,-d]/.RuleDivGradRiemann

RiemannRule28:

CD[b]@CD[-e]@RiemannCD[-a,-b,-c,-d]/.RuleDivGradRiemann

RiemannRule29:

CD[c]@CD[-e]@RiemannCD[-a,-b,-c,-d]/.RuleDivGradRiemann

RiemannRule30:

CD[d]@CD[-e]@RiemannCD[-a,-b,-c,-d]/.RuleDivGradRiemann

Fourth derivative of the Ricci scalar: conversion to Box squared:

RuleD4RicciScalar=MakeRule[{CD[b]@CD[a]@CD[-b]@CD[-a]@RicciScalarCD[],1/2CD[-m]@RicciScalarCD[]CD[m]@RicciScalarCD[]+CD[n]@CD[-n]@CD[m]@CD[-m]@RicciScalarCD[]+CD[-n]@CD[-m]@RicciScalarCD[]RicciCD[m,n]},UseSymmetries->True,MetricOn->All];

RiemannRule24:

CD[b]@CD[a]@CD[-b]@CD[-a]@RicciScalarCD[]/.RuleD4RicciScalar

Fourth derivative of the Ricci tensor:

AddIndices[TangentM,{h1,h2,h3,h4,h5,h6}]

RuleD4Ricci=MakeRule[{CD[b]@CD[a]@CD[c]@CD[-c]@RicciCD[-a,-b],1/2CD[-m]@RicciScalarCD[]CD[m]@RicciScalarCD[]-3CD[-h3]@RicciCD[-m,-h2]CD[h3]@RicciCD[m,h2]+4CD[-h3]@RicciCD[-m,-h2]CD[h2]@RicciCD[m,h3]+1/2CD[h2]@CD[-h2]@CD[m]@CD[-m]@RicciScalarCD[]+2CD[-h2]@CD[-m]@RicciScalarCD[]RicciCD[m,h2]-CD[h3]@CD[-h3]@RicciCD[-m,-h2]RicciCD[m,h2]+2RicciCD[-m,-h2]RicciCD[-h3,m]RicciCD[h2,h3]-2CD[-h4]@CD[-h3]@RicciCD[-m,-h2]RiemannCD[m,h3,h2,h4]-2RicciCD[-m,-h2]RicciCD[-h3,-h4]RiemannCD[m,h3,h2,h4]},UseSymmetries->True,MetricOn->All];

RiemannRule25:

CD[b]@CD[a]@CD[c]@CD[-c]@RicciCD[-a,-b]/.RuleD4Ricci

Now we study six MathTensor rules with products of two Riemann tensors on the LHS. There are only two xTensor different rules, depending on whether there are two or three contracted indices:
	RuleTwoRiemann3
	RuleTwoRiemann2

These are the independent rules:

RuleTwoRiemann3=MakeRule[{RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,b,c],-1/2RiemannCD[-f,-d,-g,-h]RiemannCD[-e,f,g,h]},UseSymmetries->True,MetricOn->All];

RuleTwoRiemann2=MakeRule[{RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-g,b],1/2RiemannCD[-f,-h,-c,-d]RiemannCD[-e,-g,f,h]},UseSymmetries->True,MetricOn->All];

RiemannRule7:

RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,b,c]/.RuleTwoRiemann3

RiemannRule8:

RiemannCD[-a,-b,-c,-d]RiemannCD[a,c,b,h]/.RuleTwoRiemann3

RiemannRule9a:

RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-g,b]/.RuleTwoRiemann2

RiemannRule9b:

RiemannCD[-a,-b,-c,-d]RiemannCD[e,a,b,h]/.RuleTwoRiemann2

RiemannRule9c:

RiemannCD[-a,-b,-c,-d]RiemannCD[a,f,b,h]/.RuleTwoRiemann2

RiemannRule9d:

RiemannCD[-a,-b,-c,-d]RiemannCD[a,f,g,b]/.RuleTwoRiemann2

There are seven more MathTensor rules involving two curvature tensors and derivatives, corresponding to five independent xTensor rules:
	RuleD01TwoRiemann
	RuleD11TwoRiemann
	RuleD2RicciRiemann
	RuleD2RicciDRiemann
	RuleD11bisTwoRiemann

RuleD01TwoRiemann=MakeRule[{CD[-e]@RiemannCD[a,f,b,c]RiemannCD[-a,-b,-c,-d],-1/2CD[-e]@RiemannCD[h1,f,h2,h3]RiemannCD[-h1,-d,-h2,-h3]},UseSymmetries->True,MetricOn->All];

RuleD11TwoRiemann=MakeRule[{CD[-e]@RiemannCD[-a,-b,-c,-d]CD[-f]@RiemannCD[a,g,b,c],-1/2CD[-e]@RiemannCD[-h1,-d,-h2,-h3]CD[-f]@RiemannCD[h1,g,h2,h3]},UseSymmetries->True,MetricOn->All];

RuleD2RicciRiemann=MakeRule[{CD[-d]@CD[-c]@RicciCD[-a,-b]RiemannCD[a,d,b,c],CD[-h4]@CD[-h3]@RicciCD[-h1,-h2]RiemannCD[h1,h3,h2,h4]},UseSymmetries->True,MetricOn->All];

RuleD2RicciDRiemann=MakeRule[{CD[-e]@RiemannCD[a,d,b,c]CD[-d]@CD[-c]@RicciCD[-a,-b],CD[-e]@RiemannCD[h1,h2,h3,h4]CD[-h4]@CD[-h2]@RicciCD[-h1,-h3]},UseSymmetries->True,MetricOn->All];

This rule has a typo in MathTensor's book. The index c on the RHS is actually f:

RuleD11bisTwoRiemann=MakeRule[{CD[-g]@RiemannCD[-a,-b,-c,-d]CD[g]@RiemannCD[c,e,d,f],1/2CD[-h3]@RiemannCD[-h1,-h2,-a,-b]CD[h3]@RiemannCD[h1,h2,f,e]},UseSymmetries->True,MetricOn->All];

RiemannRule34:

CD[-e]@RiemannCD[a,f,b,c]RiemannCD[-a,-b,-c,-d]/.RuleD01TwoRiemann

RiemannRule35:

CD[-e]@RiemannCD[-a,-b,-c,-d]CD[-f]@RiemannCD[a,g,b,c]/.RuleD11TwoRiemann

RiemannRule36:

CD[-e]@RiemannCD[a,c,b,f]RiemannCD[-a,-b,-c,-d]/.RuleD01TwoRiemann

RiemannRule37:

CD[-e]@RiemannCD[-a,-b,-c,-d]CD[-f]@RiemannCD[a,c,b,g]/.RuleD11TwoRiemann

RiemannRule38:

CD[-g]@RiemannCD[-a,-b,-c,-d]CD[g]@RiemannCD[c,e,d,f]/.RuleD11bisTwoRiemann

RiemannRule39:

CD[-e]@RiemannCD[a,d,b,c]CD[-d]@CD[-c]@RicciCD[-a,-b]/.RuleD2RicciDRiemann

RiemannRule40:

CD[-d]@CD[-c]@RicciCD[-a,-b]RiemannCD[a,d,b,c]/.RuleD2RicciRiemann

Finally we study six MathTensor rules with products of three curvature tensors, only four of which are independent. The corresponding xTensor rules are:
	RuleRicciTwoRiemann
	RuleThreeRiemann
	RuleThreeRiemannB
	RuleThreeRiemannC

Constructing the independent rules takes rather long because there are lots of equivalent cases:

AbsoluteTiming[Length[RuleRicciTwoRiemann=MakeRule[{RicciCD[-a,-b]RiemannCD[-c,-d,-e,a]RiemannCD[b,c,d,e],-1/2RicciCD[-h1,-h2]RiemannCD[-h3,-h4,-h5,h1]RiemannCD[h2,h5,h3,h4]},UseSymmetries->True,MetricOn->All]]]

AbsoluteTiming[Length[RuleThreeRiemann=MakeRule[{RiemannCD[-a,-b,-c,-d]RiemannCD[-e,-f,a,b]RiemannCD[c,e,d,f],1/2RiemannCD[-h1,-h2,-h3,-h4]RiemannCD[-h5,-h6,h1,h2]RiemannCD[h3,h4,h5,h6]},UseSymmetries->True,MetricOn->All]]]

AbsoluteTiming[Length[RuleThreeRiemannB=MakeRule[{RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-f,b]RiemannCD[c,e,d,f],1/4RiemannCD[-h1,-h2,-h3,-h4]RiemannCD[-h5,-h6,h3,h4]RiemannCD[h1,h2,h5,h6]},UseSymmetries->True,MetricOn->All]]]

AbsoluteTiming[Length[RuleThreeRiemannC=MakeRule[{RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-f,c]RiemannCD[b,f,d,e],RiemannCD[-h1,-h2,-h3,-h4]RiemannCD[-h5,h1,-h6,h3]RiemannCD[h2,h5,h4,h6]-1/4RiemannCD[-h1,-h2,-h3,-h4]RiemannCD[-h5,-h6,h1,h2]RiemannCD[h3,h4,h5,h6]},UseSymmetries->True,MetricOn->All]]]

RiemannRule10:

RicciCD[-a,-b]RiemannCD[-c,-d,-e,a]RiemannCD[b,c,d,e]/.RuleRicciTwoRiemann

RiemannRule11:

RiemannCD[-a,-b,-c,-d]RiemannCD[-e,-f,a,b]RiemannCD[c,e,d,f]/.RuleThreeRiemann

RiemannRule12:

RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-f,b]RiemannCD[c,e,d,f]/.RuleThreeRiemannB

RiemannRule13:

RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-f,b]RiemannCD[c,d,e,f]/.RuleThreeRiemann

RiemannRule14:

RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-f,c]RiemannCD[b,d,e,f]/.RuleThreeRiemannB

RiemannRule15:

RiemannCD[-a,-b,-c,-d]RiemannCD[-e,a,-f,c]RiemannCD[b,f,d,e]/.RuleThreeRiemannC

Summary

There are two main types of tensor rules in xTensor:

IndexRule: used to prevent dummy index collisions from dummies defined on the right hand side of the rule. No control on tensor symmetries or index character.

MakeRule: all the capabilities of IndexRule + full control of tensor symmetries and index character (covariant-contravariant, vector bundle).

Exercises

Exercise 1

Consider a tensor (Subscript[R, a b c d]) having the same mono-term symmetries as the Riemann tensor. Define a single tensor rule with MakeRule such that when it acts upon the tensor expression:

(Subscript[R, a b c d])+(Subscript[R, a c d b])+(Subscript[R, a d b c]),

it returns zero.  Hint: it is necessary to construct the Young symmetrizer of the tensor (Subscript[R, a b c d]).

Answer

Define the required structures:

Exit

<<xAct`xTensor`

DefConstantSymbol[dim,PrintAs->"d"]

DefManifold[M,dim,IndexRange[{a,m}]]

DefTensor[R[-a,-b,-c,-d],M,RiemannSymmetric[{-a,-b,-c,-d}]]

The obvious rule does not work because MakeRule only admits tensor monomials on the LHS:

MakeRule[{R[-a,-b,-c,-d]+R[-a,-c,-d,-b]+R[-a,-d,-b,-c],0}]

The Riemann tensor mono-term and multi-term symmetries can be represented with the aid of a Young tableau:

(Subscript[R, a b c d])->({{a, c}, {b, d}})

This means that we have the following equality (symmetrization along the rows and antisymmetrization along the columns):

R[-a,-b,-c,-d]==4/3ToCanonical@Antisymmetrize[Antisymmetrize[Symmetrize[Symmetrize[R[-a,-b,-c,-d],{-a,-c}],{-b,-d}],{-a,-b}],{-c,-d}]

Expand/@%

The factor 4/3 in front of ToCanonical is added to get idempotency (see below): Now we transform the previous equality into a rule:

YoungSymmetrizer=MakeRule[{R[-a,-b,-c,-d],2/3R[-a,-b,-c,-d]+1/3R[-a,-c,-b,-d]-1/3R[-a,-d,-b,-c]}]

R[-a,-b,-c,-d]/.YoungSymmetrizer

The multiple application of the rule does not change the result (idempotency)

%/.YoungSymmetrizer//ToCanonical

Finally, we answer the question asked by the exercise:

R[-a,-b,-c,-d]+R[-a,-c,-d,-b]+R[-a,-d,-b,-c]

%/.YoungSymmetrizer

ToCanonical@%

Exit

Exercise 2

Suppose that you have an equality of the form:

A==B

where A and B are tensor expressions. Create a function that transforms the equality into a MakeRule:

Answer

<<xAct`xTensor`

DefConstantSymbol[dim,PrintAs->"d"]

DefManifold[M,dim,IndexRange[{a,m}]]

DefMetric[-1,metricg[-a,-b],CD]

A possibility to transform a tensor equality into a MakeRule is:

ApplyRule[expr_Equal]:=MakeRule[Evaluate[List@@expr],MetricOn->All,ContractMetrics->True];

ApplyRuleN[expr_Equal]:=MakeRule[Evaluate[List@@expr]];

We need to know that MakeRule has the attribute HoldFirst:

Attributes@MakeRule

This is equivalent to the use of HoldPattern in the standard WL pattern matching: pattern indices constructed by MakeRule are not evaluated as WL expressions in order to prevent collision with other symbols or expressions defined previously.