geoit 0.0.2

Exact geometric algebra with governed multivectors
Documentation
//! All-algebra circuit tests using the builder API.
//!
//! For each algebra family: construct → govern → read_all → assert params match.
//! This is the S' certification that the construct-govern-read pipeline is exact.

use geoit::algebra::mv::Mv;
use geoit::algebra::signature::Signature;
use geoit::builder::*;
use geoit::governance::Expr;
use geoit::scalar::{Rat, Scalar};

/// Assert: construct(params) → govern → read_all == params
fn assert_circuit(gov: &NamedGovernance, class: &str, params: &[Scalar], label: &str) {
    let mv = gov
        .construct(class, params)
        .unwrap_or_else(|e| panic!("[{}] construct failed: {}", label, e));
    let geoit = gov
        .govern(&mv, class)
        .unwrap_or_else(|e| panic!("[{}] govern failed: {}", label, e));
    assert!(
        geoit.is_satisfied(),
        "[{}] predicate failed at {:?}",
        label,
        geoit.predicate().failing_indices()
    );
    let extracted = geoit
        .read_all()
        .unwrap_or_else(|e| panic!("[{}] read_all failed: {}", label, e));
    assert_eq!(extracted, params, "[{}] circuit didn't close", label);
}

/// Assert: Mv does NOT pass governance for the given class.
fn assert_rejects(gov: &NamedGovernance, class: &str, mv: &Mv, label: &str) {
    let result = gov.govern(mv, class);
    assert!(
        result.is_err() || !result.unwrap().is_satisfied(),
        "[{}] should have been rejected",
        label
    );
}

// ═══════════════════════════════════════════════════════════
// VGA
// ═══════════════════════════════════════════════════════════

fn vga3_gov() -> NamedGovernance {
    let alg = Algebra::new(Signature::new(0, 0, 3).unwrap());
    let class = GeomClassBuilder::new(&alg).grades(&[1]).build();
    let body = Expr::Add(
        Expr::add(
            Expr::mul(Expr::param(0), Expr::gen(0)),
            Expr::mul(Expr::param(1), Expr::gen(1)),
        ),
        Expr::mul(Expr::param(2), Expr::gen(2)),
    );
    GovernanceBuilder::new(alg)
        .class("Vector", class)
        .construction("Vector", "Vector", 3, body)
        .build()
}

#[test]
fn vga3_vector_integer() {
    let gov = vga3_gov();
    assert_circuit(
        &gov,
        "Vector",
        &[Scalar::from(3), Scalar::from(4), Scalar::from(5)],
        "VGA3 integer",
    );
}

#[test]
fn vga3_vector_rational() {
    let gov = vga3_gov();
    assert_circuit(
        &gov,
        "Vector",
        &[
            Scalar::Rat(Rat::new(1, 2)),
            Scalar::Rat(Rat::new(1, 3)),
            Scalar::Rat(Rat::new(1, 7)),
        ],
        "VGA3 rational",
    );
}

#[test]
fn vga3_vector_negative() {
    let gov = vga3_gov();
    assert_circuit(
        &gov,
        "Vector",
        &[Scalar::from(-1), Scalar::from(-2), Scalar::from(-3)],
        "VGA3 negative",
    );
}

#[test]
fn vga3_vector_zero() {
    let gov = vga3_gov();
    assert_circuit(
        &gov,
        "Vector",
        &[Scalar::from(0), Scalar::from(0), Scalar::from(0)],
        "VGA3 zero",
    );
}

#[test]
fn vga3_rejects_bivector() {
    let gov = vga3_gov();
    let bv = Mv::from_rat_terms(&[(0b011, Rat::from(1))]);
    assert_rejects(&gov, "Vector", &bv, "VGA3 bivector rejected");
}

// ═══════════════════════════════════════════════════════════
// PGA
// ═══════════════════════════════════════════════════════════

