sXAct.jl — Getting Started

Note: Auto-generated from notebooks/julia/basics.qmd via Quarto. Edit the source .qmd file, not the .ipynb.

Overview

This notebook walks through the core workflow of XAct.jl: defining a spacetime manifold, adding a metric, computing curvature tensors, and simplifying expressions using the Butler-Portugal canonicalization algorithm.

Expressions are written using the typed API — index objects and operator overloading — which validates slot counts and manifold membership at construction time rather than deep inside the engine.

Google Colab: select Runtime → Change runtime type → Julia.

1. Setup

If running on Google Colab or a fresh environment, install the package first. In the Docker image or a local dev checkout this cell is a no-op.

# Uncomment the lines below if running on Google Colab:
# using Pkg
# Pkg.add(url="https://github.com/sashakile/XAct.jl.git")

2. Setup

using XAct

2. Define a Manifold

A 4-dimensional spacetime manifold $M$ with abstract indices $a, b, c, d, e, f$.

@indices declares typed index variables bound to the manifold — -a then gives a covariant (down) index.

reset_state!()
M = def_manifold!(:M, 4, [:a, :b, :c, :d, :e, :f])
@indices M a b c d e f

3. Define a Metric

The metric $g_{ab}$ with Lorentzian signature $(-,+,+,+)$ and covariant derivative $\nabla$ (called CD internally). This automatically creates Riemann, Ricci, RicciScalar, Weyl, Einstein, and Christoffel tensors.

g = def_metric!(-1, "g[-a,-b]", :CD)

# Grab tensor handles for use throughout the notebook.
Riem = tensor(:RiemannCD)
Ric  = tensor(:RicciCD)
g_h  = tensor(:g)
TensorHead(:g)

4. Canonicalization

The Butler-Portugal algorithm brings tensor expressions into a canonical form. Build expressions with [] — the tensor handle validates the slot count and manifold membership immediately.

Symmetric metric: $g_{ba} - g_{ab} = 0$:

ToCanonical(g_h[-b,-a] - g_h[-a,-b])

0

Define a symmetric rank-2 tensor $T_{ab}$ (e.g. the energy-momentum tensor) and verify symmetry:

def_tensor!(:T, ["-a", "-b"], :M; symmetry_str="Symmetric[{-a,-b}]")
T_h = tensor(:T)
ToCanonical(T_h[-b,-a] - T_h[-a,-b])

0

String API: ToCanonical("T[-b,-a] - T[-a,-b]") is equivalent. Strings still work everywhere; the typed API adds upfront validation.

5. Contraction

Contract lowers/raises indices via the metric. Define a vector $V^a$ and contract with the metric to get $V_b$:

def_tensor!(:V, ["a"], :M)
V_h = tensor(:V)
Contract(V_h[a] * g_h[-a,-b])

\V_{\b}

6. Riemann Tensor Identities

The Riemann tensor has 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

7. Perturbation Theory

Define a perturbation tensor $h_{ab}$ (symmetric, same slots as the metric) and perturb the metric to first order:

def_tensor!(:h, ["-a", "-b"], :M; symmetry_str="Symmetric[{-a,-b}]")
def_perturbation!(:h, :g, 1)
perturb(g_h[-a,-b], 1)

\h

8. Validation

The typed API catches mistakes at construction time:

# Wrong slot count — raised before reaching the engine
try
    Riem[-a,-b]     # ERROR: RiemannCD has 4 slots, got 2
catch e
    println(e)
end
┌ Warning: Assignment to `e` in soft scope is ambiguous because a global variable by the same name exists: `e` will be treated as a new local. Disambiguate by using `local e` to suppress this warning or `global e` to assign to the existing global variable.
└ @ basics_julia.md:143
ErrorException("RiemannCD has 4 slots, got 2")

Next Steps

  • Coordinate components (xCoba): assign a basis, compute Christoffel symbols numerically
  • Covariant derivatives: commute CovDs, integration by parts
  • Invariant simplification: RiemannSimplify for scalar polynomial identities
  • Full documentation: sashakile.github.io/sxAct