Introduction to Symbolic Computations in GR with xTensor

Downloading and Installing xAct

Visit the page: http://www.xact.es
Follow installation instructions on http://www.xact.es/download.html
Linux: 
1. Download the tarball xAct_V.tgz (V is the version number)
2. sudo -i ; cd /usr/share/Mathematica/Applications/; tar xvfz ~/Downloads/xAct_V.tgz
Windows:
1. Download the zip file xAct_V.zip (V is the version number)
2. unzip its contents in C:\Program Files\Wolfram Research\Mathematica\<version>\AddOns\Applications\

Read the documentation:
http://www.xact.es/documentation.html
If you want to use xTensor, you will not avoid reading the full documentation. Better earlier than later:  xTensorDoc.nb
The reference notebook is useful too:  xTensorRefGuide.nb

The documentation is also installed locally, most likely in:
Linux:          /usr/share/Mathematica/Applications/xAct/Documentation/English/
Windows: C:\Program Files\Wolfram Research\Mathematica\<version>\AddOns\Applications\xAct\Documentation\English

Explore the documentation in xTensorDoc.nb.... Make a copy to the notebook, so that you can play with it.
cp /usr/share/Mathematica/Applications/xAct/Documentation/English/xTensorDoc.nb .
cp /usr/share/Mathematica/Applications/xAct/Documentation/English/xTensorRefGuide.nb .

Start an xTensor session

If you are already running a Mathematica session, esp. if you have loaded xTerior, xAct, ..., make a call to Quit[] before the loading of the package:
Quit[]; Needs[“xAct`xTensor`”]

Needs["xAct`xTensor`"]

Define a manifold, whose name is M4, and its dimension is 4. 
The indices used are {λ,μ,ν,ρ,σ,α,β,γ,δ}. You can put any indices you like, they should consist of one character.

Online documentation:

?DefManifold

See all available functions.
Click on any name for usage information:

?xAct`xTensor`*

DefManifold[M4,4,{λ,μ,ν,ρ,σ,α,β,γ,δ}];

DimOfManifold[M4] gives its dimension. A tangent bundle is associated with the manifold, you can refer to it as TangentM4
This is the first indication that xAct defines objects by creating Heads that have names related to the definition of the names of the Manifold, the metric, the covariant derivative, etc.

Print[
"The Manifold M4 has dimension ",DimOfManifold[M4],"\n",
"Its tangent bundle is ",Tangent[M4]," and you can refer to is using the name ",Tangent[M4]//InputForm,"   (Tangent + M4 = TangentM4)\n",
"For example: The indices of ",TangentM4," are: ",IndicesOfVBundle[TangentM4]
]

We define a metric, whose symbol will be “g” and a metric compatible, torsion free covariant derivative CD. A lot of things are defined with it by default:
1. A Christoffel covariant derivative (compatible with the metric+torsion free) with name CD and its Christoffel symbols ChristoffelCD.
2. A Levi-Civita tensor (Subscript[ϵ, αβγδ])  epsilong[ ] and the metric determinant  Detg[ ]
3. Curvature tensors RiemannCD, RicciCD, RiemannScalarCD[ ], EinsteinCD[ ], WeylCD[ ], ...

Read the output messages printed after evaluating the cell below for more information. 

Notice that the names of the symbols referring to the above tensors/tensor densities end in “g” or “CD”. This comes from the chosen (by default here) names. If the metric had name, e.g. MetricG,  and the covariant derivative CDer, then we would have epsilonMetricG, DetMetricG, RiemannCDer, RicciCDer, etc..

The  -1  in the first argument, means that the determinant of the metric is negative

DefMetric[-1,g[-μ,-ν],CD];

Tensors are symbolic objects that take indices.   An index that has a minus sign in front of it is contravariant, otherwise it is covariant.

Tensors must be defined using DefTensor: The indices must be among the list of indices in the tangent bundle of M4, TangentM4.

DefTensor[v[  α],M4];DefTensor[u[   α],M4]; (* vectors: covariant,     (1,0) tensors *)
DefTensor[ω[-α],M4];DefTensor[ξ[-α],M4]; (* 1-forms: contravariant, (0,1) tensors *)
{v[μ],u[ν],ω[-β],ξ[-γ]}

Here are more tensors. We can specify if (some of) their indices have a specific symmetry:

DefTensor[F[-α,-β]                       ,M4,Antisymmetric[{-α,-β}]]; (* (0,2) tensor, antisymmetric in α,β *)
DefTensor[S[-α,-β]                       ,M4,         Symmetric[{-α,-β}]];   (* (0,2) tensor,     symmetric in α,β *)
{F[-μ,-ν],S[-α,-β]}

