amari_core/
basis.rs

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