wedged/base/
basis_blade.rs

1
2use num_traits::{One, Inv};
3use std::ops::{Neg, Mul, MulAssign, Div, DivAssign};
4use std::fmt::{Formatter, Debug, Display, Binary, Result as FmtResult, Alignment};
5
6use crate::base::*;
7
8//So we can maybe change it later though there really is no reason it needs any more bits than this
9type Bits = i32;
10
11///
12/// Represents a single signed basis element in geometric algebra
13///
14#[repr(transparent)]
15#[derive(Clone, Copy, PartialEq, Eq, Hash)]
16pub struct BasisBlade {
17    bits: Bits
18}
19
20impl BasisBlade {
21
22    /// The maximum number of dimensions supported. This is currently 31
23    ///
24    /// This limit was put in place so that no dynamic allocation is required for BasisBlade and
25    /// we can keep the struct `Copy`. The tradeoff is that
26    /// while we can't have objects in dimensions higher than 31, it's faster and easier to use.
27    /// However, seeing as 31D multivectors have 2<sup>31</sup> components, it is unlikely those
28    /// extra dimensions will ever be needed, but the limit is open to be increased if deemed necessary
29    ///
30    pub const MAX_DIM: usize = (Bits::BITS - 1) as usize; //the bit width minus one for the sign
31
32    ///The multiplicative identity
33    pub const ONE: BasisBlade = BasisBlade { bits: 0 }; //1 is just the empty product (ie when bits==0)
34
35    ///Negative one
36    pub const NEG_ONE: BasisBlade = BasisBlade { bits: Bits::MIN }; //0 with the leading bit flipped
37
38    /// Quickly does `(-1)^n`
39    #[inline(always)]
40    const fn neg_one_pow(n:usize) -> BasisBlade {
41        BasisBlade { bits:((n & 1) as Bits) << Self::MAX_DIM }
42    }
43
44    ///
45    /// Multiplies two basis blades quickly by using only XOR
46    ///
47    /// This **only** works if `self.dim()` is less than or equal to the min dim of the vectors
48    /// in `rhs`, as this is the only way to guarantee that we don't need any swaps
49    ///
50    #[inline(always)]
51    const fn unchecked_fast_mul(self, rhs: BasisBlade) -> BasisBlade {
52        BasisBlade { bits: self.bits ^ rhs.bits }
53    }
54
55    #[cfg(test)]
56    pub(crate) const fn from_bits(bits:Bits) -> BasisBlade { BasisBlade { bits } }
57
58    ///
59    /// Computes the minimum dimension this `BasisBlade` is contained in
60    ///
61    /// # Examples
62    ///```
63    /// # use wedged::base::*;
64    /// # use num_traits::One;
65    ///
66    /// let e = BasisBlade::one();
67    /// let e1 = BasisBlade::basis_vector(0);
68    /// let e2 = BasisBlade::basis_vector(1);
69    /// let e3 = BasisBlade::basis_vector(2);
70    /// let e12 = e1*e2;
71    /// let e13 = e1*e3;
72    /// let e23 = e2*e3;
73    /// let e123 = e1*e2*e3;
74    ///
75    /// assert_eq!(e.dim(), 0);
76    /// assert_eq!(e1.dim(), 1);
77    /// assert_eq!(e2.dim(), 2);
78    /// assert_eq!(e3.dim(), 3);
79    /// assert_eq!(e12.dim(), 2);
80    /// assert_eq!(e13.dim(), 3);
81    /// assert_eq!(e23.dim(), 3);
82    /// assert_eq!(e123.dim(), 3);
83    /// assert_eq!((-e123).dim(), 3);
84    ///
85    ///```
86    ///
87    pub const fn dim(&self) -> usize {
88        (Bits::BITS - self.abs().bits.leading_zeros()) as usize
89    }
90
91    ///
92    /// Computes the grade of this `BasisBlade`
93    ///
94    /// # Examples
95    ///```
96    /// # use wedged::base::*;
97    /// # use num_traits::One;
98    ///
99    /// let e = BasisBlade::one();
100    /// let e1 = BasisBlade::basis_vector(0);
101    /// let e2 = BasisBlade::basis_vector(1);
102    /// let e3 = BasisBlade::basis_vector(2);
103    /// let e12 = e1*e2;
104    /// let e13 = e1*e3;
105    /// let e23 = e2*e3;
106    /// let e123 = e1*e2*e3;
107    ///
108    /// assert_eq!(e.grade(), 0);
109    /// assert_eq!(e1.grade(), 1);
110    /// assert_eq!(e2.grade(), 1);
111    /// assert_eq!(e3.grade(), 1);
112    /// assert_eq!(e12.grade(), 2);
113    /// assert_eq!(e13.grade(), 2);
114    /// assert_eq!(e23.grade(), 2);
115    /// assert_eq!(e123.grade(), 3);
116    /// assert_eq!((-e123).grade(), 3);
117    ///
118    ///```
119    ///
120    pub const fn grade(&self) -> usize {
121        self.abs().bits.count_ones() as usize
122    }
123
124    ///
125    /// Clears the sign bit
126    ///
127    /// This isn't `pub` since there is non-arbitry choice for when a basis blade is negative
128    /// or positive. This is simply an internal function relative the internal representation.
129    ///
130    pub(crate) const fn abs(self) -> BasisBlade {
131        //mask out the first bit
132        BasisBlade { bits: self.bits & Bits::MAX }
133    }
134
135    ///
136    /// Gets the sign bit as either `BasisBlade::one()` or `-BasisBlade::one()`
137    ///
138    /// This isn't `pub` since there is non-arbitry choice for when a basis blade is negative
139    /// or positive. This is simply an internal function relative the internal representation.
140    ///
141    pub(crate) const fn sign(self) -> BasisBlade {
142        //get just the first bit
143        BasisBlade { bits: self.bits & Bits::MIN }
144    }
145
146    pub(crate) const fn positive(self) -> bool {
147        self.sign().bits == BasisBlade::ONE.bits
148    }
149
150    pub(crate) const fn negative(self) -> bool {
151        self.sign().bits == BasisBlade::NEG_ONE.bits
152    }
153
154    /// Reverses the order of the vectors making up this basis element
155    pub const fn reverse(self) -> Self {
156        //to invert, we need to reverse the order of the basic vectors:
157        //- To do this, we must pass the `i`th vector in the mul through the `i-1` vectors before it
158        //  giving `i-1` swaps for each of the g vectors.
159        //- Summing this all up, we get `0 + 1 + .. (g-1) = g*(g-1)/2` total swaps
160        //- Now, this value is only even iff `4 | g*(g-1)`
161        //- but this can only happen if either `4|g` or `4|(g-1)` as 2 cannot divide both `g` and
162        //  `g-1` at the same time
163        //- Therefore, to invert, we negate iff g == 2,3 mod 4
164
165        //get the grade
166        let g = self.grade() as Bits;
167
168        //test if the grade is 2 or 3 mod 4 by masking out the 2nd bit
169        //and then shifting that bit to the leading position
170        let sign = (g & 0b10) << (Self::MAX_DIM-1);
171
172        //multiply self by sign
173        BasisBlade { bits: self.bits ^ sign }
174    }
175
176    /// Negates if [`grade`](BasisBlade::grade) is odd
177    pub const fn involute(self) -> Self {
178        self.unchecked_fast_mul(Self::neg_one_pow(self.grade()))
179    }
180
181    /// Multiplication for const expressions
182    pub const fn const_mul(self, rhs: Self) -> Self {
183        //we only have to abs() self since it will mask out the sign of rhs
184        let a = self.abs().bits;
185        let b = rhs.bits;
186
187        //compute the sign of the result by computing the number of swaps
188        //required to align all the basis vectors
189
190        const fn compute_swaps(a: Bits, b: Bits) -> usize {
191            if a==0 {
192                0
193            } else {
194                (a&b).count_ones() as usize + compute_swaps(a>>1, b)
195            }
196        }
197        let swaps = compute_swaps(a >> 1, b);
198
199        //if swaps is even, this is 0, if it is odd, it is Bits::MIN
200        let sign = Self::neg_one_pow(swaps);
201
202        //xor everything together
203        //self.bits ^ rhs.bits selects out all basis vectors not in common
204        //^ sign flips the sign according to the swaps we had to do
205        self.unchecked_fast_mul(rhs).unchecked_fast_mul(sign)
206    }
207
208    /// Division for const expressions
209    pub const fn const_div(self, rhs: Self) -> Self { self.const_mul(rhs.reverse()) }
210
211    ///
212    /// Returns the nth basis vector
213    ///
214    /// Panics if n is greater than the maximum dimension
215    ///
216    pub fn basis_vector(n: usize) -> BasisBlade {
217        if n >= Self::MAX_DIM {
218            panic!("Only Vectors up to dimension {} are currently supported", Self::MAX_DIM )
219        }
220        BasisBlade::const_basis_vector(n)
221    }
222
223    ///
224    /// Returns the nth basis vector
225    ///
226    /// Returns `BasisBlade::one()` if n is greater than the maximum dimension
227    ///
228    pub const fn const_basis_vector(n: usize) -> BasisBlade {
229        BasisBlade { bits: 1 << n }.abs()
230    }
231
232    ///
233    /// Gives the `i`th basis blade of grade `g` in dimension `n`
234    ///
235    /// Besides basis vectors, the choice of the ordering of basis blades is entirely arbitrary,
236    /// so there is no particular *mathematical* reason for any given ordering.
237    /// That being said, the convention used here has been chosen in order to achieve a number of
238    /// helpful properties:
239    /// 1. The index of a basis bade should be the same as its dual. There are some
240    ///    technicalities regarding signs and grades that are half the dimension,
241    ///    but this allows for the very nice properties:
242    ///    - The components of (most) blades will be the exact same (up to sign) as its dual,
243    ///      potentially speeding up computation
244    ///    - A psuedovector for a hyperplane will have the same components as its normal, simplifying
245    ///      the code for making planes.
246    /// 2. When going up in dimension, any components lower dimension should stay grouped in the same
247    ///    order with the same signs, preferably at the beginning or end of the components in the
248    ///    higher dimension. This has the potential to speed up and simplify the code for casting
249    ///    between dimensions
250    ///
251    /// Unfortunately, the above have a couple technical issues, so the following extra conventions
252    /// are chosen:
253    /// - When taking the dual with a grade in the upper half of the dimension, the result
254    ///   should have the exact same components. When taking the dual in the lower half, the
255    ///   components will be negated depending on the dimension.
256    /// - When moving up a dimension, blades with grades in the bottom half will have extra
257    ///   components *appended* whereas blades in the upper half will have their components
258    ///   *prepended*
259    ///
260    /// In order to codify these, the following formal rules are followed:
261    /// 1. if `g==0`, then the basis is just the identity
262    /// 2. if `g==1`, then the basis is e<sub>i</sub>
263    /// 3. if `g<=n/2` and `i<binom(n-1,g)`, then `basis_blade(n,g,i) == basis_blade(n-1,g,i)`
264    /// 4. if `g>n/2` and `i>binom(n-1,n-g)`, then
265    ///    `basis_blade(n,g,i) == basis_blade(n-1,g,i-binom(n-1,n-g))`
266    ///
267    /// 5. for `g<n/2`, `basis_blade(n,g,i) == basis_blade(n,n-g,i) / psuedoscalar(n)`
268    ///    - Lemma #1: for `g>n/2`, `basis_blade(n,g,i) == basis_blade(n,n-g,i) * psuedoscalar(n)`
269    ///
270    /// 6. for `g==n/2`, `i<binom(n,g)/2`,
271    ///    `basis_blade(n,g,i) == basis_blade(n,n-g,i+binom(n,g)/2) / psuedoscalar(n)`
272    ///    - Lemma #2: for `g==n/2`, `i>binom(n,g)/2`,
273    ///      `basis_blade(n,g,i) == basis_blade(n,n-g,i-binom(n,g)/2) * psuedoscalar(n)`
274    ///
275    pub fn basis_blade(n:usize, g:usize, i:usize) -> BasisBlade {
276
277        if cfg!(debug_assertions) {
278            if n >= Self::MAX_DIM {
279                panic!("Only Blades up to dimension {} are currently supported", Self::MAX_DIM );
280            }
281
282            if g>n || i>binom(n,g) {
283                panic!("No basis {}-dimensional blade of grade {} at index {}", n, g, i);
284            }
285        }
286
287        Self::const_basis_blade(n, g, i)
288
289    }
290
291    //Rule #0: if grade==0, then the basis is just the identity
292    //Rule #1: if grade==1, then the basis is e_i
293    //Rule #2: if g<=n/2 and i<binom(n-1,g), then basis_blade(n,g,i) == basis_blade(n-1,g,i)
294    //Rule #3: if g> n/2 and i>binom(n-1,n-g), then
295    //      basis_blade(n,g,i) == basis_blade(n-1,g,i-binom(n-1,n-g))
296    //
297    //Rule #4: for g<n/2, basis_blade(n,g,i) == basis_blade(n,n-g,i) / psuedoscalar(n)
298    //Lemma #1: for g>n/2, basis_blade(n,g,i) == basis_blade(n,n-g,i) * psuedoscalar(n)
299    //
300    //Rule #5: for g==n/2, i<binom(n,g)/2,
301    //      basis_blade(n,g,i) == basis_blade(n,n-g,i+binom(n,g)/2) / psuedoscalar(n)
302    //
303    //Lemma #2: for g==n/2, i>binom(n,g)/2,
304    //      basis_blade(n,g,i) == basis_blade(n,n-g,i-binom(n,g)/2) * psuedoscalar(n)
305
306
307    const fn const_undual_basis(n:usize, g:usize, i:usize) -> BasisBlade {
308
309        //invalid basis vectors
310        if g>n || i>binom(n,g) { return Self::ONE; }
311
312        if 2*g < n {
313            //Rule #3
314            Self::const_basis_blade(n, n-g, i)
315        } else if 2*g == n {
316
317            //Rule #5
318            let prev_count = binom(n,g)/2;
319            if i < prev_count {
320                Self::const_basis_blade(n, g, i + prev_count)
321            } else {
322                let sign = Self::neg_one_pow(n*(n-1)/2);
323                Self::const_basis_blade(n, g, i - prev_count).unchecked_fast_mul(sign)
324            }
325
326        } else {
327            //Rule #4
328            //the sign converts from dual to undual
329            let sign = Self::neg_one_pow(n*(n-1)/2);
330            Self::const_basis_blade(n, n-g, i).unchecked_fast_mul(sign)
331        }
332
333
334    }
335
336    /// Exactly like [`basis_blade()`](BasisBlade::basis_blade) but made `const` by removing some debug runtime checks
337    pub const fn const_basis_blade(n:usize, g:usize, i:usize) -> BasisBlade {
338
339        //invalid basis vectors
340        if g>n || i>binom(n,g) { return Self::ONE; }
341
342        //From Rule #0
343        if g==0 { return Self::ONE; }
344
345        //From Rule #1
346        if g==1 { return Self::const_basis_vector(i); }
347
348        //The below optimizations for applying Rules 4-5 only work for n>2, so we hardcode n==2
349        if n==2 && g==2 && i==0 { return BasisBlade { bits: 0b11 }; }
350
351        if 2*g < n {
352            //the number of elements of this grade in the prev dimension
353            let count_prev = binom(n-1,g);
354
355            if i < count_prev {
356                //From Rule #2
357                Self::const_basis_blade(n-1,g,i)
358            } else {
359
360                //From Rule #4:
361                //  basis_blade(n,g,i) = basis_blade(n,n-g,i) / psuedoscalar(n)
362                //Since g < n/2, n-g > n/2, and
363                //Since i > binom(n-1, g) = binom(n-1, n - (n-g))
364                //By Rule #3: letting j = i-binom(n-1, n - (n-g)) = i - binom(n-1, g)
365                //  basis_blade(n,g,i) = basis_blade(n-1,n-g,j) / psuedoscalar(n)
366                //  basis_blade(n,g,i) = basis_blade(n-1,n-g,j) * psuedoscalar(n).inv()
367                //  basis_blade(n,g,i) = basis_blade(n-1,n-g,j) * (e_n * psuedoscalar(n-1)).inv()
368                //  basis_blade(n,g,i) = basis_blade(n-1,n-g,j) * psuedoscalar(n-1).inv() * e_n
369                //  basis_blade(n,g,i) = (basis_blade(n-1,n-g,j) / psuedoscalar(n-1)) * e_n
370                //Now since n-g > n/2, n-g > (n-1)/2, so:
371                //From Rule #4 again:
372                //  basis_blade(n,g,i) = basis_blade(n-1,(n-1)-(n-g),j) * e_n
373                //  basis_blade(n,g,i) = basis_blade(n-1,g-1,j) * e_n
374
375                let j = i - count_prev;
376                let prev_blade = Self::const_basis_blade(n-1, g-1, j);
377                let e_n = Self::const_basis_vector(n-1);
378
379                //since prev_blade.dim() < n and we're doing right-mul by e_n, we can just
380                //multiply by doing the XOR of the bits
381                BasisBlade { bits: prev_blade.bits ^ e_n.bits }
382
383            }
384        } else if 2*g==n {
385            //the number of elements of this grade in the prev dimension
386            let count = binom(n,g);
387
388            if i < count/2 {
389                //From Rule #2
390                Self::const_basis_blade(n-1,g,i)
391            } else {
392                //From Lemma #2 we can derive a fact very similar to the above using the
393                //exact same logic
394
395                //TODO: explain
396
397                let j = i - count/2;
398                let prev_blade = Self::const_basis_blade(n-1, g-1, j);
399                let e_n = Self::const_basis_vector(n-1);
400                let sign = Self::neg_one_pow((n-1) * n * (n-1) / 2);
401
402                //like above, we can mul just using XOR
403                prev_blade.unchecked_fast_mul(e_n).unchecked_fast_mul(sign)
404            }
405        } else {
406            //the number of elements of the *dual* grade in the prev dimension
407            let count_prev_dual = binom(n-1, n-g);
408            if i < count_prev_dual {
409
410                //From Lemma #1
411                //  basis_blade(n,g,i) = basis_blade(n,n-g,i) * psuedoscalar(n)
412                //Since g > n/2, n-g < n/2
413                //Since i < binom(n-1, n-g)
414                //By Rule #3:
415                //  basis_blade(n,g,i) = basis_blade(n-1,n-g,i) * psuedoscalar(n)
416                //  basis_blade(n,g,i) = basis_blade(n-1,n-g,i) * e_n * psuedoscalar(n-1)
417                //  basis_blade(n,g,i) = (-1)^n * basis_blade(n-1,n-g,i) * psuedoscalar(n-1) * e_n
418                //Now we have two cases:
419                //If g > (n-1)/2: We can use Rule #4 again:
420                //  basis_blade(n,g,i) = (-1)^n * basis_blade(n-1,(n-1)-(n-g),i) * e_n
421                //  basis_blade(n,g,i) = (-1)^n * basis_blade(n-1,g-1,i) * e_n
422                //Else: g-1 == (n-1)/2, and we use Rule #5:
423                //  basis_blade(n,g,i) = (-1)^n * basis_blade(n-1,(n-1)-(n-g),j) * e_n
424                //  basis_blade(n,g,i) = (-1)^n * basis_blade(n-1,g-1,j) * e_n
425                //where j = i+binom(n-1,g-1)/2 if i<binom(n-1,g-1)/2 or j = i-binom(n-1,g-1)/2 otherwise
426
427                let prev_blade = Self::const_undual_basis(n-1,n-g,i);
428                let e_n = Self::const_basis_vector(n-1);
429                let sign = Self::neg_one_pow(n-1);
430
431                //like above, we can multiply everything together just using XOR
432                prev_blade.unchecked_fast_mul(e_n).unchecked_fast_mul(sign)
433
434            } else {
435                //From Rule #3
436                Self::const_basis_blade(n-1,g,i-count_prev_dual)
437            }
438        }
439
440    }
441
442    /// Gets the `i`th basis blade in the even subalgebra for dimension `n`
443    pub fn basis_even(n: usize, i: usize) -> BasisBlade {
444        let mut i = i;
445        for (g, binom) in components_of(n).enumerate().step_by(2) {
446            if binom > i {
447                return Self::basis_blade(n,g,i);
448            } else {
449                i -= binom;
450            }
451        }
452
453        panic!("index out of range: {}>{}", i, even_elements(n))
454    }
455
456    /// Gets the `i`th basis blade in the odd subalgebra for dimension `n`
457    pub fn basis_odd(n: usize, i: usize) -> BasisBlade {
458        let mut i = i;
459        for (g, binom) in components_of(n).enumerate().skip(1).step_by(2) {
460            if binom > i {
461                return Self::basis_blade(n,g,i);
462            } else {
463                i -= binom;
464            }
465        }
466
467        panic!("index out of range: {}>{}", i, odd_elements(n))
468    }
469
470    /// Gets the `i`th basis blade in the geometric algebra of dimension `n`
471    pub fn basis(n: usize, i: usize) -> BasisBlade {
472        let mut i = i;
473        for (g, binom) in components_of(n).enumerate() {
474            if binom > i {
475                return Self::basis_blade(n,g,i);
476            } else {
477                i -= binom;
478            }
479        }
480
481        panic!("index out of range: {}>{}", i, multivector_elements(n))
482    }
483
484    const fn get_index_sign_in(self, n: usize, g: usize) -> (usize, bool) {
485
486        //TODO: explain
487
488        const fn sign_pow(n: usize) -> bool { (n&1)==1 }
489
490        if n==0 || g==0 { return (0, self.positive()); }
491
492        let e_n = Self::const_basis_vector(n-1);
493        let contains_e_n = (self.bits & e_n.bits) != 0;
494
495        if g == 1 {
496            if contains_e_n { (n-1, self.positive()) } else { self.get_index_sign_in(n-1, g) }
497        } else if 2*g < n {
498            if contains_e_n {
499                let (index, sign) = self.unchecked_fast_mul(e_n).get_index_sign_in(n-1, g-1);
500                (index + binom(n-1, g), sign)
501            } else {
502                self.get_index_sign_in(n-1, g)
503            }
504        } else if 2*g == n {
505            if contains_e_n {
506                let (index, sign) = self.unchecked_fast_mul(e_n).get_index_sign_in(n-1, g-1);
507                (index + binom(n-1, g), sign ^ sign_pow((n-1) * n * (n-1) / 2))
508            } else {
509                self.get_index_sign_in(n-1, g)
510            }
511        } else {
512            if contains_e_n {
513
514                let (index, sign) = self.unchecked_fast_mul(e_n).get_index_sign_in(n-1, g-1);
515                let sign = sign ^ sign_pow(n-1);
516
517                if 2*(g-1) == n-1 {
518                    let count = binom(n-1, g-1);
519                    if index < count/2 {
520                        ((index + count/2), sign ^ sign_pow(n * (n-1) / 2))
521                    } else {
522                        ((index - count/2), sign)
523                    }
524                } else if g==2 && n==2 {
525                    (index, self.positive())
526                } else {
527                    (index, sign)
528                }
529
530            } else {
531                let (index, sign) = self.get_index_sign_in(n-1, g);
532                (index + binom(n-1, n-g), sign)
533            }
534        }
535
536    }
537
538    /// Gets the index and sign of this basis blade in a `Blade` of dimension `n`
539    pub const fn blade_index_sign(&self, n: usize) -> (usize, bool) {
540        let n = if n > Self::MAX_DIM { Self::MAX_DIM } else { n };
541        self.get_index_sign_in(n, self.grade())
542    }
543
544    /// Gets the index and sign of this basis blade in an `Even` of dimension `n`
545    pub const fn even_index_sign(&self, n: usize) -> (usize, bool) {
546        if self.grade()%2 == 1 { return (0,self.positive()); }
547        let (i, sign) = self.blade_index_sign(n);
548
549        //TODO: optimize by having a progressive value of the binomial coefficient
550        const fn get_start(n:usize, g:usize) -> usize {
551            if g<=1 { return 0; }
552            get_start(n, g-2) + binom(n,g-2)
553        }
554
555        (get_start(n,self.grade()) + i, sign)
556    }
557
558    /// Gets the index and sign of this basis blade in an `Odd` of dimension `n`
559    pub const fn odd_index_sign(&self, n: usize) -> (usize, bool) {
560        if self.grade().is_multiple_of(2) { return (0,self.positive()); }
561        let (i, sign) = self.blade_index_sign(n);
562
563        //TODO: optimize by having a progressive value of the binomial coefficient
564        const fn get_start(n:usize, g:usize) -> usize {
565            if g<=1 { return 0; }
566            get_start(n, g-2) + binom(n,g-2)
567        }
568
569        (get_start(n,self.grade()) + i, sign)
570    }
571
572    /// Gets the index and sign of this basis blade in a `Multivector` of dimension `n`
573    pub const fn multivector_index_sign(&self, n: usize) -> (usize, bool) {
574        let (i, sign) = self.blade_index_sign(n);
575
576        const fn get_start(n:usize, g:usize) -> usize {
577            if g==0 { return 0; }
578            get_start(n, g-1) + binom(n,g-1)
579        }
580
581        (get_start(n,self.grade()) + i, sign)
582    }
583
584}
585
586impl Binary for BasisBlade {
587    fn fmt(&self, f: &mut Formatter) -> FmtResult {
588        write!(f, "{:b}", self.bits)
589    }
590}
591
592impl Debug for BasisBlade {
593    fn fmt(&self, f: &mut Formatter) -> FmtResult { Display::fmt(self, f) }
594}
595
596impl Display for BasisBlade {
597    fn fmt(&self, f: &mut Formatter) -> FmtResult {
598
599        //converts a number into an iterator of subscript characters
600        fn subscript_digits(mut n: usize) -> impl Iterator<Item=char> {
601
602            //find the greatest power of 10 less than or equal to n
603            let mut div = 1;
604            let mut digits = 1;
605            while div*10 <= n {
606                div *= 10;
607                digits += 1;
608            }
609
610            //loop from most sig digit to least
611            (0..digits).map(
612                move |_| {
613                    let (q, r) = (n/div, n%div);
614                    let digit = unsafe { char::from_u32_unchecked(0x2080 + q as u32) };
615                    n = r;
616                    div /= 10;
617                    digit
618                }
619            )
620
621        }
622
623        let dim = self.dim();
624        let grade = self.grade();
625
626        //if we should use a '-' sign instead of swapping
627        let minus_mode = f.sign_minus() || grade<=1;
628
629        //if a sign should be printed
630        let do_sign = f.sign_plus() || minus_mode && self.negative();
631
632        //if each vector should have it's own 'e'. this is required for dim>=10
633        //as if we don't, we get ambiguity on if a digit is another vector or in the 10s place
634        let separate_e = dim>=10;
635
636        let num_chars = {
637            (if do_sign { 1 } else { 0 }) +
638            (if separate_e { 2*grade } else { 1+grade })
639        };
640
641        let padding = {
642            match f.width() {
643                None => 0,
644                Some(w) => w.saturating_sub(num_chars)
645            }
646        };
647
648        //adds the appropriate amount of padding
649        let do_padding = |f: &mut Formatter, count| {
650            for _ in 0..count {
651                write!(f, "{}", f.fill())?
652            }
653            Ok(())
654        };
655
656        //writes a single basis vector with subscript i
657        //if dim>=10, it adds an 'e'
658        let write_vector = |f: &mut Formatter, i| {
659            if separate_e { write!(f, "e")?; }
660            for d in subscript_digits(i) {
661                write!(f, "{}", d)?;
662            }
663            Ok(())
664        };
665
666        //do the padding on the left
667        match f.align() {
668            Some(Alignment::Right) => do_padding(f, padding)?,
669            Some(Alignment::Center) => do_padding(f, padding/2)?,
670            _ => ()
671        }
672
673        //for prepending a sign
674        if do_sign {
675            if self.negative() {
676                write!(f, "-")?;
677            } else {
678                write!(f, "+")?;
679            }
680        }
681
682        //if the dim<10 we can write all the vectors as subscripts of one 'e'
683        if !separate_e { write!(f, "e")?; }
684
685        //if we are in minus mode or positive, we don't want to do any swaps
686        if minus_mode || self.positive() {
687
688            //just print out all vectors apart of this blade in ascending order
689            for i in 0..Self::MAX_DIM {
690                if ((1<<i) & self.bits) != 0 {
691                    write_vector(f, i+1)?;
692                }
693            }
694
695        } else {
696            //else, we swap the first two vectors to negate the basis blade
697
698            let mut first = None;
699            let mut start = true;
700
701            for i in 0..Self::MAX_DIM {
702                if ((1<<i) & self.bits) != 0 {
703
704                    match first {
705                        //store the first vector
706                        None => first = Some(i),
707
708                        //if we've already stored the first, print the second then the first
709                        Some(j) => {
710                            write_vector(f, i+1)?;
711                            if start {
712                                write_vector(f, j+1)?;
713                                start = false;
714                            }
715                        }
716                    }
717
718                }
719            }
720
721        }
722
723        //do the padding on the left
724        match f.align() {
725            Some(Alignment::Left) | None => do_padding(f, padding)?,
726            Some(Alignment::Center) => do_padding(f, padding - padding/2)?,
727            _ => ()
728        }
729
730        Ok(())
731
732    }
733}
734
735impl One for BasisBlade {
736    fn one() -> Self { Self::ONE }
737}
738
739impl Neg for BasisBlade {
740    type Output = Self;
741    fn neg(self) -> Self {
742        //flip the first bit
743        BasisBlade { bits: self.bits ^ Bits::MIN }
744    }
745}
746
747impl Inv for BasisBlade {
748    type Output = Self;
749    fn inv(self) -> Self { self.reverse() }
750}
751
752impl Mul for BasisBlade {
753    type Output = Self;
754    fn mul(self, rhs: Self) -> Self { self.const_mul(rhs) }
755}
756
757impl Div for BasisBlade {
758    type Output = Self;
759    fn div(self, rhs: Self) -> Self { self.const_div(rhs) }
760}
761
762macro_rules! impl_bin_op {
763    ($Op:ident.$op:ident() $Assign:ident.$assign:ident()) => {
764        impl<'a> $Op<&'a BasisBlade> for BasisBlade {
765            type Output = BasisBlade;
766            fn $op(self, rhs: &'a BasisBlade) -> BasisBlade { self.$op(*rhs) }
767        }
768
769        impl<'a> $Op<BasisBlade> for &'a BasisBlade {
770            type Output = BasisBlade;
771            fn $op(self, rhs: BasisBlade) -> BasisBlade { (*self).$op(rhs) }
772        }
773
774        impl<'a,'b> $Op<&'b BasisBlade> for &'a BasisBlade {
775            type Output = BasisBlade;
776            fn $op(self, rhs: &'b BasisBlade) -> BasisBlade { (*self).$op(*rhs) }
777        }
778
779        impl $Assign for BasisBlade {
780            fn $assign(&mut self, rhs: Self) { *self = self.$op(rhs) }
781        }
782
783        impl<'a> $Assign<&'a BasisBlade> for BasisBlade {
784            fn $assign(&mut self, rhs: &'a BasisBlade) { *self = self.$op(rhs) }
785        }
786    }
787}
788
789impl_bin_op!(Mul.mul() MulAssign.mul_assign());
790impl_bin_op!(Div.div() DivAssign.div_assign());
791
792#[cfg(test)]
793#[allow(non_upper_case_globals)]
794mod tests {
795
796    use super::*;
797
798    const e: BasisBlade = BasisBlade::ONE;
799
800    const e1: BasisBlade = BasisBlade::const_basis_vector(0);
801    const e2: BasisBlade = BasisBlade::const_basis_vector(1);
802    const e3: BasisBlade = BasisBlade::const_basis_vector(2);
803    const e4: BasisBlade = BasisBlade::const_basis_vector(3);
804
805    const e12: BasisBlade = BasisBlade { bits: 0b0011 };
806    const e13: BasisBlade = BasisBlade { bits: 0b0101 };
807    const e14: BasisBlade = BasisBlade { bits: 0b1001 };
808    const e23: BasisBlade = BasisBlade { bits: 0b0110 };
809    const e24: BasisBlade = BasisBlade { bits: 0b1010 };
810    const e34: BasisBlade = BasisBlade { bits: 0b1100 };
811
812    const e123: BasisBlade = BasisBlade { bits: 0b0111 };
813    const e124: BasisBlade = BasisBlade { bits: 0b1011 };
814    const e134: BasisBlade = BasisBlade { bits: 0b1101 };
815    const e234: BasisBlade = BasisBlade { bits: 0b1110 };
816
817    const e1234: BasisBlade = BasisBlade { bits: 0b1111 };
818
819    #[test]
820    fn display() {
821
822        macro_rules! test_fmt {
823            ($e:expr; $fmt:literal $neg_alt:literal) => {
824                assert_eq!(format!("{:-}", $e), $fmt);
825                assert_eq!(format!("{}", $e), $fmt);
826                assert_eq!(format!("{:-}", -$e), concat!("-", $fmt));
827                assert_eq!(format!("{}", -$e), $neg_alt);
828
829                assert_eq!(format!("{:-?}", $e), $fmt);
830                assert_eq!(format!("{:?}", $e), $fmt);
831                assert_eq!(format!("{:-?}", -$e), concat!("-", $fmt));
832                assert_eq!(format!("{:?}", -$e), $neg_alt);
833            }
834        }
835
836        assert_eq!(format!("{}", e), "e");
837        assert_eq!(format!("{}", -e), "-e");
838        test_fmt!(e1; "e₁" "-e₁");
839        test_fmt!(e2; "e₂" "-e₂");
840        test_fmt!(e3; "e₃" "-e₃");
841        test_fmt!(e4; "e₄" "-e₄");
842        test_fmt!(e12; "e₁₂" "e₂₁");
843        test_fmt!(e13; "e₁₃" "e₃₁");
844        test_fmt!(e14; "e₁₄" "e₄₁");
845        test_fmt!(e23; "e₂₃" "e₃₂");
846        test_fmt!(e24; "e₂₄" "e₄₂");
847        test_fmt!(e34; "e₃₄" "e₄₃");
848        test_fmt!(e123; "e₁₂₃" "e₂₁₃");
849        test_fmt!(e124; "e₁₂₄" "e₂₁₄");
850        test_fmt!(e134; "e₁₃₄" "e₃₁₄");
851        test_fmt!(e234; "e₂₃₄" "e₃₂₄");
852        test_fmt!(e1234; "e₁₂₃₄" "e₂₁₃₄");
853
854
855        let e9 = BasisBlade::basis_vector(8);
856
857        test_fmt!(e9; "e₉" "-e₉");
858        test_fmt!(e1*e9; "e₁₉" "e₉₁");
859
860        //
861        //Dims greater than 10
862        //
863
864        let e10 = BasisBlade::basis_vector(9);
865        let e11 = BasisBlade::basis_vector(10);
866        test_fmt!(e10; "e₁₀" "-e₁₀");
867        test_fmt!(e11; "e₁₁" "-e₁₁");
868        test_fmt!(e10*e11; "e₁₀e₁₁" "e₁₁e₁₀");
869        test_fmt!(e1*e11; "e₁e₁₁" "e₁₁e₁");
870        test_fmt!(e1*e2*e11; "e₁e₂e₁₁" "e₂e₁e₁₁");
871
872
873    }
874
875    #[test]
876    fn abs() {
877
878        macro_rules! test_abs {
879            ($($e:ident)*) => {
880                $(
881                    assert_eq!($e.abs(), $e);
882                    assert_eq!((-$e).abs(), $e);
883                )*
884            }
885        }
886
887        test_abs!(e e1 e2 e3 e4 e12 e13 e14 e23 e24 e34 e123 e124 e134 e234 e1234);
888    }
889
890    #[test]
891    fn sign() {
892
893        macro_rules! test_sign {
894            ($($e:ident)*) => {
895                $(
896                    assert_eq!($e.sign(), e);
897                    assert_eq!((-$e).sign(), -e);
898                    assert!($e.positive());
899                    assert!(!$e.negative());
900                    assert!((-$e).negative());
901                    assert!(!(-$e).positive());
902                )*
903            }
904        }
905
906        test_sign!(e e1 e2 e3 e4 e12 e13 e14 e23 e24 e34 e123 e124 e134 e234 e1234);
907    }
908
909    macro_rules! test_mul {
910        ($b1:ident*$b2:ident == $b3:expr; $commutative:literal) => {
911
912            assert_eq!( $b1 * $b2,  $b3);
913            assert_eq!(-$b1 * $b2, -$b3);
914            assert_eq!( $b1 *-$b2, -$b3);
915            assert_eq!(-$b1 *-$b2,  $b3);
916
917            if $commutative {
918                assert_eq!( $b2 * $b1,  $b3);
919                assert_eq!(-$b2 * $b1, -$b3);
920                assert_eq!( $b2 *-$b1, -$b3);
921                assert_eq!(-$b2 *-$b1,  $b3);
922            } else {
923                assert_eq!( $b2 * $b1, -$b3);
924                assert_eq!(-$b2 * $b1,  $b3);
925                assert_eq!( $b2 *-$b1,  $b3);
926                assert_eq!(-$b2 *-$b1, -$b3);
927            }
928
929        }
930    }
931
932    #[test]
933    fn mul() {
934
935        test_mul!(e1*e1 == e; true);
936        test_mul!(e2*e2 == e; true);
937        test_mul!(e3*e3 == e; true);
938
939        test_mul!(e1*e2 == e12; false);
940        test_mul!(e1*e3 == e13; false);
941        test_mul!(e2*e3 == e23; false);
942
943        test_mul!(e13*e12 == e23; false);
944        test_mul!(e12*e23 == e13; false);
945        test_mul!(e23*e13 == e12; false);
946
947        test_mul!(e1*e12 == e2; false);
948        test_mul!(e12*e2 == e1; false);
949        test_mul!(e1*e13 == e3; false);
950        test_mul!(e13*e3 == e1; false);
951        test_mul!(e2*e23 == e3; false);
952        test_mul!(e23*e3 == e2; false);
953
954        test_mul!(e12*e3 ==  e123; true);
955        test_mul!(e13*e2 == -e123; true);
956        test_mul!(e1*e23 ==  e123; true);
957
958        test_mul!(e1*e123 ==  e23; true);
959        test_mul!(e2*e123 == -e13; true);
960        test_mul!(e3*e123 ==  e12; true);
961
962        test_mul!(e12*e123 == -e3; true);
963        test_mul!(e13*e123 ==  e2; true);
964        test_mul!(e23*e123 == -e1; true);
965
966        assert_eq!(e1*e2*e3,  e123);
967        assert_eq!(e2*e1*e3, -e123);
968        assert_eq!(e2*e3*e1,  e123);
969        assert_eq!(e3*e2*e1, -e123);
970        assert_eq!(e3*e1*e2,  e123);
971        assert_eq!(e1*e3*e2, -e123);
972
973    }
974
975    #[test]
976    fn one() {
977
978        let one = BasisBlade::one();
979
980        macro_rules! test_one {
981            ($($e:ident)*) => {
982                $(test_mul!(one*$e == $e; true);)*
983            }
984        }
985
986        test_one!(e e1 e2 e3 e4 e12 e13 e14 e23 e24 e34 e123 e124 e134 e234 e1234);
987
988    }
989
990    #[test]
991    fn inv() {
992        macro_rules! test_inv {
993            ($($e:ident)*) => {
994                $(
995                    assert_eq!(
996                        $e.inv(),
997                        {
998                            let g = $e.grade();
999                            if g==0 || g*(g-1)/2 % 2 == 0 { $e } else { -$e }
1000                        }
1001                    );
1002                )*
1003            }
1004        }
1005
1006        test_inv!(e e1 e2 e3 e4 e12 e13 e14 e23 e24 e34 e123 e124 e134 e234 e1234);
1007    }
1008
1009    #[test]
1010    fn div() {
1011
1012        macro_rules! test_div {
1013            ($($e:ident)*) => {
1014                $(assert_eq!($e/$e, e);)*
1015            }
1016        }
1017
1018        test_div!(e e1 e2 e3 e4 e12 e13 e14 e23 e24 e34 e123 e124 e134 e234 e1234);
1019
1020    }
1021
1022
1023
1024    #[test]
1025    fn basis() {
1026
1027        // for n in 0..=6 {
1028        //     println!("\nn={}", n);
1029        //     for g in 0..=n {
1030        //
1031        //         print!("g={}: ", g);
1032        //         for i in 0..binom(n,g) {
1033        //             print!("{:7}", BasisBlade::basis_blade(n,g,i));
1034        //         }
1035        //         println!();
1036        //     }
1037        // }
1038
1039        assert_eq!(e, BasisBlade::basis_blade(0,0,0));
1040
1041        assert_eq!(e,  BasisBlade::basis_blade(1,0,0));
1042        assert_eq!(e1, BasisBlade::basis_blade(1,1,0));
1043
1044        assert_eq!(e,   BasisBlade::basis_blade(2,0,0));
1045        assert_eq!(e1,  BasisBlade::basis_blade(2,1,0));
1046        assert_eq!(e2,  BasisBlade::basis_blade(2,1,1));
1047        assert_eq!(e12, BasisBlade::basis_blade(2,2,0));
1048
1049        assert_eq!(e,     BasisBlade::basis_blade(3,0,0));
1050        assert_eq!(e1,    BasisBlade::basis_blade(3,1,0));
1051        assert_eq!(e2,    BasisBlade::basis_blade(3,1,1));
1052        assert_eq!(e3,    BasisBlade::basis_blade(3,1,2));
1053        assert_eq!(e2*e3, BasisBlade::basis_blade(3,2,0));
1054        assert_eq!(e3*e1, BasisBlade::basis_blade(3,2,1));
1055        assert_eq!(e1*e2, BasisBlade::basis_blade(3,2,2));
1056        assert_eq!(e123,  BasisBlade::basis_blade(3,3,0));
1057
1058    }
1059
1060    #[test]
1061    fn basis_rule_1() {
1062        for n in 0..BasisBlade::MAX_DIM {
1063            for i in 0..n {
1064                assert_eq!(BasisBlade::basis_blade(n,1,i), BasisBlade::basis_vector(i));
1065            }
1066        }
1067    }
1068
1069    #[test]
1070    fn basis_rule_2_3() {
1071        for n in 1..=16 {
1072            for g in 0..=(n-1) {
1073                let count = binom(n,g);
1074                if 2*g <= n {
1075                    //Rule #2
1076                    let prev_count = binom(n-1,g);
1077                    for i in 0..prev_count {
1078                        assert_eq!(
1079                            BasisBlade::basis_blade(n,g,i),
1080                            BasisBlade::basis_blade(n-1,g,i)
1081                        );
1082                    }
1083                } else {
1084                    //Rule #3
1085                    let prev_count = binom(n-1,n-g);
1086                    for i in prev_count..count {
1087                        assert_eq!(
1088                            BasisBlade::basis_blade(n,g,i),
1089                            BasisBlade::basis_blade(n-1,g,i-prev_count)
1090                        );
1091                    }
1092                }
1093            }
1094
1095        }
1096    }
1097
1098    #[test]
1099    fn basis_rule_4_5() {
1100        for n in 1..=16 {
1101            for g in 0..=n {
1102                let count = binom(n,g);
1103                let ps = BasisBlade::basis_blade(n,n,0);
1104                if 2*g < n {
1105                    let prev_count = binom(n-1,g);
1106                    for i in 0..prev_count {
1107                        assert_eq!(
1108                            BasisBlade::basis_blade(n,g,i),
1109                            BasisBlade::basis_blade(n,n-g,i) / ps
1110                        );
1111                    }
1112                } else if 2*g == n {
1113                    for i in 0..count/2 {
1114                        assert_eq!(
1115                            BasisBlade::basis_blade(n,g,i),
1116                            BasisBlade::basis_blade(n,g,i+count/2) / ps
1117                        );
1118                        assert_eq!(
1119                            BasisBlade::basis_blade(n,g,i+count/2),
1120                            BasisBlade::basis_blade(n,g,i) * ps
1121                        );
1122                    }
1123                } else {
1124                    let prev_count = binom(n-1,n-g);
1125                    for i in prev_count..count {
1126                        assert_eq!(
1127                            BasisBlade::basis_blade(n,g,i),
1128                            BasisBlade::basis_blade(n,n-g,i) * ps
1129                        );
1130                    }
1131                }
1132            }
1133
1134        }
1135    }
1136
1137    #[test]
1138    fn blade_index() {
1139        for n in 1..=16 {
1140            // println!("\nn = {}:", n);
1141            for g in 0..=n {
1142                for i in 0..binom(n,g) {
1143                    let blade = BasisBlade::basis_blade(n,g,i);
1144                    // print!("{:?} ", blade.get_index_sign(n));
1145                    assert_eq!((i, true), blade.blade_index_sign(n));
1146                    assert_eq!((i, false), (-blade).blade_index_sign(n));
1147                }
1148                // println!();
1149            }
1150        }
1151    }
1152
1153    #[test]
1154    fn even_index() {
1155        for n in 1..=16 {
1156            // println!("\nn = {}:", n);
1157            for i in 0..(1<<(n/2)) {
1158                let even = BasisBlade::basis_even(n,i);
1159                // print!("{:?} ", even.even_index_sign(n));
1160                assert_eq!((i, true), even.even_index_sign(n));
1161                assert_eq!((i, false), (-even).even_index_sign(n));
1162            }
1163        }
1164    }
1165
1166    #[test]
1167    fn multivector_index() {
1168        for n in 1..=16 {
1169            for i in 0..(1<<n) {
1170                let mv = BasisBlade::basis(n,i);
1171                assert_eq!((i, true), mv.multivector_index_sign(n));
1172                assert_eq!((i, false), (-mv).multivector_index_sign(n));
1173            }
1174        }
1175    }
1176
1177    macro_rules! test_index {
1178        ($($e:expr; $n:expr, $blade:expr, $even:expr, $mv:expr;)*) => {
1179            $(
1180                assert_eq!($e.blade_index_sign($n).0, $blade);
1181                assert_eq!($e.even_index_sign($n).0, $even);
1182                assert_eq!($e.multivector_index_sign($n).0, $mv);
1183            )*
1184        }
1185    }
1186
1187    #[test]
1188    fn index_2d() {
1189        test_index!(
1190             e    ; 2, 0, 0, 0;
1191             e1   ; 2, 0, 0, 1;
1192             e2   ; 2, 1, 0, 2;
1193             e12  ; 2, 0, 1, 3;
1194        );
1195    }
1196
1197    #[test]
1198    fn index_3d() {
1199        test_index!(
1200             e    ; 3, 0, 0, 0;
1201             e1   ; 3, 0, 0, 1;
1202             e2   ; 3, 1, 0, 2;
1203             e3   ; 3, 2, 0, 3;
1204             e23  ; 3, 0, 1, 4;
1205            -e13  ; 3, 1, 2, 5;
1206             e12  ; 3, 2, 3, 6;
1207             e123 ; 3, 0, 0, 7;
1208        );
1209    }
1210
1211    #[test]
1212    fn index_4d() {
1213        test_index!(
1214             e     ; 4, 0, 0, 0;
1215             e1    ; 4, 0, 0, 1;
1216             e2    ; 4, 1, 0, 2;
1217             e3    ; 4, 2, 0, 3;
1218             e4    ; 4, 3, 0, 4;
1219             e23   ; 4, 0, 1, 5;
1220            -e13   ; 4, 1, 2, 6;
1221             e12   ; 4, 2, 3, 7;
1222             e14   ; 4, 3, 4, 8;
1223             e24   ; 4, 4, 5, 9;
1224             e34   ; 4, 5, 6, 10;
1225            -e234  ; 4, 0, 0, 11;
1226             e134  ; 4, 1, 0, 12;
1227            -e124  ; 4, 2, 0, 13;
1228             e123  ; 4, 3, 0, 14;
1229            -e1234 ; 4, 0, 7, 15;
1230        );
1231    }
1232
1233
1234}