sXAct.jl — Interactive Tutorial
This Pluto notebook introduces the core workflow of XAct.jl: manifolds, metrics, canonicalization, and curvature.
Expressions are written using the typed API — @indices declares index objects, tensor() looks up handles, and T[-a,-b] builds expressions with slot-count and manifold validation at construction time.
Each cell is reactive — editing a definition automatically re-evaluates all dependent cells.
begin
import Pkg
Pkg.activate(joinpath(@__DIR__, "..", ".."))
using XAct
end
1. Define a Manifold
begin
reset_state!()
M = def_manifold!(:M, 4, [:a, :b, :c, :d, :e, :f])
@indices M a b c d e f
end
2. Define a Metric
Lorentzian signature \((-,+,+,+)\). This automatically creates Riemann, Ricci, RicciScalar, Weyl, Einstein, and Christoffel tensors.
begin
g = def_metric!(-1, "g[-a,-b]", :CD)
Riem = tensor(:RiemannCD)
Ric = tensor(:RicciCD)
g_h = tensor(:g)
end
TensorHead(:g)
3. Canonicalization
The Butler-Portugal algorithm brings tensor expressions to canonical form. Expressions are built with [] — wrong slot count or manifold raises an error immediately, before reaching the engine.
ToCanonical(g_h[-b,-a] - g_h[-a,-b])
$$0$$
begin
def_tensor!(:T, ["-a", "-b"], :M; symmetry_str="Symmetric[{-a,-b}]")
T_h = tensor(:T)
ToCanonical(T_h[-b,-a] - T_h[-a,-b])
end
$$0$$
4. Contraction
Lower an index with the metric — \(V_b = V^a g_{ab}\):
begin
def_tensor!(:V, ["a"], :M)
V_h = tensor(:V)
Contract(V_h[a] * g_h[-a,-b])
end
$$\V_{\b}$$
5. Riemann Tensor Identities
The Riemann tensor satisfies well-known symmetries that the canonicalizer automatically recognizes.
# First Bianchi identity — R_{abcd} + R_{acdb} + R_{adbc} = 0
ToCanonical(Riem[-a,-b,-c,-d] + Riem[-a,-c,-d,-b] + Riem[-a,-d,-b,-c])
$$0$$
# Antisymmetry in the first pair — R_{abcd} + R_{bacd} = 0
ToCanonical(Riem[-a,-b,-c,-d] + Riem[-b,-a,-c,-d])
$$0$$
# Pair symmetry — R_{abcd} = R_{cdab}
ToCanonical(Riem[-a,-b,-c,-d] - Riem[-c,-d,-a,-b])
$$0$$
6. Perturbation Theory
Perturb the metric to first order:
begin
def_tensor!(:h, ["-a", "-b"], :M; symmetry_str="Symmetric[{-a,-b}]")
def_perturbation!(:h, :g, 1)
perturb(g_h[-a,-b], 1)
end
$$\h$$
7. Validation
The typed API raises errors at construction time — before the expression reaches the engine:
try
Riem[-a,-b] # ERROR: RiemannCD has 4 slots, got 2
catch e
e
end
ErrorException("RiemannCD has 4 slots, got 2")