clifford_codegen/symbolic/
verify.rs1use symbolica::atom::{Atom, AtomCore};
7
8use super::ConstraintExpr;
9
10#[derive(Debug, Clone)]
12pub enum VerificationResult {
13 Always,
15 Inconclusive(String),
17}
18
19#[derive(Debug, Default)]
21pub struct ConstraintVerifier;
22
23impl ConstraintVerifier {
24 pub fn new() -> Self {
26 Self
27 }
28
29 pub fn check_trivial(&self, constraint: &ConstraintExpr) -> VerificationResult {
34 let zero_form = constraint.as_zero_form();
35 self.check_is_zero(&zero_form)
36 }
37
38 fn check_is_zero(&self, expr: &Atom) -> VerificationResult {
40 let zero = Atom::num(0);
42
43 if expr == &zero {
45 return VerificationResult::Always;
46 }
47
48 let expanded = expr.expand();
50 if expanded == zero {
51 return VerificationResult::Always;
52 }
53
54 let expr_str = format!("{}", expanded);
56 if expr_str == "0" {
57 return VerificationResult::Always;
58 }
59
60 VerificationResult::Inconclusive(format!(
63 "Could not verify: expression simplifies to {}",
64 expanded
65 ))
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use std::sync::Mutex;
73
74 static SYMBOLICA_LOCK: Mutex<()> = Mutex::new(());
78
79 #[test]
80 fn symbolica_verify_numeric_constraint() {
81 let _guard = SYMBOLICA_LOCK.lock().unwrap();
82 let verifier = ConstraintVerifier::new();
84
85 let lhs = Atom::num(5);
87 let rhs = Atom::num(5);
88 let constraint = super::super::ConstraintExpr {
89 lhs,
90 rhs,
91 original: "5 = 5".to_string(),
92 };
93
94 let result = verifier.check_trivial(&constraint);
95 assert!(matches!(result, VerificationResult::Always));
96 }
97
98 #[test]
99 fn symbolica_verify_zero_atom() {
100 let _guard = SYMBOLICA_LOCK.lock().unwrap();
101 let verifier = ConstraintVerifier::new();
102
103 let lhs = Atom::num(0);
105 let rhs = Atom::num(0);
106 let constraint = super::super::ConstraintExpr {
107 lhs,
108 rhs,
109 original: "0 = 0".to_string(),
110 };
111
112 let result = verifier.check_trivial(&constraint);
113 assert!(matches!(result, VerificationResult::Always));
114 }
115}