T'As always, repeated indices are summed over, and the primed indices indicate the new coordinates. Note that the valence of the primed index is inverted: an upper index in the denominator is equivalent to a lower index in the numerator._{b'}(x') = T_{a}(x') d x^{a}(x') / d x'^{b'}

This transformation consists of two operations. The first involves a substitution of the original coordinates as functions of the new ones in the original tensor. The resulting tensor is then multiplied by the matrix whose elements are the derivatives of the old coordinates as functions of the new. For tensors with multiple covariant indices, the matrix multiplication is performed on each original index: the transformation is a multilinear operation, the tensor transforming linearly in each index.

As an example, we present the Mathematica code to perform a **coordinate transformation**
on a tensor with two covariant indices. Here, "xu" is the list of original coordinates,
and "xfu" is the list of those coordinates as functions of the new, primed coordinates
"xpu" (as mentioned in the Introduction, the "u"s indicate that these indices are
contravariant indices, and the "l"s denote covariant indices):

Tofxpll = Tll"Tofxpll" might be read "T of x' with two lower indices", while "dxofxpdxplu" might be read "the derivative of x as a function of x' with respect to x', whose first index is lower and whose second index is upper". The use of meaningful variable names is always encouraged as a way of making your code at least somewhat self-documenting./.Thread[ xu->xfu];dxofxpdxplu = Table[ Table[

D[ xfu[[j]], xpu[[i]]],Tpll = Table[ Table[ simpler[ Sum[ Sum[{j, dim}], {i, dim}];

Tofxpll[[k, l]] dxofxpdxplu[[i, k]] dxofxpdxplu[[j, l]],{j, dim}], {i, dim}];{l, dim}], {k, dim}]],

The first statement performs the substitution, using the **ReplaceAll** (/.) and **Rule** (->) operators.
The use of **Thread** causes corresponding
elements of the lists to be substituted. For instance, xu[[1]] will be replaced by
xfu[[1]], xu[[2]] will be replaced by xfu[[2]], etc. The second statement creates the
matrix of derivatives, and the final statement performs the matrix multiplication
(and serves as the model for all index contraction in the sequel).
Note the use of the simpler function defined in the Introduction.

It will be useful to create a series of functions which perform the basic tensor
operations discussed in this section. In general, these operations can be performed on
tensors with any number of indices. As an example of how to program such a function,
we present "**coordxform**", which performs a **coordinate transformation** on a tensor with from
1 to 5 covariant indices:

The first line documents the usage ofcoordxform::usage = "arguments are Tl...l(x), xu, xu(x'), x'u";

coordxform[ T_List, x_List, xf_List, xp_List] :=Block[ {dim, dimp, rank, Tp, Tofxp, dxofxpdxp}, (rank = TensorRank[T];If[ rank > 5,(Print[ "Error - tensor has too many indices for this function"]; Return[];),];

dim = Length[x];

If[ Length[T] == dim,,(Print[ "Error - tensor is incorrect dimension"]; Return[];)];

If[ Length[xf] == dim,,(Print[ "Error - function list x(xp) is incorrect dimension"]; Return[];)];

dimp = Length[xp];

Tofxp = T /.

Thread[ x -> xf];dxofxpdxp = Table[ Table[

D[ xf[[jj]], xp[[ii]]],If[ rank == 1,{jj, dim}], {ii, dimp}];

Tp = Table[ simpler[ Sum[If[ rank == 2,dxofxpdxp[[ii, jj]] Tofxp[[jj]],{ii, dimp}],];{jj, dim}]],

Tp = Table[ Table[ simpler[ Sum[ Sum[If[ rank == 3,dxofxpdxp[[ii, kk]] dxofxpdxp[[jj, ll]] Tofxp[[kk, ll]],{jj, dimp}], {ii, dimp}],];{ll, dim}], {kk, dim}]],

Tp = Table[ Table[ Table[ simpler[ Sum[ Sum[ Sum[If[ rank == 4,dxofxpdxp[[ii, ll]] dxofxpdxp[[jj, mm]] dxofxpdxp[[kk, nn]] Tofxp[[ll, mm, nn]],{kk, dimp}], {jj, dimp}], {ii, dimp}],];{nn, dim}], {mm, dim}], {ll, dim}]],

Tp = Table[ Table[ Table[ Table[ simpler[ Sum[ Sum[ Sum[ Sum[If[ rank == 5,dxofxpdxp[[ii, mm]] dxofxpdxp[[jj, nn]] dxofxpdxp[[kk, pp]] dxofxpdxp[[ll, qq]] Tofxp[[mm, nn, pp, qq]],{ll, dimp}], {kk, dimp}], {jj, dimp}], {ii, dimp}],];{qq, dim}], {pp, dim}], {nn, dim}], {mm, dim}]],

Tp = Table[ Table[ Table[ Table[ Table[ simpler[ Sum[ Sum[ Sum[ Sum[ Sum[Return[Tp];)];dxofxpdxp[[ii, nn]] dxofxpdxp[[jj, pp]] dxofxpdxp[[kk, qq]] dxofxpdxp[[ll, vv]] dxofxpdxp[[mm, ww]] Tofxp[[nn, pp, qq, vv, ww]],{mm, dimp}], {ll, dimp}], {kk, dimp}], {jj, dimp}], {ii, dimp}],];{ww, dim}], {vv, dim}], {qq, dim}], {pp, dim}], {nn, dim}]],

A series of If statements are used to ensure that **coordxform** is called with
arguments that are appropriate to its definition and consistent with each other. Note
that Mathematica stores a matrix as a list of lists; its Length is therefore the
number of lists at the top level. These tests also contribute to making the code more
resilient in the face of accidental misuse.

The substitution operation and the creation of the derivative matrix are essentially identical to those in the previous example. The remaining statements perform the number of matrix multiplications appropriate for the rank of the tensor being transformed. Note the index variables: the author has adopted the convention of using two letter index variables inside functions so that it is less likely that a symbol occurring in an argument will have the same name as an index variable.

Here is a Mathematica code example using the function **coordxform** define above. In this example,
we transform the Minkowski metric in spherical coordinates to eliminate the trigonometric functions
using the transformation

c = cos (theta).The third argument to

?This transformation is used extensively throughout the text in order to improve Mathematica execution times.coordxformTableForm[ gll = {{1, 0, 0, 0}, {0, r^2, 0, 0}, {0, 0, r^2 Sin[theta]^2, 0}, {0, 0, 0, -1}}]arguments are Tl...l(x), xu, xu(x'), x'uTableForm[

1 0 0 0 0 r ^{2}0 0 0 0 r ^{2}Sin[theta]^{2}0 0 0 0 -1 coordxform[ gll, {r, theta, phi, t}, {r, ArcCos[c], phi, t}, {r, c, phi, t}]]

1 0 0 0 0 - r ^{2}/ (-1+c)(1+c)0 0 0 0 - (-1+c)(1+c) r ^{2}0 0 0 0 -1

**Manipulation of index valences** are of course accomplished as matrix multiplications by the metric or its
inverse:

TThe student is encouraged to write functions "raise" and "lower" analogous to_{b}= g_{b a}T^{a}T

^{b}= g^{b a}T_{a}

The **Christoffel Connection** is defined as

Γand its lower indices are symmetric:^{a}_{b c}= g^{a e}(d_{b}g_{c e}+ d_{c}g_{b e}- d_{e}g_{b c}) / 2,

ΓWe use this symmetry to speed up the Mathematica code to compute the connection components:^{a}_{c b}= Γ^{a}_{b c}

Gull = Table[ Table[ Table[ 0, {kk, dim}], {jj, dim}], {ii, dim}];Note that we must first create a zero tensor with the correct number of indices; since the remainder of the code changes individual components, Mathematica requires that they exist before being modified. This code assumes that the metric associated with this connection is stored in "gll", that the inverse metric is "guu" and that xu is again the list of coordinates. We will assume that tensor names, once adopted, are used consistently in all code examples unless otherwise stated.Do[ Do[ Do[

Gull[[ii, jj, kk]] = simpler[ Sum[Do[ Do[ Do[guu[[ii, ll]] (D[ gll[[kk, ll]], xu[[jj]]] +{kk, jj, dim}], {jj, dim}], {ii, dim}];D[ gll[[jj, ll]], xu[[kk]]] - D[ gll[[jj, kk]], xu[[ll]]]),

{ll, dim}] / 2],

Gull[[ii, kk, jj]] = Gull[[ii, jj, kk]],{kk, jj + 1, dim}], {jj, dim - 1}], {ii, dim}];

The **Christoffel Connection** is of course used in the computation of the **Riemann Tensor** below, but it is
also used in the **geodesic equation**:

dwhere τ is the affine parameter. Obviously, the nonzero components control the geodesic deviation. Therefore if for some b, Γ^{2}x^{a}/ dτ^{2}+ Γ^{a}_{b c}(d x^{b}/ dτ) (d x^{c}/ dτ) = 0

The **Riemann Curvature Tensor** is defined as

Rand has the following symmetries:_{a b c}^{e}= d_{b}Γ^{e}_{a c}- d_{a}Γ^{e}_{b c}+ Γ^{f}_{a c}Γ^{e}_{f b}- Γ^{f}_{b c}Γ^{e}_{f a}

RIf we consider the indices in pairs, in D dimensions each antisymmetric pair has_{a b c d}= - R_{b a c d}R

_{a b c d}= - R_{a b d c}R

_{a b c d}= R_{c d a b}R

_{[a b c] d}= 0NB:The definition of the Riemann Curvature Tensor is independent of metricsignature.However, lowering the final index will induce a relative negative sign if using negative signature metrics. This effect occurs whenever the metric is involved (ie., the cosmological constant term in Einstein's Equations, the pressure term in perfect fluid Stress-Energy Tensors, etc.).

D (D - 1) / 2independent components. The pairs are symmetric, so that the first three symmetries imply that there are

(D (D - 1) / 2) (D (D - 1) / 2 + 1) / 2independent components. But the last symmetry means that we need to subtract

D ! / (4 ! (D - 4) !)components, leaving us with

Dindependent components. This implies that all D = 1 manifolds have zero curvature.^{2}(D^{2}- 1) / 12

The following Mathematica code to compute the **Riemann Curvature** components
makes use of the first three symmetries:

Rllll = Table[ Table[ Table[ Table[ 0, {ll, dim}], {kk, dim}], {jj, dim}], {ii, dim}];computing the upper half-matrix for each pair of indicies and use the symmetries to fill in the remaining components. The final symmetry is more trouble to program than it is worth.Do[ Do[ Do[ Do[

Rllll[[ii, jj, kk, mm]] = simpler[ Sum[Do[ Do[ Do[ Do[(D[ Gull[[ll, ii, kk]], xu[[jj]]] - D[ Gull[[ll, jj, kk]], xu[[ii]]] + Sum[{mm, kk + 1, dim}], {kk, dim - 1}], {jj, ii + 1, dim}], {ii, dim - 1}];Gull[[nn, ii, kk]] Gull[[ll, nn, jj]] - Gull[[nn, jj, kk]] Gull[[ll, nn, ii]],{ll, dim}]],{nn, dim}]) gll[[ll,mm]],

Rllll[[jj, ii, kk, ll]] = - Rllll[[ii, jj, kk, ll]],Do[ Do[ Do[ Do[{ll, kk + 1, dim}], {kk, dim - 1}], {jj, ii + 1, dim}], {ii, dim - 1}];

Rllll[[ii, jj, ll, kk]] = - Rllll[[ii, jj, kk, ll]],Do[ Do[ Do[ Do[{ll, kk + 1, dim}], {kk, dim - 1}], {jj, ii + 1, dim}], {ii, dim - 1}];

Rllll[[jj, ii, ll, kk]] = Rllll[[ii, jj, kk, ll]],{ll, kk + 1, dim}], {kk, dim - 1}], {jj, ii + 1, dim}], {ii, dim - 1}];

We note that if R_{a b a b} is zero, then the a-b hypersurface is flat, but none of the
manifolds we will be examining are that trivial.

We will also be interested in the **covariant derivative** of the **Riemann Curvature**:

Dthe_{a}R_{b c e f}= d_{a}R_{b c e f}- Γ^{h}_{a b}R_{h c e f}-Γ^{h}_{a c}R_{b h e f}- Γ^{h}_{a e}R_{b c h f}- Γ^{h}_{a f}R_{b c e h}= R

_{b c e f ;a},

Rand the_{a b}= g^{c d}R_{a c b d}

R = gThese tensors will be used repeatedly in the analyses below, and it makes sense for the programmer to combine all of them into a single function so that for any metric, one function call will compute them all. The inverse metric and^{a b}R_{a b}

The following **decomposition of the Riemann Curvature** [Wald]
is sometimes useful:

RIf we compute E (the_{a b c d}= C_{a b c d}+ E_{a b c d}+ G_{a b c d}E_{a b c d}= (g_{a c}R_{b d}- g_{b c}R_{a d}-g_{a d}R_{b c}+ g_{b d}R_{a c}) / (D - 2)G

_{a b c d}= (g_{a d}g_{b c}- g_{a c}g_{b d}) R / (D - 1)(D - 2)

Cllll = Rllll - Ellll - Gllll;We will of course be interested in

Rwhere the left hand side is called the_{a b}- R g_{a b}/ 2 + Λ g_{a b}= α T_{a b}α = 2 Area (S^{D - 2})

Provided that gTaking the trace of both sides with Λ = 0, we have_{a b}is dimensionless, α can be multiplied by G / c^{4}to normalize the dimensions of all terms to 1/length^{2}. However, if g_{a b}isnotdimensionless, as for instance in spherically symmetric metrics, it is easier to work with Einstein's Equations with one index raised. Then g^{a}_{b}=I^{a}_{b}and all is well so long as T^{a}_{b}has dimensions of energy density.We have chosen to use a metric of positive signature. If one wished to work with a negative signature instead:

- g
_{a b}→ - g_{a b}- Γ
^{a}_{b c}does not change sign- R
_{a b c}^{d}does not change sign- R
_{a b c d}→ - R_{a b c d}- R
_{a b}does not change sign- R → - R
- T
_{a b}does not change signso Einstein's Equations become

R_{a b}- R g_{a b}/ 2 - Λ g_{a b}= α T_{a b}

(1 - D / 2) R = α TThis fact implies that for

R = D Λ / (D/2 - 1)

We can use the following Mathematica code to see if any given metric is a solution:

simpler[ Table[ Table[In this example, L is the cosmological constant, and a replaces α as the coefficient of theRll[[ii, jj]] - R gll[[ii, jj]] / 2 + L gll[[ii, jj]],{jj, dim}], {ii, dim}] === a * Tll]

We define the **epsilon** tensor as:

εand can use the following Mathematica code to implement it in D = 4:^{a b c d ...}= | g |^{-1/2}Sign(a,b,c,d ...)

Since Mathematica indices must start with 1, we assume that the timelike index corresponds to 4 (or in general, D). This means that in even dimensions this function will produce an extra minus sign relative to the standard usage of 0 for the timelike index. The minus sign is selected for metrics of Lorentz signature. We can of course define the symbol analogously for any fixed D.epsilonuuuu[ a_, b_, c_, d_] := Signature[ {a, b, c, d}] / simpler[ Sqrt[ +-Det[ gll]]];

The next section discusses curvature invariants.

- Table of Contents
- Index:

©2005, Kenneth R. Koehler. All Rights Reserved. This document may be freely reproduced provided that this copyright notice is included.

Please send comments or suggestions to the author.