1use std::cell::RefCell;
37use std::rc::Rc;
38
39use num_bigint::BigInt;
40use num_rational::Rational64;
41
42use oxiz_core::ast::{TermId, TermManager};
43use oxiz_core::sort::SortId;
44
45use crate::Context;
46use crate::SolverResult;
47use crate::solver::SolverConfig;
48
49#[path = "z3_compat_ext.rs"]
52pub mod ext;
53pub use ext::{
54 Array, FuncDecl, Z3Optimize, distinct_bv, distinct_int, distinct_real, exists_bool,
55 forall_bool, int_numeral, ite_bool, ite_bv, ite_int, ite_real, real_numeral,
56};
57
58#[path = "z3_compat_ext2.rs"]
61pub mod ext2;
62pub use ext2::{
63 DtConstructor, DtDecl, DtField, DtSelector, DtSort, ParamVal, Z3ApplyResult, Z3AstVector,
64 Z3Constructor, Z3DatatypeSort, Z3Field, Z3FuncEntry, Z3FuncInterp, Z3Goal, Z3Params, Z3Probe,
65 Z3Statistics, Z3Tactic, Z3Value, mk_constructor,
66};
67
68#[path = "z3_compat_ext3.rs"]
71pub mod ext3;
72pub use ext3::*;
73
74#[derive(Debug, Clone, Default)]
80pub struct Z3Config {
81 inner: SolverConfig,
82}
83
84impl Z3Config {
85 #[must_use]
87 pub fn new() -> Self {
88 Self {
89 inner: SolverConfig::default(),
90 }
91 }
92
93 pub fn set_proof(&mut self, enabled: bool) -> &mut Self {
95 self.inner.proof = enabled;
96 self
97 }
98
99 #[must_use]
101 pub fn as_solver_config(&self) -> &SolverConfig {
102 &self.inner
103 }
104}
105
106pub struct Z3Context {
116 pub(crate) tm: Rc<RefCell<TermManager>>,
118 pub(crate) config: SolverConfig,
120}
121
122impl Z3Context {
123 #[must_use]
125 pub fn new(cfg: &Z3Config) -> Self {
126 Self {
127 tm: Rc::new(RefCell::new(TermManager::new())),
128 config: cfg.inner.clone(),
129 }
130 }
131
132 #[must_use]
134 pub fn bool_sort(&self) -> SortId {
135 self.tm.borrow().sorts.bool_sort
136 }
137
138 #[must_use]
140 pub fn int_sort(&self) -> SortId {
141 self.tm.borrow().sorts.int_sort
142 }
143
144 #[must_use]
146 pub fn real_sort(&self) -> SortId {
147 self.tm.borrow().sorts.real_sort
148 }
149
150 #[must_use]
152 pub fn bv_sort(&self, width: u32) -> SortId {
153 self.tm.borrow_mut().sorts.bitvec(width)
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub enum SatResult {
162 Sat,
164 Unsat,
166 Unknown,
168}
169
170impl From<SolverResult> for SatResult {
171 fn from(r: SolverResult) -> Self {
172 match r {
173 SolverResult::Sat => SatResult::Sat,
174 SolverResult::Unsat => SatResult::Unsat,
175 SolverResult::Unknown => SatResult::Unknown,
176 }
177 }
178}
179
180impl std::fmt::Display for SatResult {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 match self {
183 SatResult::Sat => write!(f, "sat"),
184 SatResult::Unsat => write!(f, "unsat"),
185 SatResult::Unknown => write!(f, "unknown"),
186 }
187 }
188}
189
190pub(crate) type FuncInterpRaw = (Vec<(Vec<String>, String)>, String, usize);
200
201pub struct Z3Model {
205 entries: Vec<(String, String, String)>,
207 func_interps: std::collections::HashMap<String, FuncInterpRaw>,
212}
213
214impl Z3Model {
215 pub(crate) fn from_context_model(
216 entries: Vec<(String, String, String)>,
217 func_interps: std::collections::HashMap<String, FuncInterpRaw>,
218 ) -> Self {
219 Self {
220 entries,
221 func_interps,
222 }
223 }
224
225 #[must_use]
229 pub fn eval_const(&self, name: &str) -> Option<&str> {
230 self.entries
231 .iter()
232 .find(|(n, _, _)| n == name)
233 .map(|(_, _, v)| v.as_str())
234 }
235
236 #[must_use]
238 pub fn entries(&self) -> &[(String, String, String)] {
239 &self.entries
240 }
241
242 #[must_use]
248 pub fn func_interp_raw(&self, func_name: &str) -> Option<&FuncInterpRaw> {
249 self.func_interps.get(func_name)
250 }
251}
252
253impl std::fmt::Display for Z3Model {
254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255 writeln!(f, "(model")?;
256 for (name, sort, value) in &self.entries {
257 writeln!(f, " (define-fun {} () {} {})", name, sort, value)?;
258 }
259 write!(f, ")")
260 }
261}
262
263pub struct Z3Solver {
269 ctx: Context,
270}
271
272impl Z3Solver {
273 #[must_use]
278 pub fn new(z3ctx: &Z3Context) -> Self {
279 let mut ctx = Context::new();
280 if z3ctx.config.proof {
282 ctx.set_option("produce-proofs", "true");
283 }
284 Self { ctx }
288 }
289
290 pub fn assert(&mut self, t: &Bool) {
292 self.ctx.assert(t.id);
293 }
294
295 #[must_use]
297 pub fn check(&mut self) -> SatResult {
298 self.ctx.check_sat().into()
299 }
300
301 pub fn push(&mut self) {
303 self.ctx.push();
304 }
305
306 pub fn pop(&mut self) {
308 self.ctx.pop();
309 }
310
311 #[must_use]
317 pub fn get_model(&self) -> Option<Z3Model> {
318 let entries = self.ctx.get_model()?;
319 let func_interps = self
321 .ctx
322 .declared_function_names()
323 .filter_map(|name| {
324 self.ctx
325 .get_func_interp_raw(name)
326 .map(|raw| (name.to_string(), raw))
327 })
328 .collect();
329 Some(Z3Model::from_context_model(entries, func_interps))
330 }
331
332 pub fn set_logic(&mut self, logic: &str) {
334 self.ctx.set_logic(logic);
335 }
336
337 #[must_use]
339 pub fn context(&self) -> &Context {
340 &self.ctx
341 }
342
343 pub fn context_mut(&mut self) -> &mut Context {
345 &mut self.ctx
346 }
347}
348
349macro_rules! build {
355 ($ctx:expr, $method:ident $(, $arg:expr)* ) => {
356 $ctx.tm.borrow_mut().$method($($arg),*)
357 };
358}
359
360#[derive(Debug, Clone)]
364pub struct Bool {
365 pub id: TermId,
367}
368
369impl Bool {
370 #[must_use]
372 pub fn from_id(id: TermId) -> Self {
373 Self { id }
374 }
375
376 #[must_use]
378 pub fn new_const(ctx: &Z3Context, name: &str) -> Self {
379 let sort = ctx.bool_sort();
380 let id = build!(ctx, mk_var, name, sort);
381 Self { id }
382 }
383
384 #[must_use]
386 pub fn from_bool(ctx: &Z3Context, value: bool) -> Self {
387 let id = build!(ctx, mk_bool, value);
388 Self { id }
389 }
390
391 #[must_use]
393 pub fn and(ctx: &Z3Context, args: &[Bool]) -> Self {
394 let ids: Vec<TermId> = args.iter().map(|b| b.id).collect();
395 let id = build!(ctx, mk_and, ids);
396 Self { id }
397 }
398
399 #[must_use]
401 pub fn or(ctx: &Z3Context, args: &[Bool]) -> Self {
402 let ids: Vec<TermId> = args.iter().map(|b| b.id).collect();
403 let id = build!(ctx, mk_or, ids);
404 Self { id }
405 }
406
407 #[must_use]
409 pub fn not(ctx: &Z3Context, arg: &Bool) -> Self {
410 let id = build!(ctx, mk_not, arg.id);
411 Self { id }
412 }
413
414 #[must_use]
416 pub fn implies(ctx: &Z3Context, lhs: &Bool, rhs: &Bool) -> Self {
417 let id = build!(ctx, mk_implies, lhs.id, rhs.id);
418 Self { id }
419 }
420
421 #[must_use]
425 pub fn iff(ctx: &Z3Context, lhs: &Bool, rhs: &Bool) -> Self {
426 let id = build!(ctx, mk_eq, lhs.id, rhs.id);
428 Self { id }
429 }
430
431 #[must_use]
433 pub fn xor(ctx: &Z3Context, lhs: &Bool, rhs: &Bool) -> Self {
434 let id = build!(ctx, mk_xor, lhs.id, rhs.id);
435 Self { id }
436 }
437}
438
439impl From<Bool> for TermId {
440 fn from(b: Bool) -> Self {
441 b.id
442 }
443}
444
445#[derive(Debug, Clone)]
449pub struct Int {
450 pub id: TermId,
452}
453
454impl Int {
455 #[must_use]
457 pub fn from_id(id: TermId) -> Self {
458 Self { id }
459 }
460
461 #[must_use]
463 pub fn new_const(ctx: &Z3Context, name: &str) -> Self {
464 let sort = ctx.int_sort();
465 let id = build!(ctx, mk_var, name, sort);
466 Self { id }
467 }
468
469 #[must_use]
471 pub fn from_i64(ctx: &Z3Context, value: i64) -> Self {
472 let id = build!(ctx, mk_int, BigInt::from(value));
473 Self { id }
474 }
475
476 #[must_use]
478 pub fn add(ctx: &Z3Context, args: &[Int]) -> Self {
479 let ids: Vec<TermId> = args.iter().map(|x| x.id).collect();
480 let id = build!(ctx, mk_add, ids);
481 Self { id }
482 }
483
484 #[must_use]
486 pub fn sub(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Self {
487 let id = build!(ctx, mk_sub, lhs.id, rhs.id);
488 Self { id }
489 }
490
491 #[must_use]
493 pub fn mul(ctx: &Z3Context, args: &[Int]) -> Self {
494 let ids: Vec<TermId> = args.iter().map(|x| x.id).collect();
495 let id = build!(ctx, mk_mul, ids);
496 Self { id }
497 }
498
499 #[must_use]
501 pub fn neg(ctx: &Z3Context, arg: &Int) -> Self {
502 let id = build!(ctx, mk_neg, arg.id);
503 Self { id }
504 }
505
506 #[must_use]
508 pub fn div(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Self {
509 let id = build!(ctx, mk_div, lhs.id, rhs.id);
510 Self { id }
511 }
512
513 #[must_use]
515 pub fn modulo(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Self {
516 let id = build!(ctx, mk_mod, lhs.id, rhs.id);
517 Self { id }
518 }
519
520 #[must_use]
522 pub fn lt(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Bool {
523 let id = build!(ctx, mk_lt, lhs.id, rhs.id);
524 Bool { id }
525 }
526
527 #[must_use]
529 pub fn le(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Bool {
530 let id = build!(ctx, mk_le, lhs.id, rhs.id);
531 Bool { id }
532 }
533
534 #[must_use]
536 pub fn gt(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Bool {
537 let id = build!(ctx, mk_gt, lhs.id, rhs.id);
538 Bool { id }
539 }
540
541 #[must_use]
543 pub fn ge(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Bool {
544 let id = build!(ctx, mk_ge, lhs.id, rhs.id);
545 Bool { id }
546 }
547
548 #[must_use]
550 pub fn eq(ctx: &Z3Context, lhs: &Int, rhs: &Int) -> Bool {
551 let id = build!(ctx, mk_eq, lhs.id, rhs.id);
552 Bool { id }
553 }
554}
555
556impl From<Int> for TermId {
557 fn from(x: Int) -> Self {
558 x.id
559 }
560}
561
562#[derive(Debug, Clone)]
566pub struct Real {
567 pub id: TermId,
569}
570
571impl Real {
572 #[must_use]
574 pub fn from_id(id: TermId) -> Self {
575 Self { id }
576 }
577
578 #[must_use]
580 pub fn new_const(ctx: &Z3Context, name: &str) -> Self {
581 let sort = ctx.real_sort();
582 let id = build!(ctx, mk_var, name, sort);
583 Self { id }
584 }
585
586 #[must_use]
588 pub fn from_frac(ctx: &Z3Context, num: i64, den: i64) -> Self {
589 let id = build!(ctx, mk_real, Rational64::new(num, den));
590 Self { id }
591 }
592
593 #[must_use]
595 pub fn add(ctx: &Z3Context, args: &[Real]) -> Self {
596 let ids: Vec<TermId> = args.iter().map(|x| x.id).collect();
597 let id = build!(ctx, mk_add, ids);
598 Self { id }
599 }
600
601 #[must_use]
603 pub fn sub(ctx: &Z3Context, lhs: &Real, rhs: &Real) -> Self {
604 let id = build!(ctx, mk_sub, lhs.id, rhs.id);
605 Self { id }
606 }
607
608 #[must_use]
610 pub fn mul(ctx: &Z3Context, args: &[Real]) -> Self {
611 let ids: Vec<TermId> = args.iter().map(|x| x.id).collect();
612 let id = build!(ctx, mk_mul, ids);
613 Self { id }
614 }
615
616 #[must_use]
618 pub fn lt(ctx: &Z3Context, lhs: &Real, rhs: &Real) -> Bool {
619 let id = build!(ctx, mk_lt, lhs.id, rhs.id);
620 Bool { id }
621 }
622
623 #[must_use]
625 pub fn le(ctx: &Z3Context, lhs: &Real, rhs: &Real) -> Bool {
626 let id = build!(ctx, mk_le, lhs.id, rhs.id);
627 Bool { id }
628 }
629
630 #[must_use]
632 pub fn eq(ctx: &Z3Context, lhs: &Real, rhs: &Real) -> Bool {
633 let id = build!(ctx, mk_eq, lhs.id, rhs.id);
634 Bool { id }
635 }
636}
637
638impl From<Real> for TermId {
639 fn from(x: Real) -> Self {
640 x.id
641 }
642}
643
644#[derive(Debug, Clone)]
648pub struct BV {
649 pub id: TermId,
651 pub width: u32,
653}
654
655impl BV {
656 #[must_use]
658 pub fn from_id(id: TermId, width: u32) -> Self {
659 Self { id, width }
660 }
661
662 #[must_use]
664 pub fn new_const(ctx: &Z3Context, name: &str, width: u32) -> Self {
665 let sort = ctx.bv_sort(width);
666 let id = build!(ctx, mk_var, name, sort);
667 Self { id, width }
668 }
669
670 #[must_use]
672 pub fn from_u64(ctx: &Z3Context, value: u64, width: u32) -> Self {
673 let id = build!(ctx, mk_bitvec, BigInt::from(value), width);
674 Self { id, width }
675 }
676
677 #[must_use]
679 pub fn bvadd(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
680 let width = lhs.width;
681 let id = build!(ctx, mk_bv_add, lhs.id, rhs.id);
682 Self { id, width }
683 }
684
685 #[must_use]
687 pub fn bvsub(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
688 let width = lhs.width;
689 let id = build!(ctx, mk_bv_sub, lhs.id, rhs.id);
690 Self { id, width }
691 }
692
693 #[must_use]
695 pub fn bvmul(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
696 let width = lhs.width;
697 let id = build!(ctx, mk_bv_mul, lhs.id, rhs.id);
698 Self { id, width }
699 }
700
701 #[must_use]
703 pub fn bvand(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
704 let width = lhs.width;
705 let id = build!(ctx, mk_bv_and, lhs.id, rhs.id);
706 Self { id, width }
707 }
708
709 #[must_use]
711 pub fn bvor(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
712 let width = lhs.width;
713 let id = build!(ctx, mk_bv_or, lhs.id, rhs.id);
714 Self { id, width }
715 }
716
717 #[must_use]
719 pub fn bvxor(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
720 let width = lhs.width;
721 let id = build!(ctx, mk_bv_xor, lhs.id, rhs.id);
722 Self { id, width }
723 }
724
725 #[must_use]
727 pub fn bvnot(ctx: &Z3Context, arg: &BV) -> Self {
728 let width = arg.width;
729 let id = build!(ctx, mk_bv_not, arg.id);
730 Self { id, width }
731 }
732
733 #[must_use]
735 pub fn bvneg(ctx: &Z3Context, arg: &BV) -> Self {
736 let width = arg.width;
737 let id = build!(ctx, mk_bv_neg, arg.id);
738 Self { id, width }
739 }
740
741 #[must_use]
743 pub fn bvult(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Bool {
744 let id = build!(ctx, mk_bv_ult, lhs.id, rhs.id);
745 Bool { id }
746 }
747
748 #[must_use]
750 pub fn bvslt(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Bool {
751 let id = build!(ctx, mk_bv_slt, lhs.id, rhs.id);
752 Bool { id }
753 }
754
755 #[must_use]
757 pub fn bvule(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Bool {
758 let id = build!(ctx, mk_bv_ule, lhs.id, rhs.id);
759 Bool { id }
760 }
761
762 #[must_use]
764 pub fn bvsle(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Bool {
765 let id = build!(ctx, mk_bv_sle, lhs.id, rhs.id);
766 Bool { id }
767 }
768
769 #[must_use]
771 pub fn eq(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Bool {
772 let id = build!(ctx, mk_eq, lhs.id, rhs.id);
773 Bool { id }
774 }
775
776 #[must_use]
778 pub fn bvshl(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
779 let width = lhs.width;
780 let id = build!(ctx, mk_bv_shl, lhs.id, rhs.id);
781 Self { id, width }
782 }
783
784 #[must_use]
786 pub fn bvlshr(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
787 let width = lhs.width;
788 let id = build!(ctx, mk_bv_lshr, lhs.id, rhs.id);
789 Self { id, width }
790 }
791
792 #[must_use]
794 pub fn bvashr(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
795 let width = lhs.width;
796 let id = build!(ctx, mk_bv_ashr, lhs.id, rhs.id);
797 Self { id, width }
798 }
799
800 #[must_use]
802 pub fn bvudiv(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
803 let width = lhs.width;
804 let id = build!(ctx, mk_bv_udiv, lhs.id, rhs.id);
805 Self { id, width }
806 }
807
808 #[must_use]
810 pub fn bvurem(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
811 let width = lhs.width;
812 let id = build!(ctx, mk_bv_urem, lhs.id, rhs.id);
813 Self { id, width }
814 }
815
816 #[must_use]
820 pub fn concat(ctx: &Z3Context, lhs: &BV, rhs: &BV) -> Self {
821 let width = lhs.width + rhs.width;
822 let id = build!(ctx, mk_bv_concat, lhs.id, rhs.id);
823 Self { id, width }
824 }
825
826 #[must_use]
835 pub fn extract(ctx: &Z3Context, high: u32, low: u32, arg: &BV) -> Self {
836 debug_assert!(
837 high >= low,
838 "extract: high ({}) must be >= low ({})",
839 high,
840 low
841 );
842 let width = high - low + 1;
843 let id = build!(ctx, mk_bv_extract, high, low, arg.id);
844 Self { id, width }
845 }
846}
847
848impl From<BV> for TermId {
849 fn from(b: BV) -> Self {
850 b.id
851 }
852}
853
854#[cfg(test)]
857mod tests {
858 use super::*;
859
860 #[test]
861 fn test_bool_and_sat() {
862 let cfg = Z3Config::new();
863 let ctx = Z3Context::new(&cfg);
864 let mut solver = Z3Solver::new(&ctx);
865
866 let _p = Bool::new_const(&ctx, "p");
870 let _q = Bool::new_const(&ctx, "q");
871
872 let true_p = Bool::from_bool(&ctx, true);
877 solver.ctx.assert(true_p.id);
878
879 assert_eq!(solver.check(), SatResult::Sat);
880 }
881
882 #[test]
883 fn test_bool_and_unsat() {
884 let cfg = Z3Config::new();
885 let ctx = Z3Context::new(&cfg);
886 let mut solver = Z3Solver::new(&ctx);
887
888 let t = solver.ctx.terms.mk_true();
890 let f = solver.ctx.terms.mk_false();
891 solver.ctx.assert(t);
892 solver.ctx.assert(f);
893
894 assert_eq!(solver.check(), SatResult::Unsat);
895 }
896
897 #[test]
898 fn test_sat_result_from_solver_result() {
899 assert_eq!(SatResult::from(SolverResult::Sat), SatResult::Sat);
900 assert_eq!(SatResult::from(SolverResult::Unsat), SatResult::Unsat);
901 assert_eq!(SatResult::from(SolverResult::Unknown), SatResult::Unknown);
902 }
903
904 #[test]
905 fn test_bool_api_term_building() {
906 let cfg = Z3Config::new();
907 let ctx = Z3Context::new(&cfg);
908
909 let p = Bool::new_const(&ctx, "p");
911 let q = Bool::new_const(&ctx, "q");
912 let _conj = Bool::and(&ctx, &[p.clone(), q.clone()]);
913 let _disj = Bool::or(&ctx, &[p.clone(), q.clone()]);
914 let _neg = Bool::not(&ctx, &p);
915 let _impl = Bool::implies(&ctx, &p, &q);
916 let _iff = Bool::iff(&ctx, &p, &q);
917 }
918
919 #[test]
920 fn test_int_api_term_building() {
921 let cfg = Z3Config::new();
922 let ctx = Z3Context::new(&cfg);
923
924 let x = Int::new_const(&ctx, "x");
925 let y = Int::new_const(&ctx, "y");
926 let five = Int::from_i64(&ctx, 5);
927
928 let _sum = Int::add(&ctx, &[x.clone(), y.clone()]);
929 let _diff = Int::sub(&ctx, &x, &y);
930 let _prod = Int::mul(&ctx, &[x.clone(), five.clone()]);
931 let _lt = Int::lt(&ctx, &x, &five);
932 let _le = Int::le(&ctx, &x, &y);
933 let _eq = Int::eq(&ctx, &x, &y);
934 }
935
936 #[test]
937 fn test_bv_api_term_building() {
938 let cfg = Z3Config::new();
939 let ctx = Z3Context::new(&cfg);
940
941 let a = BV::new_const(&ctx, "a", 32);
942 let b = BV::new_const(&ctx, "b", 32);
943 let lit = BV::from_u64(&ctx, 42, 32);
944
945 let _add = BV::bvadd(&ctx, &a, &b);
946 let _and = BV::bvand(&ctx, &a, &b);
947 let _ult = BV::bvult(&ctx, &a, &lit);
948 let concat = BV::concat(&ctx, &a, &b);
949 assert_eq!(concat.width, 64);
950 let extr = BV::extract(&ctx, 7, 0, &a);
951 assert_eq!(extr.width, 8);
952 }
953
954 #[test]
955 fn test_push_pop() {
956 let cfg = Z3Config::new();
957 let ctx = Z3Context::new(&cfg);
958 let mut solver = Z3Solver::new(&ctx);
959
960 let t = solver.ctx.terms.mk_true();
961 solver.ctx.assert(t);
962
963 solver.push();
964 let f = solver.ctx.terms.mk_false();
965 solver.ctx.assert(f);
966 assert_eq!(solver.check(), SatResult::Unsat);
967
968 solver.pop();
969 assert_eq!(solver.check(), SatResult::Sat);
970 }
971
972 #[test]
973 fn test_int_solver_sat() {
974 let cfg = Z3Config::new();
977 let ctx = Z3Context::new(&cfg);
978 let mut solver = Z3Solver::new(&ctx);
979 solver.set_logic("QF_LIA");
980
981 let x = solver
984 .ctx
985 .terms
986 .mk_var("x", solver.ctx.terms.sorts.int_sort);
987 let five = solver.ctx.terms.mk_int(BigInt::from(5));
988 let ten = solver.ctx.terms.mk_int(BigInt::from(10));
989 let c1 = solver.ctx.terms.mk_ge(x, five);
990 let c2 = solver.ctx.terms.mk_le(x, ten);
991 solver.ctx.assert(c1);
992 solver.ctx.assert(c2);
993
994 assert_eq!(solver.check(), SatResult::Sat);
995 }
996
997 #[test]
998 fn test_get_model() {
999 let cfg = Z3Config::new();
1000 let ctx = Z3Context::new(&cfg);
1001 let mut solver = Z3Solver::new(&ctx);
1002
1003 let bool_sort = solver.ctx.terms.sorts.bool_sort;
1004 let _p = solver.ctx.declare_const("p", bool_sort);
1005 let t = solver.ctx.terms.mk_true();
1006 solver.ctx.assert(t);
1007
1008 assert_eq!(solver.check(), SatResult::Sat);
1009 let model = solver.get_model();
1010 assert!(model.is_some(), "Expected a model after SAT");
1011 }
1012}