Skip to main content

pathwise_geo/
process.rs

1use crate::sde::ManifoldSDE;
2use cartan_core::Manifold;
3
4/// Brownian motion on a manifold with an explicit diffusion direction.
5///
6/// Zero drift; `diffusion_gen(x, t)` provides the tangent vector g(x, t).
7/// Directional (1D noise) -- isotropic BM requires a frame field (future work).
8pub fn brownian_motion_on_with_diffusion<M, G>(
9    manifold: M,
10    diffusion_gen: G,
11) -> ManifoldSDE<
12    M,
13    impl Fn(&M::Point, f64) -> M::Tangent + Send + Sync,
14    G,
15>
16where
17    M: Manifold + Clone + Send + Sync,
18    M::Point: Clone + Send + Sync,
19    M::Tangent: Clone + Default + Send + Sync,
20    G: Fn(&M::Point, f64) -> M::Tangent + Send + Sync,
21{
22    ManifoldSDE::new(
23        manifold,
24        |_x: &M::Point, _t: f64| M::Tangent::default(),
25        diffusion_gen,
26    )
27}
28
29/// Ornstein-Uhlenbeck process on a manifold with caller-supplied diffusion field.
30///
31/// Drift: `kappa * log_x(mu_point)` -- Riemannian log toward `mu_point`, scaled by `kappa`.
32/// Returns zero tangent on failure (when x == mu_point or log fails at cut locus).
33pub fn ou_on_with_diffusion<M, G>(
34    manifold: M,
35    kappa: f64,
36    mu_point: M::Point,
37    diffusion: G,
38) -> ManifoldSDE<
39    M,
40    impl Fn(&M::Point, f64) -> M::Tangent + Send + Sync,
41    G,
42>
43where
44    M: Manifold + Clone + Send + Sync,
45    M::Point: Clone + Send + Sync,
46    M::Tangent: Clone + Default + std::ops::Mul<f64, Output = M::Tangent> + Send + Sync,
47    G: Fn(&M::Point, f64) -> M::Tangent + Send + Sync,
48{
49    let mu_clone = mu_point.clone();
50    let manifold_clone = manifold.clone();
51    ManifoldSDE::new(
52        manifold,
53        move |x: &M::Point, _t: f64| -> M::Tangent {
54            manifold_clone
55                .log(x, &mu_clone)
56                .map(|v| v * kappa)
57                .unwrap_or_default()
58        },
59        diffusion,
60    )
61}
62
63/// Placeholder for API compatibility -- panics if the diffusion closure is called.
64/// Use `brownian_motion_on_with_diffusion` instead.
65#[deprecated(note = "Use brownian_motion_on_with_diffusion; generic Manifold has no frame field")]
66pub fn brownian_motion_on<M: Manifold + Clone>(
67    manifold: M,
68) -> ManifoldSDE<
69    M,
70    impl Fn(&M::Point, f64) -> M::Tangent + Send + Sync,
71    impl Fn(&M::Point, f64) -> M::Tangent + Send + Sync,
72>
73where
74    M::Tangent: Clone + Default,
75{
76    ManifoldSDE::new(
77        manifold,
78        |_x: &M::Point, _t: f64| M::Tangent::default(),
79        |_x: &M::Point, _t: f64| -> M::Tangent {
80            panic!("brownian_motion_on: provide explicit diffusion via brownian_motion_on_with_diffusion")
81        },
82    )
83}