reefer 0.3.0

Optimizing proc-macro for geometric algebra
Documentation
#![allow(dead_code)]
#![allow(unused)]

use reefer::algebra;

#[allow(unused_macros)]
#[allow(non_snake_case)]
#[algebra(f32, 3, 1)]
mod cga2d {
    basis! { e0 = P0 + N0 }
    basis! { eI = P0 - N0 }
    basis! { e1 = P1 }
    basis! { e2 = P2 }
    // idempotent basis element is also possible, ie
    basis! { idem = 0.5 + 0.5 * P0 }

    #[derive(Debug, Clone, Copy, PartialEq)]
    shape!(Zero {});
    #[derive(Debug, Clone, Copy, PartialEq)]
    shape!(Scalar { 1 });
    #[derive(Debug, Clone, Copy, PartialEq)]
    shape!(Vector { e0, eI, e1, e2 });
    #[derive(Debug, Clone, Copy, PartialEq)]
    shape!(Bivector {
        e0I,
        e01,
        e02,
        e1I,
        e2I,
        e12
    });
    #[derive(Debug, Clone, Copy, PartialEq)]
    shape!(Trivector {
        e0I1,
        e0I2,
        e012,
        eI12
    });
    #[derive(Debug, Clone, Copy, PartialEq)]
    shape!(Pseudoscalar { e0I12 });
    #[derive(Debug, Clone, Copy, PartialEq)]
    shape!(Idem { idem });
}

/// Test that we create the correct shapes via the `expr!` macro.
#[test]
fn shape_expr_works() {
    let z: cga2d::Zero = cga2d::expr!(|| 0.0)();
    let s: cga2d::Scalar = cga2d::expr!(|| 5.0)();
    let v: cga2d::Vector = cga2d::expr!(|| 1.0 * e0 + 2.0 * eI + 3.0 * e1 + 4.0 * e2)();
    let b: cga2d::Bivector =
        cga2d::expr!(|| { e0I + 2.0 * e01 + 3.0 * e02 + 4.0 * e1I + 5.0 * e2I + 6.0 * e12 })();
    let t: cga2d::Trivector =
        cga2d::expr!(|| { 3.0 * e0I1 + 2.0 * e0I2 + e012 + 4.0 * eI21 + 9 })();
    let p: cga2d::Pseudoscalar = cga2d::expr!(|| e0I12)();
}

/// Test that expressions that algebraically cancel to zero produce the `Zero` shape.
#[test]
fn shape_cancels_to_zero() {
    let z = cga2d::expr!(|| 1.0 * e0 - 1.0 * e0)();
    assert!(matches!(z, cga2d::Zero {}));
    let z = cga2d::expr!(|| e12 + e21)();
    assert!(matches!(z, cga2d::Zero {}));
    let z = cga2d::expr!(|| whatever - whatever)();
    assert!(matches!(z, cga2d::Zero {}));
}

/// Test that scaled basis elements multiply correctly: idem * idem = idem
#[test]
fn scaled_basis_squares_correctly() {
    let idempotent_basis = cga2d::expr!(|| idem)();
    let idempotent_square = cga2d::expr!(|| idem * idem)();

    assert_eq!(idempotent_basis, idempotent_square);
}

/// Test geometric product (multiplication)
#[test]
fn geometric_product_works() {
    // e1 * e1 = 1 (positive metric)
    let result = cga2d::expr!(|| e1 * e1)();
    assert!(matches!(result, cga2d::Scalar { _1: 1.0 }));
    // e1 * e2 produces a bivector
    let result = cga2d::expr!(|| e1 * e2)();
    assert!(matches!(result, cga2d::Bivector { e12: 1.0, .. }));
}

/// Test exterior product (wedge)
#[test]
fn wedge_product_works() {
    // e1 ^ e2 = e12 (bivector)
    let result = cga2d::expr!(|| e1 ^ e2)();
    assert!(matches!(result, cga2d::Bivector { e12: 1.0, .. }));

    // e1 ^ e1 = 0 (same vector wedges to zero)
    let result = cga2d::expr!(|| e1 ^ e1)();
    assert!(matches!(result, cga2d::Zero {}));

    // Anticommutativity: e1 ^ e2 = -(e2 ^ e1)
    let fwd = cga2d::expr!(|| e1 ^ e2)();
    let rev = cga2d::expr!(|| e2 ^ e1)();
    // They should have opposite signs
    let (cga2d::Bivector { e12: fwd_coeff, .. }, cga2d::Bivector { e12: rev_coeff, .. }) =
        (fwd, rev);
    assert!(
        (fwd_coeff + rev_coeff).abs() < 1e-6,
        "Wedge should be anticommutative"
    );
}