DefTensor[Stensor[  α,-β, -γ],M4,         Symmetric[{-β,-γ}], PrintAs->"𝒮"];  (* (1,1) tensor,symmetric in β,γ  note: [Esc]scS[Esc] gives 𝒮 *)
Stensor[μ,-ν,-λ]

If you don’t need a tensor anymore, or you need to redefine it, you have to undefine it first, using UndefTensor:

UndefTensor[Stensor]

ϕ is a scalar field; c a constant scalar field: it is defined on no manifold and its derivative is zero (see below). We also define a constant.

DefTensor[scalar[],M4,PrintAs->"ϕ"];DefTensor[const[],{},PrintAs->"c"] ; DefConstantSymbol[hbar, PrintAs-> "ℏ"];
{scalar[],const[],hbar}

If you get stuck, or make a serious error, you may need to restart your computation. First call Quit[] and then reevaluate the notebook: Evaluation -> Evaluate Notebook

(* Quit *)

Contractions: repeated upstairs+downstairs indices are contracted

{v[μ] ω[-μ],v[μ] v[-μ],
S[-α,-β] u[α],
F[-μ,-ν] v[μ] u[ν],F[-μ,-ν] v[μ] v[ν],F[-μ,-ν] v[μ] v[ν]//ToCanonical,
F[-μ,-ν] S[μ,ν],F[-μ,-ν] S[μ,ν]//ToCanonical}

If a tensorial expression is not valid - in the sense of the abstract index notation - Validate captures it:

{v[μ]v[ν]//Validate,v[μ]v[μ]//Validate,v[-μ] v[-μ]//Validate}

Let’s write down expressions using the tensors constructed for the metric g: we use the abstract index notation (see Wald)
Due to the metric, we can write (Subscript[ξ, λ]), as well as (ξ^λ).

RiemannCD[-μ,-ν,-λ,σ] v[μ] u[ν] ξ[λ] ω[-σ]

xTensor knows that the Riemann tensor is antisymmetric, need to use ToCanonical to apply it:

{RiemannCD[-μ,-ν,-λ,σ] v[μ] v[ν] ξ[λ] ω[-σ],RiemannCD[-μ,-ν,-λ,σ] v[μ] v[ν] ξ[λ] ω[-σ]//ToCanonical}

The monoterm symmetries of (Subscript[R, μνρσ]) are also known: (unfortunately “there is no algorithm at present in xTensor` to canonicalize expressions with multiterm symmetries” - section 9.2 of xTensorDoc.nb )

{RiemannCD[-μ,-ν,-λ,-σ] v[μ] u[ν] ξ[λ] ξ[σ],RiemannCD[-μ,-ν,-λ,-σ] v[μ] u[ν] ξ[λ] ξ[σ]//ToCanonical}

(Subscript[R, μνλσ ])(F^(μλ)) (u^ν)(u^σ)=(Subscript[R, λσ μν])(F^(μλ)) (u^ν)(u^σ)=-(Subscript[R, λσ μν])(F^(λμ)) (u^ν)(u^σ)=-(Subscript[R, μσ λν])(F^(μλ)) (u^ν)(u^σ)=-(Subscript[R, μν λσ])(F^(μλ)) (u^σ)(u^ν)=0

{RiemannCD[-μ,-ν,-λ,-σ] F[μ,λ]u[σ]u[ν],RiemannCD[-μ,-ν,-λ,-σ] F[μ,λ]u[σ]u[ν]//ToCanonical}

{RiemannCD[-μ,-ν,-λ,-σ] F[μ,λ] RicciCD[σ,ν],RiemannCD[-μ,-ν,-λ,-σ] F[μ,λ] RicciCD[σ,ν]//ToCanonical}

The Kronecker’s deltas

The Kronecker’s deltas are defined:
((Subscript[δ, μ])^ν), ((Subscript[δ, μ1 μ2 ... μn ])^(ν1 ν2 ... νn))=n!((Subscript[δ, [μ1])^(ν1))((Subscript[δ, μ2])^(ν2))...((Subscript[δ, μn]])^(νn))
ExpandGdelta[ Gdelta[...]  ]  expands in terms of delta[ ]. If there is a metric defined, we can have all indices up or down: indices are contracted using the metric.

Print[
"\n-------------------------------------------------------------",
"\n ((Subscript[δ, μ])^ν) =  ",delta[-μ,ν],",  ((Subscript[δ, μ])^μ) = ",delta[-μ,μ],",   ((Subscript[δ, μ])^ν) (Subscript[ω, ν]) = ",delta[-μ,ν] ω[-ν],
"\n ((Subscript[δ, μν])^(ρσ))= ",Gdelta[-μ,-ν,ρ,σ]," = ",ExpandGdelta[Gdelta[-μ,-ν,ρ,σ]],"  ((Subscript[δ, μν])^(ρσ)) (Subscript[ω, ρ]) (v^ν) =  ",Gdelta[-μ,-ν,ρ,σ] ω[-ρ] v[ν],
"\n ((Subscript[δ, μνρ])^(αβγ))=",ExpandGdelta[Gdelta[-μ,-ν,-ρ,  α,   β,  γ]],
"\n (Subscript[δ, μνραβγ])=",ExpandGdelta[Gdelta[-μ,-ν,-ρ,-α,-β,-γ]],"  (valid only if metric defined)"
]

Levi-Civita tensor

When a metric is defined, the Levi Civita tensor (Subscript[ϵ, μ1 μ2 ... μn]) is defined, and we can do contractions:

Print[
"------------------------------------------------------------\n",
epsilong[-α,-β,-γ,-δ]," ,    ",epsilong[-α,-β,-γ,-δ] g[α,β]," ,    ",epsilong[-α,-β,-γ,-δ] g[α,β]//ToCanonical,"\n",
"------------------------------------------------------------\n",
epsilong[-α,-β,-γ,-δ]epsilong[-μ,-ν,-ρ,δ],"\n",
"------------------------------------------------------------\n",
epsilong[-α,-β,-γ,-δ]epsilong[μ,ν,ρ,δ],"\n",
epsilong[-α,-β,-γ,-δ]epsilong[μ,ν,γ,δ],"\n",
epsilong[-α,-β,-γ,-δ]epsilong[μ,β,γ,δ],"\n",
epsilong[-α,-β,-γ,-δ]epsilong[α,β,γ,δ]," = 4!\n",
epsilong[-α,-β,-γ,-δ]epsilong[μ,ν,ρ,δ]epsilong[ α,β,γ,λ]
]

Metric Contractions

Use ContractMetric to contract indices:

Print[
"\n-------------------------------------------------------------",
"\n (Subscript[g, μσ])(g^(σν))    =  ",g[-μ,-σ] g[σ,ν]                             , "    ((Subscript[g, ,μ])^μ)  = ",g[-μ,μ],"    (Subscript[g, μν])(g^(μν)) = ",g[-μ,-ν] g[μ,ν],
"\n-------------------------------------------------------------",
"\n (Subscript[g, μν])(v^ν)     =  ",g[-μ,-ν]            v[ ν]                        ," = ",g[-μ,-ν]               v[  ν]                       //ContractMetric,
"\n (g^(μν))(Subscript[ω, ν])     =  ",g[μ,ν]                    ω[-ν]                      ," = ",g[μ,ν]                       ω[-ν]                      //ContractMetric,
"\n (g^(μν))(Subscript[F, νσ])    =  ",g[μ,ν]                  F[-ν,-σ]              ," = ",g[μ,ν]                    F[-ν,-σ]             //ContractMetric,
"\n (g^(νσ))(Subscript[F, μν])(Subscript[ω, σ])  =  ",g[ν,σ]                   F[-μ,-ν] ω[-σ]," = ",g[ν,σ]                    F[-μ,-ν] ω[-σ] //ContractMetric,
"\n (g^(μν))(g^(ρσ))(Subscript[F, νσ]) =  ",g[μ,ν] g[ρ,σ] F[-ν,-σ]             ," = ",g[μ,ν] g[ρ,σ] F[-ν,-σ]             //ContractMetric,
"\n",  S[-μ,-ν] g[μ,ν],"  =   ",S[-μ,-ν] g[μ,ν]//ContractMetric,
"\n-------------------------------------------------------------",
"\n",  RiemannCD[-μ,-ν,-ρ,-σ] g[ν,ρ] ,"  =  ",RiemannCD[-μ,-ν,-ρ,-σ] g[ν,ρ]//ContractMetric,
"\n","(Subscript[R, μν])(g^(μν)) = ", RicciCD[-μ,-ν] g[μ,ν],"  = " ,RicciCD[-μ,-ν] g[μ,ν]//ContractMetric,"    (no need to use ContractMetric)"
]

Covariant Derivative

We define a scalar field f[], a constant scalar field ϕ  (it is defined on no manifold), and a constant.

DefTensor[f[],M4];DefTensor[ϕ[],{}] ; DefConstantSymbol[GNewton, PrintAs-> "(Subscript[G, N])"];

The predefined, ordinary, flat,  partial derivative: [(∂_μ),(∂_ν)]=0

Print[
PD[-μ][f[]],"\n",
PD[-μ][v[ν]],"\n",
PD[-μ][f[] v[ν]],"\n",
PD[-μ][u[ρ] v[ν]],"\n",
PD[-μ][PD[-ν][u[σ]]]-PD[-ν][PD[-μ][u[σ]]]," = ", PD[-μ][PD[-ν][u[σ]]]-PD[-ν][PD[-μ][u[σ]]] //ToCanonical
]

The Covariant derivative:

Print[
"(Subscript[∇, μ]) (Subscript[G, N]) = "                                     ,CD[-μ] [GNewton]                                                                                                      ,"\n",
CD[-μ] [f[]]                 ," = ",CD[-μ] [f[]]                 //CovDToChristoffel                                                 ,"\n",
CD[-μ] [GNewton f[]]," = ",CD[-μ] [GNewton f[]]//CovDToChristoffel                                                 ,"\n",
CD[-μ][ϕ[]]                  ," = ",CD[-μ][ϕ[]]                 //CheckZeroDerivative                                             ,"  (must use CheckZeroDerivative to actually see that the derivative is zero)\n",
CD[-μ][v[ν]]               , " = ",CD[-μ][v[ν]]              //CovDToChristoffel//ScreenDollarIndices,"\n",
CD[-μ][ω[-ν]]            , " = ",CD[-μ][ω[-ν]]            //CovDToChristoffel//ScreenDollarIndices,"\n",
CD[-μ][F[-ν,-ρ]]    ," = ",CD[-μ][F[-ν,-ρ]]   //CovDToChristoffel//ScreenDollarIndices,"\n",
CD[-μ][f[]v[ν]]    , " = ",CD[-μ][f[] v[ν]]    //CovDToChristoffel//ScreenDollarIndices,"\n",
"(Subscript[∇, μ]) ((Subscript[F, νρ])(v^ν)) = "                         , CD[-μ][F[-ν,-ρ]v[ν]]
]

Print[
ChristoffelCD[   μ,-ν,-ρ]," = ",ChristoffelCD[  μ,-ν,-ρ]//ChristoffelToGradMetric//ScreenDollarIndices,"\n",
ChristoffelCD[-μ,-ν,-ρ]," = ",ChristoffelCD[-μ,-ν,-ρ]//ChristoffelToGradMetric//ScreenDollarIndices,"\n"
]

Print[
CD[-μ][v[ν]]                                                                                                                                                              ,       "= ",
CD[-μ][v[ν]]   //CovDToChristoffel//ScreenDollarIndices                                                          , "\n = ",
CD[-μ][v[ν]]  //CovDToChristoffel//ChristoffelToGradMetric//ScreenDollarIndices,"\n = ",
CD[-μ][v[ν]]  //CovDToChristoffel//ChristoffelToGradMetric//ToCanonical//ScreenDollarIndices,"\n"
]

Print[
CD[-μ]@v[ν]                                                                                                                                                              ,       "= ",
CD[-μ]@v[ν]   //CovDToChristoffel//ScreenDollarIndices                                                          , "\n = ",
CD[-μ]@v[ν]  //CovDToChristoffel//ChristoffelToGradMetric//ScreenDollarIndices,"\n = ",
CD[-μ]@v[ν]  //CovDToChristoffel//ChristoffelToGradMetric//ToCanonical//ScreenDollarIndices,"\n"
]

Print[
CD[-ρ]@CD[-μ]@v[ν]                                                                                                                                                              ,       "= ",
CD[-ρ]@CD[-μ]@v[ν]   //CovDToChristoffel//ScreenDollarIndices                                                          , "\n = ",
CD[-ρ]@CD[-μ]@v[ν]  //CovDToChristoffel//ChristoffelToGradMetric//ScreenDollarIndices,"\n = ",
CD[-ρ]@CD[-μ]@v[ν]  //CovDToChristoffel//ChristoffelToGradMetric//ToCanonical//ScreenDollarIndices,"\n"
]

(Subscript[∇, ρ])((u^μ)(Subscript[∇, μ])(S^(ρν)))

Print[
CD[-ρ]@(u[μ]CD[-μ]@S[ρ,ν])," = ",CD[-ρ]@(u[μ]CD[-μ]@S[ρ,ν])//CovDToChristoffel //ScreenDollarIndices 
]

Lie Derivatives

Print[
LieD[v[μ]][u[ν]]," = ",
LieD[v[μ]][u[ν]]//LieDToCovD //ScreenDollarIndices," = ",
LieDToCovD[LieD[v[μ]][u[ν]],CD]//ScreenDollarIndices
]

Lie Brackets:

Print[
Bracket[u[μ],v[ν]][σ]," = ",
Bracket[u[μ],v[ν]][σ] //BracketToCovD //ScreenDollarIndices, " = ",
BracketToCovD[Bracket[u[μ],v[ν]][σ],CD]//ScreenDollarIndices
]

Notice the Leibniz rule and the linearity in the 1st slot:

Print[
LieD[v[μ]][F[-ν,-ρ]]," = ",
LieD[v[μ]][F[-ν,-ρ]]//LieDToCovD //ScreenDollarIndices," = ",
LieDToCovD[LieD[v[μ]][F[-ν,-ρ]],CD]//ScreenDollarIndices,"\n",
LieD[v[μ]][F[-ν,-ρ] u[σ]],"\n",
LieD[v[μ]+7  GNewton u[μ]][F[-ν,-ρ]],"\n",
LieD[ u[μ]][GNewton v[ρ]],"\n",
LieD[ u[μ]][ f[]        v[ρ]]
]

Bracket[v[μ]+ GNewton u[λ], ω[ρ]][σ]

Bracket[ f[] u[λ], v[ρ]][σ]

Prove that (Subscript[ℒ, [u,v]])ξ=[(Subscript[ℒ, u]),(Subscript[ℒ, v])]ξ

Print[
"----------------------------------------------------------------------------------------------------\n",
"The left hand side:  (Subscript[ℒ, [u, v]]) ξ\n",
                                      LieD[                                 Bracket[ u[μ],v[ν]][σ]            ][ ξ[ρ] ]                                                             ," = ",
                                      LieD[ BracketToCovD[Bracket[ u[μ],v[ν]][σ],CD ]][ ξ[ρ] ]           //ScreenDollarIndices," = ",
eq1 = LieDToCovD[LieD[ BracketToCovD[Bracket[ u[μ],v[ν]][σ],CD ]][ ξ[ρ] ],CD]//ScreenDollarIndices,"\n",
"----------------------------------------------------------------------------------------------------\n",
"The 1st term of the RHS: (Subscript[ℒ, u])(Subscript[ℒ, v])ξ \n",
LieD [u[μ]] [ LieD [v[ν]] [ξ[ρ]] ]  ," = ",
eq2 = LieDToCovD[LieD [u[μ]] [ LieD [v[ν]] [ξ[ρ]] ],CD]//ScreenDollarIndices,"\n",
"----------------------------------------------------------------------------------------------------\n",
"The 2nd term of the RHS: (Subscript[ℒ, v])(Subscript[ℒ, u])ξ \n",
LieD [v[ν]] [ LieD [u[μ]] [ξ[ρ]] ]  ," = ",
eq3 = LieDToCovD[LieD [v[ν]] [ LieD [u[μ]] [ξ[ρ]] ],CD]//ScreenDollarIndices,"\n",
"----------------------------------------------------------------------------------------------------\n",
"The difference: (Subscript[ℒ, [u, v]])ξ - [(Subscript[ℒ, u]),(Subscript[ℒ, v])]ξ =(Subscript[ℒ, [u, v]])ξ - (Subscript[ℒ, u])(Subscript[ℒ, v])ξ + (Subscript[ℒ, v])(Subscript[ℒ, u])ξ  \n\n",
LieD[                                 Bracket[ u[μ],v[ν]][σ]            ][ ξ[ρ] ]-LieD [u[μ]] [ LieD [v[ν]] [ξ[ρ]] ]+LieD [v[ν]] [ LieD [u[μ]] [ξ[ρ]] ]  ," = \n",
eq4 = (eq1 - eq2+eq3 //Simplification)," = \n",
eq5 = (CommuteCovDs[eq4,CD,{-α,-β}] //ScreenDollarIndices)," = \n",
eq6 = (eq5 //Simplification)," = \n",
eq7 = eq6 /. {RiemannCD[ρ,-α,-β,-γ] -> -(RiemannCD[ρ,-γ,-α,-β]+RiemannCD[ρ,-β,-γ,-α])}," = \n",
eq7//ToCanonical,"\n",
"----------------------------------------------------------------------------------------------------\n"
]

Acknowledgements

This notebook has been programmed by Konstantinos Anagnostopoulos, Physics Department, National Technical University of Athens, Greece, while he was an instructor of the 4th year undergraduate course "General Relativity and Cosmology". It was created for fun, but it may turn out to be useful to everyone studying the General Theory of Relativity for the first time.
Email: konstant@mail.ntua.gr
Web:    http://physics.ntua.gr/konstant 
It is offered under a GPL/CC BY 4.0 license (in that order, depending on whether they apply on the programming part or the text part of the notebook).