1use std::collections::HashMap;
33
34use z3::ast::{Ast, Bool, Dynamic, Int};
35use z3::{FuncDecl, Params, SatResult, Solver, Sort};
36
37use crate::error::{CounterExample, VerificationError, VerificationResult};
38use crate::ir::{VerifyExpr, VerifyOp, VerifyType};
39
40pub(crate) fn new_solver() -> Solver {
47 use std::sync::Once;
48 static INIT: Once = Once::new();
49 INIT.call_once(|| z3::set_global_param("timeout", "30000"));
50 Solver::new()
51}
52
53pub struct Verifier {
73 timeout_ms: u32,
74}
75
76impl Verifier {
77 pub fn new() -> Self {
87 Self { timeout_ms: 10000 }
88 }
89
90 fn solver(&self) -> Solver {
92 let solver = crate::solver::new_solver();
93 let mut params = Params::new();
94 params.set_u32("timeout", self.timeout_ms);
95 solver.set_params(¶ms);
96 solver
97 }
98
99 pub fn check_bool(&self, value: bool) -> VerificationResult {
113 let solver = self.solver();
114
115 let assertion = Bool::from_bool(value);
116
117 solver.assert(&assertion.not());
120
121 match solver.check() {
122 SatResult::Unsat => Ok(()), SatResult::Sat => {
124 Err(VerificationError::contradiction(
126 "The assertion is not always true.",
127 None,
128 ))
129 }
130 SatResult::Unknown => Err(VerificationError::solver_unknown()),
131 }
132 }
133
134 pub fn check_int_greater_than(&self, value: i64, bound: i64) -> VerificationResult {
146 let solver = self.solver();
147
148 let v = z3::ast::Int::from_i64(value);
149 let b = z3::ast::Int::from_i64(bound);
150 let assertion = v.gt(&b);
151
152 solver.assert(&assertion.not());
154
155 match solver.check() {
156 SatResult::Unsat => Ok(()),
157 SatResult::Sat => {
158 Err(VerificationError::bounds_violation(
159 "value",
160 format!("> {}", bound),
161 format!("{}", value),
162 ))
163 }
164 SatResult::Unknown => Err(VerificationError::solver_unknown()),
165 }
166 }
167
168 pub fn check_int_less_than(&self, value: i64, bound: i64) -> VerificationResult {
180 let solver = self.solver();
181
182 let v = z3::ast::Int::from_i64(value);
183 let b = z3::ast::Int::from_i64(bound);
184 let assertion = v.lt(&b);
185
186 solver.assert(&assertion.not());
187
188 match solver.check() {
189 SatResult::Unsat => Ok(()),
190 SatResult::Sat => Err(VerificationError::bounds_violation(
191 "value",
192 format!("< {}", bound),
193 format!("{}", value),
194 )),
195 SatResult::Unknown => Err(VerificationError::solver_unknown()),
196 }
197 }
198
199 pub fn check_int_equals(&self, left: i64, right: i64) -> VerificationResult {
211 let solver = self.solver();
212
213 let l = z3::ast::Int::from_i64(left);
214 let r = z3::ast::Int::from_i64(right);
215 let assertion = l.eq(&r);
216
217 solver.assert(&assertion.not());
218
219 match solver.check() {
220 SatResult::Unsat => Ok(()),
221 SatResult::Sat => Err(VerificationError::contradiction(
222 format!("{} is not equal to {}", left, right),
223 Some(CounterExample {
224 assignments: vec![
225 ("left".to_string(), format!("{}", left)),
226 ("right".to_string(), format!("{}", right)),
227 ],
228 }),
229 )),
230 SatResult::Unknown => Err(VerificationError::solver_unknown()),
231 }
232 }
233
234 pub fn context(&self) -> VerificationContext {
255 VerificationContext::new(self.timeout_ms)
256 }
257}
258
259impl Default for Verifier {
260 fn default() -> Self {
261 Self::new()
262 }
263}
264
265pub struct VerificationContext {
271 timeout_ms: u32,
272}
273
274impl VerificationContext {
275 fn new(timeout_ms: u32) -> Self {
276 Self { timeout_ms }
277 }
278
279 pub fn solver(&self) -> Solver {
283 let solver = crate::solver::new_solver();
284 let mut params = Params::new();
285 params.set_u32("timeout", self.timeout_ms);
286 solver.set_params(¶ms);
287 solver
288 }
289
290 pub fn bool_val(&self, value: bool) -> Bool {
292 Bool::from_bool(value)
293 }
294
295 pub fn int_val(&self, value: i64) -> z3::ast::Int {
297 z3::ast::Int::from_i64(value)
298 }
299
300 pub fn bool_var(&self, name: &str) -> Bool {
302 Bool::new_const(name)
303 }
304
305 pub fn int_var(&self, name: &str) -> z3::ast::Int {
307 z3::ast::Int::new_const(name)
308 }
309
310 pub fn check_valid(&self, solver: &Solver, assertion: &Bool) -> VerificationResult {
315 solver.push();
316 solver.assert(&assertion.not());
317
318 let result = match solver.check() {
319 SatResult::Unsat => Ok(()),
320 SatResult::Sat => {
321 Err(VerificationError::contradiction(
322 "Assertion is not valid",
323 None,
324 ))
325 }
326 SatResult::Unknown => Err(VerificationError::solver_unknown()),
327 };
328
329 solver.pop(1);
330 result
331 }
332}
333
334pub struct VerificationSession {
385 vars: HashMap<String, VerifyType>,
386 assumptions: Vec<VerifyExpr>,
387}
388
389impl VerificationSession {
390 pub fn new() -> Self {
400 Self {
401 vars: HashMap::new(),
402 assumptions: Vec::new(),
403 }
404 }
405
406 pub fn declare(&mut self, name: &str, ty: VerifyType) {
422 self.vars.insert(name.to_string(), ty);
423 }
424
425 pub fn assume(&mut self, expr: &VerifyExpr) {
445 self.assumptions.push(expr.clone());
446 }
447
448 pub fn verify_with_binding(
470 &self,
471 var_name: &str,
472 var_type: VerifyType,
473 value: &VerifyExpr,
474 predicate: &VerifyExpr,
475 ) -> VerificationResult {
476 let solver = timed_solver();
478
479 let mut vars = self.vars.clone();
481 vars.insert(var_name.to_string(), var_type);
482
483 let encoder = Encoder::new(&vars);
484
485 for assumption in &self.assumptions {
487 let ast = encoder.encode(assumption);
488 if let Some(b) = ast.as_bool() {
489 solver.assert(&b);
490 }
491 }
492
493 let binding = VerifyExpr::eq(
495 VerifyExpr::var(var_name),
496 value.clone(),
497 );
498 let binding_ast = encoder.encode(&binding);
499 if let Some(b) = binding_ast.as_bool() {
500 solver.assert(&b);
501 }
502
503 let pred_ast = encoder.encode(predicate);
505 let assertion = pred_ast.as_bool().ok_or_else(|| {
506 VerificationError::solver_error("Refinement predicate must be boolean")
507 })?;
508
509 solver.push();
510 solver.assert(&assertion.not());
511
512 let result = match solver.check() {
513 SatResult::Unsat => Ok(()),
514 SatResult::Sat => Err(VerificationError::refinement_violation(
515 var_name,
516 "The value does not satisfy the refinement predicate.",
517 )),
518 SatResult::Unknown => Err(VerificationError::solver_unknown()),
519 };
520
521 solver.pop(1);
522 result
523 }
524
525 pub fn verify(&self, expr: &VerifyExpr) -> VerificationResult {
546 let solver = timed_solver();
548
549 let encoder = Encoder::new(&self.vars);
551
552 for assumption in &self.assumptions {
554 let ast = encoder.encode(assumption);
555 if let Some(b) = ast.as_bool() {
556 solver.assert(&b);
557 }
558 }
559
560 let ast = encoder.encode(expr);
562 let assertion = ast.as_bool().ok_or_else(|| {
563 VerificationError::solver_error("Assertion must be boolean")
564 })?;
565
566 solver.push();
568 solver.assert(&assertion.not());
569
570 let result = match solver.check() {
571 SatResult::Unsat => Ok(()),
572 SatResult::Sat => {
573 Err(VerificationError::contradiction(
574 "Assertion cannot be proven valid",
575 None,
576 ))
577 }
578 SatResult::Unknown => Err(VerificationError::solver_unknown()),
579 };
580
581 solver.pop(1);
582 result
583 }
584
585 pub fn check_sat(&self) -> Result<bool, VerificationError> {
591 let solver = timed_solver();
592
593 let encoder = Encoder::new(&self.vars);
594 for assumption in &self.assumptions {
595 let ast = encoder.encode(assumption);
596 if let Some(b) = ast.as_bool() {
597 solver.assert(&b);
598 }
599 }
600
601 match solver.check() {
602 SatResult::Sat => Ok(true),
603 SatResult::Unsat => Ok(false),
604 SatResult::Unknown => Err(VerificationError::solver_unknown()),
605 }
606 }
607
608 pub fn verify_temporal(
621 &self,
622 initial: &VerifyExpr,
623 transition: &VerifyExpr,
624 property: &VerifyExpr,
625 bound: u32,
626 ) -> VerificationResult {
627 let solver = timed_solver();
628
629 let mut step_vars: HashMap<String, VerifyType> = self.vars.clone();
631
632 for step in 0..=bound {
634 let suffix = format!("_{}", step);
635
636 let step_initial = rename_var_in_expr(initial, "s", &format!("s{}", suffix));
638 let step_property = rename_var_in_expr(property, "s", &format!("s{}", suffix));
639
640 step_vars.insert(format!("s{}", suffix), VerifyType::Int);
641
642 let encoder = Encoder::new(&step_vars);
643
644 if step == 0 {
646 let init_ast = encoder.encode(&step_initial);
647 if let Some(b) = init_ast.as_bool() {
648 solver.assert(&b);
649 }
650 }
651
652 if step < bound {
654 let next_suffix = format!("_{}", step + 1);
655 let step_trans = rename_var_in_expr(
656 &rename_var_in_expr(transition, "s", &format!("s{}", suffix)),
657 "s_next",
658 &format!("s{}", next_suffix),
659 );
660 let trans_ast = encoder.encode(&step_trans);
661 if let Some(b) = trans_ast.as_bool() {
662 solver.assert(&b);
663 }
664 }
665
666 let prop_ast = encoder.encode(&step_property);
668 if let Some(b) = prop_ast.as_bool() {
669 solver.push();
670 solver.assert(&b.not());
671 if solver.check() == SatResult::Sat {
672 solver.pop(1);
673 return Err(VerificationError::contradiction(
674 &format!("Property violated at step {}", step),
675 None,
676 ));
677 }
678 solver.pop(1);
679 }
680 }
681
682 Ok(())
683 }
684}
685
686pub fn rename_var_in_expr(expr: &VerifyExpr, from: &str, to: &str) -> VerifyExpr {
689
690 let r = |e: &VerifyExpr| rename_var_in_expr(e, from, to);
691 match expr {
692 VerifyExpr::Var(name) => {
694 if name == from { VerifyExpr::Var(to.to_string()) } else { expr.clone() }
695 }
696 VerifyExpr::Int(_) | VerifyExpr::Bool(_) | VerifyExpr::BitVecConst { .. } => expr.clone(),
698
699 VerifyExpr::Binary { op, left, right } => VerifyExpr::Binary {
701 op: *op,
702 left: Box::new(r(left)),
703 right: Box::new(r(right)),
704 },
705 VerifyExpr::Not(inner) => VerifyExpr::Not(Box::new(r(inner))),
706 VerifyExpr::Iff(l, ri) => VerifyExpr::Iff(Box::new(r(l)), Box::new(r(ri))),
707
708 VerifyExpr::ForAll { vars, body } => VerifyExpr::ForAll {
710 vars: vars.clone(),
711 body: Box::new(r(body)),
712 },
713 VerifyExpr::Exists { vars, body } => VerifyExpr::Exists {
714 vars: vars.clone(),
715 body: Box::new(r(body)),
716 },
717
718 VerifyExpr::Apply { name, args } => VerifyExpr::Apply {
720 name: name.clone(),
721 args: args.iter().map(|a| r(a)).collect(),
722 },
723 VerifyExpr::ApplyInt { name, args } => VerifyExpr::ApplyInt {
724 name: name.clone(),
725 args: args.iter().map(|a| r(a)).collect(),
726 },
727
728 VerifyExpr::BitVecBinary { op, left, right } => VerifyExpr::BitVecBinary {
730 op: *op,
731 left: Box::new(r(left)),
732 right: Box::new(r(right)),
733 },
734 VerifyExpr::BitVecExtract { high, low, operand } => VerifyExpr::BitVecExtract {
735 high: *high, low: *low,
736 operand: Box::new(r(operand)),
737 },
738 VerifyExpr::BitVecConcat(l, ri) => VerifyExpr::BitVecConcat(Box::new(r(l)), Box::new(r(ri))),
739
740 VerifyExpr::Select { array, index } => VerifyExpr::Select {
742 array: Box::new(r(array)),
743 index: Box::new(r(index)),
744 },
745 VerifyExpr::Store { array, index, value } => VerifyExpr::Store {
746 array: Box::new(r(array)),
747 index: Box::new(r(index)),
748 value: Box::new(r(value)),
749 },
750
751 VerifyExpr::AtState { state, expr: e } => VerifyExpr::AtState {
753 state: Box::new(r(state)),
754 expr: Box::new(r(e)),
755 },
756 VerifyExpr::Transition { from: f, to: t } => VerifyExpr::Transition {
757 from: Box::new(r(f)),
758 to: Box::new(r(t)),
759 },
760 }
761}
762
763impl Default for VerificationSession {
764 fn default() -> Self {
765 Self::new()
766 }
767}
768
769fn timed_solver() -> Solver {
771 let solver = crate::solver::new_solver();
772 let mut params = Params::new();
773 params.set_u32("timeout", 10000);
774 solver.set_params(¶ms);
775 solver
776}
777
778struct Encoder<'a> {
780 vars: &'a HashMap<String, VerifyType>,
781}
782
783impl<'a> Encoder<'a> {
784 fn new(vars: &'a HashMap<String, VerifyType>) -> Self {
785 Self { vars }
786 }
787
788 fn encode(&self, expr: &VerifyExpr) -> Dynamic {
789 match expr {
790 VerifyExpr::Int(n) => Dynamic::from_ast(&Int::from_i64(*n)),
791 VerifyExpr::Bool(b) => Dynamic::from_ast(&Bool::from_bool(*b)),
792
793 VerifyExpr::Var(name) => {
794 let ty = self.vars.get(name).cloned().unwrap_or(VerifyType::Int);
795 match ty {
796 VerifyType::Int => Dynamic::from_ast(&Int::new_const(name.as_str())),
797 VerifyType::Bool => Dynamic::from_ast(&Bool::new_const(name.as_str())),
798 VerifyType::Object => {
799 Dynamic::from_ast(&Int::new_const(name.as_str()))
800 }
801 VerifyType::Real => {
802 Dynamic::from_ast(&z3::ast::Real::new_const(name.as_str()))
803 }
804 VerifyType::BitVector(width) => {
805 Dynamic::from_ast(&z3::ast::BV::new_const(name.as_str(), width))
806 }
807 VerifyType::Array(ref idx_ty, ref elem_ty) => {
808 let idx_sort = self.type_to_sort(idx_ty);
809 let elem_sort = self.type_to_sort(elem_ty);
810 Dynamic::from_ast(&z3::ast::Array::new_const(name.as_str(), &idx_sort, &elem_sort))
811 }
812 }
813 }
814
815 VerifyExpr::Binary { op, left, right } => {
816 let l = self.encode(left);
817 let r = self.encode(right);
818 self.encode_binary(op, l, r)
819 }
820
821 VerifyExpr::Not(inner) => {
822 let i = self.encode(inner);
823 if let Some(b) = i.as_bool() {
824 Dynamic::from_ast(&b.not())
825 } else {
826 i
827 }
828 }
829
830 VerifyExpr::Apply { name, args } => {
831 self.encode_apply(name, args)
832 }
833
834 VerifyExpr::ApplyInt { name, args } => {
835 let int_sort = Sort::int();
836 let domain: Vec<&Sort> = args.iter().map(|_| &int_sort).collect();
837 let func_decl = FuncDecl::new(name.as_str(), &domain, &int_sort);
838 let encoded_args: Vec<Dynamic> =
839 args.iter().map(|a| self.encode(a)).collect();
840 let arg_refs: Vec<&dyn Ast> =
841 encoded_args.iter().map(|a| a as &dyn Ast).collect();
842 Dynamic::from_ast(&func_decl.apply(&arg_refs))
843 }
844
845 VerifyExpr::ForAll { vars, body } => {
846 if vars.is_empty() {
847 return self.encode(body);
848 }
849 let body_encoded = {
850 let b = self.encode(body);
851 b.as_bool().unwrap_or_else(|| Bool::from_bool(true))
852 };
853 let bound_consts: Vec<Dynamic> = vars.iter().map(|(name, ty)| {
854 self.make_quantifier_var(name, ty)
855 }).collect();
856 let bound_refs: Vec<&dyn Ast> = bound_consts.iter().map(|d| d as &dyn Ast).collect();
857 Dynamic::from_ast(&z3::ast::forall_const(&bound_refs, &[], &body_encoded))
858 }
859
860 VerifyExpr::Exists { vars, body } => {
861 if vars.is_empty() {
862 return self.encode(body);
863 }
864 let body_encoded = {
865 let b = self.encode(body);
866 b.as_bool().unwrap_or_else(|| Bool::from_bool(true))
867 };
868 let bound_consts: Vec<Dynamic> = vars.iter().map(|(name, ty)| {
869 self.make_quantifier_var(name, ty)
870 }).collect();
871 let bound_refs: Vec<&dyn Ast> = bound_consts.iter().map(|d| d as &dyn Ast).collect();
872 Dynamic::from_ast(&z3::ast::exists_const(&bound_refs, &[], &body_encoded))
873 }
874
875 VerifyExpr::BitVecConst { width, value } => {
878 Dynamic::from_ast(&z3::ast::BV::from_u64(*value, *width))
879 }
880
881 VerifyExpr::BitVecBinary { op, left, right } => {
882 let l = self.encode(left);
883 let r = self.encode(right);
884 self.encode_bv_binary(op, l, r)
885 }
886
887 VerifyExpr::BitVecExtract { high, low, operand } => {
888 let bv = self.encode(operand);
889 if let Some(bv) = bv.as_bv() {
890 Dynamic::from_ast(&bv.extract(*high, *low))
891 } else {
892 bv
893 }
894 }
895
896 VerifyExpr::BitVecConcat(left, right) => {
897 let l = self.encode(left);
898 let r = self.encode(right);
899 if let (Some(lb), Some(rb)) = (l.as_bv(), r.as_bv()) {
900 Dynamic::from_ast(&lb.concat(&rb))
901 } else {
902 l
903 }
904 }
905
906 VerifyExpr::Select { array, index } => {
909 let a = self.encode(array);
910 let i = self.encode(index);
911 if let Some(arr) = a.as_array() {
912 Dynamic::from_ast(&arr.select(&i))
913 } else {
914 a
915 }
916 }
917
918 VerifyExpr::Store { array, index, value } => {
919 let a = self.encode(array);
920 let i = self.encode(index);
921 let v = self.encode(value);
922 if let Some(arr) = a.as_array() {
923 Dynamic::from_ast(&arr.store(&i, &v))
924 } else {
925 a
926 }
927 }
928
929 VerifyExpr::AtState { state: _, expr } => {
932 self.encode(expr)
934 }
935
936 VerifyExpr::Transition { from, to } => {
937 let f = self.encode(from);
939 let t = self.encode(to);
940 if let (Some(fb), Some(tb)) = (f.as_bool(), t.as_bool()) {
941 Dynamic::from_ast(&Bool::and(&[&fb, &tb]))
942 } else {
943 f
944 }
945 }
946
947 VerifyExpr::Iff(left, right) => {
950 let l = self.encode(left);
951 let r = self.encode(right);
952 if let (Some(lb), Some(rb)) = (l.as_bool(), r.as_bool()) {
953 Dynamic::from_ast(&lb.iff(&rb))
954 } else {
955 Dynamic::from_ast(&l.eq(&r))
957 }
958 }
959 }
960 }
961
962 fn type_to_sort(&self, ty: &VerifyType) -> z3::Sort {
963 match ty {
964 VerifyType::Int => z3::Sort::int(),
965 VerifyType::Bool => z3::Sort::bool(),
966 VerifyType::Object => z3::Sort::int(),
967 VerifyType::Real => z3::Sort::real(),
968 VerifyType::BitVector(width) => z3::Sort::bitvector(*width),
969 VerifyType::Array(idx, elem) => {
970 let idx_sort = self.type_to_sort(idx);
971 let elem_sort = self.type_to_sort(elem);
972 z3::Sort::array(&idx_sort, &elem_sort)
973 }
974 }
975 }
976
977 fn make_quantifier_var(&self, name: &str, ty: &VerifyType) -> Dynamic {
978 match ty {
979 VerifyType::Int => Dynamic::from_ast(&Int::new_const(name)),
980 VerifyType::Bool => Dynamic::from_ast(&Bool::new_const(name)),
981 VerifyType::BitVector(w) => Dynamic::from_ast(&z3::ast::BV::new_const(name, *w)),
982 VerifyType::Object => Dynamic::from_ast(&Int::new_const(name)),
983 VerifyType::Real => Dynamic::from_ast(&z3::ast::Real::new_const(name)),
984 VerifyType::Array(idx, elem) => {
985 let idx_sort = self.type_to_sort(idx);
986 let elem_sort = self.type_to_sort(elem);
987 Dynamic::from_ast(&z3::ast::Array::new_const(name, &idx_sort, &elem_sort))
988 }
989 }
990 }
991
992 fn encode_binary(&self, op: &VerifyOp, l: Dynamic, r: Dynamic) -> Dynamic {
993 match op {
994 VerifyOp::Add => {
996 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
997 Dynamic::from_ast(&(li + ri))
998 } else {
999 l
1000 }
1001 }
1002 VerifyOp::Sub => {
1003 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1004 Dynamic::from_ast(&(li - ri))
1005 } else {
1006 l
1007 }
1008 }
1009 VerifyOp::Mul => {
1010 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1011 Dynamic::from_ast(&(li * ri))
1012 } else {
1013 l
1014 }
1015 }
1016 VerifyOp::Div => {
1017 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1018 Dynamic::from_ast(&(li / ri))
1019 } else {
1020 l
1021 }
1022 }
1023 VerifyOp::FloorDiv => {
1026 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1027 Dynamic::from_ast(&(li.to_real() / ri.to_real()).to_int())
1028 } else {
1029 l
1030 }
1031 }
1032
1033 VerifyOp::Gt => {
1035 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1036 Dynamic::from_ast(&li.gt(&ri))
1037 } else {
1038 Dynamic::from_ast(&Bool::from_bool(false))
1039 }
1040 }
1041 VerifyOp::Lt => {
1042 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1043 Dynamic::from_ast(&li.lt(&ri))
1044 } else {
1045 Dynamic::from_ast(&Bool::from_bool(false))
1046 }
1047 }
1048 VerifyOp::Gte => {
1049 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1050 Dynamic::from_ast(&li.ge(&ri))
1051 } else {
1052 Dynamic::from_ast(&Bool::from_bool(false))
1053 }
1054 }
1055 VerifyOp::Lte => {
1056 if let (Some(li), Some(ri)) = (l.as_int(), r.as_int()) {
1057 Dynamic::from_ast(&li.le(&ri))
1058 } else {
1059 Dynamic::from_ast(&Bool::from_bool(false))
1060 }
1061 }
1062
1063 VerifyOp::Eq => Dynamic::from_ast(&l.eq(&r)),
1065 VerifyOp::Neq => Dynamic::from_ast(&l.eq(&r).not()),
1066
1067 VerifyOp::And => {
1069 if let (Some(lb), Some(rb)) = (l.as_bool(), r.as_bool()) {
1070 Dynamic::from_ast(&Bool::and(&[&lb, &rb]))
1071 } else {
1072 Dynamic::from_ast(&Bool::from_bool(false))
1073 }
1074 }
1075 VerifyOp::Or => {
1076 if let (Some(lb), Some(rb)) = (l.as_bool(), r.as_bool()) {
1077 Dynamic::from_ast(&Bool::or(&[&lb, &rb]))
1078 } else {
1079 Dynamic::from_ast(&Bool::from_bool(false))
1080 }
1081 }
1082 VerifyOp::Implies => {
1083 if let (Some(lb), Some(rb)) = (l.as_bool(), r.as_bool()) {
1084 Dynamic::from_ast(&lb.implies(&rb))
1085 } else {
1086 Dynamic::from_ast(&Bool::from_bool(true))
1087 }
1088 }
1089 }
1090 }
1091
1092 fn encode_bv_binary(&self, op: &crate::ir::BitVecOp, l: Dynamic, r: Dynamic) -> Dynamic {
1093 use crate::ir::BitVecOp;
1094 if let (Some(lb), Some(rb)) = (l.as_bv(), r.as_bv()) {
1095 match op {
1096 BitVecOp::And => Dynamic::from_ast(&lb.bvand(&rb)),
1097 BitVecOp::Or => Dynamic::from_ast(&lb.bvor(&rb)),
1098 BitVecOp::Xor => Dynamic::from_ast(&lb.bvxor(&rb)),
1099 BitVecOp::Not => Dynamic::from_ast(&lb.bvnot()),
1100 BitVecOp::Shl => Dynamic::from_ast(&lb.bvshl(&rb)),
1101 BitVecOp::Shr => Dynamic::from_ast(&lb.bvlshr(&rb)),
1102 BitVecOp::AShr => Dynamic::from_ast(&lb.bvashr(&rb)),
1103 BitVecOp::Add => Dynamic::from_ast(&lb.bvadd(&rb)),
1104 BitVecOp::Sub => Dynamic::from_ast(&lb.bvsub(&rb)),
1105 BitVecOp::Mul => Dynamic::from_ast(&lb.bvmul(&rb)),
1106 BitVecOp::SDiv => Dynamic::from_ast(&lb.bvsdiv(&rb)),
1107 BitVecOp::SRem => Dynamic::from_ast(&lb.bvsrem(&rb)),
1108 BitVecOp::ULt => Dynamic::from_ast(&lb.bvult(&rb)),
1109 BitVecOp::SLt => Dynamic::from_ast(&lb.bvslt(&rb)),
1110 BitVecOp::ULe => Dynamic::from_ast(&lb.bvule(&rb)),
1111 BitVecOp::SLe => Dynamic::from_ast(&lb.bvsle(&rb)),
1112 BitVecOp::Eq => Dynamic::from_ast(&lb.eq(&rb)),
1113 }
1114 } else {
1115 l
1116 }
1117 }
1118
1119 fn encode_apply(&self, name: &str, args: &[VerifyExpr]) -> Dynamic {
1120 let int_sort = Sort::int();
1121 let domain: Vec<&Sort> = args.iter().map(|_| &int_sort).collect();
1122 let range = Sort::bool();
1123
1124 let func_decl = FuncDecl::new(name, &domain, &range);
1125
1126 let encoded_args: Vec<Dynamic> = args.iter().map(|a| self.encode(a)).collect();
1127 let arg_refs: Vec<&dyn Ast> = encoded_args.iter().map(|a| a as &dyn Ast).collect();
1128
1129 Dynamic::from_ast(&func_decl.apply(&arg_refs))
1130 }
1131}
1132
1133#[cfg(test)]
1134mod tests {
1135 use super::*;
1136
1137 #[test]
1138 fn test_tautology() {
1139 let verifier = Verifier::new();
1140 assert!(verifier.check_bool(true).is_ok());
1141 }
1142
1143 #[test]
1144 fn test_contradiction() {
1145 let verifier = Verifier::new();
1146 assert!(verifier.check_bool(false).is_err());
1147 }
1148
1149 #[test]
1150 fn test_int_greater_than_valid() {
1151 let verifier = Verifier::new();
1152 assert!(verifier.check_int_greater_than(10, 5).is_ok());
1153 }
1154
1155 #[test]
1156 fn test_int_greater_than_invalid() {
1157 let verifier = Verifier::new();
1158 assert!(verifier.check_int_greater_than(3, 5).is_err());
1159 }
1160
1161 #[test]
1162 fn test_int_equals_valid() {
1163 let verifier = Verifier::new();
1164 assert!(verifier.check_int_equals(42, 42).is_ok());
1165 }
1166
1167 #[test]
1168 fn test_int_equals_invalid() {
1169 let verifier = Verifier::new();
1170 assert!(verifier.check_int_equals(1, 2).is_err());
1171 }
1172
1173 #[test]
1174 fn test_context_api() {
1175 let verifier = Verifier::new();
1176 let vctx = verifier.context();
1177 let solver = vctx.solver();
1178
1179 let p = vctx.bool_var("p");
1181 let tautology = Bool::or(&[&p, &p.not()]);
1182
1183 assert!(vctx.check_valid(&solver, &tautology).is_ok());
1184 }
1185
1186 #[test]
1187 fn test_context_contradiction() {
1188 let verifier = Verifier::new();
1189 let vctx = verifier.context();
1190 let solver = vctx.solver();
1191
1192 let p = vctx.bool_var("p");
1194 let contradiction = Bool::and(&[&p, &p.not()]);
1195
1196 assert!(vctx.check_valid(&solver, &contradiction).is_err());
1197 }
1198
1199 #[test]
1204 fn test_session_integer_bounds() {
1205 let mut session = VerificationSession::new();
1206
1207 session.declare("x", VerifyType::Int);
1209
1210 session.assume(&VerifyExpr::eq(
1212 VerifyExpr::var("x"),
1213 VerifyExpr::int(10),
1214 ));
1215
1216 let result = session.verify(&VerifyExpr::gt(
1218 VerifyExpr::var("x"),
1219 VerifyExpr::int(5),
1220 ));
1221 assert!(result.is_ok(), "10 > 5 should be provable");
1222 }
1223
1224 #[test]
1225 fn test_session_integer_contradiction() {
1226 let mut session = VerificationSession::new();
1227
1228 session.declare("x", VerifyType::Int);
1230
1231 session.assume(&VerifyExpr::eq(
1233 VerifyExpr::var("x"),
1234 VerifyExpr::int(10),
1235 ));
1236
1237 let result = session.verify(&VerifyExpr::lt(
1239 VerifyExpr::var("x"),
1240 VerifyExpr::int(5),
1241 ));
1242 assert!(result.is_err(), "10 < 5 should not be provable");
1243 }
1244
1245 #[test]
1246 fn test_session_uninterpreted_functions() {
1247 let mut session = VerificationSession::new();
1248
1249 session.declare("x", VerifyType::Object);
1251
1252 session.assume(&VerifyExpr::implies(
1254 VerifyExpr::apply("Mortal", vec![VerifyExpr::var("x")]),
1255 VerifyExpr::apply("Human", vec![VerifyExpr::var("x")]),
1256 ));
1257
1258 session.assume(&VerifyExpr::apply("Mortal", vec![VerifyExpr::var("x")]));
1260
1261 let result = session.verify(&VerifyExpr::apply("Human", vec![VerifyExpr::var("x")]));
1263 assert!(result.is_ok(), "Should deduce Human(x) from Mortal(x) and Mortal(x)->Human(x)");
1264 }
1265
1266 #[test]
1267 fn test_session_modal_structural_reasoning() {
1268 let mut session = VerificationSession::new();
1269
1270 session.declare("A", VerifyType::Object);
1272 session.declare("B", VerifyType::Object);
1273
1274 session.assume(&VerifyExpr::implies(
1276 VerifyExpr::apply("Possible", vec![VerifyExpr::var("A")]),
1277 VerifyExpr::apply("Possible", vec![VerifyExpr::var("B")]),
1278 ));
1279
1280 session.assume(&VerifyExpr::apply("Possible", vec![VerifyExpr::var("A")]));
1282
1283 let result = session.verify(&VerifyExpr::apply("Possible", vec![VerifyExpr::var("B")]));
1285 assert!(result.is_ok(), "Should deduce Possible(B) from modus ponens");
1286 }
1287
1288 #[test]
1289 fn test_session_arithmetic() {
1290 let mut session = VerificationSession::new();
1291
1292 session.declare("x", VerifyType::Int);
1294 session.declare("y", VerifyType::Int);
1295
1296 session.assume(&VerifyExpr::eq(VerifyExpr::var("x"), VerifyExpr::int(5)));
1298 session.assume(&VerifyExpr::eq(VerifyExpr::var("y"), VerifyExpr::int(3)));
1299
1300 let sum = VerifyExpr::binary(
1302 VerifyOp::Add,
1303 VerifyExpr::var("x"),
1304 VerifyExpr::var("y"),
1305 );
1306 let result = session.verify(&VerifyExpr::gt(sum, VerifyExpr::int(7)));
1307 assert!(result.is_ok(), "5 + 3 > 7 should be provable");
1308 }
1309
1310 #[test]
1311 fn test_session_logic_and_or() {
1312 let mut session = VerificationSession::new();
1313
1314 session.declare("p", VerifyType::Bool);
1316 session.declare("q", VerifyType::Bool);
1317
1318 session.assume(&VerifyExpr::eq(VerifyExpr::var("p"), VerifyExpr::bool(true)));
1320 session.assume(&VerifyExpr::eq(VerifyExpr::var("q"), VerifyExpr::bool(false)));
1321
1322 let result = session.verify(&VerifyExpr::or(
1324 VerifyExpr::var("p"),
1325 VerifyExpr::var("q"),
1326 ));
1327 assert!(result.is_ok(), "true || false should be provable");
1328
1329 let result = session.verify(&VerifyExpr::not(VerifyExpr::and(
1331 VerifyExpr::var("p"),
1332 VerifyExpr::var("q"),
1333 )));
1334 assert!(result.is_ok(), "!(true && false) should be provable");
1335 }
1336}