hoomd_manifold/
lib.rs

1// Copyright (c) 2024-2026 The Regents of the University of Michigan.
2// Part of hoomd-rs, released under the BSD 3-Clause License.
3
4#![doc(
5    html_favicon_url = "https://raw.githubusercontent.com/glotzerlab/hoomd-rs/7352214172a490cc716492e9724ff42720a0018a/doc/theme/favicon.svg"
6)]
7#![doc(
8    html_logo_url = "https://raw.githubusercontent.com/glotzerlab/hoomd-rs/7352214172a490cc716492e9724ff42720a0018a/doc/theme/favicon.svg"
9)]
10
11//! Tools for non-Euclidean geometries.
12//!
13//! ## Spherical points
14//!
15//! [`Spherical`] describes a point on an N-sphere of radius R embedded in
16//! [`Cartesian<N+1>`]. The components of a point on an N-sphere
17//! satisfy
18//! ```math
19//! \sum_{i=1}^{N+1}x_i^2 = R^2
20//! ```
21//! [`Spherical`] implements a distance metric through the trait
22//! [`Metric`] which calculates the geodesic distance on the
23//! surface of an N-sphere. Use [`Spherical`] to describe spaces with constant
24//! positive curvature.
25//!
26//! [`Cartesian<N+1>`]: hoomd_vector::Cartesian
27//! [`Metric`]: hoomd_vector::Metric
28//!
29//! ## Hyperbolic
30//! [`Hyperbolic`] describes a point on the upper sheet of an N-dimensional
31//! two-sheeted Hyperbolic with skirt R embedded in (N+1)-dimensional Minkowski
32//! space. The components of a point on the Hyperbolic satisfy
33//! ```math
34//! x_1^2 + \cdots + x_{N-1}^2 - x_{N}^2 = -R^2
35//! ```
36//! [`Hyperbolic`] implements a distance metric through the trait
37//! [`Metric`] which calculates the geodesic distance on the
38//! surface of a Hyperboloid. Use [`Hyperbolic`] embedded in [`Minkowski`]
39//! to implement hyperbolic space.
40//!
41//! ## Minkowski
42//!
43//! [`Minkowski<N>`] implements (N-1,1)-dimensional Minkowski space with the
44//! metric signature $`(+ \;\cdots\; +\; -)`$. [`Minkowski`] supports
45//! [`Vector`] operations such as vector addition and rescaling, but is not a
46//! true inner product space. The distance metric on Minkowski space is given
47//! by the "spacetime interval"
48//! ```math
49//! d_M^2(\vec{u},\vec{v}) = (\vec{u}-\vec{v})^T \eta (\vec{u}-\vec{v})
50//! = (u_1-v_1)^2 +\cdots + (u_{N-1}-v_{N-1})^2 - (u_N - v_N)^2
51//! ```
52//!
53//! ```
54//! use hoomd_manifold::Minkowski;
55//! use hoomd_vector::{Metric, Vector};
56//!
57//! let u = Minkowski::from([1.0, 0.0, 0.0, -1.0]);
58//! let v = Minkowski::from([2.0, 0.0, 1.0, 1.0]);
59//! let w = Minkowski::from([0.0, 0.0, 0.0, 3.0]);
60//! let del = (u + w).distance(&v);
61//! assert_eq!(1.0, del);
62//! ```
63//! ## Hyperbolic Rotations
64//! "Hyperbolic rotations" describe elements of the group SO(N,1), which
65//! preserve hyperboloids embedded in [`Minkowski`]. Transformations include
66//! pure spatial rotations as well as "boosts".
67//!
68//! For two-dimensional hyperbolic surfaces, use [`HyperbolicAngle`] to
69//! implement elements of SO(2,1) which rotate points about the z-axis or boost
70//! points along the x- and y-axes. Use [`HyperbolicRotationMatrix`] to
71//! generate the matrix from the values defined by [`HyperbolicAngle`].
72//!
73//! Rotation about the z axis:
74//! ```
75//! use hoomd_manifold::{
76//!     HyperbolicAngle, HyperbolicRotate, HyperbolicRotationMatrix, Minkowski,
77//! };
78//! use std::f64::consts::PI;
79//!
80//! let v = Minkowski::from([1.0, 0.0, 1.0]);
81//! let rotation_about_z = HyperbolicAngle::from((PI / 2.0, 0.0_f64, 0.0_f64));
82//! let matrix = HyperbolicRotationMatrix::from(rotation_about_z);
83//! let rotated = matrix.hyperbolic_rotate(&v);
84//! // rotated is approximately [0.0,1.0,1.0]);
85//! ```
86//!
87//! Boost in the y direction:
88//! ```
89//! use hoomd_manifold::{
90//!     HyperbolicAngle, HyperbolicRotate, HyperbolicRotationMatrix, Minkowski,
91//! };
92//! use std::f64::consts::PI;
93//!
94//! let v = Minkowski::from([1.0, 0.0, 1.0]);
95//! let boost_in_y = HyperbolicAngle::from((0.0_f64, 0.0_f64, 0.5_f64));
96//! let matrix = HyperbolicRotationMatrix::from(boost_in_y);
97//! let boosted = matrix.hyperbolic_rotate(&v);
98//! // rotated is approximately [1.0,sinh(0.5),cosh(0.5)]);
99//! ```
100//!
101//! For three-dimensional hyperbolic surfaces, use [`Biquaternion`].
102//! Biquaternions are a generalization of quaternions which allow for complex
103//! coefficients. Unit biquaternions give a representation of SO(3,1); this can
104//! either be done by converting the biquaternions to a
105//! [`HyperbolicRotationMatrix`] or by using the [`UnitBiquaternion`] algebra
106//! directly.
107//!
108//! Rotate point in 3D hyperbolic space about z axis using matrix
109//! representation:
110//! ```
111//! use hoomd_manifold::{
112//!     Biquaternion, HyperbolicRotate, HyperbolicRotationMatrix, Minkowski,
113//!     UnitBiquaternion,
114//! };
115//! use num::complex::Complex;
116//! use std::f64::consts::PI;
117//!
118//! let q = Biquaternion::from([
119//!     Complex::new((PI / 4.0).sin(), 0.0),
120//!     Complex::new(0.0, 0.0),
121//!     Complex::new(0.0, 0.0),
122//!     Complex::new((PI / 4.0).cos(), 0.0),
123//! ]);
124//! let v = q.to_unit_unchecked();
125//! let x = Minkowski::from([0.0, 1.0, 0.0, 1.0]);
126//! let rotation_about_x = HyperbolicRotationMatrix::from(v);
127//! let rotated = rotation_about_x.hyperbolic_rotate(&x);
128//! // rotated vector is approximately [0.0, 0.0, 1.0, 1.0];
129//! ```
130//!
131//! Boost point in 3D hyperbolic space in x direction using biquaternion
132//! algebra:
133//! ```
134//! use hoomd_manifold::{
135//!     Biquaternion, HyperbolicRotate, Minkowski, UnitBiquaternion,
136//! };
137//! use num::complex::Complex;
138//! use std::f64::consts::PI;
139//!
140//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
141//! let x = Minkowski::from([0.0, 0.0, 0.0, 1.0]);
142//! let q = Biquaternion::from([
143//!     Complex::new(0.0, PI / 4.0).sinh(),
144//!     Complex::new(0.0, 0.0),
145//!     Complex::new(0.0, 0.0),
146//!     Complex::new(0.0, PI / 4.0).cosh(),
147//! ]);
148//! let v = q.to_unit()?;
149//! let boosted = v.hyperbolic_rotate(&x);
150//! // boosted is approximately [(PI/2.0).sinh(), 0.0, 0.0, (PI/2.0).cosh()]
151//! # Ok(())
152//! # }
153//! ```
154//!
155//! # Complete documentation
156//!
157//! `hoomd-manifold` is is a part of *hoomd-rs*. Read the [complete documentation]
158//! for more information.
159//!
160//! [complete documentation]: https://hoomd-rs.readthedocs.io
161
162mod biquaternion;
163mod hyperbolic_angle;
164mod minkowski;
165mod sphere;
166
167pub use biquaternion::{Biquaternion, UnitBiquaternion};
168pub use hyperbolic_angle::HyperbolicAngle;
169pub use minkowski::{Hyperbolic, HyperbolicDisk, HyperbolicRotationMatrix, Minkowski};
170pub use sphere::{Spherical, SphericalDisk};
171
172use hoomd_vector::Vector;
173use thiserror::Error;
174
175/// Enumerate possible sources of error in fallible vector math operations.
176#[non_exhaustive]
177#[derive(Error, PartialEq, Debug)]
178pub enum Error {
179    /// Attempted to normalize a norm zero biquaternion
180    #[error("Biquaternion with norm zero cannot be normalized")]
181    InvalidBiquaternionMagnitude,
182
183    /// Attempted converting a value to a vector with a dimension not equal to the value's length.
184    #[error("source length does not match the target dimensions")]
185    InvalidVectorLength,
186}
187
188/// Linear transformations preserving hyperboloids.
189pub trait HyperbolicRotate<V: Vector> {
190    /// Type of the related rotation matrix
191    type Matrix: HyperbolicRotate<V>;
192    /// Apply a SO(N-1,1) transformation to an N-dimensional Minkowski vector
193    #[must_use]
194    fn hyperbolic_rotate(&self, vector: &V) -> V;
195}