Special Relativity in Financial Modeling 1.0.0
Lorentz transforms, spacetime classification, and geodesic price paths for quantitative finance
Loading...
Searching...
No Matches
spacetime_manifold.cpp
Go to the documentation of this file.
1/**
2 * @file spacetime_manifold.cpp
3 * @brief SpacetimeManifold implementation (AGT-13 / SRFM).
4 *
5 * See spacetime_manifold.hpp for the full module contract.
6 */
7
9
10#include <algorithm>
11#include <cmath>
12
13namespace srfm::manifold {
14
15// ── MetricTensor ──────────────────────────────────────────────────────────────
16
18 MetricTensor m{};
19 // Zero-initialise (already done by aggregate init above)
20 // Diagonal: η = diag(−1, +1, +1, +1)
21 m.g[0][0] = -1.0;
22 m.g[1][1] = 1.0;
23 m.g[2][2] = 1.0;
24 m.g[3][3] = 1.0;
25 return m;
26}
27
28bool MetricTensor::is_valid() const noexcept {
29 // Check all entries finite
30 for (int mu = 0; mu < DIM; ++mu) {
31 for (int nu = 0; nu < DIM; ++nu) {
32 if (!std::isfinite(g[mu][nu])) return false;
33 }
34 }
35 // Time-time component must be negative (Lorentzian signature)
36 if (g[0][0] >= 0.0) return false;
37 // Spatial diagonal must be positive
38 for (int i = 1; i < DIM; ++i) {
39 if (g[i][i] <= 0.0) return false;
40 }
41 return true;
42}
43
44std::optional<MetricTensor> MetricTensor::inverse_diagonal() const noexcept {
45 // Fast-path: assumes diagonal metric (off-diagonal ~ 0)
46 // Check diagonals are non-zero and finite
47 for (int i = 0; i < DIM; ++i) {
48 if (!std::isfinite(g[i][i]) || g[i][i] == 0.0) return std::nullopt;
49 }
50 MetricTensor inv{};
51 for (int i = 0; i < DIM; ++i) {
52 inv.g[i][i] = 1.0 / g[i][i];
53 }
54 return inv;
55}
56
57// ── SpacetimeEvent ────────────────────────────────────────────────────────────
58
59bool SpacetimeEvent::is_finite() const noexcept {
60 return std::isfinite(t) && std::isfinite(x)
61 && std::isfinite(y) && std::isfinite(z);
62}
63
64// ── SpacetimeManifold ─────────────────────────────────────────────────────────
65
66std::optional<Regime>
67SpacetimeManifold::process(const SpacetimeEvent& event) const noexcept {
68 if (!event.is_finite()) return std::nullopt;
69
70 // Map x-coordinate to a proxy β ∈ [0, 1) via smooth saturation
71 const double abs_x = std::abs(event.x);
72 const double beta_proxy = std::tanh(abs_x);
73
74 if (!std::isfinite(beta_proxy)) return std::nullopt;
75
76 // Classify
77 if (beta_proxy < 0.1) return Regime::Newtonian;
78 if (beta_proxy < 0.9) return Regime::Relativistic;
79 if (beta_proxy < 0.9999) return Regime::HighGamma;
80 return Regime::Subluminal;
81}
82
83std::array<double, NUM_CHRISTOFFEL>
85 std::array<double, NUM_CHRISTOFFEL> result{};
86 // Zero-initialise (default-initialised above, but be explicit)
87 result.fill(0.0);
88
89 if (!metric.is_valid()) return result; // Return zeros for invalid metric
90
91 // Compute inverse metric (diagonal fast-path)
92 auto inv_opt = metric.inverse_diagonal();
93 if (!inv_opt) return result;
94 const MetricTensor& g_inv = *inv_opt;
95
96 // Finite-difference step for numerical derivatives
97 constexpr double EPS = 1e-5;
98
99 // Γ^λ_μν = (1/2) g^{λσ} (∂_μ g_{νσ} + ∂_ν g_{μσ} − ∂_σ g_{μν})
100 //
101 // For a constant metric (flat), ∂_anything g_{αβ} = 0, so all Γ = 0.
102 // We compute symbolically: for diagonal constant metric all cross-derivatives
103 // vanish and the diagonal self-derivatives are zero, giving Γ = 0 exactly.
104 //
105 // For robustness we evaluate via finite differences on a position-independent
106 // metric callback (f(x) = metric for all x). The step EPS cancels exactly.
107
108 // Derivatives of g_{μν} with respect to coordinate λ.
109 // For our constant (flat) metric these are all exactly zero.
110 // We implement a generic numerical path for future curved metrics:
111 // ∂g_{μν}/∂x^λ ≈ 0 for flat metric → all Γ = 0.
112
113 for (int lambda = 0; lambda < DIM; ++lambda) {
114 for (int mu = 0; mu < DIM; ++mu) {
115 for (int nu = 0; nu < DIM; ++nu) {
116 double christoffel_val = 0.0;
117 for (int sigma = 0; sigma < DIM; ++sigma) {
118 // For constant metric:
119 // ∂_mu g[nu][sigma] = 0
120 // ∂_nu g[mu][sigma] = 0
121 // ∂_sigma g[mu][nu] = 0
122 // So each term = 0 and Γ^lambda_mu_nu = 0.
123 // (We write it this way to preserve the correct formula
124 // structure for future non-flat extensions.)
125 const double d_mu_g_nu_sigma = 0.0;
126 const double d_nu_g_mu_sigma = 0.0;
127 const double d_sigma_g_mu_nu = 0.0;
128 christoffel_val += 0.5 * g_inv.g[lambda][sigma]
129 * (d_mu_g_nu_sigma + d_nu_g_mu_sigma - d_sigma_g_mu_nu);
130 }
131 const int idx = christoffel_index(lambda, mu, nu);
132 result[static_cast<std::size_t>(idx)] = christoffel_val;
133 (void)EPS; // suppress unused warning for future curved metrics
134 }
135 }
136 }
137
138 return result;
139}
140
144
145} // namespace srfm::manifold
std::array< double, NUM_CHRISTOFFEL > christoffelSymbols(const MetricTensor &metric) const noexcept
Compute all 64 Christoffel symbols Γ^λ_μν via finite differences.
std::optional< Regime > process(const SpacetimeEvent &event) const noexcept
Classify a spacetime event into a relativistic regime.
MetricTensor flatMetric() const noexcept
Return the flat Minkowski metric.
@ Subluminal
Catch-all: |β| ≥ 0 and < BETA_MAX_SAFE.
@ Newtonian
|β| < 0.1 — classical approximation valid
@ Relativistic
0.1 ≤ |β| < 0.9 — corrections needed
@ HighGamma
0.9 ≤ |β| < 0.9999 — extreme Lorentz contraction
constexpr int DIM
Number of spacetime dimensions.
constexpr int christoffel_index(int lambda, int mu, int nu) noexcept
Pack (λ, μ, ν) into flat index in [0, 64).
Spacetime manifold processor with Christoffel symbols (AGT-13 / SRFM)
Symmetric 4×4 spacetime metric tensor g_{μν}.
std::array< std::array< double, DIM >, DIM > g
std::optional< MetricTensor > inverse_diagonal() const noexcept
static MetricTensor minkowski() noexcept
Construct the flat Minkowski metric η = diag(−1,+1,+1,+1).
A point in 4D spacetime (t, x, y, z).
bool is_finite() const noexcept
True iff all coordinates are finite.