Riemann Invariant Simplification (Invar)

This tutorial covers the use of the Invar module for simplifying scalar polynomial invariants of the Riemann tensor. This is essential for proving the equivalence of different spacetime metrics.

1. Setup

We'll need a manifold and a metric to work with.

Julia

using XAct
reset_state!()
def_manifold!(:M, 4, [:a, :b, :c, :d, :e, :f, :g, :h])
def_metric!(-1, "g[-a,-b]", :CD)
MetricObj(:g, :M, :CD, -1)

Python

import xact
xact.reset()
M = xact.Manifold("M", 4, ["a", "b", "c", "d", "e", "f", "g", "h"])
g = xact.Metric(M, "g", signature=-1, covd="CD")

2. RiemannToPerm

The core of the Invar pipeline is converting tensor expressions into a canonical permutation representation.

Julia

expr = "RiemannCD[-a, -b, b, a]"
res = RiemannToPerm(expr, :CD)
1-element Vector{Tuple{Rational{Int64}, RPerm}}:
 (-1, RPerm(:CD, InvariantCase([0]), [3, 4, 1, 2]))

RiemannToPerm may return a single RPerm or a vector of (coeff, RPerm)

rperm = res isa RPerm ? res : res[1][2]
println("Permutation form: ", rperm.perm)
Permutation form: [3, 4, 1, 2]

Python

rperm = xact.riemann_to_perm("RiemannCD[-a, -b, b, a]", "CD")
print(f"Permutation: {rperm}")

3. Loading the Invar Database

RiemannSimplify requires the pre-computed Invar database. The database ships with Wolfram xAct and must be available at resources/xAct/Invar/.

invar_db_dir = joinpath(@__DIR__, "..", "..", "resources", "xAct", "Invar")
_has_invar_db = isdir(invar_db_dir) && isdir(joinpath(invar_db_dir, "Riemann"))

if _has_invar_db
    LoadInvarDB(invar_db_dir)
    println("Invar database loaded")
else
    @warn "Invar database not found at $invar_db_dir — skipping RiemannSimplify examples"
end
┌ Warning: Invar database not found at /home/runner/work/XAct.jl/XAct.jl/docs/build/examples/../../resources/xAct/Invar — skipping RiemannSimplify examples
└ @ Main invar.md:67

4. RiemannSimplify

RiemannSimplify is the high-level entry point for simplifying Riemann invariants. It uses a pre-computed database of multi-term identities.

Consider the Kretschmann scalar. Different dummy index labelings should simplify to the same canonical form.

Julia

expr1 = "RiemannCD[-a,-b,-c,-d] RiemannCD[a,b,c,d]"
expr2 = "RiemannCD[-c,-d,-a,-b] RiemannCD[c,d,a,b]"
diff = "$expr1 - $expr2"
_has_invar_db && println("Difference simplified: ", RiemannSimplify(diff, :CD))
false

Python

diff = "RiemannCD[-a,-b,-c,-d] RiemannCD[a,b,c,d] - RiemannCD[-c,-d,-a,-b] RiemannCD[c,d,a,b]"
result = xact.riemann_simplify(diff, "CD")
print(f"Result: {result}")

Wolfram (xAct)

RiemannSimplify[RiemannCD[-a,-b,-c,-d] RiemannCD[a,b,c,d] - RiemannCD[-c,-d,-a,-b] RiemannCD[c,d,a,b], CD]
(* returns 0 *)

5. Simplification Levels

You can control the depth of simplification using the level parameter:

  1. Identity only
  2. Monoterm (cyclic)
  3. Bianchi identities
  4. Covariant derivative commutation
  5. Dimension-dependent identities
  6. Dual invariants (4D only)

Julia

expr = "2 RiemannCD[-a,-b,-c,-d] RiemannCD[a,c,b,d] + RiemannCD[-a,-b,-c,-d] RiemannCD[a,b,c,d]"
_has_invar_db && println("Level 2: ", RiemannSimplify(expr, :CD; level=2))
_has_invar_db && println("Level 3: ", RiemannSimplify(expr, :CD; level=3))
false

6. Dual Invariants (4D)

In 4 dimensions, we can simplify invariants involving the Levi-Civita epsilon tensor (represented as DualRiemann in Wolfram, or via n_epsilon=1 cases in Invar).

Julia Dual invariants are only supported if dim=4.

_has_invar_db && println(
    "Level 6 (4D) result: ",
    RiemannSimplify("RiemannCD[-a, -b, b, a]", :CD; level=6, dim=4),
)
false

7. Summary

The Invar module provides:

  • RiemannToPerm: Tensor string → Canonical Permutation
  • PermToRiemann: Canonical Permutation → Tensor string
  • RiemannSimplify: End-to-end multi-term simplification
  • InvSimplify: Low-level simplification of invariant lists

This page was generated using Literate.jl.