Download rust/crates/hyperkitty-constraints/src/evaluator.rs from Snapkitty/hyperkitty-constraint-dsl: direct link, hf CLI and curl.
- Browser
- Download file 6.64 kB
-
https://huggingface.co/Snapkitty/hyperkitty-constraint-dsl/resolve/main/rust/crates/hyperkitty-constraints/src/evaluator.rs
- Command line
-
hf download hf://Snapkitty/hyperkitty-constraint-dsl/rust/crates/hyperkitty-constraints/src/evaluator.rs
-
curl -L -o evaluator.rs https://huggingface.co/Snapkitty/hyperkitty-constraint-dsl/resolve/main/rust/crates/hyperkitty-constraints/src/evaluator.rs
6.64 kB
| use crate::ast::ConstraintProgram; | |
| use std::collections::HashMap; | |
| /// Evaluator for constraint programs. | |
| /// | |
| /// The Evaluator executes a compiled ConstraintProgram against a set of variable bindings. | |
| /// Each constraint is tested: if all its requirements pass, evaluation succeeds. If any | |
| /// requirement fails, the "otherwise" action determines the constraint's result (reject = false, | |
| /// accept = true). | |
| /// | |
| /// NAND Lowering (Future Enhancement): | |
| /// The current evaluator uses boolean algebra directly. Future versions will lower constraints | |
| /// to NAND gates for cryptographic finality. Mapping: | |
| /// - Predicate(x) → lookup x in bindings | |
| /// - Check(name) → built-in gate or binding lookup | |
| /// - AND of requirements → cascaded NAND implementations | |
| /// - Constraint evaluation → NAND commitment to immutable ledger (WORM) | |
| pub struct Evaluator { | |
| pub program: ConstraintProgram, | |
| } | |
| impl Evaluator { | |
| pub fn new(program: ConstraintProgram) -> Self { | |
| Self { program } | |
| } | |
| /// Evaluate the constraint program against provided bindings. | |
| /// | |
| /// Returns Ok(true) if all constraints pass, Ok(false) if any fails. | |
| /// Returns Err only on internal evaluation errors. | |
| pub fn evaluate(&self, bindings: &HashMap<String, bool>) -> hyperkitty_core::Result<bool> { | |
| Ok(self.program.evaluate(bindings)) | |
| } | |
| /// Evaluate a single constraint by name. | |
| /// | |
| /// Useful for debugging or selective constraint testing. | |
| pub fn evaluate_constraint( | |
| &self, | |
| name: &str, | |
| bindings: &HashMap<String, bool>, | |
| ) -> hyperkitty_core::Result<bool> { | |
| for constraint in &self.program.constraints { | |
| if constraint.name == name { | |
| return Ok(constraint.evaluate(bindings)); | |
| } | |
| } | |
| Err(hyperkitty_core::Error::Custom( | |
| format!("Constraint not found: {}", name) | |
| )) | |
| } | |
| /// Count how many constraints pass. | |
| pub fn count_passing(&self, bindings: &HashMap<String, bool>) -> usize { | |
| self.program | |
| .constraints | |
| .iter() | |
| .filter(|c| c.evaluate(bindings)) | |
| .count() | |
| } | |
| /// Get detailed evaluation report for debugging. | |
| pub fn report(&self, bindings: &HashMap<String, bool>) -> String { | |
| let mut report = String::new(); | |
| report.push_str(&format!( | |
| "Constraint Evaluation Report ({} constraints)\n", | |
| self.program.constraints.len() | |
| )); | |
| report.push_str(&"=".repeat(60)); | |
| report.push('\n'); | |
| for constraint in &self.program.constraints { | |
| let result = constraint.evaluate(bindings); | |
| let status = if result { "PASS" } else { "FAIL" }; | |
| report.push_str(&format!( | |
| " [{}] {}: {} (otherwise: {:?})\n", | |
| status, constraint.name, constraint.param, constraint.otherwise | |
| )); | |
| for req in &constraint.requires { | |
| report.push_str(&format!(" - {:?}\n", req)); | |
| } | |
| } | |
| report.push_str(&"=".repeat(60)); | |
| report.push('\n'); | |
| report.push_str(&format!( | |
| "Overall: {}/{} constraints passed\n", | |
| self.count_passing(bindings), | |
| self.program.constraints.len() | |
| )); | |
| report | |
| } | |
| } | |
| impl Default for Evaluator { | |
| fn default() -> Self { | |
| Self { | |
| program: ConstraintProgram::new(), | |
| } | |
| } | |
| } | |
| mod tests { | |
| use super::*; | |
| use crate::ast::{Constraint, OtherwiseAction, Requirement}; | |
| fn test_evaluator_all_pass() { | |
| let mut prog = ConstraintProgram::new(); | |
| let mut c = Constraint::new("test".to_string(), "msg".to_string(), OtherwiseAction::Reject); | |
| c.add_requirement(Requirement::Check("always_true".to_string())); | |
| prog.add_constraint(c); | |
| let evaluator = Evaluator::new(prog); | |
| let bindings = HashMap::new(); | |
| assert!(evaluator.evaluate(&bindings).unwrap()); | |
| } | |
| fn test_evaluator_one_fails() { | |
| let mut prog = ConstraintProgram::new(); | |
| let mut c1 = Constraint::new("c1".to_string(), "msg".to_string(), OtherwiseAction::Reject); | |
| c1.add_requirement(Requirement::Check("always_true".to_string())); | |
| prog.add_constraint(c1); | |
| let mut c2 = Constraint::new("c2".to_string(), "msg".to_string(), OtherwiseAction::Reject); | |
| c2.add_requirement(Requirement::Check("always_false".to_string())); | |
| prog.add_constraint(c2); | |
| let evaluator = Evaluator::new(prog); | |
| let bindings = HashMap::new(); | |
| assert!(!evaluator.evaluate(&bindings).unwrap()); | |
| } | |
| fn test_evaluate_single_constraint() { | |
| let mut prog = ConstraintProgram::new(); | |
| let mut c1 = Constraint::new("first".to_string(), "msg".to_string(), OtherwiseAction::Reject); | |
| c1.add_requirement(Requirement::Check("always_true".to_string())); | |
| prog.add_constraint(c1); | |
| let mut c2 = Constraint::new("second".to_string(), "msg".to_string(), OtherwiseAction::Reject); | |
| c2.add_requirement(Requirement::Check("always_false".to_string())); | |
| prog.add_constraint(c2); | |
| let evaluator = Evaluator::new(prog); | |
| let bindings = HashMap::new(); | |
| assert!(evaluator.evaluate_constraint("first", &bindings).unwrap()); | |
| assert!(!evaluator.evaluate_constraint("second", &bindings).unwrap()); | |
| } | |
| fn test_count_passing() { | |
| let mut prog = ConstraintProgram::new(); | |
| for i in 0..3 { | |
| let mut c = Constraint::new( | |
| format!("c{}", i), | |
| "msg".to_string(), | |
| OtherwiseAction::Reject, | |
| ); | |
| c.add_requirement(Requirement::Check("always_true".to_string())); | |
| prog.add_constraint(c); | |
| } | |
| let evaluator = Evaluator::new(prog); | |
| let bindings = HashMap::new(); | |
| assert_eq!(evaluator.count_passing(&bindings), 3); | |
| } | |
| fn test_evaluator_report() { | |
| let mut prog = ConstraintProgram::new(); | |
| let mut c = Constraint::new("test".to_string(), "msg".to_string(), OtherwiseAction::Reject); | |
| c.add_requirement(Requirement::Check("always_true".to_string())); | |
| prog.add_constraint(c); | |
| let evaluator = Evaluator::new(prog); | |
| let bindings = HashMap::new(); | |
| let report = evaluator.report(&bindings); | |
| assert!(report.contains("Constraint Evaluation Report")); | |
| assert!(report.contains("test")); | |
| assert!(report.contains("PASS")); | |
| } | |
| } | |