20#include "../../include/srfm/tensor/geodesic_n.hpp"
31 , christoffel_(christoffel)
36std::optional<std::pair<Eigen::VectorXd, Eigen::VectorXd>>
38 const int D = manifold_.dim();
41 Eigen::VectorXd dx = s.u;
44 Eigen::VectorXd du = Eigen::VectorXd::Zero(D);
50 auto gamma_opt = christoffel_.all_symbols(s.x);
51 if (!gamma_opt) {
return std::nullopt; }
52 const auto& gamma = *gamma_opt;
54 for (
int lambda = 0; lambda < D; ++lambda) {
56 for (
int mu = 0; mu < D; ++mu) {
57 for (
int nu = 0; nu < D; ++nu) {
58 acc += gamma[lambda][mu][nu] * s.u(mu) * s.u(nu);
64 return std::make_pair(std::move(dx), std::move(du));
68GeodesicSolverN::advance(
const GeodesicState& s,
69 const Eigen::VectorXd& dx,
70 const Eigen::VectorXd& du,
71 double scale)
noexcept {
73 result.x = s.x + scale * dx;
74 result.u = s.u + scale * du;
80std::optional<GeodesicState>
84 if (!f1) {
return std::nullopt; }
85 const auto& [dx1, du1] = *f1;
90 if (!f2) {
return std::nullopt; }
91 const auto& [dx2, du2] = *f2;
96 if (!f3) {
return std::nullopt; }
97 const auto& [dx3, du3] = *f3;
102 if (!f4) {
return std::nullopt; }
103 const auto& [dx4, du4] = *f4;
107 result.
x = s.x + (dtau / 6.0) * (dx1 + 2.0 * dx2 + 2.0 * dx3 + dx4);
108 result.
u = s.u + (dtau / 6.0) * (du1 + 2.0 * du2 + 2.0 * du3 + du4);
113std::optional<std::vector<GeodesicState>>
116 int n_steps)
const noexcept {
117 if (n_steps <= 0) {
return std::vector<GeodesicState>{}; }
119 std::vector<GeodesicState> traj;
120 traj.reserve(
static_cast<std::size_t
>(n_steps));
123 for (
int i = 0; i < n_steps; ++i) {
124 auto next = step(current, dtau);
125 if (!next) {
return std::nullopt; }
126 current = std::move(*next);
127 traj.push_back(current);
135 const std::vector<GeodesicState>& traj)
const noexcept {
136 if (traj.size() < 2) {
return std::nullopt; }
138 const Eigen::VectorXd& x0 = traj.front().x;
139 const Eigen::VectorXd& x1 = traj.back().x;
141 const int N =
static_cast<int>(traj.size());
142 double max_dev = 0.0;
144 for (
int i = 1; i < N - 1; ++i) {
146 double t =
static_cast<double>(i) /
static_cast<double>(N - 1);
149 Eigen::VectorXd x_line = x0 + t * (x1 - x0);
152 double dev = (traj[
static_cast<std::size_t
>(i)].x - x_line).norm();
Computes Christoffel symbols Γ^λ_μν for an NAssetManifold.
GeodesicSolverN(const NAssetManifold &manifold, const ChristoffelN &christoffel) noexcept
Construct from manifold and Christoffel symbol provider.
std::optional< std::vector< GeodesicState > > integrate(GeodesicState initial, double dtau, int n_steps) const noexcept
Integrate the geodesic for n_steps steps of size dtau.
std::optional< double > geodesic_deviation(const std::vector< GeodesicState > &traj) const noexcept
Measure the maximum deviation of a trajectory from a straight line.
std::optional< GeodesicState > step(const GeodesicState &s, double dtau) const noexcept
Advance the geodesic by one RK4 step of proper-time dtau.
(N+1)-dimensional Lorentzian manifold for N financial assets.
Position and 4-velocity state on the manifold.
Eigen::VectorXd x
Position coordinates.
Eigen::VectorXd u
Tangent vector (4-velocity, dx/dτ).