Skip to main content

clifford/
lib.rs

1#![doc = include_str!("../README.md")]
2//!
3//! # For Linear Algebra Users
4//!
5//! If you know linear algebra, you're already halfway to understanding Geometric Algebra (GA).
6//! This section maps concepts you know to their GA equivalents.
7//!
8//! ## From Vectors to Blades
9//!
10//! In LA, you work with vectors. In GA, vectors are just one type of **blade**:
11//!
12//! | Grade | Name | LA Analogue | Geometric Meaning |
13//! |-------|------|-------------|-------------------|
14//! | 0 | Scalar | Real number | Magnitude, no direction |
15//! | 1 | Vector | Vector in R^n | Directed line segment |
16//! | 2 | Bivector | (no direct equivalent) | Oriented plane segment |
17//! | 3 | Trivector | (no direct equivalent) | Oriented volume |
18//! | n | Pseudoscalar | Determinant (sort of) | Oriented n-volume |
19//!
20//! **Key insight**: The cross product `a × b` in 3D actually produces a bivector
21//! (oriented plane), not a vector. The "vector" you get is the **dual** of that plane.
22//!
23//! ## From Products to the Geometric Product
24//!
25//! In LA, you have separate operations: dot product, cross product, matrix multiplication.
26//! In GA, the **geometric product** unifies them:
27//!
28//! ```text
29//! a * b = a·b + a∧b
30//!       = (inner product) + (outer product)
31//!       = (scalar part) + (bivector part)
32//! ```
33//!
34//! | LA Operation | GA Equivalent | Result |
35//! |--------------|---------------|--------|
36//! | Dot product `a·b` | Inner product | Scalar (grade 0) |
37//! | Cross product `a×b` | `*(a∧b)` (dual of wedge) | Vector (grade 1) |
38//! | Matrix multiply | Geometric product | Mixed grades |
39//!
40//! ## From Rotations to Rotors
41//!
42//! This is where GA really shines. Rotations are represented by **rotors**:
43//!
44//! | Dimension | LA Representation | GA Representation |
45//! |-----------|-------------------|-------------------|
46//! | 2D | 2×2 rotation matrix | Rotor (scalar + bivector) |
47//! | 2D | Complex number `e^{iθ}` | Rotor `cos(θ/2) + sin(θ/2)e₁₂` |
48//! | 3D | 3×3 rotation matrix | Rotor (scalar + bivector) |
49//! | 3D | Quaternion | Rotor `s + xy·e₁₂ + xz·e₁₃ + yz·e₂₃` |
50//! | nD | SO(n) matrix | Rotor (even-grade multivector) |
51//!
52//! **Quaternions ARE rotors!** The imaginary units i, j, k are bivectors e₂₃, e₃₁, e₁₂.
53//!
54//! ## Module Guide
55//!
56//! - [`algebra`]: Generic [`Multivector`](algebra::Multivector) for any metric signature.
57//!   Use when you need maximum flexibility or exotic algebras.
58//!
59//! - [`specialized::euclidean`]: Optimized types for 2D/3D Euclidean geometry.
60//!   Use for standard vector math, rotations, reflections.
61//!
62//! - [`specialized::projective`]: Projective GA (PGA) for rigid body transforms.
63//!   Use when you need unified rotation + translation (like 4×4 matrices, but better).
64//!
65//! - [`basis`]: Low-level blade representation. Rarely needed directly.
66//!
67//! - [`signature`]: Metric signatures defining the algebra. Use [`prelude`] instead.
68//!
69//! ## Quick Decision Guide
70//!
71//! | Task | Recommended Module |
72//! |------|-------------------|
73//! | 2D/3D rotations | [`specialized::euclidean`] |
74//! | Rigid body transforms | [`specialized::projective`] |
75//! | Robotics kinematics | [`specialized::projective`] |
76//! | Graphics transforms | [`specialized::projective`] |
77//! | Physics simulations | [`algebra`] with appropriate signature |
78//! | Learning GA | Start with [`specialized::euclidean::dim3`] |
79//!
80#![doc(
81    html_logo_url = "https://raw.githubusercontent.com/DevonMorris/clifford/main/assets/clifford.png",
82    html_favicon_url = "https://raw.githubusercontent.com/DevonMorris/clifford/main/assets/clifford.png"
83)]
84
85// Ensure nalgebra feature flags are mutually exclusive
86#[cfg(any(
87    all(feature = "nalgebra-0_32", feature = "nalgebra-0_33"),
88    all(feature = "nalgebra-0_32", feature = "nalgebra-0_34"),
89    all(feature = "nalgebra-0_33", feature = "nalgebra-0_34"),
90))]
91compile_error!(
92    "Features `nalgebra-0_32`, `nalgebra-0_33`, and `nalgebra-0_34` are mutually exclusive. Enable only one."
93);
94
95pub mod algebra;
96pub mod basis;
97pub mod norm;
98pub mod ops;
99pub mod prelude;
100pub mod scalar;
101pub mod signature;
102pub mod specialized;
103pub mod wrappers;
104
105// ============================================================================
106// Error Types
107// ============================================================================
108
109/// Error returned when a geometric constraint is not satisfied.
110///
111/// This error is returned by `new_checked()` constructors on constrained types
112/// (like `Motor`, `Bivector`, `Flector` in PGA) when the provided coefficients
113/// violate the geometric constraint.
114///
115/// # Example
116///
117/// ```ignore
118/// use clifford::generated::projective3::Motor;
119///
120/// // Valid motor - constraint satisfied
121/// let m = Motor::new(1.0, 0.1, 0.2, 0.3, 0.01, 0.02, 0.03);
122///
123/// // Check with explicit coefficients
124/// let result = Motor::new_checked(1.0, 0.1, 0.2, 0.3, 0.01, 0.02, 0.03, 999.0, 1e-10);
125/// assert!(result.is_err()); // e0123 = 999.0 violates constraint
126/// ```
127#[derive(Debug, Clone)]
128pub struct ConstraintError {
129    /// The type that failed the constraint check.
130    pub type_name: &'static str,
131    /// The constraint expression that was violated.
132    pub constraint: &'static str,
133    /// The residual value (how far from zero).
134    pub residual: f64,
135}
136
137impl ConstraintError {
138    /// Creates a new constraint error.
139    pub fn new(type_name: &'static str, constraint: &'static str, residual: f64) -> Self {
140        Self {
141            type_name,
142            constraint,
143            residual,
144        }
145    }
146}
147
148impl std::fmt::Display for ConstraintError {
149    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150        write!(
151            f,
152            "{} constraint violated: {} (residual: {:.2e})",
153            self.type_name, self.constraint, self.residual
154        )
155    }
156}
157
158impl std::error::Error for ConstraintError {}
159
160/// Test utilities available only during testing.
161#[cfg(test)]
162pub(crate) mod test_utils {
163    /// Standard epsilon for relative comparisons in tests.
164    ///
165    /// Use this constant instead of magic numbers like `1e-10` or `1e-9`.
166    /// Relative comparisons are more robust than absolute comparisons because
167    /// they scale with the magnitude of values being compared.
168    ///
169    /// # Example
170    /// ```ignore
171    /// use approx::relative_eq;
172    /// use crate::test_utils::RELATIVE_EQ_EPS;
173    ///
174    /// prop_assert!(relative_eq!(a, b, epsilon = RELATIVE_EQ_EPS, max_relative = RELATIVE_EQ_EPS));
175    /// ```
176    pub const RELATIVE_EQ_EPS: f64 = 1e-10;
177}