use crate::algebra::mv::Mv;
use crate::algebra::ops;
use crate::algebra::signature::Signature;
use crate::governance::construction::Construction;
use crate::governance::field::FieldOp;
use crate::governance::geoit::Geoit;
use crate::governance::geom_class::GeomClass;
use crate::governance::governance::Governance;
use crate::governance::reading::ExtractionError;
use crate::governance::rule::{ReadingDerivation, TransformOp, TransformRule};
use crate::scalar::Scalar;
pub fn is_constructible(s: &Scalar) -> bool {
match s {
Scalar::Rat(_) => true, Scalar::Big(_) => true, Scalar::Radical(r) => {
let deg = r.tower().total_degree();
deg > 0 && (deg & (deg - 1)) == 0
}
}
}
pub fn is_geoit_constructible(geoit: &Geoit) -> Result<bool, ExtractionError> {
let params = geoit.read_all()?;
Ok(params.iter().all(is_constructible))
}
#[derive(Clone, Debug)]
pub struct Pencil {
pub a: Mv,
pub b: Mv,
pub join: Mv,
pub sig: Signature,
}
impl Pencil {
pub fn new(a: Mv, b: Mv, sig: Signature) -> Self {
let join = ops::outer(&a, &b, &sig);
Pencil { a, b, join, sig }
}
pub fn at(&self, t: &Scalar) -> Mv {
let one = Scalar::from(1i64);
let one_minus_t = one - t.clone();
let part_a = self.a.scale(&one_minus_t);
let part_b = self.b.scale(t);
part_a + part_b
}
pub fn join_grade(&self) -> Option<u8> {
for (mask, coeff) in self.join.blades() {
if !coeff.is_zero() {
return Some(crate::algebra::blade_new::grade(mask));
}
}
None
}
}
#[derive(Clone, Debug)]
pub struct PencilLevel {
pub source_classes: Vec<usize>,
pub operation: PencilOp,
pub result_class: GeomClass,
}
#[derive(Clone, Debug)]
pub enum PencilOp {
Join,
Meet,
Interpolate(Scalar),
}
impl std::fmt::Display for PencilOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PencilOp::Join => write!(f, "Join (∧)"),
PencilOp::Meet => write!(f, "Meet (∨)"),
PencilOp::Interpolate(t) => write!(f, "Interpolate({})", t),
}
}
}
pub fn build_pencil_hierarchy(gov: &Governance) -> Vec<PencilLevel> {
let mut levels = Vec::new();
let n = gov.sig.n();
for i in 0..gov.geom_classes.len() {
for j in i..gov.geom_classes.len() {
let class_i = &gov.geom_classes[i];
let class_j = &gov.geom_classes[j];
let join_grades = crate::governance::geom_class::outer_result_grades(
class_i.grade_mask,
class_j.grade_mask,
n,
);
if join_grades != 0
&& join_grades != class_i.grade_mask
&& join_grades != class_j.grade_mask
{
levels.push(PencilLevel {
source_classes: vec![i, j],
operation: PencilOp::Join,
result_class: GeomClass {
grade_mask: join_grades,
equations: vec![],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: None,
},
});
}
let meet_grades = meet_result_grades(class_i.grade_mask, class_j.grade_mask, n);
if meet_grades != 0
&& meet_grades != class_i.grade_mask
&& meet_grades != class_j.grade_mask
{
levels.push(PencilLevel {
source_classes: vec![i, j],
operation: PencilOp::Meet,
result_class: GeomClass {
grade_mask: meet_grades,
equations: vec![],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: None,
},
});
}
}
}
levels
}
pub fn identity_construction(grade_mask: u64, sig: &Signature, class_index: usize) -> Construction {
use crate::governance::expr::Expr;
let vm = crate::governance::reading::VariableMap::for_grade_mask(sig, grade_mask);
let arity = vm.num_vars;
if arity == 0 {
return Construction {
class_index,
arity: 0,
body: Expr::Literal(Scalar::from(0i64)),
};
}
let mut terms: Vec<Box<Expr>> = Vec::new();
for (param_idx, &mask) in vm.var_to_mask.iter().enumerate() {
let mut blade_expr: Option<Box<Expr>> = None;
for gen in 0..sig.n() {
if mask & (1u64 << gen) != 0 {
let g = Expr::gen(gen);
blade_expr = Some(match blade_expr {
None => g,
Some(prev) => Expr::mul(prev, g),
});
}
}
let blade = blade_expr.unwrap_or(Expr::lit(1)); terms.push(Expr::mul(Expr::param(param_idx), blade));
}
let mut body = *terms.remove(0);
for t in terms {
body = Expr::Add(Box::new(body), t);
}
Construction {
class_index,
arity,
body,
}
}
pub fn extend_governance_with_joins(gov: &Governance) -> Governance {
let levels = build_pencil_hierarchy(gov);
if levels.is_empty() {
return gov.clone();
}
let mut new_gov = gov.clone();
let mut existing_masks: Vec<u64> = gov.geom_classes.iter().map(|c| c.grade_mask).collect();
for level in &levels {
let mask = level.result_class.grade_mask;
if existing_masks.contains(&mask) {
continue;
}
existing_masks.push(mask);
let new_class_idx = new_gov.geom_classes.len();
let class =
derive_join_constraints(gov, level.source_classes[0], level.source_classes[1], mask);
new_gov
.constructions
.push(identity_construction(mask, &gov.sig, new_class_idx));
new_gov.geom_classes.push(class);
}
new_gov
}
fn derive_join_constraints(
gov: &Governance,
class_a: usize,
class_b: usize,
join_mask: u64,
) -> GeomClass {
let vm = crate::governance::reading::VariableMap::for_grade_mask(&gov.sig, join_mask);
if vm.num_vars == 0 {
return GeomClass {
grade_mask: join_mask,
equations: vec![],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: None,
};
}
let norm =
crate::governance::geom_class::norm_poly(&gov.sig, join_mask, vm.num_vars, &vm.mask_to_var);
let candidates = vec![norm];
let constr_a = gov.constructions.iter().find(|c| c.class_index == class_a);
let constr_b = gov.constructions.iter().find(|c| c.class_index == class_b);
let (constr_a, constr_b) = match (constr_a, constr_b) {
(Some(a), Some(b)) => (a, b),
_ => {
return GeomClass {
grade_mask: join_mask,
equations: vec![],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: None,
}
}
};
let grid_size = 3; let grid_a = crate::governance::validation::grid_points(constr_a.arity, grid_size);
let grid_b = crate::governance::validation::grid_points(constr_b.arity, grid_size);
if grid_a.len() * grid_b.len() > 1000 {
return GeomClass {
grade_mask: join_mask,
equations: vec![],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: None,
};
}
let mut all_zero = vec![true; candidates.len()];
let mut all_nonzero = vec![true; candidates.len()];
for pa in &grid_a {
let params_a: Vec<Scalar> = pa.iter().map(|&r| Scalar::Rat(r)).collect();
let mv_a = constr_a.body.eval(&crate::governance::expr::EvalContext {
params: ¶ms_a,
sig: &gov.sig,
derived_gens: &gov.derived_gens,
constructions: &gov.constructions,
mv_table: &[],
governances: &[],
mv_governance_indices: &[],
embeddings: &[],
morphisms: &[],
probe_mv: None,
object_mv: None,
});
for pb in &grid_b {
let params_b: Vec<Scalar> = pb.iter().map(|&r| Scalar::Rat(r)).collect();
let mv_b = constr_b.body.eval(&crate::governance::expr::EvalContext {
params: ¶ms_b,
sig: &gov.sig,
derived_gens: &gov.derived_gens,
constructions: &gov.constructions,
mv_table: &[],
governances: &[],
mv_governance_indices: &[],
embeddings: &[],
morphisms: &[],
probe_mv: None,
object_mv: None,
});
let join = ops::outer(&mv_a, &mv_b, &gov.sig);
let values: Vec<crate::scalar::Rat> = vm
.var_to_mask
.iter()
.map(|&mask| {
join.coefficient(mask)
.try_as_rat()
.unwrap_or(crate::scalar::Rat::ZERO)
})
.collect();
for (i, cand) in candidates.iter().enumerate() {
let val = cand.eval(&values);
if !val.is_zero() {
all_zero[i] = false;
}
if val.is_zero() {
all_nonzero[i] = false;
}
}
}
}
let mut equations = Vec::new();
let mut inequalities = Vec::new();
for (i, cand) in candidates.into_iter().enumerate() {
if all_zero[i] {
equations.push(cand);
} else if all_nonzero[i] {
inequalities.push(cand);
}
}
GeomClass {
grade_mask: join_mask,
equations,
inequalities,
field_op: FieldOp::default(),
expected_profile: None,
}
}
pub fn meet(a: &Mv, b: &Mv, sig: &Signature) -> Mv {
let da = ops::dual(a, sig);
let db = ops::dual(b, sig);
let join_of_duals = ops::outer(&da, &db, sig);
ops::undual(&join_of_duals, sig)
}
pub fn meet_result_grades(a_mask: u64, b_mask: u64, n: u8) -> u64 {
let mut result = 0u64;
for j in 0..=n {
if a_mask & (1u64 << j) == 0 {
continue;
}
for k in 0..=n {
if b_mask & (1u64 << k) == 0 {
continue;
}
if j + k >= n {
let g = j + k - n;
result |= 1u64 << g;
}
}
}
result
}
pub fn build_full_hierarchy(
gov: &Governance,
max_depth: usize,
) -> (Governance, Vec<Vec<PencilLevel>>) {
let mut current = gov.clone();
let mut all_levels = Vec::new();
for _depth in 0..max_depth {
let levels = build_pencil_hierarchy(¤t);
if levels.is_empty() {
break;
}
let old_class_count = current.geom_classes.len();
current = extend_governance_with_joins(¤t);
let new_class_count = current.geom_classes.len();
all_levels.push(levels);
if new_class_count == old_class_count {
break;
}
}
(current, all_levels)
}
#[derive(Clone, Debug, PartialEq)]
pub enum PencilType {
Elliptic,
Parabolic,
Hyperbolic,
Homogeneous,
}
pub fn classify_pencil(a: &Mv, b: &Mv, class: &GeomClass, sig: &Signature) -> PencilType {
use crate::governance::reading::VariableMap;
if class.equations.is_empty() {
return PencilType::Homogeneous;
}
let var_map = VariableMap::for_grade_mask(sig, class.grade_mask);
let eval_at = |alpha_num: i128, alpha_den: i128| -> Vec<crate::scalar::Rat> {
let alpha = crate::scalar::Rat::new(alpha_num, alpha_den);
let one_minus = crate::scalar::Rat::ONE - alpha;
let interpolated = a.scale(&Scalar::Rat(alpha)) + b.scale(&Scalar::Rat(one_minus));
let values: Vec<crate::scalar::Rat> = var_map
.var_to_mask
.iter()
.map(|&mask| {
interpolated
.coefficient(mask)
.try_as_rat()
.unwrap_or(crate::scalar::Rat::ZERO)
})
.collect();
class.equations.iter().map(|eq| eq.eval(&values)).collect()
};
let at_0 = eval_at(0, 1); let at_half = eval_at(1, 2); let at_1 = eval_at(1, 1);
let all_zero = at_0
.iter()
.chain(at_half.iter())
.chain(at_1.iter())
.all(|r| r.is_zero());
if all_zero {
return PencilType::Homogeneous;
}
let mut max_degree = 0u32;
let mut has_positive_discriminant = false;
let mut has_negative_discriminant = false;
for i in 0..class.equations.len() {
let f0 = at_0[i];
let f1 = at_1[i];
let fhalf = at_half[i];
let c2 = f0 * crate::scalar::Rat::from(2) + f1 * crate::scalar::Rat::from(2)
- fhalf * crate::scalar::Rat::from(4);
let c1 = f1 - f0 - c2;
let _c0 = f0;
if !c2.is_zero() {
max_degree = max_degree.max(2);
let disc = c1 * c1 - _c0 * c2 * crate::scalar::Rat::from(4);
if disc.is_positive() {
has_positive_discriminant = true;
} else if disc.is_negative() {
has_negative_discriminant = true;
}
} else if !c1.is_zero() {
max_degree = max_degree.max(1);
}
}
if max_degree == 0 {
return PencilType::Homogeneous;
}
if has_negative_discriminant {
return PencilType::Elliptic;
}
if has_positive_discriminant {
return PencilType::Hyperbolic;
}
PencilType::Parabolic
}
pub fn is_pencil_constructible(level: &PencilLevel) -> bool {
for eq in &level.result_class.equations {
let deg = eq.max_degree();
if deg <= 1 {
continue;
}
if deg & (deg - 1) != 0 {
return false;
}
}
true
}
pub fn pencil_levels_to_rules(levels: &[PencilLevel], gov: &Governance) -> Vec<TransformRule> {
let mut rules = Vec::new();
let mut existing_masks: Vec<u64> = gov.geom_classes.iter().map(|c| c.grade_mask).collect();
let base_class_count = existing_masks.len();
for level in levels {
let mask = level.result_class.grade_mask;
if existing_masks.contains(&mask) {
continue;
}
existing_masks.push(mask);
let output_class = base_class_count + rules.len();
let (op, name) = match level.operation {
PencilOp::Join => (
TransformOp::Outer,
format!(
"Join_{}_{}",
level.source_classes[0], level.source_classes[1]
),
),
PencilOp::Meet => (
TransformOp::Regressive,
format!(
"Meet_{}_{}",
level.source_classes[0], level.source_classes[1]
),
),
PencilOp::Interpolate(_) => continue, };
rules.push(TransformRule {
name,
input_classes: level.source_classes.clone(),
output_class,
operation: op,
reading_derivation: ReadingDerivation::Rederive,
});
}
rules
}
#[cfg(test)]
mod tests {
use super::*;
use crate::governance::geom_class::{inner_product_poly, norm_poly};
use crate::governance::reading::VariableMap;
use crate::governance::{govern, Construction, Expr, GeomClass};
use crate::scalar::Rat;
fn cga2_gov() -> Governance {
let sig = Signature::new(1, 0, 3).unwrap();
let gm = 0b10u64;
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))]);
let vm = VariableMap::for_grade_mask(&sig, gm);
let null_eq = norm_poly(&sig, gm, vm.num_vars, &vm.mask_to_var);
let ip_eq = inner_product_poly(&einf, &sig, gm, Rat::ONE, vm.num_vars, &vm.mask_to_var);
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),
);
Governance {
sig,
derived_gens: vec![eo, einf],
geom_classes: vec![GeomClass {
grade_mask: gm,
equations: vec![null_eq, ip_eq],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: None,
}],
constructions: vec![Construction {
class_index: 0,
arity: 2,
body,
}],
probe: None,
transform_rules: vec![],
}
}
#[test]
fn rational_is_constructible() {
assert!(is_constructible(&Scalar::from(3i64)));
assert!(is_constructible(&Scalar::Rat(Rat::new(1, 7))));
}
#[test]
fn surd_is_constructible() {
let s = Scalar::Radical(crate::scalar::radical::RadicalElement::sqrt(Rat::from(2)));
assert!(is_constructible(&s));
}
#[test]
fn cube_root_not_constructible() {
let s = Scalar::Radical(crate::scalar::radical::RadicalElement::cbrt(Rat::from(2)));
assert!(!is_constructible(&s));
}
#[test]
fn degree_4_is_constructible() {
let s2 = crate::scalar::radical::RadicalElement::sqrt(Rat::from(2));
let s3 = crate::scalar::radical::RadicalElement::sqrt(Rat::from(3));
let s = Scalar::Radical(s2.add(&s3));
assert!(is_constructible(&s));
}
#[test]
fn geoit_constructibility() {
let gov = cga2_gov();
let params = vec![Scalar::from(3i64), Scalar::from(4i64)];
let mv = gov.construct(0, ¶ms).unwrap();
let geoit = govern(&mv, &gov, 0).unwrap();
assert!(is_geoit_constructible(&geoit).unwrap());
}
#[test]
fn geoit_rational_constructible() {
let gov = cga2_gov();
let params = vec![Scalar::Rat(Rat::new(1, 3)), Scalar::Rat(Rat::new(1, 7))];
let mv = gov.construct(0, ¶ms).unwrap();
let geoit = govern(&mv, &gov, 0).unwrap();
assert!(is_geoit_constructible(&geoit).unwrap());
}
#[test]
fn pencil_endpoints() {
let sig = Signature::new(0, 0, 3).unwrap();
let a = Mv::from_rat_terms(&[(0b001, Rat::from(1))]);
let b = Mv::from_rat_terms(&[(0b010, Rat::from(1))]);
let p = Pencil::new(a.clone(), b.clone(), sig);
assert_eq!(p.at(&Scalar::from(0i64)), a);
assert_eq!(p.at(&Scalar::from(1i64)), b);
}
#[test]
fn pencil_midpoint() {
let sig = Signature::new(0, 0, 3).unwrap();
let a = Mv::from_rat_terms(&[(0b001, Rat::from(2))]);
let b = Mv::from_rat_terms(&[(0b001, Rat::from(4))]);
let p = Pencil::new(a, b, sig);
let mid = p.at(&Scalar::Rat(Rat::new(1, 2)));
assert_eq!(mid.coefficient(0b001), Scalar::from(3i64));
}
#[test]
fn pencil_join_grade() {
let sig = Signature::new(0, 0, 3).unwrap();
let a = Mv::from_rat_terms(&[(0b001, Rat::from(1))]); let b = Mv::from_rat_terms(&[(0b010, Rat::from(1))]); let p = Pencil::new(a, b, sig);
assert_eq!(p.join_grade(), Some(2)); }
#[test]
fn cga_point_pencil() {
let gov = cga2_gov();
let p1 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let pencil = Pencil::new(p1, p2, gov.sig);
assert_eq!(pencil.join_grade(), Some(2));
assert!(!pencil.join.is_zero());
}
#[test]
fn cga_point_pencil_collinear() {
let gov = cga2_gov();
let einf = &gov.derived_gens[1];
let p1 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p3 = gov
.construct(0, &[Scalar::from(2i64), Scalar::from(0i64)])
.unwrap();
let line = ops::outer(&ops::outer(&p1, &p2, &gov.sig), einf, &gov.sig);
let test = ops::outer(&p3, &line, &gov.sig);
assert!(test.is_zero(), "collinear point should lie on the CGA line");
}
#[test]
fn cga_point_pencil_noncollinear() {
let gov = cga2_gov();
let einf = &gov.derived_gens[1];
let p1 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p3 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(1i64)])
.unwrap();
let line = ops::outer(&ops::outer(&p1, &p2, &gov.sig), einf, &gov.sig);
let test = ops::outer(&p3, &line, &gov.sig);
assert!(
!test.is_zero(),
"non-collinear point should NOT lie on the CGA line"
);
}
#[test]
fn cga_circle_from_three_points() {
let gov = cga2_gov();
let p1 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(1i64)])
.unwrap();
let p3 = gov
.construct(0, &[Scalar::from(-1i64), Scalar::from(0i64)])
.unwrap();
let circle = ops::outer(&ops::outer(&p1, &p2, &gov.sig), &p3, &gov.sig);
assert!(
!circle.is_zero(),
"circle through 3 non-collinear points should be nonzero"
);
for (mask, coeff) in circle.blades() {
if !coeff.is_zero() {
assert_eq!(
crate::algebra::blade_new::grade(mask),
3,
"circle should be grade 3, got grade {} at mask {:#b}",
crate::algebra::blade_new::grade(mask),
mask
);
}
}
}
#[test]
fn cga_fourth_point_on_circle() {
let gov = cga2_gov();
let p1 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(1i64)])
.unwrap();
let p3 = gov
.construct(0, &[Scalar::from(-1i64), Scalar::from(0i64)])
.unwrap();
let p4 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(-1i64)])
.unwrap();
let circle = ops::outer(&ops::outer(&p1, &p2, &gov.sig), &p3, &gov.sig);
let test = ops::outer(&p4, &circle, &gov.sig);
assert!(
test.is_zero(),
"fourth point on unit circle should be incident"
);
}
#[test]
fn cga_point_not_on_circle() {
let gov = cga2_gov();
let p1 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(1i64)])
.unwrap();
let p3 = gov
.construct(0, &[Scalar::from(-1i64), Scalar::from(0i64)])
.unwrap();
let p_off = gov
.construct(0, &[Scalar::from(2i64), Scalar::from(2i64)])
.unwrap();
let circle = ops::outer(&ops::outer(&p1, &p2, &gov.sig), &p3, &gov.sig);
let test = ops::outer(&p_off, &circle, &gov.sig);
assert!(
!test.is_zero(),
"point at (2,2) should NOT be on the unit circle"
);
}
#[test]
fn hierarchy_cga2_point() {
let gov = cga2_gov();
let levels = build_pencil_hierarchy(&gov);
assert!(!levels.is_empty(), "should find at least one pencil level");
assert!(
levels[0].result_class.grade_permitted(2),
"join of points should be grade 2"
);
}
#[test]
fn constructibility_chain() {
let sig = Signature::new(0, 0, 3).unwrap();
let gov = Governance {
sig,
derived_gens: vec![],
geom_classes: vec![GeomClass::grades_only(&[1])],
constructions: vec![Construction {
class_index: 0,
arity: 3,
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)),
),
}],
probe: None,
transform_rules: vec![],
};
let v1 = gov
.construct(
0,
&[Scalar::from(0i64), Scalar::from(0i64), Scalar::from(0i64)],
)
.unwrap();
let v2 = gov
.construct(
0,
&[Scalar::from(3i64), Scalar::from(6i64), Scalar::from(9i64)],
)
.unwrap();
let pencil = Pencil::new(v1, v2, sig);
let v_interp = pencil.at(&Scalar::Rat(Rat::new(1, 3)));
let geoit = govern(&v_interp, &gov, 0).unwrap();
let extracted = geoit.read_all().unwrap();
assert_eq!(extracted[0], Scalar::from(1i64));
assert_eq!(extracted[1], Scalar::from(2i64));
assert_eq!(extracted[2], Scalar::from(3i64));
assert!(is_geoit_constructible(&geoit).unwrap());
}
#[test]
fn identity_construction_vga3_grade1() {
let sig = Signature::new(0, 0, 3).unwrap();
let c = identity_construction(0b10, &sig, 0); assert_eq!(c.arity, 3); let params = vec![Scalar::from(1i64), Scalar::from(2i64), Scalar::from(3i64)];
let ctx = crate::governance::expr::EvalContext {
params: ¶ms,
sig: &sig,
derived_gens: &[],
constructions: &[],
mv_table: &[],
governances: &[],
mv_governance_indices: &[],
embeddings: &[],
morphisms: &[],
probe_mv: None,
object_mv: None,
};
let mv = c.body.eval(&ctx);
assert_eq!(mv.coefficient(0b001), Scalar::from(1i64));
assert_eq!(mv.coefficient(0b010), Scalar::from(2i64));
assert_eq!(mv.coefficient(0b100), Scalar::from(3i64));
}
#[test]
fn identity_construction_grade2() {
let sig = Signature::new(0, 0, 3).unwrap();
let c = identity_construction(0b100, &sig, 0); assert_eq!(c.arity, 3); }
#[test]
fn extend_adds_join_class() {
let gov = cga2_gov();
assert_eq!(gov.geom_classes.len(), 1); let ext = extend_governance_with_joins(&gov);
assert!(
ext.geom_classes.len() > 1,
"should add at least one join class"
);
let join_class = &ext.geom_classes[1];
assert!(
join_class.grade_permitted(2),
"Point∧Point should be grade 2"
);
}
#[test]
fn pe4_govern_join_of_two_points() {
let gov = cga2_gov();
let ext = extend_governance_with_joins(&gov);
let p1 = ext
.construct(0, &[Scalar::from(0i64), Scalar::from(0i64)])
.unwrap();
let p2 = ext
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let pp = ops::outer(&p1, &p2, &ext.sig);
assert!(!pp.is_zero(), "join of distinct points should be nonzero");
let join_class_idx = 1; let geoit = govern(&pp, &ext, join_class_idx).unwrap();
let readings = geoit.read_all().unwrap();
assert!(!readings.is_empty(), "should extract blade coefficients");
assert!(
is_geoit_constructible(&geoit).unwrap(),
"join of rational points should be constructible"
);
}
#[test]
fn pe4_recursive_extension() {
let gov = cga2_gov();
let ext1 = extend_governance_with_joins(&gov);
assert!(ext1.geom_classes.len() >= 2);
let ext2 = extend_governance_with_joins(&ext1);
assert!(
ext2.geom_classes.len() >= 3,
"second extension should add grade-3 class, got {} classes",
ext2.geom_classes.len()
);
let circle_idx = ext2
.geom_classes
.iter()
.position(|c| c.grade_permitted(3))
.expect("should have a grade-3 class");
let p1 = ext2
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p2 = ext2
.construct(0, &[Scalar::from(0i64), Scalar::from(1i64)])
.unwrap();
let p3 = ext2
.construct(0, &[Scalar::from(-1i64), Scalar::from(0i64)])
.unwrap();
let circle = ops::outer(&ops::outer(&p1, &p2, &ext2.sig), &p3, &ext2.sig);
assert!(!circle.is_zero());
let geoit = govern(&circle, &ext2, circle_idx).unwrap();
let readings = geoit.read_all().unwrap();
assert!(
!readings.is_empty(),
"should extract circle blade coefficients"
);
assert!(
is_geoit_constructible(&geoit).unwrap(),
"circle through rational points should be constructible"
);
}
#[test]
fn pe4_full_chain_with_incidence() {
let gov = cga2_gov();
let ext = extend_governance_with_joins(&extend_governance_with_joins(&gov));
let circle_idx = ext
.geom_classes
.iter()
.position(|c| c.grade_permitted(3))
.expect("need grade-3 class");
let p1 = ext
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p2 = ext
.construct(0, &[Scalar::from(0i64), Scalar::from(1i64)])
.unwrap();
let p3 = ext
.construct(0, &[Scalar::from(-1i64), Scalar::from(0i64)])
.unwrap();
let p4 = ext
.construct(0, &[Scalar::from(0i64), Scalar::from(-1i64)])
.unwrap();
let p_off = ext
.construct(0, &[Scalar::from(2i64), Scalar::from(2i64)])
.unwrap();
let circle = ops::outer(&ops::outer(&p1, &p2, &ext.sig), &p3, &ext.sig);
let circle_geoit = govern(&circle, &ext, circle_idx).unwrap();
assert!(is_geoit_constructible(&circle_geoit).unwrap());
assert!(
ops::outer(&p4, &circle, &ext.sig).is_zero(),
"P4 should be on the circle"
);
assert!(
!ops::outer(&p_off, &circle, &ext.sig).is_zero(),
"P_off should NOT be on the circle"
);
let p1_geoit = govern(&p1, &ext, 0).unwrap();
let p4_geoit = govern(&p4, &ext, 0).unwrap();
assert!(is_geoit_constructible(&p1_geoit).unwrap());
assert!(is_geoit_constructible(&p4_geoit).unwrap());
}
#[test]
fn meet_vga3_bivectors() {
let sig = Signature::new(0, 0, 3).unwrap();
let b1 = Mv::from_rat_terms(&[(0b011, Rat::from(1))]); let b2 = Mv::from_rat_terms(&[(0b101, Rat::from(1))]); let m = meet(&b1, &b2, &sig);
assert!(
!m.is_zero(),
"meet of two bivectors sharing a factor should be nonzero"
);
for (mask, coeff) in m.blades() {
if !coeff.is_zero() {
assert_eq!(
crate::algebra::blade_new::grade(mask),
1,
"meet of two grade-2 in 3-gen should be grade 1"
);
}
}
}
#[test]
fn meet_result_grades_vga3() {
let result = meet_result_grades(0b100, 0b100, 3);
assert_eq!(result, 0b10); }
#[test]
fn meet_result_grades_cga2() {
let result = meet_result_grades(0b1000, 0b1000, 4);
assert_eq!(result, 0b100); }
#[test]
fn meet_cga2_circles() {
let gov = cga2_gov();
let p1 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(1i64)])
.unwrap();
let p3 = gov
.construct(0, &[Scalar::from(-1i64), Scalar::from(0i64)])
.unwrap();
let p4 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(-1i64)])
.unwrap();
let p5 = gov
.construct(0, &[Scalar::from(2i64), Scalar::from(0i64)])
.unwrap();
let circle1 = ops::outer(&ops::outer(&p1, &p2, &gov.sig), &p3, &gov.sig);
let circle2 = ops::outer(&ops::outer(&p1, &p4, &gov.sig), &p5, &gov.sig);
let intersection = meet(&circle1, &circle2, &gov.sig);
assert!(
!intersection.is_zero(),
"two intersecting circles should have nonzero meet"
);
}
#[test]
fn inherited_constraints_nonempty() {
let gov = cga2_gov();
let ext = extend_governance_with_joins(&gov);
assert!(ext.geom_classes.len() >= 2);
let join_class = &ext.geom_classes[1];
let has_constraints =
!join_class.equations.is_empty() || !join_class.inequalities.is_empty();
assert!(join_class.grade_permitted(2));
let _ = has_constraints; }
#[test]
fn inherited_constraints_vga3() {
let sig = Signature::new(0, 0, 3).unwrap();
let gov = Governance {
sig,
derived_gens: vec![],
geom_classes: vec![GeomClass::grades_only(&[1])],
constructions: vec![Construction {
class_index: 0,
arity: 3,
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)),
),
}],
probe: None,
transform_rules: vec![],
};
let ext = extend_governance_with_joins(&gov);
assert!(ext.geom_classes.len() >= 2);
let bv_class = &ext.geom_classes[1];
assert!(bv_class.grade_permitted(2));
assert!(
bv_class.equations.is_empty(),
"VGA bivector norm should not be constrained to zero"
);
}
#[test]
fn constraint_inheritance_governs_correctly() {
let gov = cga2_gov();
let ext = extend_governance_with_joins(&gov);
let p1 = ext
.construct(0, &[Scalar::from(0i64), Scalar::from(0i64)])
.unwrap();
let p2 = ext
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let pp = ops::outer(&p1, &p2, &ext.sig);
let join_class_idx = 1;
let result = govern(&pp, &ext, join_class_idx);
assert!(
result.is_ok(),
"join should pass governance with inherited constraints: {:?}",
result.err()
);
}
#[test]
fn full_hierarchy_cga2_produces_levels() {
let gov = cga2_gov();
let (ext, all_levels) = build_full_hierarchy(&gov, 5);
assert!(
!all_levels.is_empty(),
"CGA(2) should produce at least one hierarchy level"
);
assert!(
ext.geom_classes.len() > gov.geom_classes.len(),
"extended governance should have more classes"
);
}
#[test]
fn full_hierarchy_fixpoint() {
let sig = Signature::new(0, 0, 3).unwrap();
let gov = Governance {
sig,
derived_gens: vec![],
geom_classes: vec![GeomClass::grades_only(&[1])],
constructions: vec![Construction {
class_index: 0,
arity: 3,
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)),
),
}],
probe: None,
transform_rules: vec![],
};
let (ext, all_levels) = build_full_hierarchy(&gov, 10);
assert!(
ext.geom_classes.len() <= 4,
"VGA(3) should have at most 4 class levels"
);
assert!(all_levels.len() >= 1);
}
#[test]
fn classify_pencil_cga2_points() {
let gov = cga2_gov();
let p1 = gov
.construct(0, &[Scalar::from(0i64), Scalar::from(0i64)])
.unwrap();
let p2 = gov
.construct(0, &[Scalar::from(1i64), Scalar::from(0i64)])
.unwrap();
let class = &gov.geom_classes[0];
let pt = classify_pencil(&p1, &p2, class, &gov.sig);
assert_ne!(
pt,
PencilType::Homogeneous,
"pencil of two CGA points should not be homogeneous"
);
}
#[test]
fn classify_pencil_vga_vectors_homogeneous() {
let sig = Signature::new(0, 0, 3).unwrap();
let class = GeomClass::grades_only(&[1]);
let a = Mv::from_rat_terms(&[(0b001, Rat::from(1))]);
let b = Mv::from_rat_terms(&[(0b010, Rat::from(1))]);
assert_eq!(
classify_pencil(&a, &b, &class, &sig),
PencilType::Homogeneous
);
}
#[test]
fn pencil_constructibility_join_level() {
let level = PencilLevel {
source_classes: vec![0, 0],
operation: PencilOp::Join,
result_class: GeomClass::grades_only(&[2]),
};
assert!(is_pencil_constructible(&level));
}
#[test]
fn pencil_levels_to_rules_produces_rules() {
let gov = cga2_gov();
let levels = build_pencil_hierarchy(&gov);
let rules = pencil_levels_to_rules(&levels, &gov);
let has_join = rules
.iter()
.any(|r| matches!(r.operation, TransformOp::Outer));
assert!(
has_join || levels.is_empty(),
"should produce join rules from pencil levels"
);
}
}