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
8type Bits = i32;
10
11#[repr(transparent)]
15#[derive(Clone, Copy, PartialEq, Eq, Hash)]
16pub struct BasisBlade {
17 bits: Bits
18}
19
20impl BasisBlade {
21
22 pub const MAX_DIM: usize = (Bits::BITS - 1) as usize; pub const ONE: BasisBlade = BasisBlade { bits: 0 }; pub const NEG_ONE: BasisBlade = BasisBlade { bits: Bits::MIN }; #[inline(always)]
40 const fn neg_one_pow(n:usize) -> BasisBlade {
41 BasisBlade { bits:((n & 1) as Bits) << Self::MAX_DIM }
42 }
43
44 #[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 pub const fn dim(&self) -> usize {
88 (Bits::BITS - self.abs().bits.leading_zeros()) as usize
89 }
90
91 pub const fn grade(&self) -> usize {
121 self.abs().bits.count_ones() as usize
122 }
123
124 pub(crate) const fn abs(self) -> BasisBlade {
131 BasisBlade { bits: self.bits & Bits::MAX }
133 }
134
135 pub(crate) const fn sign(self) -> BasisBlade {
142 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 pub const fn reverse(self) -> Self {
156 let g = self.grade() as Bits;
167
168 let sign = (g & 0b10) << (Self::MAX_DIM-1);
171
172 BasisBlade { bits: self.bits ^ sign }
174 }
175
176 pub const fn involute(self) -> Self {
178 self.unchecked_fast_mul(Self::neg_one_pow(self.grade()))
179 }
180
181 pub const fn const_mul(self, rhs: Self) -> Self {
183 let a = self.abs().bits;
185 let b = rhs.bits;
186
187 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 let sign = Self::neg_one_pow(swaps);
201
202 self.unchecked_fast_mul(rhs).unchecked_fast_mul(sign)
206 }
207
208 pub const fn const_div(self, rhs: Self) -> Self { self.const_mul(rhs.reverse()) }
210
211 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 pub const fn const_basis_vector(n: usize) -> BasisBlade {
229 BasisBlade { bits: 1 << n }.abs()
230 }
231
232 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 const fn const_undual_basis(n:usize, g:usize, i:usize) -> BasisBlade {
308
309 if g>n || i>binom(n,g) { return Self::ONE; }
311
312 if 2*g < n {
313 Self::const_basis_blade(n, n-g, i)
315 } else if 2*g == n {
316
317 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 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 pub const fn const_basis_blade(n:usize, g:usize, i:usize) -> BasisBlade {
338
339 if g>n || i>binom(n,g) { return Self::ONE; }
341
342 if g==0 { return Self::ONE; }
344
345 if g==1 { return Self::const_basis_vector(i); }
347
348 if n==2 && g==2 && i==0 { return BasisBlade { bits: 0b11 }; }
350
351 if 2*g < n {
352 let count_prev = binom(n-1,g);
354
355 if i < count_prev {
356 Self::const_basis_blade(n-1,g,i)
358 } else {
359
360 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 BasisBlade { bits: prev_blade.bits ^ e_n.bits }
382
383 }
384 } else if 2*g==n {
385 let count = binom(n,g);
387
388 if i < count/2 {
389 Self::const_basis_blade(n-1,g,i)
391 } else {
392 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 prev_blade.unchecked_fast_mul(e_n).unchecked_fast_mul(sign)
404 }
405 } else {
406 let count_prev_dual = binom(n-1, n-g);
408 if i < count_prev_dual {
409
410 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 prev_blade.unchecked_fast_mul(e_n).unchecked_fast_mul(sign)
433
434 } else {
435 Self::const_basis_blade(n-1,g,i-count_prev_dual)
437 }
438 }
439
440 }
441
442 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 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 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 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 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 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 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 pub const fn odd_index_sign(&self, n: usize) -> (usize, bool) {
560 if self.grade()%2 == 0 { return (0,self.positive()); }
561 let (i, sign) = self.blade_index_sign(n);
562
563 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 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 fn subscript_digits(mut n: usize) -> impl Iterator<Item=char> {
601
602 let mut div = 1;
604 let mut digits = 1;
605 while div*10 <= n {
606 div *= 10;
607 digits += 1;
608 }
609
610 (0..digits).into_iter().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 let minus_mode = f.sign_minus() || grade<=1;
628
629 let do_sign = f.sign_plus() || minus_mode && self.negative();
631
632 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 let do_padding = |f: &mut Formatter, count| {
650 for _ in 0..count {
651 write!(f, "{}", f.fill())?
652 }
653 Ok(())
654 };
655
656 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 match f.align() {
668 Some(Alignment::Right) => do_padding(f, padding)?,
669 Some(Alignment::Center) => do_padding(f, padding/2)?,
670 _ => ()
671 }
672
673 if do_sign {
675 if self.negative() {
676 write!(f, "-")?;
677 } else {
678 write!(f, "+")?;
679 }
680 }
681
682 if !separate_e { write!(f, "e")?; }
684
685 if minus_mode || self.positive() {
687
688 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 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 None => first = Some(i),
707
708 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 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 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 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 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 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 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 for g in 0..=n {
1142 for i in 0..binom(n,g) {
1143 let blade = BasisBlade::basis_blade(n,g,i);
1144 assert_eq!((i, true), blade.blade_index_sign(n));
1146 assert_eq!((i, false), (-blade).blade_index_sign(n));
1147 }
1148 }
1150 }
1151 }
1152
1153 #[test]
1154 fn even_index() {
1155 for n in 1..=16 {
1156 for i in 0..(1<<(n/2)) {
1158 let even = BasisBlade::basis_even(n,i);
1159 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}