use crate::algebra::mv::Mv;
use crate::algebra::signature::Signature;
use crate::governance::construction::{Construction, ConstructionError};
use crate::governance::expr::ContextShape;
use crate::governance::expr::Expr;
use crate::governance::field::FieldOp;
use crate::governance::geoit::Geoit;
use crate::governance::geom_class::GeomClass;
use crate::governance::geom_class::{inner_product_poly, norm_poly};
use crate::governance::governance::Governance;
use crate::governance::poly::Poly;
use crate::governance::profile::GeneratorProfile;
use crate::governance::reading::VariableMap;
use crate::governance::rule::{apply_transform, TransformOp, TransformRule};
use crate::governance::{self, GovernanceError};
use crate::scalar::{Rat, Scalar};
use super::algebra::Algebra;
pub struct GeomClassBuilder<'a> {
algebra: &'a Algebra,
grades: Vec<u8>,
equations: Vec<Poly>,
inequalities: Vec<Poly>,
field_op: FieldOp,
expected_profile: Option<GeneratorProfile>,
}
impl<'a> GeomClassBuilder<'a> {
pub fn new(algebra: &'a Algebra) -> Self {
GeomClassBuilder {
algebra,
grades: Vec::new(),
equations: Vec::new(),
inequalities: Vec::new(),
field_op: FieldOp::default(),
expected_profile: None,
}
}
pub fn grades(mut self, gs: &[u8]) -> Self {
self.grades = gs.to_vec();
self
}
pub fn equation(mut self, poly: Poly) -> Self {
self.equations.push(poly);
self
}
pub fn inequality(mut self, poly: Poly) -> Self {
self.inequalities.push(poly);
self
}
pub fn null_constraint(mut self) -> Self {
let gm = self.grade_mask();
let vm = VariableMap::for_grade_mask(self.algebra.sig(), gm);
let np = norm_poly(self.algebra.sig(), gm, vm.num_vars, &vm.mask_to_var);
if !np.is_zero() {
self.equations.push(np);
}
self
}
pub fn normalization(mut self, reference: &Mv, value: i64) -> Self {
let gm = self.grade_mask();
let vm = VariableMap::for_grade_mask(self.algebra.sig(), gm);
let ip = inner_product_poly(
reference,
self.algebra.sig(),
gm,
Rat::from(value),
vm.num_vars,
&vm.mask_to_var,
);
if !ip.is_zero() {
self.equations.push(ip);
}
self
}
pub fn field_op(mut self, op: FieldOp) -> Self {
self.field_op = op;
self
}
pub fn expected_profile(mut self, profile: GeneratorProfile) -> Self {
self.expected_profile = Some(profile);
self
}
pub fn build(self) -> GeomClass {
GeomClass {
grade_mask: self.grade_mask(),
equations: self.equations,
inequalities: self.inequalities,
field_op: self.field_op,
expected_profile: self.expected_profile,
}
}
fn grade_mask(&self) -> u64 {
let mut mask = 0u64;
for &g in &self.grades {
mask |= 1u64 << g;
}
mask
}
}
pub struct GovernanceBuilder {
algebra: Algebra,
class_names: Vec<String>,
classes: Vec<GeomClass>,
construction_names: Vec<String>,
constructions: Vec<Construction>,
probe: Option<crate::governance::field::ProbeSpec>,
rule_names: Vec<String>,
rules: Vec<TransformRule>,
}
impl GovernanceBuilder {
pub fn new(algebra: Algebra) -> Self {
GovernanceBuilder {
algebra,
class_names: Vec::new(),
classes: Vec::new(),
construction_names: Vec::new(),
constructions: Vec::new(),
probe: None,
rule_names: Vec::new(),
rules: Vec::new(),
}
}
pub fn class(mut self, name: &str, class: GeomClass) -> Self {
self.class_names.push(name.to_string());
self.classes.push(class);
self
}
pub fn construction(mut self, name: &str, class_name: &str, arity: usize, body: Expr) -> Self {
let class_index = self
.class_names
.iter()
.position(|n| n == class_name)
.unwrap_or_else(|| {
panic!(
"GovernanceBuilder: class '{}' not found (add it before its construction)",
class_name
)
});
self.construction_names.push(name.to_string());
self.constructions.push(Construction {
class_index,
arity,
body,
});
self
}
pub fn probe(mut self, construction_name: &str, arity: usize) -> Self {
let idx = self
.construction_names
.iter()
.position(|n| n == construction_name)
.unwrap_or_else(|| {
panic!(
"GovernanceBuilder: construction '{}' not found for probe",
construction_name
)
});
self.probe = Some(crate::governance::field::ProbeSpec {
construction_index: idx,
arity,
});
self
}
pub fn rule(
mut self,
name: &str,
input_class_names: &[&str],
output_class_name: &str,
op: TransformOp,
) -> Self {
let input_classes: Vec<usize> = input_class_names
.iter()
.map(|n| {
self.class_names
.iter()
.position(|cn| cn == n)
.unwrap_or_else(|| {
panic!(
"GovernanceBuilder: class '{}' not found for rule '{}'",
n, name
)
})
})
.collect();
let output_class = self
.class_names
.iter()
.position(|cn| cn == output_class_name)
.unwrap_or_else(|| {
panic!(
"GovernanceBuilder: output class '{}' not found for rule '{}'",
output_class_name, name
)
});
self.rule_names.push(name.to_string());
self.rules.push(TransformRule {
name: name.to_string(),
input_classes,
output_class,
operation: op,
reading_derivation: crate::governance::rule::ReadingDerivation::Rederive,
});
self
}
pub fn build(self) -> NamedGovernance {
let derived_gen_count = self.algebra.derived_gens().len();
let construction_count = self.constructions.len();
for (i, c) in self.constructions.iter().enumerate() {
let shape =
ContextShape::for_construction(c.arity, derived_gen_count, construction_count);
if let Err(errors) = c.body.validate(&shape) {
panic!(
"GovernanceBuilder: construction '{}' (index {}) has invalid expression tree: {:?}",
self.construction_names[i], i, errors
);
}
}
let gov = Governance {
sig: *self.algebra.sig(),
derived_gens: self.algebra.derived_gens().to_vec(),
geom_classes: self.classes,
constructions: self.constructions,
probe: self.probe,
transform_rules: self.rules,
};
NamedGovernance {
gov: std::sync::Arc::new(gov),
class_names: self.class_names,
construction_names: self.construction_names,
rule_names: self.rule_names,
}
}
}
#[derive(Clone, Debug)]
pub struct NamedGovernance {
gov: std::sync::Arc<Governance>,
class_names: Vec<String>,
construction_names: Vec<String>,
rule_names: Vec<String>,
}
impl NamedGovernance {
pub fn inner(&self) -> &Governance {
&self.gov
}
pub fn arc(&self) -> &std::sync::Arc<Governance> {
&self.gov
}
pub fn construct(&self, name: &str, params: &[Scalar]) -> Result<Mv, crate::error::Error> {
let idx = self.construction_index(name)?;
Ok(self.gov.construct(idx, params)?)
}
pub fn construct_by_index(
&self,
idx: usize,
params: &[Scalar],
) -> Result<Mv, ConstructionError> {
self.gov.construct(idx, params)
}
pub fn govern(&self, mv: &Mv, class_name: &str) -> Result<Geoit, crate::error::Error> {
let idx = self.class_index(class_name)?;
Ok(governance::govern_shared(
mv,
std::sync::Arc::clone(&self.gov),
idx,
)?)
}
pub fn govern_by_index(&self, mv: &Mv, class_index: usize) -> Result<Geoit, GovernanceError> {
governance::govern_shared(mv, std::sync::Arc::clone(&self.gov), class_index)
}
pub fn is_valid(&self, mv: &Mv, class_name: &str) -> Result<bool, crate::error::NotFoundError> {
let idx = self.class_index(class_name)?;
Ok(self.gov.is_valid(mv, idx))
}
pub fn class_index(&self, name: &str) -> Result<usize, crate::error::NotFoundError> {
self.class_names
.iter()
.position(|n| n == name)
.ok_or_else(|| crate::error::NotFoundError::Class(name.to_string()))
}
pub fn construction_index(&self, name: &str) -> Result<usize, crate::error::NotFoundError> {
self.construction_names
.iter()
.position(|n| n == name)
.ok_or_else(|| crate::error::NotFoundError::Construction(name.to_string()))
}
pub fn class_names(&self) -> &[String] {
&self.class_names
}
pub fn construction_names(&self) -> &[String] {
&self.construction_names
}
pub fn rule_names(&self) -> &[String] {
&self.rule_names
}
pub fn rule_index(&self, name: &str) -> Result<usize, crate::error::NotFoundError> {
self.rule_names
.iter()
.position(|n| n == name)
.ok_or_else(|| crate::error::NotFoundError::Construction(name.to_string()))
}
pub fn transform(
&self,
rule_name: &str,
inputs: &[&Geoit],
) -> Result<Geoit, crate::error::Error> {
let idx = self.rule_index(rule_name)?;
let rule = &self.gov.transform_rules[idx];
Ok(apply_transform(
rule,
inputs,
std::sync::Arc::clone(&self.gov),
)?)
}
pub fn sig(&self) -> &Signature {
&self.gov.sig
}
}
#[cfg(test)]
mod tests {
use super::*;
fn vga3_governance() -> 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 builder_construct_by_name() {
let gov = vga3_governance();
let mv = gov
.construct(
"Vector",
&[Scalar::from(3), Scalar::from(4), Scalar::from(5)],
)
.unwrap();
assert_eq!(mv.coefficient(0b001), Scalar::from(3));
assert_eq!(mv.coefficient(0b010), Scalar::from(4));
assert_eq!(mv.coefficient(0b100), Scalar::from(5));
}
#[test]
fn builder_govern_by_name() {
let gov = vga3_governance();
let params = vec![Scalar::from(3), Scalar::from(4), Scalar::from(5)];
let mv = gov.construct("Vector", ¶ms).unwrap();
let geoit = gov.govern(&mv, "Vector").unwrap();
assert!(geoit.is_satisfied());
let extracted = geoit.read_all().unwrap();
assert_eq!(extracted, params);
}
#[test]
fn builder_is_valid() {
let gov = vga3_governance();
let mv = gov
.construct(
"Vector",
&[Scalar::from(1), Scalar::from(0), Scalar::from(0)],
)
.unwrap();
assert!(gov.is_valid(&mv, "Vector").unwrap());
}
#[test]
fn builder_cga2_with_constraints() {
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 point_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),
);
let gov = GovernanceBuilder::new(alg)
.class("Point", point_class)
.construction("Point", "Point", 2, body)
.build();
let params = vec![Scalar::from(3), Scalar::from(4)];
let mv = gov.construct("Point", ¶ms).unwrap();
let geoit = gov.govern(&mv, "Point").unwrap();
assert!(geoit.is_satisfied());
let extracted = geoit.read_all().unwrap();
assert_eq!(extracted, params);
}
#[test]
fn builder_missing_class() {
let gov = vga3_governance();
assert!(gov.class_index("Nonexistent").is_err());
}
#[test]
fn builder_missing_construction() {
let gov = vga3_governance();
assert!(gov.construction_index("Nonexistent").is_err());
}
#[test]
fn builder_rule_roundtrip() {
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)),
);
let gov = GovernanceBuilder::new(alg)
.class("Vector", class)
.construction("Vector", "Vector", 3, body)
.rule("Reverse", &["Vector"], "Vector", TransformOp::Reverse)
.build();
assert_eq!(gov.rule_names(), &["Reverse"]);
assert!(gov.rule_index("Reverse").is_ok());
assert!(gov.rule_index("Missing").is_err());
let params = vec![Scalar::from(3), Scalar::from(4), Scalar::from(5)];
let mv = gov.construct("Vector", ¶ms).unwrap();
let geoit = gov.govern(&mv, "Vector").unwrap();
let reversed = gov.transform("Reverse", &[&geoit]).unwrap();
assert!(reversed.is_satisfied());
assert_eq!(reversed.mv(), geoit.mv());
}
}