pub mod category;
pub mod compile;
pub mod composition;
pub mod construction;
pub mod expr;
pub mod family;
pub mod field;
pub mod geoit;
pub mod geom_class;
#[allow(clippy::module_inception)]
pub mod governance;
pub mod groebner;
pub mod morphism;
pub mod pencil;
pub mod phase;
pub mod poly;
pub mod predicate;
pub mod profile;
pub mod reading;
pub mod rotor;
pub mod rule;
pub mod triangular;
pub mod validation;
pub use self::category::GovernanceCategory;
pub use self::composition::{compose, Embedding, EmbeddingError};
pub use self::construction::Construction;
pub use self::expr::Expr;
pub use self::expr::{ContextShape, EvalError};
pub use self::family::{GovernanceFamily, GovernanceRegistry};
pub use self::field::{FieldOp, ProbeSpec};
pub use self::geoit::Geoit;
pub use self::geom_class::GeomClass;
pub use self::governance::Governance;
pub use self::groebner::GroebnerError;
pub use self::phase::Phase;
pub use self::predicate::Predicate;
pub use self::profile::GeneratorProfile;
pub use self::reading::{ExtractionError, ExtractionMap, ReadingRules, VariableMap};
pub use self::rule::{apply_transform, ProofTerm, TransformOp, TransformRule};
use crate::algebra::blade_new::grade;
use crate::algebra::mv::Mv;
use crate::scalar::{Rat, Scalar};
#[derive(Clone, Debug)]
pub enum GovernanceError {
ClassOutOfRange {
index: usize,
len: usize,
},
BladeMaskOutOfRange {
mask: u64,
max_generators: u8,
},
GradeViolation {
mask: u64,
grade: u8,
},
EquationsFailed {
class_index: usize,
failures: Vec<(usize, Scalar)>,
},
InequalitiesFailed {
class_index: usize,
failures: Vec<(usize, Scalar)>,
},
ReadingDerivation(reading::ExtractionError),
ProfileMismatch {
class_index: usize,
expected: profile::GeneratorProfile,
actual: profile::GeneratorProfile,
},
}
pub fn govern(mv: &Mv, gov: &Governance, class_index: usize) -> Result<Geoit, GovernanceError> {
govern_shared(mv, std::sync::Arc::new(gov.clone()), class_index)
}
pub fn govern_shared(
mv: &Mv,
gov: std::sync::Arc<Governance>,
class_index: usize,
) -> Result<Geoit, GovernanceError> {
if class_index >= gov.geom_classes.len() {
return Err(GovernanceError::ClassOutOfRange {
index: class_index,
len: gov.geom_classes.len(),
});
}
let n = gov.sig.n();
let max_mask = if n >= 64 { u64::MAX } else { (1u64 << n) - 1 };
for (mask, _) in mv.blades() {
if mask > max_mask {
return Err(GovernanceError::BladeMaskOutOfRange {
mask,
max_generators: n,
});
}
}
let class = &gov.geom_classes[class_index];
for (mask, coeff) in mv.blades() {
if !coeff.is_zero() {
let g = grade(mask);
if !class.grade_permitted(g) {
return Err(GovernanceError::GradeViolation { mask, grade: g });
}
}
}
let var_map = VariableMap::for_grade_mask(&gov.sig, class.grade_mask);
let values: Vec<Rat> = var_map
.var_to_mask
.iter()
.map(|&mask| mv.coefficient(mask).try_as_rat().unwrap_or(Rat::ZERO))
.collect();
let eq_residuals: Vec<Scalar> = class
.equations
.iter()
.map(|poly| Scalar::Rat(poly.eval(&values)))
.collect();
let ineq_values: Vec<Scalar> = class
.inequalities
.iter()
.map(|poly| Scalar::Rat(poly.eval(&values)))
.collect();
let equations_satisfied: Vec<bool> = eq_residuals.iter().map(|r| r.is_zero()).collect();
let inequalities_satisfied: Vec<bool> = ineq_values.iter().map(|v| !v.is_zero()).collect();
let pred = Predicate::new(
class_index,
&eq_residuals,
&ineq_values,
equations_satisfied.clone(),
inequalities_satisfied.clone(),
eq_residuals.iter().any(|r| r.is_big())
|| ineq_values.iter().any(|v| v.is_big())
|| mv.blades().any(|(_, c)| c.is_big()),
);
let eq_failures: Vec<(usize, Scalar)> = equations_satisfied
.iter()
.enumerate()
.filter(|(_, &s)| !s)
.map(|(i, _)| (i, eq_residuals[i].clone()))
.collect();
let ineq_failures: Vec<(usize, Scalar)> = inequalities_satisfied
.iter()
.enumerate()
.filter(|(_, &s)| !s)
.map(|(i, _)| (i, ineq_values[i].clone()))
.collect();
if !eq_failures.is_empty() {
return Err(GovernanceError::EquationsFailed {
class_index,
failures: eq_failures,
});
}
if !ineq_failures.is_empty() {
return Err(GovernanceError::InequalitiesFailed {
class_index,
failures: ineq_failures,
});
}
let ph = phase::compute_phase(mv, &gov.sig);
let prof = profile::GeneratorProfile::compute(mv, &gov.sig);
if let Some(ref expected) = class.expected_profile {
let unexpected = prof.all_participation() & !expected.all_participation();
if unexpected != 0 {
return Err(GovernanceError::ProfileMismatch {
class_index,
expected: *expected,
actual: prof,
});
}
}
let construction = gov
.constructions
.iter()
.find(|c| c.class_index == class_index);
let rules = if let Some(constr) = construction {
if gov.sig.dimension() <= 32 {
ReadingRules::derive_from_groebner(class, constr, &gov.sig, &gov.derived_gens)
.map_err(GovernanceError::ReadingDerivation)?
} else {
ReadingRules::derive_from_probing(constr, &gov.sig, &gov.derived_gens)
.map_err(GovernanceError::ReadingDerivation)?
}
} else {
ReadingRules::derive_from_grade_mask(class, 0, &gov.sig)
};
Ok(Geoit {
mv: mv.clone(),
governance: gov,
predicate: pred,
phase: ph,
readings: rules,
profile: prof,
proof: rule::ProofTerm::Checked { class_index },
})
}
impl std::fmt::Display for GovernanceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GovernanceError::ClassOutOfRange { index, len } => {
write!(f, "class_index {} out of range (have {})", index, len)
}
GovernanceError::BladeMaskOutOfRange {
mask,
max_generators,
} => write!(
f,
"blade mask {:#b} exceeds {} generators",
mask, max_generators
),
GovernanceError::GradeViolation { mask, grade } => {
write!(f, "blade {:#b} (grade {}) not permitted", mask, grade)
}
GovernanceError::EquationsFailed {
class_index,
failures,
} => {
write!(f, "class {} equations failed: ", class_index)?;
for (i, (idx, residual)) in failures.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "eq[{}] residual={}", idx, residual)?;
}
Ok(())
}
GovernanceError::InequalitiesFailed {
class_index,
failures,
} => {
write!(f, "class {} inequalities failed: ", class_index)?;
for (i, (idx, value)) in failures.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "ineq[{}] value={}", idx, value)?;
}
Ok(())
}
GovernanceError::ReadingDerivation(e) => write!(f, "reading derivation: {}", e),
GovernanceError::ProfileMismatch {
class_index,
expected,
actual,
} => write!(
f,
"class {} profile mismatch: expected {}, got {}",
class_index, expected, actual
),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::algebra::signature::Signature;
use crate::scalar::Rat;
fn vga3_gov() -> Governance {
Governance {
sig: Signature::new(0, 0, 3).unwrap(),
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![],
}
}
#[test]
fn govern_valid() {
let gov = vga3_gov();
let mv = gov
.construct(
0,
&[Scalar::from(3i64), Scalar::from(4i64), Scalar::from(5i64)],
)
.unwrap();
let geoit = govern(&mv, &gov, 0).unwrap();
assert_eq!(geoit.phase(), Phase::Commitment);
assert!(geoit.is_satisfied());
}
#[test]
fn govern_invalid_mv() {
let gov = vga3_gov();
let bv = Mv::from_rat_terms(&[(0b011, Rat::from(1))]);
let result = govern(&bv, &gov, 0);
assert!(result.is_err());
}
#[test]
fn govern_class_out_of_range() {
let gov = vga3_gov();
let mv = Mv::new();
assert!(matches!(
govern(&mv, &gov, 99),
Err(GovernanceError::ClassOutOfRange { .. })
));
}
#[test]
fn govern_blade_out_of_range() {
let gov = vga3_gov();
let mv = Mv::from_rat_terms(&[(0b1000, Rat::from(1))]);
assert!(matches!(
govern(&mv, &gov, 0),
Err(GovernanceError::BladeMaskOutOfRange { .. })
));
}
#[test]
fn govern_profile_match_passes() {
let sig = Signature::new(0, 0, 3).unwrap();
let expected = profile::GeneratorProfile {
i_participation: 0,
d_participation: 0,
h_participation: 0b111,
};
let gov = Governance {
sig,
derived_gens: vec![],
geom_classes: vec![GeomClass {
grade_mask: 0b10,
equations: vec![],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: Some(expected),
}],
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 mv = gov
.construct(
0,
&[Scalar::from(1i64), Scalar::from(2i64), Scalar::from(3i64)],
)
.unwrap();
let geoit = govern(&mv, &gov, 0).unwrap();
assert!(geoit.is_satisfied());
}
#[test]
fn govern_profile_mismatch_rejected() {
let sig = Signature::new(1, 0, 3).unwrap(); let h_only = profile::GeneratorProfile {
i_participation: 0,
d_participation: 0,
h_participation: 0b1110, };
let gov = Governance {
sig,
derived_gens: vec![],
geom_classes: vec![GeomClass {
grade_mask: 0b10,
equations: vec![],
inequalities: vec![],
field_op: FieldOp::default(),
expected_profile: Some(h_only),
}],
constructions: vec![],
probe: None,
transform_rules: vec![],
};
let mv = Mv::from_rat_terms(&[(0b0001, Rat::from(1)), (0b0010, Rat::from(2))]);
assert!(matches!(
govern(&mv, &gov, 0),
Err(GovernanceError::ProfileMismatch { .. })
));
}
#[test]
fn govern_no_expected_profile_backward_compatible() {
let gov = vga3_gov();
assert!(gov.geom_classes[0].expected_profile.is_none());
let mv = gov
.construct(
0,
&[Scalar::from(1i64), Scalar::from(0i64), Scalar::from(0i64)],
)
.unwrap();
assert!(govern(&mv, &gov, 0).is_ok());
}
}