fn pga2_gov() -> NamedGovernance {
    let alg = Algebra::new(Signature::new(0, 1, 2).unwrap());
    use geoit::governance::poly::Poly;
    use geoit::governance::reading::VariableMap;
    let gm = 0b10u64; // grade 1
    let vm = VariableMap::for_grade_mask(alg.sig(), gm);
    // Inequality: v2² + v4² ≠ 0 (direction part nonzero)
    let mut weight = Poly::zero(vm.num_vars);
    if let Some(&v2) = vm.mask_to_var.get(&0b010) {
        let mut exp = vec![0u8; vm.num_vars];
        exp[v2] = 2;
        weight.add_term(exp, Rat::from(1));
    }
    if let Some(&v4) = vm.mask_to_var.get(&0b100) {
        let mut exp = vec![0u8; vm.num_vars];
        exp[v4] = 2;
        weight.add_term(exp, Rat::from(1));
    }
    let class = GeomClassBuilder::new(&alg)
        .grades(&[1])
        .inequality(weight)
        .build();
    let body = Expr::Add(
        Expr::add(
            Expr::mul(Expr::param(0), Expr::gen(1)),
            Expr::mul(Expr::param(1), Expr::gen(2)),
        ),
        Expr::mul(Expr::param(2), Expr::gen(0)),
    );
    GovernanceBuilder::new(alg)
        .class("Line", class)
        .construction("Line", "Line", 3, body)
        .build()
}

#[test]
fn pga2_line_circuit() {
    let gov = pga2_gov();
    assert_circuit(
        &gov,
        "Line",
        &[Scalar::from(1), Scalar::from(0), Scalar::from(0)],
        "PGA2 line",
    );
    assert_circuit(
        &gov,
        "Line",
        &[Scalar::from(1), Scalar::from(1), Scalar::from(-3)],
        "PGA2 line diagonal",
    );
}

// ═══════════════════════════════════════════════════════════
// CGA
// ═══════════════════════════════════════════════════════════

fn cga2_gov() -> NamedGovernance {
    let mut alg = Algebra::new(Signature::new(1, 0, 3).unwrap());
    let eo = Mv::from_rat_terms(&[(0b0001, Rat::new(1, 2)), (0b0010, Rat::new(1, 2))]);
    let einf = Mv::from_rat_terms(&[(0b0001, Rat::from(-1)), (0b0010, Rat::from(1))]);
    alg.add_derived("eo", eo);
    alg.add_derived("einf", einf.clone());

    let class = GeomClassBuilder::new(&alg)
        .grades(&[1])
        .null_constraint()
        .normalization(&einf, 1)
        .build();

    let eucl = Expr::Add(
        Expr::mul(Expr::param(0), Expr::gen(2)),
        Expr::mul(Expr::param(1), Expr::gen(3)),
    );
    let r_sq = Expr::Add(
        Expr::mul(Expr::param(0), Expr::param(0)),
        Expr::mul(Expr::param(1), Expr::param(1)),
    );
    let neg_half_r2 = Expr::mul(
        Box::new(Expr::Literal(Scalar::Rat(Rat::new(-1, 2)))),
        Box::new(r_sq),
    );
    let conformal = Expr::Mul(neg_half_r2, Expr::dgen(1));
    let body = Expr::Add(
        Box::new(Expr::Add(Box::new(eucl), Box::new(conformal))),
        Expr::dgen(0),
    );

    GovernanceBuilder::new(alg)
        .class("Point", class)
        .construction("Point", "Point", 2, body)
        .build()
}

#[test]
fn cga2_point_origin() {
    let gov = cga2_gov();
    assert_circuit(
        &gov,
        "Point",
        &[Scalar::from(0), Scalar::from(0)],
        "CGA2 origin",
    );
}

#[test]
fn cga2_point_integer() {
    let gov = cga2_gov();
    assert_circuit(
        &gov,
        "Point",
        &[Scalar::from(3), Scalar::from(4)],
        "CGA2 integer",
    );
}

