reefer 0.3.0

Optimizing proc-macro for geometric algebra
Documentation
use crate::clifford::{Graded, Involution, Mask};
use abstalg::{BooleanAlgebra, BoundedOrder, DistributiveLattice, Domain, Lattice, PartialOrder};
use std::ops::BitXor;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Metric<U: Mask> {
    /// dimensions of the frame
    pub dimensions: usize,
    /// number of basis elements with positive square
    pub positive: usize,
    /// number of basis elements with negative square
    pub negative: usize,
    /// bitmask representing all basis elements
    pub supremum: U,
    /// bitmask representing the basis elements with positive square
    pub hypermum: U,
    /// bitmask representing the basis elements with negative square
    pub imagimum: U,
    /// bitmask representing the empty basis element
    pub infinum: U,
}

impl<U: Mask> PartialOrder for Metric<U> {
    fn leq(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
        (*elem1 & *elem2) == *elem1
    }
    fn less_than(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
        let meet = *elem1 & *elem2;
        meet == *elem1 && meet != *elem2
    }
    fn comparable(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
        let meet = *elem1 & *elem2;
        meet == *elem1 || meet == *elem2
    }
}

impl<U: Mask> BoundedOrder for Metric<U> {
    fn max(&self) -> Self::Elem {
        self.supremum
    }
    fn min(&self) -> Self::Elem {
        self.infinum
    }
}

impl<U: Mask> Lattice for Metric<U> {
    #[inline]
    fn meet(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
        *elem1 & *elem2
    }
    #[inline]
    fn join(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
        *elem1 | *elem2
    }
}

impl<U: Mask> DistributiveLattice for Metric<U> {}

impl<U: Mask> BooleanAlgebra for Metric<U> {
    fn not(&self, elem: &Self::Elem) -> Self::Elem {
        *elem ^ self.supremum
    }
}

impl<U: Mask> Metric<U> {
    #[inline]
    /// Return the scalar (grade-0) blade for this metric.
    pub fn one(&self) -> U {
        self.infinum
    }
}

impl<U: Mask> Domain for Metric<U> {
    type Elem = U;
    fn equals(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
        elem1 == elem2
    }
    fn contains(&self, elem: &Self::Elem) -> bool {
        self.supremum & *elem == *elem
    }
}

impl<U: Mask> Metric<U> {
    /// Create a new FrameMetric given the count of positive and negative basis elements.
    #[inline]
    pub fn new(positive: usize, negative: usize) -> Self {
        Self {
            dimensions: positive + negative,
            positive,
            negative,
            supremum: U::ones(positive + negative, 0),
            hypermum: U::ones(positive, 0),
            imagimum: U::ones(negative, positive),
            infinum: U::ZERO,
        }
    }
    // /// Determine the swap parity between two basis elements. Does not account for metric.
    // #[inline]
    // #[must_use]
    // fn swap_parity(&self, lhs: U, mut rhs: U) -> bool {
    //     let mut parity = false;
    //     while !rhs.is_zero() {
    //         let rhs_bit = rhs & (!rhs + 1); // least significant bit of rhs
    //         rhs ^= rhs_bit; // clear least significant bit
    //         let mask_lower = rhs_bit - 1; // masks for bits below rhs_bit
    //         let mask_upper = !mask_lower ^ rhs_bit; // masks for bits above
    //         let lhs_upper = lhs & mask_upper; // bits rhs_bit needs to move past
    //         let swaps = lhs_upper.count_ones(); // how many swaps needed
    //         parity ^= swaps & 1 != 0; // flip parity if odd number of swaps
    //     }
    //     parity
    // }
    // /// Determine the metric parity of a basis element. Does not account for swaps.
    // #[inline]
    // #[must_use]
    // pub fn metric_parity(&self, basis: U) -> bool {
    //     // the metric is determined by the oddness of the number of negative basis elements
    //     (basis & self.imagimum).count_ones() & 1 != 0
    // }
    #[inline]
    /// Compute the sign introduced by multiplying `lhs` and `rhs` under the metric.
    pub fn mul_parity(&self, lhs: U, rhs: U) -> bool {
        // self.swap_parity(lhs, rhs) ^ self.metric_parity(lhs & rhs)
        // but faster
        // todo: could be even faster!
        (0..self.dimensions)
            .map(|k| (lhs >> k) & rhs)
            .fold(self.hypermum & lhs & rhs, BitXor::bitxor)
            .parity()
    }
    #[inline]
    /// Compute the symmetric difference between two basis masks.
    pub fn sym_diff(&self, lhs: U, rhs: U) -> U {
        lhs ^ rhs
    }
}

impl<U: Mask> Graded for Metric<U> {
    type Grade = u32;
    type Output = Option<Self::Elem>;
    fn grade_of(&self, elem: &Self::Elem) -> Self::Grade {
        elem.count_ones()
    }
    fn grade_by(&self, elem: &Self::Elem, grade: Self::Grade) -> Self::Output {
        (self.grade_of(elem) == grade).then_some(*elem)
    }
}

impl<U: Mask> Involution for Metric<U> {
    type Output = bool;
    #[inline]
    fn automorphism(&self, elem: Self::Elem) -> Self::Output {
        let g = self.grade_of(&elem);
        g & 1 != 0
    }
    #[inline]
    fn reverse(&self, elem: Self::Elem) -> Self::Output {
        let g = self.grade_of(&elem);
        g & 2 != 0
    }
    #[inline]
    fn conjugate(&self, elem: Self::Elem) -> Self::Output {
        let g = self.grade_of(&elem);
        (g & 1 != 0) ^ (g & 2 != 0)
    }
}