amari_core/
basis.rs

1//! Basis blade utilities and naming conventions
2
3use crate::Multivector;
4use alloc::string::{String, ToString};
5use alloc::vec;
6use alloc::vec::Vec;
7
8/// Get the grade (number of basis vectors) in a blade
9#[inline(always)]
10pub fn blade_grade(blade_index: usize) -> usize {
11    blade_index.count_ones() as usize
12}
13
14/// Get human-readable name for a basis blade
15pub fn blade_name(blade_index: usize, dim: usize) -> String {
16    if blade_index == 0 {
17        return String::from("1"); // Scalar
18    }
19
20    let mut name = String::new();
21    name.push('e');
22
23    for i in 0..dim {
24        if (blade_index >> i) & 1 == 1 {
25            if name.len() > 1 {
26                name.push('_');
27            }
28            name.push_str(&(i + 1).to_string());
29        }
30    }
31
32    name
33}
34
35/// Builder for constructing multivectors with named components
36pub struct MultivectorBuilder<const P: usize, const Q: usize, const R: usize> {
37    coefficients: Vec<f64>,
38}
39
40impl<const P: usize, const Q: usize, const R: usize> Default for MultivectorBuilder<P, Q, R> {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46impl<const P: usize, const Q: usize, const R: usize> MultivectorBuilder<P, Q, R> {
47    pub fn new() -> Self {
48        Self {
49            coefficients: vec![0.0; Multivector::<P, Q, R>::BASIS_COUNT],
50        }
51    }
52
53    /// Set scalar component
54    pub fn scalar(mut self, value: f64) -> Self {
55        self.coefficients[0] = value;
56        self
57    }
58
59    /// Set coefficient for basis vector e_i (1-indexed)
60    pub fn e(mut self, i: usize, value: f64) -> Self {
61        assert!(i >= 1 && i <= P + Q + R, "Basis vector index out of range");
62        self.coefficients[1 << (i - 1)] = value;
63        self
64    }
65
66    /// Set coefficient for bivector e_i ∧ e_j
67    pub fn e_wedge(mut self, i: usize, j: usize, value: f64) -> Self {
68        assert!(i != j, "Cannot wedge a vector with itself");
69        assert!(i >= 1 && i <= P + Q + R, "Basis vector i out of range");
70        assert!(j >= 1 && j <= P + Q + R, "Basis vector j out of range");
71
72        let index = (1 << (i - 1)) | (1 << (j - 1));
73        let sign = if i < j { 1.0 } else { -1.0 };
74        self.coefficients[index] = sign * value;
75        self
76    }
77
78    /// Build the multivector
79    pub fn build(self) -> Multivector<P, Q, R> {
80        Multivector::from_coefficients(self.coefficients)
81    }
82}
83
84/// Helper to create standard basis vectors
85pub struct Basis;
86
87impl Basis {
88    /// Create basis vector e1
89    pub fn e1<const P: usize, const Q: usize, const R: usize>() -> Multivector<P, Q, R> {
90        Multivector::basis_vector(0)
91    }
92
93    /// Create basis vector e2
94    pub fn e2<const P: usize, const Q: usize, const R: usize>() -> Multivector<P, Q, R> {
95        Multivector::basis_vector(1)
96    }
97
98    /// Create basis vector e3
99    pub fn e3<const P: usize, const Q: usize, const R: usize>() -> Multivector<P, Q, R> {
100        Multivector::basis_vector(2)
101    }
102
103    /// Create basis bivector e12
104    pub fn e12<const P: usize, const Q: usize, const R: usize>() -> Multivector<P, Q, R> {
105        let e1 = Self::e1();
106        let e2 = Self::e2();
107        e1.outer_product(&e2)
108    }
109
110    /// Create basis bivector e23
111    pub fn e23<const P: usize, const Q: usize, const R: usize>() -> Multivector<P, Q, R> {
112        let e2 = Self::e2();
113        let e3 = Self::e3();
114        e2.outer_product(&e3)
115    }
116
117    /// Create basis bivector e31
118    pub fn e31<const P: usize, const Q: usize, const R: usize>() -> Multivector<P, Q, R> {
119        let e3 = Self::e3();
120        let e1 = Self::e1();
121        e3.outer_product(&e1)
122    }
123
124    /// Create pseudoscalar for 3D (e123)
125    pub fn e123<const P: usize, const Q: usize, const R: usize>() -> Multivector<P, Q, R> {
126        let e1 = Self::e1();
127        let e2 = Self::e2();
128        let e3 = Self::e3();
129        e1.outer_product(&e2).outer_product(&e3)
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136
137    type Cl3 = Multivector<3, 0, 0>;
138
139    #[test]
140    fn test_blade_names() {
141        assert_eq!(blade_name(0, 3), "1");
142        assert_eq!(blade_name(1, 3), "e1");
143        assert_eq!(blade_name(2, 3), "e2");
144        assert_eq!(blade_name(3, 3), "e1_2");
145        assert_eq!(blade_name(7, 3), "e1_2_3");
146    }
147
148    #[test]
149    fn test_builder() {
150        let mv = MultivectorBuilder::<3, 0, 0>::new()
151            .scalar(2.0)
152            .e(1, 3.0)
153            .e(2, 4.0)
154            .e_wedge(1, 2, 5.0)
155            .build();
156
157        assert_eq!(mv.get(0), 2.0); // Scalar
158        assert_eq!(mv.get(1), 3.0); // e1
159        assert_eq!(mv.get(2), 4.0); // e2
160        assert_eq!(mv.get(3), 5.0); // e12
161    }
162
163    #[test]
164    fn test_basis_helpers() {
165        let e1: Cl3 = Basis::e1();
166        let e2: Cl3 = Basis::e2();
167        let e12: Cl3 = Basis::e12();
168
169        assert_eq!(e1.get(1), 1.0);
170        assert_eq!(e2.get(2), 1.0);
171        assert_eq!(e12.get(3), 1.0);
172
173        // Verify e1 ∧ e2 = e12
174        let computed_e12 = e1.outer_product(&e2);
175        assert_eq!(computed_e12.get(3), e12.get(3));
176    }
177}