Special Relativity in Financial Modeling 1.0.0
Lorentz transforms, spacetime classification, and geodesic price paths for quantitative finance
Loading...
Searching...
No Matches
n_asset_manifold.cpp
Go to the documentation of this file.
1/**
2 * @file n_asset_manifold.cpp
3 * @brief Implementation of NAssetManifold.
4 *
5 * See include/srfm/tensor/n_asset_manifold.hpp for the public API contract.
6 */
7
8#include "../../include/srfm/tensor/n_asset_manifold.hpp"
9
10#include <algorithm>
11#include <cmath>
12
13namespace srfm::tensor {
14
15// ── Constructor ───────────────────────────────────────────────────────────────
16
18 Eigen::MatrixXd covariance,
19 double c_market) noexcept
20 : n_assets_(n_assets)
21 , c_market_(c_market)
22 , covariance_(std::move(covariance))
23 , inv_valid_(false)
24{
25 build_metric();
26 build_inverse_metric();
27}
28
29// ── Factory ───────────────────────────────────────────────────────────────────
30
31std::optional<NAssetManifold>
32NAssetManifold::make(int n, Eigen::MatrixXd cov, double c_market) noexcept {
33 // Validate n_assets >= 1.
34 if (n < 1) {
35 return std::nullopt;
36 }
37
38 // Validate c_market > 0.
39 if (c_market <= 0.0) {
40 return std::nullopt;
41 }
42
43 // Validate covariance dimensions.
44 if (cov.rows() != n || cov.cols() != n) {
45 return std::nullopt;
46 }
47
48 // Validate symmetry (allow small numerical noise).
49 const double sym_tol = 1e-10;
50 for (int i = 0; i < n; ++i) {
51 for (int j = 0; j < n; ++j) {
52 if (std::abs(cov(i, j) - cov(j, i)) > sym_tol) {
53 return std::nullopt;
54 }
55 }
56 }
57
58 // Symmetrise numerically.
59 Eigen::MatrixXd cov_sym = 0.5 * (cov + cov.transpose());
60
61 // Validate positive-definiteness: all eigenvalues must be > 0.
62 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov_sym,
63 Eigen::EigenvaluesOnly);
64 if (eig.info() != Eigen::Success) {
65 return std::nullopt;
66 }
67 if (eig.eigenvalues().minCoeff() <= 0.0) {
68 return std::nullopt;
69 }
70
71 return NAssetManifold(n, std::move(cov_sym), c_market);
72}
73
74// ── Metric construction ───────────────────────────────────────────────────────
75
76void NAssetManifold::build_metric() noexcept {
77 const int D = n_assets_ + 1;
78 metric_ = Eigen::MatrixXd::Zero(D, D);
79
80 // Time-time component.
81 metric_(0, 0) = -(c_market_ * c_market_);
82
83 // Spatial block: copy covariance matrix into rows/cols 1..N.
84 if (covariance_.rows() == n_assets_ && covariance_.cols() == n_assets_) {
85 metric_.block(1, 1, n_assets_, n_assets_) = covariance_;
86 }
87 // Time-space cross terms remain zero.
88}
89
90void NAssetManifold::build_inverse_metric() noexcept {
91 const int D = n_assets_ + 1;
92
93 // Use full-pivot LU for numerical stability.
94 Eigen::FullPivLU<Eigen::MatrixXd> lu(metric_);
95 if (!lu.isInvertible()) {
96 inv_metric_ = Eigen::MatrixXd::Zero(D, D);
97 inv_valid_ = false;
98 return;
99 }
100
101 inv_metric_ = lu.inverse();
102 inv_valid_ = true;
103}
104
105// ── Metric tensor accessors ───────────────────────────────────────────────────
106
107std::optional<Eigen::MatrixXd>
108NAssetManifold::metric_at(const Eigen::VectorXd& x) const noexcept {
109 if (x.size() != dim()) {
110 return std::nullopt;
111 }
112 // Constant metric — x is unused.
113 return metric_;
114}
115
116std::optional<Eigen::MatrixXd>
117NAssetManifold::inverse_metric_at(const Eigen::VectorXd& x) const noexcept {
118 if (x.size() != dim()) {
119 return std::nullopt;
120 }
121 if (!inv_valid_) {
122 return std::nullopt;
123 }
124 return inv_metric_;
125}
126
127// ── Line element ──────────────────────────────────────────────────────────────
128
129std::optional<double>
130NAssetManifold::line_element_sq(const Eigen::VectorXd& x,
131 const Eigen::VectorXd& dx) const noexcept {
132 if (x.size() != dim() || dx.size() != dim()) {
133 return std::nullopt;
134 }
135 // ds² = dx^T · g · dx
136 return dx.dot(metric_ * dx);
137}
138
139// ── Other public methods ──────────────────────────────────────────────────────
140
141std::optional<Eigen::MatrixXd> NAssetManifold::covariance() const noexcept {
142 return covariance_;
143}
144
145bool NAssetManifold::reduces_to_4d(const NAssetManifold& other) const noexcept {
146 // Compatible with 4D means other has n_assets == 3.
147 if (other.n_assets() != 3) {
148 return false;
149 }
150 // This manifold must have at least 3 spatial dimensions.
151 return n_assets_ >= 3;
152}
153
154} // namespace srfm::tensor
(N+1)-dimensional Lorentzian manifold for N financial assets.
std::optional< Eigen::MatrixXd > covariance() const noexcept
Returns the covariance matrix used to build the metric.
std::optional< Eigen::MatrixXd > inverse_metric_at(const Eigen::VectorXd &x) const noexcept
Evaluate the inverse metric g^μν at point x.
std::optional< Eigen::MatrixXd > metric_at(const Eigen::VectorXd &x) const noexcept
Evaluate the metric tensor at point x.
std::optional< double > line_element_sq(const Eigen::VectorXd &x, const Eigen::VectorXd &dx) const noexcept
Compute the squared line element ds² = g_μν dx^μ dx^ν.
static std::optional< NAssetManifold > make(int n, Eigen::MatrixXd cov, double c_market=1.0) noexcept
Factory: validate inputs then construct.
bool reduces_to_4d(const NAssetManifold &other) const noexcept
Check structural compatibility with a 4D (N=3) manifold.
NAssetManifold(int n_assets, Eigen::MatrixXd covariance, double c_market=1.0) noexcept
Construct an NAssetManifold directly.