1use crate::mbqi::{MBQIResult, MBQISolver};
4use crate::simplify::Simplifier;
5use oxiz_core::ast::{TermId, TermKind, TermManager};
6use oxiz_sat::{
7 Lit, RestartStrategy, Solver as SatSolver, SolverConfig as SatConfig,
8 SolverResult as SatResult, TheoryCallback, TheoryCheckResult, Var,
9};
10use oxiz_theories::arithmetic::ArithSolver;
11use oxiz_theories::euf::EufSolver;
12use oxiz_theories::{EqualityNotification, Theory, TheoryCombination};
13use rustc_hash::FxHashMap;
14use smallvec::SmallVec;
15
16#[derive(Debug, Clone)]
18pub enum ProofStep {
19 Input {
21 index: u32,
23 clause: Vec<Lit>,
25 },
26 Resolution {
28 index: u32,
30 left: u32,
32 right: u32,
34 pivot: Var,
36 clause: Vec<Lit>,
38 },
39 TheoryLemma {
41 index: u32,
43 theory: String,
45 clause: Vec<Lit>,
47 explanation: Vec<TermId>,
49 },
50}
51
52#[derive(Debug, Clone)]
54pub struct Proof {
55 steps: Vec<ProofStep>,
57 empty_clause_index: Option<u32>,
59}
60
61impl Proof {
62 #[must_use]
64 pub fn new() -> Self {
65 Self {
66 steps: Vec::new(),
67 empty_clause_index: None,
68 }
69 }
70
71 pub fn add_step(&mut self, step: ProofStep) {
73 self.steps.push(step);
74 }
75
76 pub fn set_empty_clause(&mut self, index: u32) {
78 self.empty_clause_index = Some(index);
79 }
80
81 #[must_use]
83 pub fn is_complete(&self) -> bool {
84 self.empty_clause_index.is_some()
85 }
86
87 #[must_use]
89 pub fn len(&self) -> usize {
90 self.steps.len()
91 }
92
93 #[must_use]
95 pub fn is_empty(&self) -> bool {
96 self.steps.is_empty()
97 }
98
99 #[must_use]
101 pub fn format(&self) -> String {
102 let mut result = String::from("(proof\n");
103 for step in &self.steps {
104 match step {
105 ProofStep::Input { index, clause } => {
106 result.push_str(&format!(" (input {} {:?})\n", index, clause));
107 }
108 ProofStep::Resolution {
109 index,
110 left,
111 right,
112 pivot,
113 clause,
114 } => {
115 result.push_str(&format!(
116 " (resolution {} {} {} {:?} {:?})\n",
117 index, left, right, pivot, clause
118 ));
119 }
120 ProofStep::TheoryLemma {
121 index,
122 theory,
123 clause,
124 ..
125 } => {
126 result.push_str(&format!(
127 " (theory-lemma {} {} {:?})\n",
128 index, theory, clause
129 ));
130 }
131 }
132 }
133 if let Some(idx) = self.empty_clause_index {
134 result.push_str(&format!(" (empty-clause {})\n", idx));
135 }
136 result.push_str(")\n");
137 result
138 }
139}
140
141impl Default for Proof {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147#[derive(Debug, Clone)]
149#[allow(dead_code)]
150enum Constraint {
151 Eq(TermId, TermId),
153 Diseq(TermId, TermId),
155 Lt(TermId, TermId),
157 Le(TermId, TermId),
159 Gt(TermId, TermId),
161 Ge(TermId, TermId),
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167enum Polarity {
168 Positive,
170 Negative,
172 Both,
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
178pub enum SolverResult {
179 Sat,
181 Unsat,
183 Unknown,
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub enum TheoryMode {
190 Eager,
192 Lazy,
194}
195
196#[derive(Debug, Clone)]
198pub struct SolverConfig {
199 pub timeout_ms: u64,
201 pub parallel: bool,
203 pub num_threads: usize,
205 pub proof: bool,
207 pub model: bool,
209 pub theory_mode: TheoryMode,
211 pub simplify: bool,
213 pub max_conflicts: u64,
215 pub max_decisions: u64,
217 pub restart_strategy: RestartStrategy,
219 pub enable_clause_minimization: bool,
221 pub enable_clause_subsumption: bool,
223 pub enable_variable_elimination: bool,
225 pub variable_elimination_limit: usize,
227 pub enable_blocked_clause_elimination: bool,
229 pub enable_symmetry_breaking: bool,
231 pub enable_inprocessing: bool,
233 pub inprocessing_interval: u64,
235}
236
237impl Default for SolverConfig {
238 fn default() -> Self {
239 Self::balanced()
240 }
241}
242
243impl SolverConfig {
244 #[must_use]
247 pub fn fast() -> Self {
248 Self {
249 timeout_ms: 0,
250 parallel: false,
251 num_threads: 4,
252 proof: false,
253 model: true,
254 theory_mode: TheoryMode::Eager,
255 simplify: true, max_conflicts: 0,
257 max_decisions: 0,
258 restart_strategy: RestartStrategy::Geometric, enable_clause_minimization: true, enable_clause_subsumption: false, enable_variable_elimination: false, variable_elimination_limit: 0,
263 enable_blocked_clause_elimination: false, enable_symmetry_breaking: false,
265 enable_inprocessing: false, inprocessing_interval: 0,
267 }
268 }
269
270 #[must_use]
273 pub fn balanced() -> Self {
274 Self {
275 timeout_ms: 0,
276 parallel: false,
277 num_threads: 4,
278 proof: false,
279 model: true,
280 theory_mode: TheoryMode::Eager,
281 simplify: true,
282 max_conflicts: 0,
283 max_decisions: 0,
284 restart_strategy: RestartStrategy::Glucose, enable_clause_minimization: true,
286 enable_clause_subsumption: true,
287 enable_variable_elimination: true,
288 variable_elimination_limit: 1000, enable_blocked_clause_elimination: true,
290 enable_symmetry_breaking: false, enable_inprocessing: true,
292 inprocessing_interval: 10000,
293 }
294 }
295
296 #[must_use]
299 pub fn thorough() -> Self {
300 Self {
301 timeout_ms: 0,
302 parallel: false,
303 num_threads: 4,
304 proof: false,
305 model: true,
306 theory_mode: TheoryMode::Eager,
307 simplify: true,
308 max_conflicts: 0,
309 max_decisions: 0,
310 restart_strategy: RestartStrategy::Glucose,
311 enable_clause_minimization: true,
312 enable_clause_subsumption: true,
313 enable_variable_elimination: true,
314 variable_elimination_limit: 5000, enable_blocked_clause_elimination: true,
316 enable_symmetry_breaking: true, enable_inprocessing: true,
318 inprocessing_interval: 5000, }
320 }
321
322 #[must_use]
325 pub fn minimal() -> Self {
326 Self {
327 timeout_ms: 0,
328 parallel: false,
329 num_threads: 1,
330 proof: false,
331 model: true,
332 theory_mode: TheoryMode::Lazy, simplify: false,
334 max_conflicts: 0,
335 max_decisions: 0,
336 restart_strategy: RestartStrategy::Geometric,
337 enable_clause_minimization: false,
338 enable_clause_subsumption: false,
339 enable_variable_elimination: false,
340 variable_elimination_limit: 0,
341 enable_blocked_clause_elimination: false,
342 enable_symmetry_breaking: false,
343 enable_inprocessing: false,
344 inprocessing_interval: 0,
345 }
346 }
347
348 #[must_use]
350 pub fn with_proof(mut self) -> Self {
351 self.proof = true;
352 self
353 }
354
355 #[must_use]
357 pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
358 self.timeout_ms = timeout_ms;
359 self
360 }
361
362 #[must_use]
364 pub fn with_max_conflicts(mut self, max_conflicts: u64) -> Self {
365 self.max_conflicts = max_conflicts;
366 self
367 }
368
369 #[must_use]
371 pub fn with_max_decisions(mut self, max_decisions: u64) -> Self {
372 self.max_decisions = max_decisions;
373 self
374 }
375
376 #[must_use]
378 pub fn with_parallel(mut self, num_threads: usize) -> Self {
379 self.parallel = true;
380 self.num_threads = num_threads;
381 self
382 }
383
384 #[must_use]
386 pub fn with_restart_strategy(mut self, strategy: RestartStrategy) -> Self {
387 self.restart_strategy = strategy;
388 self
389 }
390
391 #[must_use]
393 pub fn with_theory_mode(mut self, mode: TheoryMode) -> Self {
394 self.theory_mode = mode;
395 self
396 }
397}
398
399#[derive(Debug, Clone, Default)]
401pub struct Statistics {
402 pub decisions: u64,
404 pub conflicts: u64,
406 pub propagations: u64,
408 pub restarts: u64,
410 pub learned_clauses: u64,
412 pub theory_propagations: u64,
414 pub theory_conflicts: u64,
416}
417
418impl Statistics {
419 #[must_use]
421 pub fn new() -> Self {
422 Self::default()
423 }
424
425 pub fn reset(&mut self) {
427 *self = Self::default();
428 }
429}
430
431#[derive(Debug, Clone)]
433pub struct Model {
434 assignments: FxHashMap<TermId, TermId>,
436}
437
438impl Model {
439 #[must_use]
441 pub fn new() -> Self {
442 Self {
443 assignments: FxHashMap::default(),
444 }
445 }
446
447 #[must_use]
449 pub fn get(&self, term: TermId) -> Option<TermId> {
450 self.assignments.get(&term).copied()
451 }
452
453 pub fn set(&mut self, term: TermId, value: TermId) {
455 self.assignments.insert(term, value);
456 }
457
458 pub fn minimize(&self, essential_vars: &[TermId]) -> Model {
461 let mut minimized = Model::new();
462
463 for &var in essential_vars {
465 if let Some(&value) = self.assignments.get(&var) {
466 minimized.set(var, value);
467 }
468 }
469
470 minimized
471 }
472
473 #[must_use]
475 pub fn size(&self) -> usize {
476 self.assignments.len()
477 }
478
479 #[must_use]
481 pub fn assignments(&self) -> &FxHashMap<TermId, TermId> {
482 &self.assignments
483 }
484
485 pub fn eval(&self, term: TermId, manager: &mut TermManager) -> TermId {
488 if let Some(val) = self.get(term) {
490 return val;
491 }
492
493 let Some(t) = manager.get(term).cloned() else {
495 return term;
496 };
497
498 match t.kind {
499 TermKind::True
501 | TermKind::False
502 | TermKind::IntConst(_)
503 | TermKind::RealConst(_)
504 | TermKind::BitVecConst { .. } => term,
505
506 TermKind::Var(_) => self.get(term).unwrap_or(term),
508
509 TermKind::Not(arg) => {
511 let arg_val = self.eval(arg, manager);
512 if let Some(t) = manager.get(arg_val) {
513 match t.kind {
514 TermKind::True => manager.mk_false(),
515 TermKind::False => manager.mk_true(),
516 _ => manager.mk_not(arg_val),
517 }
518 } else {
519 manager.mk_not(arg_val)
520 }
521 }
522
523 TermKind::And(ref args) => {
524 let mut eval_args = Vec::new();
525 for &arg in args {
526 let val = self.eval(arg, manager);
527 if let Some(t) = manager.get(val) {
528 if matches!(t.kind, TermKind::False) {
529 return manager.mk_false();
530 }
531 if !matches!(t.kind, TermKind::True) {
532 eval_args.push(val);
533 }
534 } else {
535 eval_args.push(val);
536 }
537 }
538 if eval_args.is_empty() {
539 manager.mk_true()
540 } else if eval_args.len() == 1 {
541 eval_args[0]
542 } else {
543 manager.mk_and(eval_args)
544 }
545 }
546
547 TermKind::Or(ref args) => {
548 let mut eval_args = Vec::new();
549 for &arg in args {
550 let val = self.eval(arg, manager);
551 if let Some(t) = manager.get(val) {
552 if matches!(t.kind, TermKind::True) {
553 return manager.mk_true();
554 }
555 if !matches!(t.kind, TermKind::False) {
556 eval_args.push(val);
557 }
558 } else {
559 eval_args.push(val);
560 }
561 }
562 if eval_args.is_empty() {
563 manager.mk_false()
564 } else if eval_args.len() == 1 {
565 eval_args[0]
566 } else {
567 manager.mk_or(eval_args)
568 }
569 }
570
571 TermKind::Implies(lhs, rhs) => {
572 let lhs_val = self.eval(lhs, manager);
573 let rhs_val = self.eval(rhs, manager);
574
575 if let Some(t) = manager.get(lhs_val) {
576 if matches!(t.kind, TermKind::False) {
577 return manager.mk_true();
578 }
579 if matches!(t.kind, TermKind::True) {
580 return rhs_val;
581 }
582 }
583
584 if let Some(t) = manager.get(rhs_val) {
585 if matches!(t.kind, TermKind::True) {
586 return manager.mk_true();
587 }
588 }
589
590 manager.mk_implies(lhs_val, rhs_val)
591 }
592
593 TermKind::Ite(cond, then_br, else_br) => {
594 let cond_val = self.eval(cond, manager);
595
596 if let Some(t) = manager.get(cond_val) {
597 match t.kind {
598 TermKind::True => return self.eval(then_br, manager),
599 TermKind::False => return self.eval(else_br, manager),
600 _ => {}
601 }
602 }
603
604 let then_val = self.eval(then_br, manager);
605 let else_val = self.eval(else_br, manager);
606 manager.mk_ite(cond_val, then_val, else_val)
607 }
608
609 TermKind::Eq(lhs, rhs) => {
610 let lhs_val = self.eval(lhs, manager);
611 let rhs_val = self.eval(rhs, manager);
612
613 if lhs_val == rhs_val {
614 manager.mk_true()
615 } else {
616 manager.mk_eq(lhs_val, rhs_val)
617 }
618 }
619
620 TermKind::Neg(arg) => {
622 let arg_val = self.eval(arg, manager);
623 if let Some(t) = manager.get(arg_val) {
624 match &t.kind {
625 TermKind::IntConst(n) => return manager.mk_int(-n),
626 TermKind::RealConst(r) => return manager.mk_real(-r),
627 _ => {}
628 }
629 }
630 manager.mk_not(arg_val)
631 }
632
633 TermKind::Add(ref args) => {
634 let eval_args: Vec<_> = args.iter().map(|&a| self.eval(a, manager)).collect();
635 manager.mk_add(eval_args)
636 }
637
638 TermKind::Sub(lhs, rhs) => {
639 let lhs_val = self.eval(lhs, manager);
640 let rhs_val = self.eval(rhs, manager);
641 manager.mk_sub(lhs_val, rhs_val)
642 }
643
644 TermKind::Mul(ref args) => {
645 let eval_args: Vec<_> = args.iter().map(|&a| self.eval(a, manager)).collect();
646 manager.mk_mul(eval_args)
647 }
648
649 _ => self.get(term).unwrap_or(term),
651 }
652 }
653}
654
655impl Default for Model {
656 fn default() -> Self {
657 Self::new()
658 }
659}
660
661impl Model {
662 pub fn pretty_print(&self, manager: &TermManager) -> String {
664 if self.assignments.is_empty() {
665 return "(model)".to_string();
666 }
667
668 let mut lines = vec!["(model".to_string()];
669 let printer = oxiz_core::smtlib::Printer::new(manager);
670
671 for (&var, &value) in &self.assignments {
672 if let Some(term) = manager.get(var) {
673 if let TermKind::Var(name) = &term.kind {
675 let sort_str = Self::format_sort(term.sort, manager);
676 let value_str = printer.print_term(value);
677 let name_str = format!("{:?}", name);
679 lines.push(format!(
680 " (define-fun {} () {} {})",
681 name_str, sort_str, value_str
682 ));
683 }
684 }
685 }
686 lines.push(")".to_string());
687 lines.join("\n")
688 }
689
690 fn format_sort(sort: oxiz_core::sort::SortId, manager: &TermManager) -> String {
692 if sort == manager.sorts.bool_sort {
693 "Bool".to_string()
694 } else if sort == manager.sorts.int_sort {
695 "Int".to_string()
696 } else if sort == manager.sorts.real_sort {
697 "Real".to_string()
698 } else if let Some(s) = manager.sorts.get(sort) {
699 if let Some(w) = s.bitvec_width() {
700 format!("(_ BitVec {})", w)
701 } else {
702 "Unknown".to_string()
703 }
704 } else {
705 "Unknown".to_string()
706 }
707 }
708}
709
710#[derive(Debug, Clone)]
712pub struct NamedAssertion {
713 #[allow(dead_code)]
715 pub term: TermId,
716 pub name: Option<String>,
718 pub index: u32,
720}
721
722#[derive(Debug, Clone)]
724pub struct UnsatCore {
725 pub names: Vec<String>,
727 pub indices: Vec<u32>,
729}
730
731impl UnsatCore {
732 #[must_use]
734 pub fn new() -> Self {
735 Self {
736 names: Vec::new(),
737 indices: Vec::new(),
738 }
739 }
740
741 #[must_use]
743 pub fn is_empty(&self) -> bool {
744 self.indices.is_empty()
745 }
746
747 #[must_use]
749 pub fn len(&self) -> usize {
750 self.indices.len()
751 }
752}
753
754impl Default for UnsatCore {
755 fn default() -> Self {
756 Self::new()
757 }
758}
759
760#[derive(Debug)]
762pub struct Solver {
763 config: SolverConfig,
765 sat: SatSolver,
767 euf: EufSolver,
769 arith: ArithSolver,
771 mbqi: MBQISolver,
773 has_quantifiers: bool,
775 term_to_var: FxHashMap<TermId, Var>,
777 var_to_term: Vec<TermId>,
779 var_to_constraint: FxHashMap<Var, Constraint>,
781 logic: Option<String>,
783 assertions: Vec<TermId>,
785 named_assertions: Vec<NamedAssertion>,
787 #[allow(dead_code)]
790 assumption_vars: FxHashMap<u32, Var>,
791 model: Option<Model>,
793 unsat_core: Option<UnsatCore>,
795 context_stack: Vec<ContextState>,
797 trail: Vec<TrailOp>,
799 theory_processed_up_to: usize,
801 produce_unsat_cores: bool,
803 has_false_assertion: bool,
805 polarities: FxHashMap<TermId, Polarity>,
807 polarity_aware: bool,
809 theory_aware_branching: bool,
811 proof: Option<Proof>,
813 simplifier: Simplifier,
815 statistics: Statistics,
817}
818
819#[derive(Debug, Clone, Copy)]
821#[allow(dead_code)]
822pub struct TheoryDecision {
823 pub var: Var,
825 pub value: bool,
827 pub priority: i32,
829}
830
831struct TheoryManager<'a> {
833 euf: &'a mut EufSolver,
835 arith: &'a mut ArithSolver,
837 var_to_constraint: &'a FxHashMap<Var, Constraint>,
839 term_to_var: &'a FxHashMap<TermId, Var>,
841 level_stack: Vec<usize>,
843 processed_count: usize,
845 theory_mode: TheoryMode,
847 pending_assignments: Vec<(Lit, bool)>,
849 #[allow(dead_code)]
851 decision_hints: Vec<TheoryDecision>,
852 pending_equalities: Vec<EqualityNotification>,
854 processed_equalities: FxHashMap<(TermId, TermId), bool>,
856 statistics: &'a mut Statistics,
858 max_conflicts: u64,
860 #[allow(dead_code)]
862 max_decisions: u64,
863}
864
865impl<'a> TheoryManager<'a> {
866 #[allow(clippy::too_many_arguments)]
867 fn new(
868 euf: &'a mut EufSolver,
869 arith: &'a mut ArithSolver,
870 var_to_constraint: &'a FxHashMap<Var, Constraint>,
871 term_to_var: &'a FxHashMap<TermId, Var>,
872 theory_mode: TheoryMode,
873 statistics: &'a mut Statistics,
874 max_conflicts: u64,
875 max_decisions: u64,
876 ) -> Self {
877 Self {
878 euf,
879 arith,
880 var_to_constraint,
881 term_to_var,
882 level_stack: vec![0],
883 processed_count: 0,
884 theory_mode,
885 pending_assignments: Vec::new(),
886 decision_hints: Vec::new(),
887 pending_equalities: Vec::new(),
888 processed_equalities: FxHashMap::default(),
889 statistics,
890 max_conflicts,
891 max_decisions,
892 }
893 }
894
895 #[allow(dead_code)]
898 fn propagate_equalities(&mut self) -> TheoryCheckResult {
899 while let Some(eq) = self.pending_equalities.pop() {
901 let key = if eq.lhs < eq.rhs {
903 (eq.lhs, eq.rhs)
904 } else {
905 (eq.rhs, eq.lhs)
906 };
907
908 if self.processed_equalities.contains_key(&key) {
909 continue;
910 }
911 self.processed_equalities.insert(key, true);
912
913 let lhs_node = self.euf.intern(eq.lhs);
915 let rhs_node = self.euf.intern(eq.rhs);
916 if let Err(_e) = self
917 .euf
918 .merge(lhs_node, rhs_node, eq.reason.unwrap_or(eq.lhs))
919 {
920 continue;
922 }
923
924 if let Some(conflict_terms) = self.euf.check_conflicts() {
926 let conflict_lits = self.terms_to_conflict_clause(&conflict_terms);
927 return TheoryCheckResult::Conflict(conflict_lits);
928 }
929
930 self.arith.notify_equality(eq);
932 }
933
934 TheoryCheckResult::Sat
935 }
936
937 #[allow(dead_code)]
941 fn model_based_combination(&mut self) -> TheoryCheckResult {
942 let mut shared_terms: Vec<TermId> = Vec::new();
944
945 for &term in self.term_to_var.keys() {
948 shared_terms.push(term);
949 }
950
951 if shared_terms.len() < 2 {
952 return TheoryCheckResult::Sat;
953 }
954
955 for i in 0..shared_terms.len() {
958 for j in (i + 1)..shared_terms.len() {
959 let t1 = shared_terms[i];
960 let t2 = shared_terms[j];
961
962 let t1_node = self.euf.intern(t1);
964 let t2_node = self.euf.intern(t2);
965
966 if self.euf.are_equal(t1_node, t2_node) {
967 let t1_value = self.arith.value(t1);
970 let t2_value = self.arith.value(t2);
971
972 if let (Some(v1), Some(v2)) = (t1_value, t2_value) {
973 if v1 != v2 {
974 let conflict_lits = self.terms_to_conflict_clause(&[t1, t2]);
978 return TheoryCheckResult::Conflict(conflict_lits);
979 }
980 }
981 }
982 }
983 }
984
985 TheoryCheckResult::Sat
986 }
987
988 #[allow(dead_code)]
990 fn add_shared_equality(&mut self, lhs: TermId, rhs: TermId, reason: Option<TermId>) {
991 self.pending_equalities
992 .push(EqualityNotification { lhs, rhs, reason });
993 }
994
995 #[allow(dead_code)]
998 fn get_decision_hints(&mut self) -> &[TheoryDecision] {
999 self.decision_hints.clear();
1001
1002 &self.decision_hints
1013 }
1014
1015 fn terms_to_conflict_clause(&self, terms: &[TermId]) -> SmallVec<[Lit; 8]> {
1018 let mut conflict = SmallVec::new();
1019 for &term in terms {
1020 if let Some(&var) = self.term_to_var.get(&term) {
1021 conflict.push(Lit::neg(var));
1023 }
1024 }
1025 conflict
1026 }
1027
1028 fn process_constraint(
1030 &mut self,
1031 constraint: Constraint,
1032 is_positive: bool,
1033 ) -> TheoryCheckResult {
1034 match constraint {
1035 Constraint::Eq(lhs, rhs) => {
1036 if is_positive {
1037 let lhs_node = self.euf.intern(lhs);
1039 let rhs_node = self.euf.intern(rhs);
1040 if let Err(_e) = self.euf.merge(lhs_node, rhs_node, lhs) {
1041 return TheoryCheckResult::Sat;
1043 }
1044
1045 if let Some(conflict_terms) = self.euf.check_conflicts() {
1047 let conflict_lits = self.terms_to_conflict_clause(&conflict_terms);
1049 return TheoryCheckResult::Conflict(conflict_lits);
1050 }
1051 } else {
1052 let lhs_node = self.euf.intern(lhs);
1054 let rhs_node = self.euf.intern(rhs);
1055 self.euf.assert_diseq(lhs_node, rhs_node, lhs);
1056
1057 if let Some(conflict_terms) = self.euf.check_conflicts() {
1059 let conflict_lits = self.terms_to_conflict_clause(&conflict_terms);
1060 return TheoryCheckResult::Conflict(conflict_lits);
1061 }
1062 }
1063 }
1064 Constraint::Diseq(lhs, rhs) => {
1065 if is_positive {
1066 let lhs_node = self.euf.intern(lhs);
1068 let rhs_node = self.euf.intern(rhs);
1069 self.euf.assert_diseq(lhs_node, rhs_node, lhs);
1070
1071 if let Some(conflict_terms) = self.euf.check_conflicts() {
1072 let conflict_lits = self.terms_to_conflict_clause(&conflict_terms);
1073 return TheoryCheckResult::Conflict(conflict_lits);
1074 }
1075 } else {
1076 let lhs_node = self.euf.intern(lhs);
1078 let rhs_node = self.euf.intern(rhs);
1079 if let Err(_e) = self.euf.merge(lhs_node, rhs_node, lhs) {
1080 return TheoryCheckResult::Sat;
1081 }
1082
1083 if let Some(conflict_terms) = self.euf.check_conflicts() {
1084 let conflict_lits = self.terms_to_conflict_clause(&conflict_terms);
1085 return TheoryCheckResult::Conflict(conflict_lits);
1086 }
1087 }
1088 }
1089 Constraint::Lt(_lhs, _rhs)
1092 | Constraint::Le(_lhs, _rhs)
1093 | Constraint::Gt(_lhs, _rhs)
1094 | Constraint::Ge(_lhs, _rhs) => {
1095 }
1100 }
1101 TheoryCheckResult::Sat
1102 }
1103}
1104
1105impl TheoryCallback for TheoryManager<'_> {
1106 fn on_assignment(&mut self, lit: Lit) -> TheoryCheckResult {
1107 let var = lit.var();
1108 let is_positive = !lit.is_neg();
1109
1110 self.statistics.propagations += 1;
1112
1113 if self.theory_mode == TheoryMode::Lazy {
1115 if self.var_to_constraint.contains_key(&var) {
1117 self.pending_assignments.push((lit, is_positive));
1118 }
1119 return TheoryCheckResult::Sat;
1120 }
1121
1122 let Some(constraint) = self.var_to_constraint.get(&var).cloned() else {
1125 return TheoryCheckResult::Sat;
1126 };
1127
1128 self.processed_count += 1;
1129 self.statistics.theory_propagations += 1;
1130
1131 let result = self.process_constraint(constraint, is_positive);
1132
1133 if matches!(result, TheoryCheckResult::Conflict(_)) {
1135 self.statistics.theory_conflicts += 1;
1136 self.statistics.conflicts += 1;
1137
1138 if self.max_conflicts > 0 && self.statistics.conflicts >= self.max_conflicts {
1140 return TheoryCheckResult::Sat; }
1142 }
1143
1144 result
1145 }
1146
1147 fn final_check(&mut self) -> TheoryCheckResult {
1148 if self.theory_mode == TheoryMode::Lazy {
1150 for &(lit, is_positive) in &self.pending_assignments.clone() {
1151 let var = lit.var();
1152 let Some(constraint) = self.var_to_constraint.get(&var).cloned() else {
1153 continue;
1154 };
1155
1156 self.statistics.theory_propagations += 1;
1157
1158 let result = self.process_constraint(constraint, is_positive);
1160 if let TheoryCheckResult::Conflict(conflict) = result {
1161 self.statistics.theory_conflicts += 1;
1162 self.statistics.conflicts += 1;
1163
1164 if self.max_conflicts > 0 && self.statistics.conflicts >= self.max_conflicts {
1166 return TheoryCheckResult::Sat; }
1168
1169 return TheoryCheckResult::Conflict(conflict);
1170 }
1171 }
1172 self.pending_assignments.clear();
1174 }
1175
1176 if let Some(conflict_terms) = self.euf.check_conflicts() {
1178 let conflict_lits = self.terms_to_conflict_clause(&conflict_terms);
1180 self.statistics.theory_conflicts += 1;
1181 self.statistics.conflicts += 1;
1182
1183 if self.max_conflicts > 0 && self.statistics.conflicts >= self.max_conflicts {
1185 return TheoryCheckResult::Sat; }
1187
1188 return TheoryCheckResult::Conflict(conflict_lits);
1189 }
1190
1191 match self.arith.check() {
1193 Ok(result) => {
1194 match result {
1195 oxiz_theories::TheoryCheckResult::Sat => {
1196 self.model_based_combination()
1199 }
1200 oxiz_theories::TheoryCheckResult::Unsat(conflict_terms) => {
1201 let conflict_lits = self.terms_to_conflict_clause(&conflict_terms);
1203 self.statistics.theory_conflicts += 1;
1204 self.statistics.conflicts += 1;
1205
1206 if self.max_conflicts > 0 && self.statistics.conflicts >= self.max_conflicts
1208 {
1209 return TheoryCheckResult::Sat; }
1211
1212 TheoryCheckResult::Conflict(conflict_lits)
1213 }
1214 oxiz_theories::TheoryCheckResult::Propagate(_) => {
1215 self.model_based_combination()
1217 }
1218 oxiz_theories::TheoryCheckResult::Unknown => {
1219 TheoryCheckResult::Sat
1221 }
1222 }
1223 }
1224 Err(_error) => {
1225 TheoryCheckResult::Sat
1228 }
1229 }
1230 }
1231
1232 fn on_backtrack(&mut self, level: u32) {
1233 while self.level_stack.len() > (level as usize + 1) {
1235 self.level_stack.pop();
1236 self.euf.pop();
1237 self.arith.pop();
1238 }
1239 self.processed_count = *self.level_stack.last().unwrap_or(&0);
1240
1241 if self.theory_mode == TheoryMode::Lazy {
1243 self.pending_assignments.clear();
1244 }
1245 }
1246}
1247
1248#[derive(Debug, Clone)]
1250enum TrailOp {
1251 AssertionAdded { index: usize },
1253 VarCreated {
1255 #[allow(dead_code)]
1256 var: Var,
1257 term: TermId,
1258 },
1259 ConstraintAdded { var: Var },
1261 FalseAssertionSet,
1263 NamedAssertionAdded { index: usize },
1265}
1266
1267#[derive(Debug, Clone)]
1269struct ContextState {
1270 num_assertions: usize,
1271 num_vars: usize,
1272 has_false_assertion: bool,
1273 trail_position: usize,
1275}
1276
1277impl Default for Solver {
1278 fn default() -> Self {
1279 Self::new()
1280 }
1281}
1282
1283impl Solver {
1284 #[must_use]
1286 pub fn new() -> Self {
1287 Self::with_config(SolverConfig::default())
1288 }
1289
1290 #[must_use]
1292 pub fn with_config(config: SolverConfig) -> Self {
1293 let proof_enabled = config.proof;
1294
1295 let sat_config = SatConfig {
1297 restart_strategy: config.restart_strategy,
1298 enable_inprocessing: config.enable_inprocessing,
1299 inprocessing_interval: config.inprocessing_interval,
1300 ..SatConfig::default()
1301 };
1302
1303 Self {
1313 config,
1314 sat: SatSolver::with_config(sat_config),
1315 euf: EufSolver::new(),
1316 arith: ArithSolver::lra(),
1317 mbqi: MBQISolver::new(),
1318 has_quantifiers: false,
1319 term_to_var: FxHashMap::default(),
1320 var_to_term: Vec::new(),
1321 var_to_constraint: FxHashMap::default(),
1322 logic: None,
1323 assertions: Vec::new(),
1324 named_assertions: Vec::new(),
1325 assumption_vars: FxHashMap::default(),
1326 model: None,
1327 unsat_core: None,
1328 context_stack: Vec::new(),
1329 trail: Vec::new(),
1330 theory_processed_up_to: 0,
1331 produce_unsat_cores: false,
1332 has_false_assertion: false,
1333 polarities: FxHashMap::default(),
1334 polarity_aware: true, theory_aware_branching: true, proof: if proof_enabled {
1337 Some(Proof::new())
1338 } else {
1339 None
1340 },
1341 simplifier: Simplifier::new(),
1342 statistics: Statistics::new(),
1343 }
1344 }
1345
1346 #[must_use]
1348 pub fn get_proof(&self) -> Option<&Proof> {
1349 self.proof.as_ref()
1350 }
1351
1352 #[must_use]
1354 pub fn get_statistics(&self) -> &Statistics {
1355 &self.statistics
1356 }
1357
1358 pub fn reset_statistics(&mut self) {
1360 self.statistics.reset();
1361 }
1362
1363 pub fn set_theory_aware_branching(&mut self, enabled: bool) {
1365 self.theory_aware_branching = enabled;
1366 }
1367
1368 #[must_use]
1370 pub fn theory_aware_branching(&self) -> bool {
1371 self.theory_aware_branching
1372 }
1373
1374 pub fn set_produce_unsat_cores(&mut self, produce: bool) {
1376 self.produce_unsat_cores = produce;
1377 }
1378
1379 pub fn set_logic(&mut self, logic: &str) {
1381 self.logic = Some(logic.to_string());
1382 }
1383
1384 fn collect_polarities(&mut self, term: TermId, polarity: Polarity, manager: &TermManager) {
1387 let current = self.polarities.get(&term).copied();
1389 let new_polarity = match (current, polarity) {
1390 (Some(Polarity::Both), _) | (_, Polarity::Both) => Polarity::Both,
1391 (Some(Polarity::Positive), Polarity::Negative)
1392 | (Some(Polarity::Negative), Polarity::Positive) => Polarity::Both,
1393 (Some(p), _) => p,
1394 (None, p) => p,
1395 };
1396 self.polarities.insert(term, new_polarity);
1397
1398 if current == Some(Polarity::Both) {
1400 return;
1401 }
1402
1403 let Some(t) = manager.get(term) else {
1405 return;
1406 };
1407
1408 match &t.kind {
1409 TermKind::Not(arg) => {
1410 let neg_polarity = match polarity {
1411 Polarity::Positive => Polarity::Negative,
1412 Polarity::Negative => Polarity::Positive,
1413 Polarity::Both => Polarity::Both,
1414 };
1415 self.collect_polarities(*arg, neg_polarity, manager);
1416 }
1417 TermKind::And(args) | TermKind::Or(args) => {
1418 for &arg in args {
1419 self.collect_polarities(arg, polarity, manager);
1420 }
1421 }
1422 TermKind::Implies(lhs, rhs) => {
1423 let neg_polarity = match polarity {
1424 Polarity::Positive => Polarity::Negative,
1425 Polarity::Negative => Polarity::Positive,
1426 Polarity::Both => Polarity::Both,
1427 };
1428 self.collect_polarities(*lhs, neg_polarity, manager);
1429 self.collect_polarities(*rhs, polarity, manager);
1430 }
1431 TermKind::Ite(cond, then_br, else_br) => {
1432 self.collect_polarities(*cond, Polarity::Both, manager);
1433 self.collect_polarities(*then_br, polarity, manager);
1434 self.collect_polarities(*else_br, polarity, manager);
1435 }
1436 TermKind::Xor(lhs, rhs) | TermKind::Eq(lhs, rhs) => {
1437 self.collect_polarities(*lhs, Polarity::Both, manager);
1439 self.collect_polarities(*rhs, Polarity::Both, manager);
1440 }
1441 _ => {
1442 }
1444 }
1445 }
1446
1447 fn get_or_create_var(&mut self, term: TermId) -> Var {
1449 if let Some(&var) = self.term_to_var.get(&term) {
1450 return var;
1451 }
1452
1453 let var = self.sat.new_var();
1454 self.term_to_var.insert(term, var);
1455 self.trail.push(TrailOp::VarCreated { var, term });
1456
1457 while self.var_to_term.len() <= var.index() {
1458 self.var_to_term.push(TermId::new(0));
1459 }
1460 self.var_to_term[var.index()] = term;
1461 var
1462 }
1463
1464 pub fn assert(&mut self, term: TermId, manager: &mut TermManager) {
1466 let index = self.assertions.len();
1467 self.assertions.push(term);
1468 self.trail.push(TrailOp::AssertionAdded { index });
1469
1470 if let Some(t) = manager.get(term) {
1472 match t.kind {
1473 TermKind::False => {
1474 if !self.has_false_assertion {
1476 self.has_false_assertion = true;
1477 self.trail.push(TrailOp::FalseAssertionSet);
1478 }
1479 if self.produce_unsat_cores {
1480 let na_index = self.named_assertions.len();
1481 self.named_assertions.push(NamedAssertion {
1482 term,
1483 name: None,
1484 index: index as u32,
1485 });
1486 self.trail
1487 .push(TrailOp::NamedAssertionAdded { index: na_index });
1488 }
1489 return;
1490 }
1491 TermKind::True => {
1492 if self.produce_unsat_cores {
1494 let na_index = self.named_assertions.len();
1495 self.named_assertions.push(NamedAssertion {
1496 term,
1497 name: None,
1498 index: index as u32,
1499 });
1500 self.trail
1501 .push(TrailOp::NamedAssertionAdded { index: na_index });
1502 }
1503 return;
1504 }
1505 _ => {}
1506 }
1507 }
1508
1509 let term_to_encode = if self.config.simplify {
1511 self.simplifier.simplify(term, manager)
1512 } else {
1513 term
1514 };
1515
1516 if let Some(t) = manager.get(term_to_encode) {
1518 match t.kind {
1519 TermKind::False => {
1520 if !self.has_false_assertion {
1521 self.has_false_assertion = true;
1522 self.trail.push(TrailOp::FalseAssertionSet);
1523 }
1524 return;
1525 }
1526 TermKind::True => {
1527 return;
1529 }
1530 _ => {}
1531 }
1532 }
1533
1534 if self.polarity_aware {
1536 self.collect_polarities(term_to_encode, Polarity::Positive, manager);
1537 }
1538
1539 let lit = self.encode(term_to_encode, manager);
1541 self.sat.add_clause([lit]);
1542
1543 if self.produce_unsat_cores {
1544 let na_index = self.named_assertions.len();
1545 self.named_assertions.push(NamedAssertion {
1546 term,
1547 name: None,
1548 index: index as u32,
1549 });
1550 self.trail
1551 .push(TrailOp::NamedAssertionAdded { index: na_index });
1552 }
1553 }
1554
1555 pub fn assert_named(&mut self, term: TermId, name: &str, manager: &mut TermManager) {
1557 let index = self.assertions.len();
1558 self.assertions.push(term);
1559 self.trail.push(TrailOp::AssertionAdded { index });
1560
1561 if let Some(t) = manager.get(term) {
1563 match t.kind {
1564 TermKind::False => {
1565 if !self.has_false_assertion {
1567 self.has_false_assertion = true;
1568 self.trail.push(TrailOp::FalseAssertionSet);
1569 }
1570 if self.produce_unsat_cores {
1571 let na_index = self.named_assertions.len();
1572 self.named_assertions.push(NamedAssertion {
1573 term,
1574 name: Some(name.to_string()),
1575 index: index as u32,
1576 });
1577 self.trail
1578 .push(TrailOp::NamedAssertionAdded { index: na_index });
1579 }
1580 return;
1581 }
1582 TermKind::True => {
1583 if self.produce_unsat_cores {
1585 let na_index = self.named_assertions.len();
1586 self.named_assertions.push(NamedAssertion {
1587 term,
1588 name: Some(name.to_string()),
1589 index: index as u32,
1590 });
1591 self.trail
1592 .push(TrailOp::NamedAssertionAdded { index: na_index });
1593 }
1594 return;
1595 }
1596 _ => {}
1597 }
1598 }
1599
1600 if self.polarity_aware {
1602 self.collect_polarities(term, Polarity::Positive, manager);
1603 }
1604
1605 let lit = self.encode(term, manager);
1607 self.sat.add_clause([lit]);
1608
1609 if self.produce_unsat_cores {
1610 let na_index = self.named_assertions.len();
1611 self.named_assertions.push(NamedAssertion {
1612 term,
1613 name: Some(name.to_string()),
1614 index: index as u32,
1615 });
1616 self.trail
1617 .push(TrailOp::NamedAssertionAdded { index: na_index });
1618 }
1619 }
1620
1621 #[must_use]
1623 pub fn get_unsat_core(&self) -> Option<&UnsatCore> {
1624 self.unsat_core.as_ref()
1625 }
1626
1627 fn encode(&mut self, term: TermId, manager: &mut TermManager) -> Lit {
1629 let Some(t) = manager.get(term).cloned() else {
1631 let var = self.get_or_create_var(term);
1632 return Lit::pos(var);
1633 };
1634
1635 match &t.kind {
1636 TermKind::True => {
1637 let var = self.get_or_create_var(manager.mk_true());
1638 self.sat.add_clause([Lit::pos(var)]);
1639 Lit::pos(var)
1640 }
1641 TermKind::False => {
1642 let var = self.get_or_create_var(manager.mk_false());
1643 self.sat.add_clause([Lit::neg(var)]);
1644 Lit::neg(var)
1645 }
1646 TermKind::Var(_) => {
1647 let var = self.get_or_create_var(term);
1648 Lit::pos(var)
1649 }
1650 TermKind::Not(arg) => {
1651 let arg_lit = self.encode(*arg, manager);
1652 arg_lit.negate()
1653 }
1654 TermKind::And(args) => {
1655 let result_var = self.get_or_create_var(term);
1656 let result = Lit::pos(result_var);
1657
1658 let mut arg_lits: Vec<Lit> = Vec::new();
1659 for &arg in args {
1660 arg_lits.push(self.encode(arg, manager));
1661 }
1662
1663 let polarity = if self.polarity_aware {
1665 self.polarities
1666 .get(&term)
1667 .copied()
1668 .unwrap_or(Polarity::Both)
1669 } else {
1670 Polarity::Both
1671 };
1672
1673 if polarity != Polarity::Negative {
1676 for &arg in &arg_lits {
1677 self.sat.add_clause([result.negate(), arg]);
1678 }
1679 }
1680
1681 if polarity != Polarity::Positive {
1684 let mut clause: Vec<Lit> = arg_lits.iter().map(|l| l.negate()).collect();
1685 clause.push(result);
1686 self.sat.add_clause(clause);
1687 }
1688
1689 result
1690 }
1691 TermKind::Or(args) => {
1692 let result_var = self.get_or_create_var(term);
1693 let result = Lit::pos(result_var);
1694
1695 let mut arg_lits: Vec<Lit> = Vec::new();
1696 for &arg in args {
1697 arg_lits.push(self.encode(arg, manager));
1698 }
1699
1700 let polarity = if self.polarity_aware {
1702 self.polarities
1703 .get(&term)
1704 .copied()
1705 .unwrap_or(Polarity::Both)
1706 } else {
1707 Polarity::Both
1708 };
1709
1710 if polarity != Polarity::Negative {
1713 let mut clause: Vec<Lit> = vec![result.negate()];
1714 clause.extend(arg_lits.iter().copied());
1715 self.sat.add_clause(clause);
1716 }
1717
1718 if polarity != Polarity::Positive {
1721 for &arg in &arg_lits {
1722 self.sat.add_clause([arg.negate(), result]);
1723 }
1724 }
1725
1726 result
1727 }
1728 TermKind::Xor(lhs, rhs) => {
1729 let lhs_lit = self.encode(*lhs, manager);
1730 let rhs_lit = self.encode(*rhs, manager);
1731
1732 let result_var = self.get_or_create_var(term);
1733 let result = Lit::pos(result_var);
1734
1735 self.sat.add_clause([result.negate(), lhs_lit, rhs_lit]);
1740 self.sat
1742 .add_clause([result.negate(), lhs_lit.negate(), rhs_lit.negate()]);
1743
1744 self.sat.add_clause([lhs_lit.negate(), rhs_lit, result]);
1746 self.sat.add_clause([lhs_lit, rhs_lit.negate(), result]);
1748
1749 result
1750 }
1751 TermKind::Implies(lhs, rhs) => {
1752 let lhs_lit = self.encode(*lhs, manager);
1753 let rhs_lit = self.encode(*rhs, manager);
1754
1755 let result_var = self.get_or_create_var(term);
1756 let result = Lit::pos(result_var);
1757
1758 self.sat
1761 .add_clause([result.negate(), lhs_lit.negate(), rhs_lit]);
1762
1763 self.sat.add_clause([lhs_lit, result]);
1766 self.sat.add_clause([rhs_lit.negate(), result]);
1767
1768 result
1769 }
1770 TermKind::Ite(cond, then_br, else_br) => {
1771 let cond_lit = self.encode(*cond, manager);
1772 let then_lit = self.encode(*then_br, manager);
1773 let else_lit = self.encode(*else_br, manager);
1774
1775 let result_var = self.get_or_create_var(term);
1776 let result = Lit::pos(result_var);
1777
1778 self.sat
1781 .add_clause([cond_lit.negate(), result.negate(), then_lit]);
1782 self.sat
1784 .add_clause([cond_lit.negate(), then_lit.negate(), result]);
1785
1786 self.sat.add_clause([cond_lit, result.negate(), else_lit]);
1788 self.sat.add_clause([cond_lit, else_lit.negate(), result]);
1790
1791 result
1792 }
1793 TermKind::Eq(lhs, rhs) => {
1794 let lhs_term = manager.get(*lhs);
1796 let is_bool_eq = lhs_term.is_some_and(|t| t.sort == manager.sorts.bool_sort);
1797
1798 if is_bool_eq {
1799 let lhs_lit = self.encode(*lhs, manager);
1801 let rhs_lit = self.encode(*rhs, manager);
1802
1803 let result_var = self.get_or_create_var(term);
1804 let result = Lit::pos(result_var);
1805
1806 self.sat
1809 .add_clause([result.negate(), lhs_lit.negate(), rhs_lit]);
1810 self.sat
1811 .add_clause([result.negate(), rhs_lit.negate(), lhs_lit]);
1812
1813 self.sat.add_clause([lhs_lit, rhs_lit, result]);
1815 self.sat
1816 .add_clause([lhs_lit.negate(), rhs_lit.negate(), result]);
1817
1818 result
1819 } else {
1820 let var = self.get_or_create_var(term);
1823 self.var_to_constraint
1824 .insert(var, Constraint::Eq(*lhs, *rhs));
1825 self.trail.push(TrailOp::ConstraintAdded { var });
1826 Lit::pos(var)
1827 }
1828 }
1829 TermKind::Distinct(args) => {
1830 if args.len() <= 1 {
1833 let var = self.get_or_create_var(manager.mk_true());
1835 return Lit::pos(var);
1836 }
1837
1838 let result_var = self.get_or_create_var(term);
1839 let result = Lit::pos(result_var);
1840
1841 let mut diseq_lits = Vec::new();
1842 for i in 0..args.len() {
1843 for j in (i + 1)..args.len() {
1844 let eq = manager.mk_eq(args[i], args[j]);
1845 let eq_lit = self.encode(eq, manager);
1846 diseq_lits.push(eq_lit.negate());
1847 }
1848 }
1849
1850 for &diseq in &diseq_lits {
1852 self.sat.add_clause([result.negate(), diseq]);
1853 }
1854
1855 let mut clause: Vec<Lit> = diseq_lits.iter().map(|l| l.negate()).collect();
1857 clause.push(result);
1858 self.sat.add_clause(clause);
1859
1860 result
1861 }
1862 TermKind::Let { bindings, body } => {
1863 let substituted = *body;
1867 for (name, value) in bindings.iter().rev() {
1868 let _ = (name, value);
1871 }
1872 self.encode(substituted, manager)
1873 }
1874 TermKind::IntConst(_) | TermKind::RealConst(_) | TermKind::BitVecConst { .. } => {
1877 let var = self.get_or_create_var(term);
1880 Lit::pos(var)
1881 }
1882 TermKind::Neg(_)
1883 | TermKind::Add(_)
1884 | TermKind::Sub(_, _)
1885 | TermKind::Mul(_)
1886 | TermKind::Div(_, _)
1887 | TermKind::Mod(_, _) => {
1888 let var = self.get_or_create_var(term);
1890 Lit::pos(var)
1891 }
1892 TermKind::Lt(lhs, rhs) => {
1893 let var = self.get_or_create_var(term);
1895 self.var_to_constraint
1896 .insert(var, Constraint::Lt(*lhs, *rhs));
1897 self.trail.push(TrailOp::ConstraintAdded { var });
1898 Lit::pos(var)
1899 }
1900 TermKind::Le(lhs, rhs) => {
1901 let var = self.get_or_create_var(term);
1903 self.var_to_constraint
1904 .insert(var, Constraint::Le(*lhs, *rhs));
1905 self.trail.push(TrailOp::ConstraintAdded { var });
1906 Lit::pos(var)
1907 }
1908 TermKind::Gt(lhs, rhs) => {
1909 let var = self.get_or_create_var(term);
1911 self.var_to_constraint
1912 .insert(var, Constraint::Gt(*lhs, *rhs));
1913 self.trail.push(TrailOp::ConstraintAdded { var });
1914 Lit::pos(var)
1915 }
1916 TermKind::Ge(lhs, rhs) => {
1917 let var = self.get_or_create_var(term);
1919 self.var_to_constraint
1920 .insert(var, Constraint::Ge(*lhs, *rhs));
1921 self.trail.push(TrailOp::ConstraintAdded { var });
1922 Lit::pos(var)
1923 }
1924 TermKind::BvConcat(_, _)
1925 | TermKind::BvExtract { .. }
1926 | TermKind::BvNot(_)
1927 | TermKind::BvAnd(_, _)
1928 | TermKind::BvOr(_, _)
1929 | TermKind::BvXor(_, _)
1930 | TermKind::BvAdd(_, _)
1931 | TermKind::BvSub(_, _)
1932 | TermKind::BvMul(_, _)
1933 | TermKind::BvUdiv(_, _)
1934 | TermKind::BvSdiv(_, _)
1935 | TermKind::BvUrem(_, _)
1936 | TermKind::BvSrem(_, _)
1937 | TermKind::BvShl(_, _)
1938 | TermKind::BvLshr(_, _)
1939 | TermKind::BvAshr(_, _) => {
1940 let var = self.get_or_create_var(term);
1942 Lit::pos(var)
1943 }
1944 TermKind::BvUlt(_, _)
1945 | TermKind::BvUle(_, _)
1946 | TermKind::BvSlt(_, _)
1947 | TermKind::BvSle(_, _) => {
1948 let var = self.get_or_create_var(term);
1950 Lit::pos(var)
1951 }
1952 TermKind::Select(_, _) | TermKind::Store(_, _, _) => {
1953 let var = self.get_or_create_var(term);
1955 Lit::pos(var)
1956 }
1957 TermKind::Apply { .. } => {
1958 let var = self.get_or_create_var(term);
1960 Lit::pos(var)
1961 }
1962 TermKind::Forall { patterns, .. } => {
1963 self.has_quantifiers = true;
1965 self.mbqi.add_quantifier(term, manager);
1966 for pattern in patterns {
1968 for &trigger in pattern {
1969 self.mbqi.collect_ground_terms(trigger, manager);
1970 }
1971 }
1972 let var = self.get_or_create_var(term);
1974 Lit::pos(var)
1975 }
1976 TermKind::Exists { patterns, .. } => {
1977 self.has_quantifiers = true;
1979 self.mbqi.add_quantifier(term, manager);
1980 for pattern in patterns {
1982 for &trigger in pattern {
1983 self.mbqi.collect_ground_terms(trigger, manager);
1984 }
1985 }
1986 let var = self.get_or_create_var(term);
1988 Lit::pos(var)
1989 }
1990 TermKind::StringLit(_)
1992 | TermKind::StrConcat(_, _)
1993 | TermKind::StrLen(_)
1994 | TermKind::StrSubstr(_, _, _)
1995 | TermKind::StrAt(_, _)
1996 | TermKind::StrReplace(_, _, _)
1997 | TermKind::StrReplaceAll(_, _, _)
1998 | TermKind::StrToInt(_)
1999 | TermKind::IntToStr(_)
2000 | TermKind::StrInRe(_, _) => {
2001 let var = self.get_or_create_var(term);
2003 Lit::pos(var)
2004 }
2005 TermKind::StrContains(_, _)
2006 | TermKind::StrPrefixOf(_, _)
2007 | TermKind::StrSuffixOf(_, _)
2008 | TermKind::StrIndexOf(_, _, _) => {
2009 let var = self.get_or_create_var(term);
2011 Lit::pos(var)
2012 }
2013 TermKind::FpLit { .. }
2015 | TermKind::FpPlusInfinity { .. }
2016 | TermKind::FpMinusInfinity { .. }
2017 | TermKind::FpPlusZero { .. }
2018 | TermKind::FpMinusZero { .. }
2019 | TermKind::FpNaN { .. } => {
2020 let var = self.get_or_create_var(term);
2022 Lit::pos(var)
2023 }
2024 TermKind::FpAbs(_)
2026 | TermKind::FpNeg(_)
2027 | TermKind::FpSqrt(_, _)
2028 | TermKind::FpRoundToIntegral(_, _)
2029 | TermKind::FpAdd(_, _, _)
2030 | TermKind::FpSub(_, _, _)
2031 | TermKind::FpMul(_, _, _)
2032 | TermKind::FpDiv(_, _, _)
2033 | TermKind::FpRem(_, _)
2034 | TermKind::FpMin(_, _)
2035 | TermKind::FpMax(_, _)
2036 | TermKind::FpFma(_, _, _, _) => {
2037 let var = self.get_or_create_var(term);
2039 Lit::pos(var)
2040 }
2041 TermKind::FpLeq(_, _)
2043 | TermKind::FpLt(_, _)
2044 | TermKind::FpGeq(_, _)
2045 | TermKind::FpGt(_, _)
2046 | TermKind::FpEq(_, _)
2047 | TermKind::FpIsNormal(_)
2048 | TermKind::FpIsSubnormal(_)
2049 | TermKind::FpIsZero(_)
2050 | TermKind::FpIsInfinite(_)
2051 | TermKind::FpIsNaN(_)
2052 | TermKind::FpIsNegative(_)
2053 | TermKind::FpIsPositive(_) => {
2054 let var = self.get_or_create_var(term);
2056 Lit::pos(var)
2057 }
2058 TermKind::FpToFp { .. }
2060 | TermKind::FpToSBV { .. }
2061 | TermKind::FpToUBV { .. }
2062 | TermKind::FpToReal(_)
2063 | TermKind::RealToFp { .. }
2064 | TermKind::SBVToFp { .. }
2065 | TermKind::UBVToFp { .. } => {
2066 let var = self.get_or_create_var(term);
2068 Lit::pos(var)
2069 }
2070 TermKind::DtConstructor { .. }
2072 | TermKind::DtTester { .. }
2073 | TermKind::DtSelector { .. } => {
2074 let var = self.get_or_create_var(term);
2076 Lit::pos(var)
2077 }
2078 }
2079 }
2080
2081 pub fn check(&mut self, manager: &mut TermManager) -> SolverResult {
2083 if self.has_false_assertion {
2085 self.build_unsat_core_trivial_false();
2086 return SolverResult::Unsat;
2087 }
2088
2089 if self.assertions.is_empty() {
2090 return SolverResult::Sat;
2091 }
2092
2093 if self.config.max_conflicts > 0 && self.statistics.conflicts >= self.config.max_conflicts {
2095 return SolverResult::Unknown;
2096 }
2097 if self.config.max_decisions > 0 && self.statistics.decisions >= self.config.max_decisions {
2098 return SolverResult::Unknown;
2099 }
2100
2101 let mut theory_manager = TheoryManager::new(
2103 &mut self.euf,
2104 &mut self.arith,
2105 &self.var_to_constraint,
2106 &self.term_to_var,
2107 self.config.theory_mode,
2108 &mut self.statistics,
2109 self.config.max_conflicts,
2110 self.config.max_decisions,
2111 );
2112
2113 let max_mbqi_iterations = 100;
2115 let mut mbqi_iteration = 0;
2116
2117 loop {
2118 let sat_result = self.sat.solve_with_theory(&mut theory_manager);
2119
2120 match sat_result {
2121 SatResult::Unsat => {
2122 self.build_unsat_core();
2123 return SolverResult::Unsat;
2124 }
2125 SatResult::Unknown => {
2126 return SolverResult::Unknown;
2127 }
2128 SatResult::Sat => {
2129 if !self.has_quantifiers {
2131 self.build_model(manager);
2132 self.unsat_core = None;
2133 return SolverResult::Sat;
2134 }
2135
2136 self.build_model(manager);
2138
2139 let model_assignments = self
2141 .model
2142 .as_ref()
2143 .map(|m| m.assignments().clone())
2144 .unwrap_or_default();
2145 let mbqi_result = self.mbqi.check_with_model(&model_assignments, manager);
2146
2147 match mbqi_result {
2148 MBQIResult::NoQuantifiers | MBQIResult::Satisfied => {
2149 self.unsat_core = None;
2151 return SolverResult::Sat;
2152 }
2153 MBQIResult::InstantiationLimit => {
2154 return SolverResult::Unknown;
2156 }
2157 MBQIResult::Conflict(conflict_terms) => {
2158 let lits: Vec<Lit> = conflict_terms
2160 .iter()
2161 .filter_map(|&t| self.term_to_var.get(&t).map(|&v| Lit::neg(v)))
2162 .collect();
2163 if !lits.is_empty() {
2164 self.sat.add_clause(lits);
2165 }
2166 }
2168 MBQIResult::NewInstantiations(instantiations) => {
2169 for inst in instantiations {
2171 let lit = self.encode(inst.result, manager);
2174 self.sat.add_clause([lit]);
2175 }
2176 }
2178 }
2179
2180 mbqi_iteration += 1;
2181 if mbqi_iteration >= max_mbqi_iterations {
2182 return SolverResult::Unknown;
2183 }
2184
2185 theory_manager = TheoryManager::new(
2187 &mut self.euf,
2188 &mut self.arith,
2189 &self.var_to_constraint,
2190 &self.term_to_var,
2191 self.config.theory_mode,
2192 &mut self.statistics,
2193 self.config.max_conflicts,
2194 self.config.max_decisions,
2195 );
2196 }
2197 }
2198 }
2199 }
2200
2201 pub fn check_with_assumptions(
2204 &mut self,
2205 assumptions: &[TermId],
2206 manager: &mut TermManager,
2207 ) -> SolverResult {
2208 self.push();
2210
2211 for &assumption in assumptions {
2213 self.assert(assumption, manager);
2214 }
2215
2216 let result = self.check(manager);
2218
2219 self.pop();
2221
2222 result
2223 }
2224
2225 pub fn check_sat_only(&mut self, manager: &mut TermManager) -> SolverResult {
2228 if self.assertions.is_empty() {
2229 return SolverResult::Sat;
2230 }
2231
2232 match self.sat.solve() {
2233 SatResult::Sat => {
2234 self.build_model(manager);
2235 SolverResult::Sat
2236 }
2237 SatResult::Unsat => SolverResult::Unsat,
2238 SatResult::Unknown => SolverResult::Unknown,
2239 }
2240 }
2241
2242 fn build_model(&mut self, manager: &mut TermManager) {
2244 let mut model = Model::new();
2245 let sat_model = self.sat.model();
2246
2247 for (&term, &var) in &self.term_to_var {
2249 let val = sat_model.get(var.index()).copied();
2250 if let Some(v) = val {
2251 let bool_val = if v.is_true() {
2252 manager.mk_true()
2253 } else if v.is_false() {
2254 manager.mk_false()
2255 } else {
2256 continue;
2257 };
2258 model.set(term, bool_val);
2259 }
2260 }
2261
2262 for &term in self.term_to_var.keys() {
2265 if let Some(value) = self.arith.value(term) {
2266 let value_term = if *value.denom() == 1 {
2268 manager.mk_int(*value.numer())
2270 } else {
2271 manager.mk_real(value)
2273 };
2274 model.set(term, value_term);
2275 }
2276 }
2277
2278 self.model = Some(model);
2279 }
2280
2281 fn build_unsat_core_trivial_false(&mut self) {
2283 if !self.produce_unsat_cores {
2284 self.unsat_core = None;
2285 return;
2286 }
2287
2288 let mut core = UnsatCore::new();
2290
2291 for (i, &term) in self.assertions.iter().enumerate() {
2292 if term == TermId::new(1) {
2293 core.indices.push(i as u32);
2295
2296 if let Some(named) = self.named_assertions.iter().find(|na| na.index == i as u32) {
2298 if let Some(ref name) = named.name {
2299 core.names.push(name.clone());
2300 }
2301 }
2302 }
2303 }
2304
2305 self.unsat_core = Some(core);
2306 }
2307
2308 fn build_unsat_core(&mut self) {
2310 if !self.produce_unsat_cores {
2311 self.unsat_core = None;
2312 return;
2313 }
2314
2315 let mut core = UnsatCore::new();
2320
2321 if !self.assumption_vars.is_empty() {
2323 for na in &self.named_assertions {
2328 core.indices.push(na.index);
2329 if let Some(ref name) = na.name {
2330 core.names.push(name.clone());
2331 }
2332 }
2333 } else {
2334 for na in &self.named_assertions {
2337 core.indices.push(na.index);
2338 if let Some(ref name) = na.name {
2339 core.names.push(name.clone());
2340 }
2341 }
2342 }
2343
2344 self.unsat_core = Some(core);
2345 }
2346
2347 pub fn enable_assumption_based_cores(&mut self) {
2351 self.produce_unsat_cores = true;
2352 }
2355
2356 pub fn minimize_unsat_core(&mut self, manager: &mut TermManager) -> Option<UnsatCore> {
2359 if !self.produce_unsat_cores {
2360 return None;
2361 }
2362
2363 let core = self.unsat_core.as_ref()?;
2365 if core.is_empty() {
2366 return Some(core.clone());
2367 }
2368
2369 let mut core_assertions: Vec<_> = core
2371 .indices
2372 .iter()
2373 .map(|&idx| {
2374 let assertion = self.assertions[idx as usize];
2375 let name = self
2376 .named_assertions
2377 .iter()
2378 .find(|na| na.index == idx)
2379 .and_then(|na| na.name.clone());
2380 (idx, assertion, name)
2381 })
2382 .collect();
2383
2384 let mut i = 0;
2386 while i < core_assertions.len() {
2387 let mut temp_solver = Solver::new();
2389 temp_solver.set_logic(self.logic.as_deref().unwrap_or("ALL"));
2390
2391 for (j, &(_, assertion, _)) in core_assertions.iter().enumerate() {
2393 if i != j {
2394 temp_solver.assert(assertion, manager);
2395 }
2396 }
2397
2398 if temp_solver.check(manager) == SolverResult::Unsat {
2400 core_assertions.remove(i);
2402 } else {
2404 i += 1;
2406 }
2407 }
2408
2409 let mut minimized = UnsatCore::new();
2411 for (idx, _, name) in core_assertions {
2412 minimized.indices.push(idx);
2413 if let Some(n) = name {
2414 minimized.names.push(n);
2415 }
2416 }
2417
2418 Some(minimized)
2419 }
2420
2421 #[must_use]
2423 pub fn model(&self) -> Option<&Model> {
2424 self.model.as_ref()
2425 }
2426
2427 pub fn assert_many(&mut self, terms: &[TermId], manager: &mut TermManager) {
2430 for &term in terms {
2431 self.assert(term, manager);
2432 }
2433 }
2434
2435 #[must_use]
2437 pub fn num_assertions(&self) -> usize {
2438 self.assertions.len()
2439 }
2440
2441 #[must_use]
2443 pub fn num_variables(&self) -> usize {
2444 self.term_to_var.len()
2445 }
2446
2447 #[must_use]
2449 pub fn has_assertions(&self) -> bool {
2450 !self.assertions.is_empty()
2451 }
2452
2453 #[must_use]
2455 pub fn context_level(&self) -> usize {
2456 self.context_stack.len()
2457 }
2458
2459 pub fn push(&mut self) {
2461 self.context_stack.push(ContextState {
2462 num_assertions: self.assertions.len(),
2463 num_vars: self.var_to_term.len(),
2464 has_false_assertion: self.has_false_assertion,
2465 trail_position: self.trail.len(),
2466 });
2467 self.sat.push();
2468 self.euf.push();
2469 self.arith.push();
2470 }
2471
2472 pub fn pop(&mut self) {
2474 if let Some(state) = self.context_stack.pop() {
2475 while self.trail.len() > state.trail_position {
2477 if let Some(op) = self.trail.pop() {
2478 match op {
2479 TrailOp::AssertionAdded { index } => {
2480 if self.assertions.len() > index {
2481 self.assertions.truncate(index);
2482 }
2483 }
2484 TrailOp::VarCreated { var: _, term } => {
2485 self.term_to_var.remove(&term);
2487 }
2488 TrailOp::ConstraintAdded { var } => {
2489 self.var_to_constraint.remove(&var);
2491 }
2492 TrailOp::FalseAssertionSet => {
2493 self.has_false_assertion = false;
2495 }
2496 TrailOp::NamedAssertionAdded { index } => {
2497 if self.named_assertions.len() > index {
2499 self.named_assertions.truncate(index);
2500 }
2501 }
2502 }
2503 }
2504 }
2505
2506 self.assertions.truncate(state.num_assertions);
2508 self.var_to_term.truncate(state.num_vars);
2509 self.has_false_assertion = state.has_false_assertion;
2510
2511 self.sat.pop();
2512 self.euf.pop();
2513 self.arith.pop();
2514 }
2515 }
2516
2517 pub fn reset(&mut self) {
2519 self.sat.reset();
2520 self.euf.reset();
2521 self.arith.reset();
2522 self.term_to_var.clear();
2523 self.var_to_term.clear();
2524 self.var_to_constraint.clear();
2525 self.assertions.clear();
2526 self.named_assertions.clear();
2527 self.model = None;
2528 self.unsat_core = None;
2529 self.context_stack.clear();
2530 self.trail.clear();
2531 self.logic = None;
2532 self.theory_processed_up_to = 0;
2533 self.has_false_assertion = false;
2534 }
2535
2536 #[must_use]
2538 pub fn config(&self) -> &SolverConfig {
2539 &self.config
2540 }
2541
2542 pub fn set_config(&mut self, config: SolverConfig) {
2544 self.config = config;
2545 }
2546
2547 #[must_use]
2549 pub fn stats(&self) -> &oxiz_sat::SolverStats {
2550 self.sat.stats()
2551 }
2552}
2553
2554#[cfg(test)]
2555mod tests {
2556 use super::*;
2557
2558 #[test]
2559 fn test_solver_empty() {
2560 let mut solver = Solver::new();
2561 let mut manager = TermManager::new();
2562 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2563 }
2564
2565 #[test]
2566 fn test_solver_true() {
2567 let mut solver = Solver::new();
2568 let mut manager = TermManager::new();
2569 let t = manager.mk_true();
2570 solver.assert(t, &mut manager);
2571 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2572 }
2573
2574 #[test]
2575 fn test_solver_false() {
2576 let mut solver = Solver::new();
2577 let mut manager = TermManager::new();
2578 let f = manager.mk_false();
2579 solver.assert(f, &mut manager);
2580 assert_eq!(solver.check(&mut manager), SolverResult::Unsat);
2581 }
2582
2583 #[test]
2584 fn test_solver_push_pop() {
2585 let mut solver = Solver::new();
2586 let mut manager = TermManager::new();
2587
2588 let t = manager.mk_true();
2589 solver.assert(t, &mut manager);
2590 solver.push();
2591
2592 let f = manager.mk_false();
2593 solver.assert(f, &mut manager);
2594 assert_eq!(solver.check(&mut manager), SolverResult::Unsat);
2595
2596 solver.pop();
2597 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2598 }
2599
2600 #[test]
2601 fn test_unsat_core_trivial() {
2602 let mut solver = Solver::new();
2603 let mut manager = TermManager::new();
2604 solver.set_produce_unsat_cores(true);
2605
2606 let t = manager.mk_true();
2607 let f = manager.mk_false();
2608
2609 solver.assert_named(t, "a1", &mut manager);
2610 solver.assert_named(f, "a2", &mut manager);
2611 solver.assert_named(t, "a3", &mut manager);
2612
2613 assert_eq!(solver.check(&mut manager), SolverResult::Unsat);
2614
2615 let core = solver.get_unsat_core();
2616 assert!(core.is_some());
2617
2618 let core = core.unwrap();
2619 assert!(!core.is_empty());
2620 assert!(core.names.contains(&"a2".to_string()));
2621 }
2622
2623 #[test]
2624 fn test_unsat_core_not_produced_when_sat() {
2625 let mut solver = Solver::new();
2626 let mut manager = TermManager::new();
2627 solver.set_produce_unsat_cores(true);
2628
2629 let t = manager.mk_true();
2630 solver.assert_named(t, "a1", &mut manager);
2631 solver.assert_named(t, "a2", &mut manager);
2632
2633 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2634 assert!(solver.get_unsat_core().is_none());
2635 }
2636
2637 #[test]
2638 fn test_unsat_core_disabled() {
2639 let mut solver = Solver::new();
2640 let mut manager = TermManager::new();
2641 let f = manager.mk_false();
2644 solver.assert(f, &mut manager);
2645 assert_eq!(solver.check(&mut manager), SolverResult::Unsat);
2646
2647 assert!(solver.get_unsat_core().is_none());
2649 }
2650
2651 #[test]
2652 fn test_boolean_encoding_and() {
2653 let mut solver = Solver::new();
2654 let mut manager = TermManager::new();
2655
2656 let p = manager.mk_var("p", manager.sorts.bool_sort);
2658 let q = manager.mk_var("q", manager.sorts.bool_sort);
2659 let and = manager.mk_and(vec![p, q]);
2660
2661 solver.assert(and, &mut manager);
2662 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2663
2664 let model = solver.model().expect("Should have model");
2666 assert!(model.get(p).is_some());
2667 assert!(model.get(q).is_some());
2668 }
2669
2670 #[test]
2671 fn test_boolean_encoding_or() {
2672 let mut solver = Solver::new();
2673 let mut manager = TermManager::new();
2674
2675 let p = manager.mk_var("p", manager.sorts.bool_sort);
2677 let q = manager.mk_var("q", manager.sorts.bool_sort);
2678 let or = manager.mk_or(vec![p, q]);
2679 let not_p = manager.mk_not(p);
2680
2681 solver.assert(or, &mut manager);
2682 solver.assert(not_p, &mut manager);
2683 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2684 }
2685
2686 #[test]
2687 fn test_boolean_encoding_implies() {
2688 let mut solver = Solver::new();
2689 let mut manager = TermManager::new();
2690
2691 let p = manager.mk_var("p", manager.sorts.bool_sort);
2693 let q = manager.mk_var("q", manager.sorts.bool_sort);
2694 let implies = manager.mk_implies(p, q);
2695 let not_q = manager.mk_not(q);
2696
2697 solver.assert(implies, &mut manager);
2698 solver.assert(p, &mut manager);
2699 solver.assert(not_q, &mut manager);
2700 assert_eq!(solver.check(&mut manager), SolverResult::Unsat);
2701 }
2702
2703 #[test]
2704 fn test_boolean_encoding_distinct() {
2705 let mut solver = Solver::new();
2706 let mut manager = TermManager::new();
2707
2708 let p = manager.mk_var("p", manager.sorts.bool_sort);
2710 let q = manager.mk_var("q", manager.sorts.bool_sort);
2711 let r = manager.mk_var("r", manager.sorts.bool_sort);
2712 let distinct = manager.mk_distinct(vec![p, q, r]);
2713
2714 solver.assert(distinct, &mut manager);
2715 solver.assert(p, &mut manager);
2716 solver.assert(q, &mut manager);
2717 assert_eq!(solver.check(&mut manager), SolverResult::Unsat);
2718 }
2719
2720 #[test]
2721 fn test_model_evaluation_bool() {
2722 let mut solver = Solver::new();
2723 let mut manager = TermManager::new();
2724
2725 let p = manager.mk_var("p", manager.sorts.bool_sort);
2726 let q = manager.mk_var("q", manager.sorts.bool_sort);
2727
2728 solver.assert(p, &mut manager);
2730 solver.assert(manager.mk_not(q), &mut manager);
2731 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2732
2733 let model = solver.model().expect("Should have model");
2734
2735 let p_val = model.eval(p, &mut manager);
2737 assert_eq!(p_val, manager.mk_true());
2738
2739 let q_val = model.eval(q, &mut manager);
2741 assert_eq!(q_val, manager.mk_false());
2742
2743 let and_term = manager.mk_and(vec![p, q]);
2745 let and_val = model.eval(and_term, &mut manager);
2746 assert_eq!(and_val, manager.mk_false());
2747
2748 let or_term = manager.mk_or(vec![p, q]);
2750 let or_val = model.eval(or_term, &mut manager);
2751 assert_eq!(or_val, manager.mk_true());
2752 }
2753
2754 #[test]
2755 fn test_model_evaluation_ite() {
2756 let mut solver = Solver::new();
2757 let mut manager = TermManager::new();
2758
2759 let p = manager.mk_var("p", manager.sorts.bool_sort);
2760 let q = manager.mk_var("q", manager.sorts.bool_sort);
2761 let r = manager.mk_var("r", manager.sorts.bool_sort);
2762
2763 solver.assert(p, &mut manager);
2765 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2766
2767 let model = solver.model().expect("Should have model");
2768
2769 let ite_term = manager.mk_ite(p, q, r);
2771 let ite_val = model.eval(ite_term, &mut manager);
2772 let q_val = model.eval(q, &mut manager);
2774 assert_eq!(ite_val, q_val);
2775 }
2776
2777 #[test]
2778 fn test_model_evaluation_implies() {
2779 let mut solver = Solver::new();
2780 let mut manager = TermManager::new();
2781
2782 let p = manager.mk_var("p", manager.sorts.bool_sort);
2783 let q = manager.mk_var("q", manager.sorts.bool_sort);
2784
2785 solver.assert(manager.mk_not(p), &mut manager);
2787 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2788
2789 let model = solver.model().expect("Should have model");
2790
2791 let implies_term = manager.mk_implies(p, q);
2793 let implies_val = model.eval(implies_term, &mut manager);
2794 assert_eq!(implies_val, manager.mk_true());
2795 }
2796
2797 #[test]
2798 fn test_arithmetic_model_generation() {
2799 use num_bigint::BigInt;
2800
2801 let mut solver = Solver::new();
2802 let mut manager = TermManager::new();
2803
2804 let x = manager.mk_var("x", manager.sorts.int_sort);
2806 let y = manager.mk_var("y", manager.sorts.int_sort);
2807
2808 let ten = manager.mk_int(BigInt::from(10));
2810 let zero = manager.mk_int(BigInt::from(0));
2811 let sum = manager.mk_add(vec![x, y]);
2812
2813 let eq = manager.mk_eq(sum, ten);
2814 let x_ge_0 = manager.mk_ge(x, zero);
2815 let y_ge_0 = manager.mk_ge(y, zero);
2816
2817 solver.assert(eq, &mut manager);
2818 solver.assert(x_ge_0, &mut manager);
2819 solver.assert(y_ge_0, &mut manager);
2820
2821 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2822
2823 let model = solver.model();
2825 assert!(model.is_some(), "Should have a model for SAT result");
2826 }
2827
2828 #[test]
2829 fn test_model_pretty_print() {
2830 let mut solver = Solver::new();
2831 let mut manager = TermManager::new();
2832
2833 let p = manager.mk_var("p", manager.sorts.bool_sort);
2834 let q = manager.mk_var("q", manager.sorts.bool_sort);
2835
2836 solver.assert(p, &mut manager);
2837 solver.assert(manager.mk_not(q), &mut manager);
2838 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
2839
2840 let model = solver.model().expect("Should have model");
2841 let pretty = model.pretty_print(&manager);
2842
2843 assert!(pretty.contains("(model"));
2845 assert!(pretty.contains("define-fun"));
2846 assert!(pretty.contains("p") || pretty.contains("q"));
2848 }
2849
2850 #[test]
2851 fn test_trail_based_undo_assertions() {
2852 let mut solver = Solver::new();
2853 let mut manager = TermManager::new();
2854
2855 let p = manager.mk_var("p", manager.sorts.bool_sort);
2856 let q = manager.mk_var("q", manager.sorts.bool_sort);
2857
2858 assert_eq!(solver.assertions.len(), 0);
2860 assert_eq!(solver.trail.len(), 0);
2861
2862 solver.assert(p, &mut manager);
2864 assert_eq!(solver.assertions.len(), 1);
2865 assert!(!solver.trail.is_empty());
2866
2867 solver.push();
2869 let trail_len_after_push = solver.trail.len();
2870 solver.assert(q, &mut manager);
2871 assert_eq!(solver.assertions.len(), 2);
2872 assert!(solver.trail.len() > trail_len_after_push);
2873
2874 solver.pop();
2876 assert_eq!(solver.assertions.len(), 1);
2877 assert_eq!(solver.assertions[0], p);
2878 }
2879
2880 #[test]
2881 fn test_trail_based_undo_variables() {
2882 let mut solver = Solver::new();
2883 let mut manager = TermManager::new();
2884
2885 let p = manager.mk_var("p", manager.sorts.bool_sort);
2886 let q = manager.mk_var("q", manager.sorts.bool_sort);
2887
2888 solver.assert(p, &mut manager);
2890 let initial_var_count = solver.term_to_var.len();
2891
2892 solver.push();
2894 solver.assert(q, &mut manager);
2895 assert!(solver.term_to_var.len() >= initial_var_count);
2896
2897 solver.pop();
2899 assert_eq!(solver.assertions.len(), 1);
2901 }
2902
2903 #[test]
2904 fn test_trail_based_undo_constraints() {
2905 use num_bigint::BigInt;
2906
2907 let mut solver = Solver::new();
2908 let mut manager = TermManager::new();
2909
2910 let x = manager.mk_var("x", manager.sorts.int_sort);
2911 let zero = manager.mk_int(BigInt::from(0));
2912
2913 let c1 = manager.mk_ge(x, zero);
2915 solver.assert(c1, &mut manager);
2916 let initial_constraint_count = solver.var_to_constraint.len();
2917
2918 solver.push();
2920 let ten = manager.mk_int(BigInt::from(10));
2921 let c2 = manager.mk_le(x, ten);
2922 solver.assert(c2, &mut manager);
2923 assert!(solver.var_to_constraint.len() >= initial_constraint_count);
2924
2925 solver.pop();
2927 assert_eq!(solver.var_to_constraint.len(), initial_constraint_count);
2928 }
2929
2930 #[test]
2931 fn test_trail_based_undo_false_assertion() {
2932 let mut solver = Solver::new();
2933 let mut manager = TermManager::new();
2934
2935 assert!(!solver.has_false_assertion);
2936
2937 solver.push();
2938 solver.assert(manager.mk_false(), &mut manager);
2939 assert!(solver.has_false_assertion);
2940
2941 solver.pop();
2942 assert!(!solver.has_false_assertion);
2943 }
2944
2945 #[test]
2946 fn test_trail_based_undo_named_assertions() {
2947 let mut solver = Solver::new();
2948 let mut manager = TermManager::new();
2949 solver.set_produce_unsat_cores(true);
2950
2951 let p = manager.mk_var("p", manager.sorts.bool_sort);
2952
2953 solver.assert_named(p, "assertion1", &mut manager);
2954 assert_eq!(solver.named_assertions.len(), 1);
2955
2956 solver.push();
2957 let q = manager.mk_var("q", manager.sorts.bool_sort);
2958 solver.assert_named(q, "assertion2", &mut manager);
2959 assert_eq!(solver.named_assertions.len(), 2);
2960
2961 solver.pop();
2962 assert_eq!(solver.named_assertions.len(), 1);
2963 assert_eq!(
2964 solver.named_assertions[0].name,
2965 Some("assertion1".to_string())
2966 );
2967 }
2968
2969 #[test]
2970 fn test_trail_based_undo_nested_push_pop() {
2971 let mut solver = Solver::new();
2972 let mut manager = TermManager::new();
2973
2974 let p = manager.mk_var("p", manager.sorts.bool_sort);
2975 solver.assert(p, &mut manager);
2976
2977 solver.push();
2979 let q = manager.mk_var("q", manager.sorts.bool_sort);
2980 solver.assert(q, &mut manager);
2981 assert_eq!(solver.assertions.len(), 2);
2982
2983 solver.push();
2985 let r = manager.mk_var("r", manager.sorts.bool_sort);
2986 solver.assert(r, &mut manager);
2987 assert_eq!(solver.assertions.len(), 3);
2988
2989 solver.pop();
2991 assert_eq!(solver.assertions.len(), 2);
2992
2993 solver.pop();
2995 assert_eq!(solver.assertions.len(), 1);
2996 assert_eq!(solver.assertions[0], p);
2997 }
2998
2999 #[test]
3000 fn test_config_presets() {
3001 let _fast = SolverConfig::fast();
3003 let _balanced = SolverConfig::balanced();
3004 let _thorough = SolverConfig::thorough();
3005 let _minimal = SolverConfig::minimal();
3006 }
3007
3008 #[test]
3009 fn test_config_fast_characteristics() {
3010 let config = SolverConfig::fast();
3011
3012 assert!(!config.enable_variable_elimination);
3014 assert!(!config.enable_blocked_clause_elimination);
3015 assert!(!config.enable_symmetry_breaking);
3016 assert!(!config.enable_inprocessing);
3017 assert!(!config.enable_clause_subsumption);
3018
3019 assert!(config.enable_clause_minimization);
3021 assert!(config.simplify);
3022
3023 assert_eq!(config.restart_strategy, RestartStrategy::Geometric);
3025 }
3026
3027 #[test]
3028 fn test_config_balanced_characteristics() {
3029 let config = SolverConfig::balanced();
3030
3031 assert!(config.enable_variable_elimination);
3033 assert!(config.enable_blocked_clause_elimination);
3034 assert!(config.enable_inprocessing);
3035 assert!(config.enable_clause_minimization);
3036 assert!(config.enable_clause_subsumption);
3037 assert!(config.simplify);
3038
3039 assert!(!config.enable_symmetry_breaking);
3041
3042 assert_eq!(config.restart_strategy, RestartStrategy::Glucose);
3044
3045 assert_eq!(config.variable_elimination_limit, 1000);
3047 assert_eq!(config.inprocessing_interval, 10000);
3048 }
3049
3050 #[test]
3051 fn test_config_thorough_characteristics() {
3052 let config = SolverConfig::thorough();
3053
3054 assert!(config.enable_variable_elimination);
3056 assert!(config.enable_blocked_clause_elimination);
3057 assert!(config.enable_symmetry_breaking); assert!(config.enable_inprocessing);
3059 assert!(config.enable_clause_minimization);
3060 assert!(config.enable_clause_subsumption);
3061 assert!(config.simplify);
3062
3063 assert_eq!(config.variable_elimination_limit, 5000);
3065 assert_eq!(config.inprocessing_interval, 5000);
3066 }
3067
3068 #[test]
3069 fn test_config_minimal_characteristics() {
3070 let config = SolverConfig::minimal();
3071
3072 assert!(!config.simplify);
3074 assert!(!config.enable_variable_elimination);
3075 assert!(!config.enable_blocked_clause_elimination);
3076 assert!(!config.enable_symmetry_breaking);
3077 assert!(!config.enable_inprocessing);
3078 assert!(!config.enable_clause_minimization);
3079 assert!(!config.enable_clause_subsumption);
3080
3081 assert_eq!(config.theory_mode, TheoryMode::Lazy);
3083
3084 assert_eq!(config.num_threads, 1);
3086 }
3087
3088 #[test]
3089 fn test_config_builder_pattern() {
3090 let config = SolverConfig::fast()
3092 .with_proof()
3093 .with_timeout(5000)
3094 .with_max_conflicts(1000)
3095 .with_max_decisions(2000)
3096 .with_parallel(8)
3097 .with_restart_strategy(RestartStrategy::Luby)
3098 .with_theory_mode(TheoryMode::Lazy);
3099
3100 assert!(config.proof);
3101 assert_eq!(config.timeout_ms, 5000);
3102 assert_eq!(config.max_conflicts, 1000);
3103 assert_eq!(config.max_decisions, 2000);
3104 assert!(config.parallel);
3105 assert_eq!(config.num_threads, 8);
3106 assert_eq!(config.restart_strategy, RestartStrategy::Luby);
3107 assert_eq!(config.theory_mode, TheoryMode::Lazy);
3108 }
3109
3110 #[test]
3111 fn test_solver_with_different_configs() {
3112 let mut manager = TermManager::new();
3113
3114 let mut solver_fast = Solver::with_config(SolverConfig::fast());
3116 let mut solver_balanced = Solver::with_config(SolverConfig::balanced());
3117 let mut solver_thorough = Solver::with_config(SolverConfig::thorough());
3118 let mut solver_minimal = Solver::with_config(SolverConfig::minimal());
3119
3120 let t = manager.mk_true();
3122 solver_fast.assert(t, &mut manager);
3123 solver_balanced.assert(t, &mut manager);
3124 solver_thorough.assert(t, &mut manager);
3125 solver_minimal.assert(t, &mut manager);
3126
3127 assert_eq!(solver_fast.check(&mut manager), SolverResult::Sat);
3128 assert_eq!(solver_balanced.check(&mut manager), SolverResult::Sat);
3129 assert_eq!(solver_thorough.check(&mut manager), SolverResult::Sat);
3130 assert_eq!(solver_minimal.check(&mut manager), SolverResult::Sat);
3131 }
3132
3133 #[test]
3134 fn test_config_default_is_balanced() {
3135 let default = SolverConfig::default();
3136 let balanced = SolverConfig::balanced();
3137
3138 assert_eq!(
3140 default.enable_variable_elimination,
3141 balanced.enable_variable_elimination
3142 );
3143 assert_eq!(
3144 default.enable_clause_minimization,
3145 balanced.enable_clause_minimization
3146 );
3147 assert_eq!(
3148 default.enable_symmetry_breaking,
3149 balanced.enable_symmetry_breaking
3150 );
3151 assert_eq!(default.restart_strategy, balanced.restart_strategy);
3152 }
3153
3154 #[test]
3155 fn test_theory_combination_arith_solver() {
3156 use oxiz_theories::arithmetic::ArithSolver;
3157 use oxiz_theories::{EqualityNotification, TheoryCombination};
3158
3159 let mut arith = ArithSolver::lra();
3160 let mut manager = TermManager::new();
3161
3162 let x = manager.mk_var("x", manager.sorts.int_sort);
3164 let y = manager.mk_var("y", manager.sorts.int_sort);
3165
3166 let _x_var = arith.intern(x);
3168 let _y_var = arith.intern(y);
3169
3170 let eq_notification = EqualityNotification {
3172 lhs: x,
3173 rhs: y,
3174 reason: None,
3175 };
3176
3177 let accepted = arith.notify_equality(eq_notification);
3178 assert!(
3179 accepted,
3180 "ArithSolver should accept equality notification for known terms"
3181 );
3182
3183 assert!(
3185 arith.is_relevant(x),
3186 "x should be relevant to arithmetic solver"
3187 );
3188 assert!(
3189 arith.is_relevant(y),
3190 "y should be relevant to arithmetic solver"
3191 );
3192
3193 let z = manager.mk_var("z", manager.sorts.int_sort);
3195 assert!(
3196 !arith.is_relevant(z),
3197 "z should not be relevant (not interned)"
3198 );
3199
3200 let eq_unknown = EqualityNotification {
3202 lhs: x,
3203 rhs: z,
3204 reason: None,
3205 };
3206 let accepted_unknown = arith.notify_equality(eq_unknown);
3207 assert!(
3208 !accepted_unknown,
3209 "ArithSolver should reject equality with unknown term"
3210 );
3211 }
3212
3213 #[test]
3214 fn test_theory_combination_get_shared_equalities() {
3215 use oxiz_theories::TheoryCombination;
3216 use oxiz_theories::arithmetic::ArithSolver;
3217
3218 let arith = ArithSolver::lra();
3219
3220 let shared = arith.get_shared_equalities();
3222 assert!(
3223 shared.is_empty(),
3224 "ArithSolver should return empty shared equalities (placeholder)"
3225 );
3226 }
3227
3228 #[test]
3229 fn test_equality_notification_fields() {
3230 use oxiz_theories::EqualityNotification;
3231
3232 let mut manager = TermManager::new();
3233 let x = manager.mk_var("x", manager.sorts.int_sort);
3234 let y = manager.mk_var("y", manager.sorts.int_sort);
3235
3236 let eq1 = EqualityNotification {
3238 lhs: x,
3239 rhs: y,
3240 reason: Some(x),
3241 };
3242 assert_eq!(eq1.lhs, x);
3243 assert_eq!(eq1.rhs, y);
3244 assert_eq!(eq1.reason, Some(x));
3245
3246 let eq2 = EqualityNotification {
3248 lhs: x,
3249 rhs: y,
3250 reason: None,
3251 };
3252 assert_eq!(eq2.reason, None);
3253
3254 let eq3 = eq1;
3256 assert_eq!(eq3.lhs, eq1.lhs);
3257 assert_eq!(eq3.rhs, eq1.rhs);
3258 }
3259
3260 #[test]
3261 fn test_assert_many() {
3262 let mut solver = Solver::new();
3263 let mut manager = TermManager::new();
3264
3265 let p = manager.mk_var("p", manager.sorts.bool_sort);
3266 let q = manager.mk_var("q", manager.sorts.bool_sort);
3267 let r = manager.mk_var("r", manager.sorts.bool_sort);
3268
3269 solver.assert_many(&[p, q, r], &mut manager);
3271
3272 assert_eq!(solver.num_assertions(), 3);
3273 assert_eq!(solver.check(&mut manager), SolverResult::Sat);
3274 }
3275
3276 #[test]
3277 fn test_num_assertions_and_variables() {
3278 let mut solver = Solver::new();
3279 let mut manager = TermManager::new();
3280
3281 assert_eq!(solver.num_assertions(), 0);
3282 assert!(!solver.has_assertions());
3283
3284 let p = manager.mk_var("p", manager.sorts.bool_sort);
3285 let q = manager.mk_var("q", manager.sorts.bool_sort);
3286
3287 solver.assert(p, &mut manager);
3288 assert_eq!(solver.num_assertions(), 1);
3289 assert!(solver.has_assertions());
3290
3291 solver.assert(q, &mut manager);
3292 assert_eq!(solver.num_assertions(), 2);
3293
3294 assert!(solver.num_variables() > 0);
3296 }
3297
3298 #[test]
3299 fn test_context_level() {
3300 let mut solver = Solver::new();
3301
3302 assert_eq!(solver.context_level(), 0);
3303
3304 solver.push();
3305 assert_eq!(solver.context_level(), 1);
3306
3307 solver.push();
3308 assert_eq!(solver.context_level(), 2);
3309
3310 solver.pop();
3311 assert_eq!(solver.context_level(), 1);
3312
3313 solver.pop();
3314 assert_eq!(solver.context_level(), 0);
3315 }
3316
3317 #[test]
3320 fn test_quantifier_basic_forall() {
3321 let mut solver = Solver::new();
3322 let mut manager = TermManager::new();
3323 let bool_sort = manager.sorts.bool_sort;
3324
3325 let x = manager.mk_var("x", bool_sort);
3328 let p_x = manager.mk_apply("P", [x], bool_sort);
3329 let forall = manager.mk_forall([("x", bool_sort)], p_x);
3330
3331 solver.assert(forall, &mut manager);
3332
3333 let result = solver.check(&mut manager);
3335 assert!(
3337 result == SolverResult::Sat || result == SolverResult::Unknown,
3338 "Basic forall should not be unsat"
3339 );
3340 }
3341
3342 #[test]
3343 fn test_quantifier_basic_exists() {
3344 let mut solver = Solver::new();
3345 let mut manager = TermManager::new();
3346 let bool_sort = manager.sorts.bool_sort;
3347
3348 let x = manager.mk_var("x", bool_sort);
3350 let p_x = manager.mk_apply("P", [x], bool_sort);
3351 let exists = manager.mk_exists([("x", bool_sort)], p_x);
3352
3353 solver.assert(exists, &mut manager);
3354
3355 let result = solver.check(&mut manager);
3356 assert!(
3357 result == SolverResult::Sat || result == SolverResult::Unknown,
3358 "Basic exists should not be unsat"
3359 );
3360 }
3361
3362 #[test]
3363 fn test_quantifier_with_ground_terms() {
3364 let mut solver = Solver::new();
3365 let mut manager = TermManager::new();
3366 let int_sort = manager.sorts.int_sort;
3367 let bool_sort = manager.sorts.bool_sort;
3368
3369 let zero = manager.mk_int(0);
3371 let one = manager.mk_int(1);
3372
3373 let p_0 = manager.mk_apply("P", [zero], bool_sort);
3375 let p_1 = manager.mk_apply("P", [one], bool_sort);
3376 solver.assert(p_0, &mut manager);
3377 solver.assert(p_1, &mut manager);
3378
3379 let x = manager.mk_var("x", int_sort);
3381 let p_x = manager.mk_apply("P", [x], bool_sort);
3382 let forall = manager.mk_forall([("x", int_sort)], p_x);
3383 solver.assert(forall, &mut manager);
3384
3385 let result = solver.check(&mut manager);
3386 assert!(
3388 result == SolverResult::Sat || result == SolverResult::Unknown,
3389 "Quantifier with matching ground terms should be satisfiable"
3390 );
3391 }
3392
3393 #[test]
3394 fn test_quantifier_instantiation() {
3395 let mut solver = Solver::new();
3396 let mut manager = TermManager::new();
3397 let int_sort = manager.sorts.int_sort;
3398 let bool_sort = manager.sorts.bool_sort;
3399
3400 let c = manager.mk_apply("c", [], int_sort);
3402
3403 let x = manager.mk_var("x", int_sort);
3405 let f_x = manager.mk_apply("f", [x], int_sort);
3406 let zero = manager.mk_int(0);
3407 let f_x_gt_0 = manager.mk_gt(f_x, zero);
3408 let forall = manager.mk_forall([("x", int_sort)], f_x_gt_0);
3409 solver.assert(forall, &mut manager);
3410
3411 let f_c = manager.mk_apply("f", [c], int_sort);
3413 let f_c_exists = manager.mk_apply("exists_f_c", [f_c], bool_sort);
3414 solver.assert(f_c_exists, &mut manager);
3415
3416 let result = solver.check(&mut manager);
3417 assert!(
3419 result == SolverResult::Sat || result == SolverResult::Unknown,
3420 "Quantifier instantiation test"
3421 );
3422 }
3423
3424 #[test]
3425 fn test_quantifier_mbqi_solver_integration() {
3426 use crate::mbqi::MBQISolver;
3427
3428 let mut mbqi = MBQISolver::new();
3429 let mut manager = TermManager::new();
3430 let int_sort = manager.sorts.int_sort;
3431
3432 let x = manager.mk_var("x", int_sort);
3434 let zero = manager.mk_int(0);
3435 let x_gt_0 = manager.mk_gt(x, zero);
3436 let forall = manager.mk_forall([("x", int_sort)], x_gt_0);
3437
3438 mbqi.add_quantifier(forall, &manager);
3440
3441 let one = manager.mk_int(1);
3443 let two = manager.mk_int(2);
3444 mbqi.add_candidate(one, int_sort);
3445 mbqi.add_candidate(two, int_sort);
3446
3447 assert!(mbqi.is_enabled(), "MBQI should be enabled by default");
3449 }
3450
3451 #[test]
3452 fn test_quantifier_pattern_matching() {
3453 let mut solver = Solver::new();
3454 let mut manager = TermManager::new();
3455 let int_sort = manager.sorts.int_sort;
3456
3457 let x = manager.mk_var("x", int_sort);
3459 let f_x = manager.mk_apply("f", [x], int_sort);
3460 let g_x = manager.mk_apply("g", [x], int_sort);
3461 let body = manager.mk_eq(f_x, g_x);
3462
3463 let pattern: smallvec::SmallVec<[_; 2]> = smallvec::smallvec![f_x];
3465 let patterns: smallvec::SmallVec<[_; 2]> = smallvec::smallvec![pattern];
3466
3467 let forall = manager.mk_forall_with_patterns([("x", int_sort)], body, patterns);
3468 solver.assert(forall, &mut manager);
3469
3470 let c = manager.mk_apply("c", [], int_sort);
3472 let f_c = manager.mk_apply("f", [c], int_sort);
3473 let f_c_eq_c = manager.mk_eq(f_c, c);
3474 solver.assert(f_c_eq_c, &mut manager);
3475
3476 let result = solver.check(&mut manager);
3477 assert!(
3478 result == SolverResult::Sat || result == SolverResult::Unknown,
3479 "Pattern matching should allow instantiation"
3480 );
3481 }
3482
3483 #[test]
3484 fn test_quantifier_multiple() {
3485 let mut solver = Solver::new();
3486 let mut manager = TermManager::new();
3487 let int_sort = manager.sorts.int_sort;
3488
3489 let x = manager.mk_var("x", int_sort);
3491 let y = manager.mk_var("y", int_sort);
3492 let x_plus_y = manager.mk_add([x, y]);
3493 let y_plus_x = manager.mk_add([y, x]);
3494 let commutative = manager.mk_eq(x_plus_y, y_plus_x);
3495
3496 let inner_forall = manager.mk_forall([("y", int_sort)], commutative);
3497 let outer_forall = manager.mk_forall([("x", int_sort)], inner_forall);
3498
3499 solver.assert(outer_forall, &mut manager);
3500
3501 let result = solver.check(&mut manager);
3502 assert!(
3503 result == SolverResult::Sat || result == SolverResult::Unknown,
3504 "Nested forall should be handled"
3505 );
3506 }
3507
3508 #[test]
3509 fn test_quantifier_with_model() {
3510 let mut solver = Solver::new();
3511 let mut manager = TermManager::new();
3512 let bool_sort = manager.sorts.bool_sort;
3513
3514 let p = manager.mk_var("p", bool_sort);
3516 solver.assert(p, &mut manager);
3517
3518 let x = manager.mk_var("x", bool_sort);
3520 let not_x = manager.mk_not(x);
3521 let x_or_not_x = manager.mk_or([x, not_x]);
3522 let tautology = manager.mk_forall([("x", bool_sort)], x_or_not_x);
3523 solver.assert(tautology, &mut manager);
3524
3525 let result = solver.check(&mut manager);
3526 assert_eq!(
3527 result,
3528 SolverResult::Sat,
3529 "Tautology in quantifier should be SAT"
3530 );
3531
3532 if let Some(model) = solver.model() {
3534 assert!(model.size() > 0, "Model should have assignments");
3535 }
3536 }
3537
3538 #[test]
3539 fn test_quantifier_push_pop() {
3540 let mut solver = Solver::new();
3541 let mut manager = TermManager::new();
3542 let int_sort = manager.sorts.int_sort;
3543
3544 let x = manager.mk_var("x", int_sort);
3546 let zero = manager.mk_int(0);
3547 let x_gt_0 = manager.mk_gt(x, zero);
3548 let forall = manager.mk_forall([("x", int_sort)], x_gt_0);
3549
3550 solver.push();
3551 solver.assert(forall, &mut manager);
3552
3553 let result1 = solver.check(&mut manager);
3554 assert!(
3555 result1 == SolverResult::Sat || result1 == SolverResult::Unknown,
3556 "Quantifier in pushed context"
3557 );
3558
3559 solver.pop();
3560
3561 let result2 = solver.check(&mut manager);
3563 assert_eq!(
3564 result2,
3565 SolverResult::Sat,
3566 "After pop, should be trivially SAT"
3567 );
3568 }
3569
3570 #[test]
3577 #[ignore = "Requires complete arithmetic constraint encoding to simplex (see process_constraint in solver.rs)"]
3578 fn test_integer_contradiction_unsat() {
3579 use num_bigint::BigInt;
3580
3581 let mut solver = Solver::new();
3582 let mut manager = TermManager::new();
3583
3584 let x = manager.mk_var("x", manager.sorts.int_sort);
3586 let zero = manager.mk_int(BigInt::from(0));
3587
3588 let x_ge_0 = manager.mk_ge(x, zero);
3590 solver.assert(x_ge_0, &mut manager);
3591
3592 let x_lt_0 = manager.mk_lt(x, zero);
3594 solver.assert(x_lt_0, &mut manager);
3595
3596 let result = solver.check(&mut manager);
3598 assert_eq!(
3599 result,
3600 SolverResult::Unsat,
3601 "x >= 0 AND x < 0 should be UNSAT"
3602 );
3603 }
3604}