#[test]
fn cga2_point_rational() {
    let gov = cga2_gov();
    assert_circuit(
        &gov,
        "Point",
        &[Scalar::Rat(Rat::new(1, 2)), Scalar::Rat(Rat::new(1, 3))],
        "CGA2 rational",
    );
}

#[test]
fn cga2_point_many() {
    let gov = cga2_gov();
    let cases: Vec<(i64, i64)> = vec![(0, 0), (1, 0), (0, 1), (3, 4), (-1, -1), (10, -7)];
    for (x, y) in cases {
        assert_circuit(
            &gov,
            "Point",
            &[Scalar::from(x), Scalar::from(y)],
            &format!("CGA2 ({},{})", x, y),
        );
    }
}

#[test]
fn cga2_point_null_verified() {
    // Verify the constructed point actually has norm² = 0
    let gov = cga2_gov();
    let mv = gov
        .construct("Point", &[Scalar::from(3), Scalar::from(4)])
        .unwrap();
    let sig = *gov.sig();
    let ns = geoit::algebra::ops::norm_squared(&mv, &sig);
    assert!(ns.is_zero(), "CGA point should be null, got norm² = {}", ns);
}

// ═══════════════════════════════════════════════════════════
// STA (both conventions)
// ═══════════════════════════════════════════════════════════

fn sta_gov(sig: Signature) -> NamedGovernance {
    let alg = Algebra::new(sig);
    let class = GeomClassBuilder::new(&alg).grades(&[1]).build();
    let body = Expr::Add(
        Expr::add(
            Expr::add(
                Expr::mul(Expr::param(0), Expr::gen(0)),
                Expr::mul(Expr::param(1), Expr::gen(1)),
            ),
            Expr::mul(Expr::param(2), Expr::gen(2)),
        ),
        Expr::mul(Expr::param(3), Expr::gen(3)),
    );
    GovernanceBuilder::new(alg)
        .class("FourVector", class)
        .construction("FourVector", "FourVector", 4, body)
        .build()
}

#[test]
fn sta_west_coast() {
    let gov = sta_gov(Signature::new(3, 0, 1).unwrap());
    assert_circuit(
        &gov,
        "FourVector",
        &[
            Scalar::from(5),
            Scalar::from(1),
            Scalar::from(0),
            Scalar::from(0),
        ],
        "STA-WC",
    );
}

#[test]
fn sta_east_coast() {
    let gov = sta_gov(Signature::new(1, 0, 3).unwrap());
    assert_circuit(
        &gov,
        "FourVector",
        &[
            Scalar::from(5),
            Scalar::from(3),
            Scalar::from(4),
            Scalar::from(0),
        ],
        "STA-EC",
    );
}

// ═══════════════════════════════════════════════════════════
// HIGH-DIMENSIONAL SPARSE
// ═══════════════════════════════════════════════════════════

fn qga3_gov() -> NamedGovernance {
    let alg = Algebra::new(Signature::new(3, 0, 6).unwrap());
    let class = GeomClassBuilder::new(&alg).grades(&[1]).build();
    // 9-parameter vector construction
    let mut body = Expr::mul(Expr::param(0), Expr::gen(0));
    for k in 1..9u8 {
        body = Expr::add(body, Expr::mul(Expr::param(k as usize), Expr::gen(k)));
    }
    GovernanceBuilder::new(alg)
        .class("Vector", class)
        .construction("Vector", "Vector", 9, *body)
        .build()
}

#[test]
fn qga3_vector_circuit() {
    let gov = qga3_gov();
    let params: Vec<Scalar> = (1..=9).map(|i| Scalar::from(i as i64)).collect();
    assert_circuit(&gov, "Vector", &params, "QGA3 vector");
}

#[test]
fn qga3_sparse_circuit() {
    // Most coefficients zero — tests sparse product optimization
    let gov = qga3_gov();
    let mut params: Vec<Scalar> = vec![Scalar::from(0); 9];
    params[0] = Scalar::from(1);
    params[8] = Scalar::from(-1);
    assert_circuit(&gov, "Vector", &params, "QGA3 sparse");
}