Introduction
Introduction
The question to answer in this notebook is “what is the vacuum spacetime geometry outside a static, spherically symmetric, non-spinning black hole?”
The Schwarzschild metric is the answer. In this notebook, we derive it ab-initio. The derivation is certainly not novel, but the novel contribution here is advancement of the calculus, moving its compiler from proof-of-concept to prototype. This metric is demonstrated in another notebook, Interactive black hole dynamics: Schwarzschild orbits via UD calculus. The calculus automates symbolic operations such as covariant differentiation, tensor quotienting, canonicalizing indices, etc. The compiler translates between index notations in and component representations in Wolfram arrays. A script version of this notebook, minus the prose, is available at https://github.com/rebcabin/RelativityToolkit/blob/main/schwarzschild_from_scratch.wl.
The Schwarzschild metric is the answer. In this notebook, we derive it ab-initio. The derivation is certainly not novel, but the novel contribution here is advancement of the calculus, moving its compiler from proof-of-concept to prototype. This metric is demonstrated in another notebook, Interactive black hole dynamics: Schwarzschild orbits via UD calculus. The calculus automates symbolic operations such as covariant differentiation, tensor quotienting, canonicalizing indices, etc. The compiler translates between index notations in and component representations in Wolfram arrays. A script version of this notebook, minus the prose, is available at https://github.com/rebcabin/RelativityToolkit/blob/main/schwarzschild_from_scratch.wl.
Audience
Audience
◼
With the exception of MTW, I do not put standard textbooks in the References section, but instead offer clickable (non-affiliate!) links in the prose of this notebook.
Initialize the Relativity Toolkit
Initialize the Relativity Toolkit
The toolkit is currently implemented as a script rather than as a Package, prioritizing development flexibility and transparency over encapsulation. All symbols, including internal variables in Module constructs, are loaded into the Global namespace. That makes it difficult to find just the intentional exports of the toolkit without reading the code or the reference manual. This inconvenience will be mitigated in future versions.
Optional: Quit for a Fresh Kernel
Optional: Quit for a Fresh Kernel
◼
Note, if you call Quit in a notebook, evaluation may hang. If you want to “Evaluate Notebook,” mark the following two cells “Evaluatable” in the CellProperty menu, call Quit and FrontEndTokenExecute once each, then comment out the cells, or mark them unevaluatable again. Alternatively, you can quit the kernel via the Evaluation menu (last item). At that point, you can “Evaluate Notebook” in a clean environment. Otherwise, you can evaluate cells in this notebook individually.
->
In[]:=
Quit[];
In[]:=
FrontEndTokenExecute["DeleteGeneratedCells"]
Set Download Loci and Load Main Script
Set Download Loci and Load Main Script
In[]:=
RTbranch="v1.11.0";RTbase="https://raw.githubusercontent.com/rebcabin/RelativityToolkit/"<>RTbranch<>"/";RTbust="?t="<>ToString[Round[AbsoluteTime[]]];(*Forcefreshdownload*)RTrules=RTbase<>"RelativityToolkit.wl"<>RTbust;RTtests=RTbase<>"RelativityToolkit_RegressionTests.wl"<>RTbust;RTviz=RTbase<>"RelativityToolkit_VisualShowcase.wl"<>RTbust;Get[RTrules];
»
Relativity Toolkit version :1.11.0
»
Relativity Connection Symbol :Γ
Optional: See all Tests and Results from Prior Works
Optional: See all Tests and Results from Prior Works
Make any of the following cells evaluatable if you wish. They’re unevaluatable by default to keep this notebook trim.
Get[RTtests];
In[]:=
Get[RTviz](*nosemicolon,onpurpose*)
In[]:=
Get[RTbase<>"covariant_derivative.wl"]
In[]:=
Get[RTbase<>"law_of_gamma.wl"]
Get[RTbase<>"connections_to_christoffels.wl"]
Get[RTbase<>"calculate_riemann.wl"]
Optional: Configure Relativity Connection Symbol
Optional: Configure Relativity Connection Symbol
To properly compose covariant derivatives, must know the user’s reserved symbols for non-tensorial objects like connection coefficients. In gravitational physics, these force-producing connections are called Γ (capital gamma). Other theories like electrodynamics and Yang-Mills use other connection symbols.
We’re going with Γ for this relativity/gravitation notebook, it’s the default, so the following cell is optional.
In[]:=
SetConnection[Γ];
Relativity Engine: Connection set to Γ
Solution Strategy
Solution Strategy
The story of Karl Schwarzschild’s solution, while he was enlisted in the Prussian Army in WWI, of the Einstein field equations very soon after publication in 1915 is fascinating. Perhaps Karl followed a strategy like the following:
1
.Guess at the form of the Schwarzschild metric, : that is, make an ansatz.
g
μν
2
.Grind this form through new compiler components to generate (1) Christoffel symbols, (2) the Riemann curvature tensor , and finally (3) the Ricci tensor , which is a specific contraction of Riemann.
μ
R
λνρ
R
μν
3
.Consult the Einstein field equations (not derived in this notebook):
R
μν
1
2
g
μν
8πG
4
c
T
μν
(
1
)where is the trace of Ricci, namely .
R
μν
g
R
μν
4
.Set the Einstein equations equal to zero for the vacuum (=0, no stress-energy).
T
μν
5
.Contract the Einstein equations against to get the Ricci trace, :
μν
g
R
μν
g
R
μν
1
2
μν
g
g
μν
1
2
(
2
)6
.Substitute this back into the Einstein equations to deduce that the all components of Ricci vanish in the vacuum:
R
μν
1
2
g
μν
R
μν
(
3
)7
.Derive an ODE for terms in the ansatz from vanishing Ricci components.
8
.To solve the ODE, invoke boundary conditions at infinity, and invoke a Newtonian far-field approximation to evaluate constants of integration.
9
.Compare against Wolfram’s stored resource.
◼
I was fortunate to have Schwarzschild’s son, Martin, as one of my advisors in graduate school.
Introducing New Compiler Functions
Introducing New Compiler Functions
has been enhanced with several new functions in service of this task. The following paragraphs sketch their functionality, and the rest of the notebook illustrates their use by example. These functions are not specific to this task, however. In the future, we’ll need them for the Kerr metric (spinning black holes), as well as for other problems in general relativity, gauge theory, and differential geometry.
In this notebook, “matrix” is a synonym for a Wolfram 2D array. A tensor is either a matrix or a collection of symbolic expressions that satisfy coordinate-transformation rules.
MatrixToUDRules
Converts the non-zero elements of a matrix of components into rules for later application, via Replace and ReplaceAll, to symbolic expressions in .
ChristoffelsFromMetric
Computes torsion-free Christoffel symbols from a symmetric metric tensor written in notation.
Contract
Contracts a given bound index in a expression over a given set of coordinate symbols. Analogous to Wolfram built-in Replace.
ContractAll
Contracts all bound indices in a expression over a given set of coordinate symbols. Analogous to Wolfram built-in ReplaceAll.
EvaluateUDPartials
Converts (compiles) partial derivatives notation into forms that Wolfram can manipulate.
MakeIndexer
Makes a function that can index a matrix via symbolic coordinates rather than by Part numbers.
CalculateRiemannComponent
Given Christoffel symbols via an indexer, calculate a component of the Riemann curvature tensor, specified via natural coordinate symbols, by contracting over the Christoffel symbols.
CalculateRicciComponent
Given a Riemann tensor via an indexer, calculate a component of the Ricci tensor, a particular contraction of the Riemann tensor. Specify the desired component via natural coordinate symbols.
Ansatz
Ansatz
Set up a coordinate system in flat spacetime, at a safe distance from the central black hole, but with origin at the center of the black hole. Measure all events with respect to this coordinate system. Curvature of actual spacetime, as opposed to coordinate system, are accounted for by solving equations of motion with respect to proper time.
Assume as a guess, or ansatz, the following form for an element of proper distance along a geodesic:
d=-A(r)d+B(r)d+d+(θ)d≡d+d+d+d
2
s
2
t
2
r
2
r
2
θ
2
r
2
sin
2
ϕ
g
tt
2
t
g
rr
2
r
g
θθ
2
θ
g
ϕϕ
2
ϕ
(
4
)with two unknown functions of radius, and , and with symbolic coordinates, , all assumed to be functions of proper time, τ, the time experienced by a particle in free-fall on a geodesic. Particularly, are all functions of time. Notice these functions do not depend on the angle coordinates θ and ϕ. That is the meaning of “spherically symmetric.” They also do not depend on coordinate time, and that is the meaning of “static.”
A(r)
B(r)
t,r,θ,ϕ
t(τ),r(τ),...,A(r(τ)),B(r(τ))
Covariant Metric Tensor
Covariant Metric Tensor
Express the covariant metric tensor of this ansatz as a diagonal matrix (Wolfram array); save the coordinates for later:
g
μν
In[]:=
EchoSchwAnsatz=DiagonalMatrix[{-A[r],B[r],,}]//MatrixForm,"Schw ansatz :";coords={t,r,θ,ϕ};
2
r
2
r
2
Sin[θ]
»
Schw ansatz :
-A[r] | 0 | 0 | 0 |
0 | B[r] | 0 | 0 |
0 | 0 | 2 r | 0 |
0 | 0 | 0 | 2 r 2 Sin[θ] |
◼
Coordinate time, , is also a function of proper time, i.e., it’s , expressing time dilation.
t
t(τ)
◼
The component of is negative because we adopt the sign convention.
g
tt
g
μν
(-1,1,1,1)
Metric Rules
Metric Rules
Call the new compiler function, MatrixToUDRules, to create rules that map -indexed components of a given symbol, say gDD, to the components of the ansatz matrix. We’ll need these rules later to concretize abstract expressions.
In[]:=
Echo[SchwRules=MatrixToUDRules[SchwAnsatz,gDD,,coords],"Schw rules :"];
»
Schw rules :gDD-A[r],gDDB[r],gDD,gDD
t
t
r
r
θ
θ
2
r
ϕ
ϕ
2
r
2
Sin[θ]
◼
For brevity, MatrixToUDRules doesn’t produce rules for zeros in the matrix. We’ll put those in later, by hand, in a concise way that exploits structural knowledge of .
g
◼
TODO: Sparse-matrix version of MatrixToUDRules that handles zero elements without manual intervention.
Contravariant Metric Tensor and Rules
Contravariant Metric Tensor and Rules
The contravariant version, , of is just the matrix inverse of the covariant version (because =). Ending with the needed rules for , we get:
μν
g
g
g
μν
μρ
g
g
ρν
μ
δ
ν
gUU
In[]:=
SchwAnsatzInv=Inverse[SchwAnsatz];Echo[SchwInvRules=MatrixToUDRules[SchwAnsatzInv,gUU,,coords],"Schw Inv rules :"];
»
Schw Inv rules :gUU-,gUU,gUU,gUU
t
t
1
A[r]
r
r
1
B[r]
θ
θ
1
2
r
ϕ
ϕ
2
Csc[θ]
2
r
Christoffel Symbols
Christoffel Symbols
The functions developed in an earlier notebook, Riemann Curvature in + Compiler POC, are captured in a new compiler function, ChristoffelsFromMetric, which computes the required commutator of covariant derivatives. See it exposed here as an unevaluated contraction over a bound Unique index:
In[]:=
Echo[ChristoffelsFromMetric[gDD,gUU,σ,μ,ν],"Unevaluated Contraction :"];
»
Unevaluated Contraction :gUU+-
1
2
σ
λ.11
gDD
λ.11
μ
,ν
gDD
λ.11
ν
,μ
gDD
μ
ν
,λ.11
The new compiler function ContractAll expands a contraction as a sum over all coordinates. The up-down index pairs are now coordinate symbols rather than summation indices. Each term in the following exhibit is a product of concrete components, not a further (recursive) contraction. We can tell not to contract when a coordinate symbol, rather than a (usually Greek) index appears in up-down, paired index positions.
Inspect One Component
Inspect One Component
Now we can see clearly the reason for the rules above:
Kill Off-Diagonal Elements
Kill Off-Diagonal Elements
Here are the promised extra rules to zero-out the off-diagonal components:
◼
Recall that MatrixToUDRules does not currently do this, for practical reasons.
Notice, again, the unevaluated derivatives. doesn’t evaluate derivatives until you tell it to do so.
◼
Killing the off-diagonal terms is not strictly necessary in this step because the next function, EvaluateUDPartials, would have zeroed them out anyway. But it’s conceptually cleaner this way.
Evaluate Partial Derivatives
Evaluate Partial Derivatives
All Γ Components
All Γ Components
Now that we’re happy with a reduction strategy, apply it to all components of Γ in a new 3D matrix, one dimension for each index:
◼
Here we really needed to kill the off-diagonal terms manually to produce a visually tolerable result.
Γ Indexer
Γ Indexer
To reduce opportunities for human error, we really want to index objects with coordinate symbols rather than with numerical Part or levelspec numbers. We’d rather write Γget[r,t,t] than Γ〚1,0,0〛. MakeIndexer is the new compiler function that makes a function that maps symbolic coordinates to Part expressions. Test Γget on an arbitrary component:
The Riemann Ansatz in Full
The Riemann Ansatz in Full
(Optional) Visualization
(Optional) Visualization
◼
Please tolerate some imprecision in this section for the sake of brevity.
Top-left towers represent tidal forces (boosts caused by boosts). Bottom-right towers represent spatial curvature. Off-diagonal towers in the Kerr metric indicate that the black hole’s rotation entwines these two sectors.
Riemann Indexer
Riemann Indexer
As with Γ, index Riemann via coordinate symbols. Look at a couple of components and check a famous antisymmetry condition:
The Ricci Ansatz
The Ricci Ansatz
Build Ricci via another new compiler function, CalculateRicciComponent, which contracts Riemann over its single up index and its second down index. Pass in Rget and the coords, and iterate over the remaining 16 index values. This is big but inspectable.
The Einstein Vacuum Equations
The Einstein Vacuum Equations
Of course, we’ll need a getter for Ricci.
Final Equation and Solution
Final Equation and Solution
Constant of Integration
Constant of Integration
Demand the Newtonian limit: that the black hole behave like a normal Newtonian star when we are far away from it.
Validation Against Wolfram Function Repository
Validation Against Wolfram Function Repository
Pulling together all results:
and comparing against the WFR resource
we see a perfect match, except for WFR’s convention of formal symbols (with underdots).
In this notebook, we derived the Schwarzschild metric for a static, spherically symmetric vacuum spacetime via , the symbolic tensor calculator and compiler.
The primary contribution of this work is advancing for deeper calculations in general relativity. Compiler components in the toolkit translate a symbolic layer in index notation to a matrix layer for processing by existing Wolfram resources. Additional compiler functions support indexing by coordinate symbols rather than by row number and column number, for improved readability.
Validation points include:
◼
Symbolic Integrity: handles index valence, canonicalization, and contraction.
◼
Algebraic Simplification: generates the Riemann and Ricci tensors and decouples the vacuum field equations.
◼
Ground Truth Verification: The final derived solution matches the standard result in the Wolfram Function Repository exactly.
References
References
1
.Beckman, Brian. From the steam age to quantum fields: a unified approach via UD tensorial calculus. Wolfram Community post.
2
.3
.4
.5
.6
.7
.8
.9
.10
.[MTW] Misner, Charles W.; Thorne, Kip S.; Wheeler, John Archibald. Gravitation. Princeton University Press, 2017.
11
.Petrov, A. Z. Classification of spaces defining gravitational fields, Scientific Transactions of Kazan State University, 114, 55 (1954)
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
Schwarzschild metric from scratch via compilation
by Brian Beckman
Wolfram Community, STAFF PICKS, February 16, 2026
https://community.wolfram.com/groups/-/m/t/3640287
by Brian Beckman
Wolfram Community, STAFF PICKS, February 16, 2026
https://community.wolfram.com/groups/-/m/t/3640287