/// Test inner product (contraction)
#[test]
fn inner_product_works() {
    // e1 | e2 = 0 (orthogonal vectors in Euclidean part)
    let result = cga2d::expr!(|| e1 | e2)();
    assert!(
        matches!(result, cga2d::Zero {}),
        "e1 | e2 should be zero (orthogonal)"
    );

    // e0 | eI should give a scalar (these are the conformal basis elements)
    let result = cga2d::expr!(|| e0 | eI)();
    // This will be optimized to a constant scalar, check it exists
    let _ = result; // Just verify it compiles
}

/// Test negation
#[test]
fn negation_works() {
    // Test that negation works in expressions
    let pos = cga2d::expr!(|| e1)();
    let neg = cga2d::expr!(|| -e1)();

    // Verify they're negatives by checking components
    let (cga2d::Vector { e1: pos_coeff, .. }, cga2d::Vector { e1: neg_coeff, .. }) = (pos, neg);
    assert!(
        (pos_coeff + neg_coeff).abs() < 1e-6,
        "Negation should flip sign"
    );
}

/// Test subtraction
#[test]
fn subtraction_works() {
    let result = cga2d::expr!(|| 2.0 * e1 - 1.0 * e1)();
    let cga2d::Vector {
        e1: coeff,
        e0,
        eI,
        e2,
    } = result;
    assert!((coeff - 1.0).abs() < 1e-6, "Expected coefficient 1.0");
    assert!(
        e0.abs() < 1e-6 && eI.abs() < 1e-6 && e2.abs() < 1e-6,
        "Other components should be zero"
    );
}

/// Test reverse operation
#[test]
fn reverse_works() {
    // Test that reverse operation compiles and runs
    // Reverse behavior depends on grade: vectors unchanged, bivectors may flip sign
    let biv = cga2d::expr!(|| e0 ^ e1)();
    let rev = cga2d::expr!(|| (e0 ^ e1).reverse())();

    // Just verify the operation works - algebraic correctness depends on metric
    let _ = (biv, rev); // Ensure both compute successfully
}

/// Test sandwich product (rotation/transformation)
#[test]
fn sandwich_product_works() {
    // Create a simple bivector for testing sandwich
    let biv = cga2d::expr!(|| e1 ^ e2)();
    let target = cga2d::expr!(|| e1)();

    // Apply sandwich: bivector.sandwich(target) = bivector * target * bivector.reverse()
    // For a bivector B and vector v: B * v * ~B
    let result = cga2d::expr!(|b: cga2d::Bivector, t: cga2d::Vector| b.sandwich(t))(biv, target);

    // Just verify the operation works and returns a vector-like result
    let _ = result; // Verify compilation and execution
}

/// Test parameterized expressions
#[test]
fn parameterized_expressions_work() {
    // Simple scaling
    let scale = cga2d::expr!(|v: cga2d::Vector| 2.0 * v);
    let input = cga2d::Vector {
        e0: 1.0,
        eI: 0.0,
        e1: 1.0,
        e2: 0.0,
    };
    let result = scale(input);

    assert!((result.e0 - 2.0).abs() < 1e-6);
    assert!((result.e1 - 2.0).abs() < 1e-6);

    // Addition with parameter
    let translate = cga2d::expr!(|v: cga2d::Vector| v + e1);
    let input = cga2d::Vector {
        e0: 0.0,
        eI: 0.0,
        e1: 1.0,
        e2: 0.0,
    };
    let result = translate(input);

    assert!((result.e1 - 2.0).abs() < 1e-6);
}

/// Test mixed operations
#[test]
fn mixed_operations_work() {
    // Combine addition, multiplication, and wedge
    let result = cga2d::expr!(|| (e1 + e2) ^ (e1 - e2))();
    // (e1 + e2) ^ (e1 - e2) = e1^e1 - e1^e2 + e2^e1 - e2^e2
    //                       = 0 - e12 - e12 - 0 = -2*e12
    let cga2d::Bivector { e12: coeff, .. } = result;
    assert!(
        (coeff + 2.0).abs() < 1e-6,
        "Expected coefficient -2.0, got {}",
        coeff
    );
}

/// Test scalar multiplication distributes correctly
#[test]
fn scalar_multiplication_distributes() {
    let v1 = cga2d::expr!(|| 2.0 * (e1 + e2))();
    let v2 = cga2d::expr!(|| 2.0 * e1 + 2.0 * e2)();

    assert_eq!(v1, v2, "Scalar multiplication should distribute");
}

/// Test associativity of addition
#[test]
fn addition_is_associative() {
    let r1 = cga2d::expr!(|| (e1 + e2) + e0)();
    let r2 = cga2d::expr!(|| e1 + (e2 + e0))();

    assert_eq!(r1, r2, "Addition should be associative");
}