1use std::{collections::HashSet, hash::Hash};
2
3use derive_where::derive_where;
4use itertools::Itertools;
5use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
6
7use crate::{ConstDecl, ThyFunc, Types};
8
9#[derive_where(Hash, Clone, Debug)]
10pub struct Bind<T: Types> {
11 pub name: T::Var,
12 pub sort: Sort<T>,
13 pub preds: Vec<Pred<T>>,
14}
15
16#[derive_where(Hash, Clone, Debug)]
17pub enum Constraint<T: Types> {
18 Pred(Pred<T>, #[derive_where(skip)] Option<T::Tag>),
19 Conj(Vec<Self>),
20 ForAll(Bind<T>, Box<Self>),
21}
22
23impl<T: Types> Constraint<T> {
24 pub const TRUE: Self = Self::Pred(Pred::TRUE, None);
25
26 pub fn foralls(bindings: Vec<Bind<T>>, c: Self) -> Self {
27 bindings
28 .into_iter()
29 .rev()
30 .fold(c, |c, bind| Constraint::ForAll(bind, Box::new(c)))
31 }
32
33 pub fn conj(mut cstrs: Vec<Self>) -> Self {
34 if cstrs.len() == 1 { cstrs.remove(0) } else { Self::Conj(cstrs) }
35 }
36
37 pub fn concrete_head_count(&self) -> usize {
41 fn go<T: Types>(c: &Constraint<T>, count: &mut usize) {
42 match c {
43 Constraint::Conj(cs) => cs.iter().for_each(|c| go(c, count)),
44 Constraint::ForAll(_, c) => go(c, count),
45 Constraint::Pred(head, _) => {
46 if head.is_concrete() && !head.is_trivially_true() {
47 *count += 1;
48 }
49 }
50 }
51 }
52 let mut count = 0;
53 go(self, &mut count);
54 count
55 }
56
57 pub fn flatten<F1>(&self, is_underscore: F1) -> Vec<FlatConstraint<T>>
64 where
65 F1: Copy + Fn(&T::Var) -> bool,
66 {
67 match self {
68 Constraint::Pred(pred, tag) => {
69 vec![FlatConstraint {
70 binders: vec![],
71 assumptions: Default::default(),
72 head: pred.clone(),
73 tag: tag.clone(),
74 }]
75 }
76 Constraint::Conj(constrs) => {
77 constrs
78 .iter()
79 .flat_map(|constr| constr.flatten(is_underscore))
80 .collect_vec()
81 }
82 Constraint::ForAll(bind, constr) => {
83 let mut flat_constrs = constr.flatten(is_underscore);
84 for constr in &mut flat_constrs {
85 if !is_underscore(&bind.name) {
86 constr.binders.push((bind.name.clone(), bind.sort.clone()));
87 }
88 for pred in &bind.preds {
89 constr.add_assumption(pred.clone());
90 }
91 }
97 flat_constrs
98 }
99 }
100 }
101}
102
103pub type WKVarAndConstrs<T> = (WKVar<T>, FlatConstraint<T>, Vec<FlatConstraint<T>>);
104pub type VarSorts<T> = (<T as Types>::Var, Sort<T>);
105
106#[derive_where(Clone, Debug)]
107pub struct FlatConstraint<T: Types> {
108 pub binders: Vec<(T::Var, Sort<T>)>,
113 pub assumptions: FxIndexSet<Pred<T>>,
116 pub head: Pred<T>,
117 #[derive_where(skip)]
118 pub tag: Option<T::Tag>,
119}
120
121impl<T: Types> FlatConstraint<T> {
122 pub fn remove_binders(&self, vars: &HashSet<T::Var>) -> (Vec<ConstDecl<T>>, FlatConstraint<T>) {
128 let mut new_binders = self.binders.clone();
129 let removed_binders = new_binders
130 .extract_if(.., |(var, _sort)| vars.contains(var))
131 .map(|(var, sort)| ConstDecl { name: var, sort, comment: None })
132 .collect_vec();
133 let new_constraint = FlatConstraint {
134 binders: new_binders,
135 assumptions: self.assumptions.clone(),
136 head: self.head.clone(),
137 tag: self.tag.clone(),
138 };
139 (removed_binders, new_constraint)
140 }
141
142 pub fn add_assumption(&mut self, assumption: Pred<T>) {
143 match assumption {
144 a @ Pred::KVar(_, _) => {
145 self.assumptions.insert(a);
146 }
147 Pred::Expr(e) => {
148 self.assumptions
149 .extend(e.as_conjunction().into_iter().map(|e| Pred::Expr(e)));
150 }
151 }
152 }
153
154 pub fn preconditions(&self) -> FxIndexSet<Pred<T>> {
155 self.assumptions.clone()
158 }
159
160 pub fn wkvars_and_constrs(&self) -> Vec<WKVarAndConstrs<T>> {
184 let mut wkvars_and_constraints = self
185 .assumptions
186 .iter()
187 .flat_map(|assumption| {
188 assumption
189 .wkvars_in_conj()
190 .into_iter()
191 .map(|wkvar| (wkvar, self.clone(), vec![]))
192 })
193 .collect_vec();
194 let mut frontier: Vec<_> = self
197 .assumptions
198 .iter()
199 .enumerate()
200 .filter_map(|(i, assumption)| {
201 if let Pred::Expr(assumption_expr) = assumption
202 && assumption_expr.has_wkvar_reachable_by_split()
203 {
204 let mut flat_constraint = self.clone();
205 flat_constraint.assumptions.shift_remove_index(i);
206 Some((assumption_expr.clone(), flat_constraint, vec![]))
207 } else {
208 None
209 }
210 })
211 .collect_vec();
212 while let Some((e, mut constr, other_constrs)) = frontier.pop() {
213 match e {
214 Expr::WKVar(wkvar) => {
221 wkvars_and_constraints.push((wkvar, constr, other_constrs));
227 }
228 Expr::And(conjs) => {
236 for (i, new_assumption) in conjs.iter().enumerate() {
237 if !(matches!(new_assumption, Expr::WKVar(..))
238 || new_assumption.has_wkvar_reachable_by_split())
239 {
240 continue;
241 }
242 let mut new_constr = constr.clone();
243 for (j, other_new_assumption) in conjs.iter().enumerate() {
244 if i == j {
245 continue;
246 }
247 new_constr.add_assumption(Pred::Expr(other_new_assumption.clone()));
248 }
249 frontier.push((new_assumption.clone(), new_constr, other_constrs.clone()));
250 }
251 }
252 Expr::Quantifier(Quantifier::Exists, _, _) => {
256 let (new_vars, hoisted_e) = e.hoist_exists();
257 constr.binders.extend(new_vars);
258 frontier.push((hoisted_e, constr, other_constrs));
259 }
260 Expr::Or(disjuncts) => {
275 for (i, disjunct) in disjuncts.iter().enumerate() {
276 if !(matches!(disjunct, Expr::WKVar(..))
277 || disjunct.has_wkvar_reachable_by_split())
278 {
279 continue;
280 }
281 let mut new_other_constrs = other_constrs.clone();
282 for (j, other_disjunct) in disjuncts.iter().enumerate() {
283 if i == j {
284 continue;
285 }
286 let mut new_other_constr = constr.clone();
287 new_other_constr.add_assumption(Pred::Expr(other_disjunct.clone()));
288 new_other_constrs.push(new_other_constr);
289 }
290 frontier.push((disjunct.clone(), constr.clone(), new_other_constrs));
291 }
292 }
293 _ => {}
294 }
295 }
296 wkvars_and_constraints
297 }
298}
299
300#[derive_where(Hash, Clone, Debug)]
301pub struct DataDecl<T: Types> {
302 pub name: T::Sort,
303 pub vars: usize,
304 pub ctors: Vec<DataCtor<T>>,
305}
306
307impl<T: Types> DataDecl<T> {
308 pub fn deps(&self, acc: &mut Vec<T::Sort>) {
309 for ctor in &self.ctors {
310 for field in &ctor.fields {
311 field.sort.deps(acc);
312 }
313 }
314 }
315}
316
317#[derive_where(Hash, Clone, Debug)]
318pub struct SortDecl<T: Types> {
319 pub name: T::Sort,
320 pub vars: usize,
321}
322
323#[derive_where(Hash, Clone, Debug)]
324pub struct DataCtor<T: Types> {
325 pub name: T::Var,
326 pub fields: Vec<DataField<T>>,
327}
328
329#[derive_where(Hash, Clone, Debug)]
330pub struct DataField<T: Types> {
331 pub name: T::Var,
332 pub sort: Sort<T>,
333}
334
335#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
336pub enum Sort<T: Types> {
337 Int,
338 Bool,
339 Real,
340 Str,
341 BitVec(Box<Sort<T>>),
342 BvSize(u32),
343 Var(usize),
344 Func(Box<[Self; 2]>),
345 Abs(usize, Box<Self>),
346 App(SortCtor<T>, Vec<Self>),
347}
348
349impl<T: Types> Sort<T> {
350 pub fn deps(&self, acc: &mut Vec<T::Sort>) {
351 match self {
352 Sort::App(SortCtor::Data(dt_name), args) => {
353 acc.push(dt_name.clone());
354 for arg in args {
355 arg.deps(acc);
356 }
357 }
358 Sort::Func(input_and_output) => {
359 let [input, output] = &**input_and_output;
360 input.deps(acc);
361 output.deps(acc);
362 }
363 Sort::Abs(_, sort) => {
364 sort.deps(acc);
365 }
366 _ => {}
367 }
368 }
369
370 pub fn mk_func<I>(params: usize, inputs: I, output: Sort<T>) -> Sort<T>
371 where
372 I: IntoIterator<Item = Sort<T>>,
373 I::IntoIter: DoubleEndedIterator,
374 {
375 let sort = inputs
376 .into_iter()
377 .rev()
378 .fold(output, |output, input| Sort::Func(Box::new([input, output])));
379
380 (0..params)
381 .rev()
382 .fold(sort, |sort, i| Sort::Abs(i, Box::new(sort)))
383 }
384
385 pub(crate) fn peel_out_abs(&self) -> (usize, &Sort<T>) {
386 let mut n = 0;
387 let mut curr = self;
388 while let Sort::Abs(i, sort) = curr {
389 assert_eq!(*i, n);
390 n += 1;
391 curr = sort;
392 }
393 (n, curr)
394 }
395
396 fn free_var_sorts_to_int_help(&mut self, bound: &mut HashSet<usize>) {
397 match self {
398 Sort::Int
399 | Sort::Real
400 | Sort::Bool
401 | Sort::Str
402 | Sort::BvSize(..)
403 | Sort::BitVec(..) => {}
404 Sort::Abs(var, inner) => {
405 bound.insert(*var);
406 inner.free_var_sorts_to_int_help(bound);
407 bound.remove(var);
408 }
409 Sort::App(_, args) => {
410 for arg in args {
411 arg.free_var_sorts_to_int_help(bound);
412 }
413 }
414 Sort::Func(inner) => {
415 let [arg, out] = &mut **inner;
416 arg.free_var_sorts_to_int_help(bound);
417 out.free_var_sorts_to_int_help(bound);
418 }
419 Sort::Var(v) => {
420 if !bound.contains(v) {
421 *self = Sort::Int;
422 }
423 }
424 }
425 }
426
427 pub(crate) fn free_var_sorts_to_int(&mut self) {
428 let mut bound = HashSet::new();
429 self.free_var_sorts_to_int_help(&mut bound);
430 }
431}
432
433#[derive_where(Hash, Debug, Clone)]
434pub struct FunSort<T: Types> {
435 pub params: usize,
436 pub inputs: Vec<Sort<T>>,
437 pub output: Sort<T>,
438}
439
440impl<T: Types> FunSort<T> {
441 pub fn deps(&self, acc: &mut Vec<T::Sort>) {
442 for sort in &self.inputs {
443 sort.deps(acc);
444 }
445 self.output.deps(acc);
446 }
447
448 pub fn into_sort(self) -> Sort<T> {
449 Sort::mk_func(self.params, self.inputs, self.output)
450 }
451
452 pub fn to_sort(&self) -> Sort<T> {
453 Sort::mk_func(self.params, self.inputs.clone(), self.output.clone())
454 }
455}
456
457#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
458pub enum SortCtor<T: Types> {
459 Set,
460 Map,
461 Data(T::Sort),
462}
463
464#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
465pub enum Pred<T: Types> {
466 KVar(T::KVar, Vec<Expr<T>>),
467 Expr(Expr<T>),
468}
469
470impl<T: Types> Pred<T> {
471 pub const TRUE: Self = Pred::Expr(Expr::TRUE);
472
473 pub fn is_trivially_true(&self) -> bool {
474 match self {
475 Pred::Expr(e) => e.is_trivially_true(),
476 Pred::KVar(..) => false,
477 }
478 }
479
480 pub fn is_concrete(&self) -> bool {
481 matches!(self, Pred::Expr(_))
482 }
483
484 pub fn wkvars_in_conj(&self) -> Vec<WKVar<T>> {
487 match self {
488 Pred::Expr(e) => e.wkvars_in_conj(),
489 Pred::KVar(..) => vec![],
490 }
491 }
492
493 pub fn strip_wkvars(&self) -> Self {
495 match self {
496 Pred::Expr(e) => Pred::Expr(e.strip_wkvars()),
497 Pred::KVar(..) => self.clone(),
498 }
499 }
500}
501
502#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq)]
503pub enum BinRel {
504 Eq,
505 Ne,
506 Gt,
507 Ge,
508 Lt,
509 Le,
510}
511
512impl BinRel {
513 pub const INEQUALITIES: [BinRel; 4] = [BinRel::Gt, BinRel::Ge, BinRel::Lt, BinRel::Le];
514}
515
516#[derive_where(PartialEq, Eq, Hash, Debug, Clone)]
517pub struct WKVar<T: Types> {
518 pub wkvid: T::Var,
519 pub args: Vec<Expr<T>>,
520}
521
522#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
523pub enum Expr<T: Types> {
524 Constant(Constant<T>),
525 Var(T::Var),
526 App(Box<Self>, Option<Vec<Sort<T>>>, Vec<Self>, Option<Sort<T>>),
527 Neg(Box<Self>),
528 BinaryOp(BinOp, Box<[Self; 2]>),
529 IfThenElse(Box<[Self; 3]>),
530 And(Vec<Self>),
531 Or(Vec<Self>),
532 Not(Box<Self>),
533 Imp(Box<[Self; 2]>),
534 Iff(Box<[Self; 2]>),
535 Atom(BinRel, Box<[Self; 2]>),
536 Let(T::Var, Box<[Self; 2]>),
537 ThyFunc(ThyFunc),
538 IsCtor(T::Var, Box<Self>),
539 Quantifier(Quantifier, Vec<(T::Var, Sort<T>)>, Box<Self>),
540 WKVar(WKVar<T>),
546}
547
548impl<T: Types> From<Constant<T>> for Expr<T> {
549 fn from(v: Constant<T>) -> Self {
550 Self::Constant(v)
551 }
552}
553
554impl<T: Types> Expr<T> {
555 pub const FALSE: Self = Expr::Constant(Constant::Boolean(false));
556 pub const TRUE: Self = Expr::Constant(Constant::Boolean(true));
557
558 pub const fn int(val: u128) -> Expr<T> {
559 Expr::Constant(Constant::Numeral(val))
560 }
561
562 pub fn eq(self, other: Self) -> Self {
563 Expr::Atom(BinRel::Eq, Box::new([self, other]))
564 }
565
566 pub fn and(mut exprs: Vec<Self>) -> Self {
567 if exprs.len() == 1 { exprs.remove(0) } else { Self::And(exprs) }
568 }
569
570 pub fn var_sorts_to_int(&mut self) {
571 match self {
572 Expr::Constant(_) | Expr::ThyFunc(_) | Expr::Var(_) => {}
573 Expr::App(func, sort_args, args, out_sort) => {
574 func.var_sorts_to_int();
575 for arg in args {
576 arg.var_sorts_to_int();
577 }
578 if let Some(sort_args) = sort_args {
579 for sort_arg in sort_args {
580 sort_arg.free_var_sorts_to_int();
581 }
582 }
583 if let Some(out_sort) = out_sort {
584 out_sort.free_var_sorts_to_int();
585 }
586 }
587 Expr::Neg(e) | Expr::Not(e) => {
588 e.var_sorts_to_int();
589 }
590 Expr::BinaryOp(_, exprs)
591 | Expr::Imp(exprs)
592 | Expr::Iff(exprs)
593 | Expr::Atom(_, exprs) => {
594 let [e1, e2] = &mut **exprs;
595 e1.var_sorts_to_int();
596 e2.var_sorts_to_int();
597 }
598 Expr::IfThenElse(exprs) => {
599 let [p, e1, e2] = &mut **exprs;
600 p.var_sorts_to_int();
601 e1.var_sorts_to_int();
602 e2.var_sorts_to_int();
603 }
604 Expr::And(exprs) | Expr::Or(exprs) => {
605 for e in exprs {
606 e.var_sorts_to_int();
607 }
608 }
609 Expr::Let(_, exprs) => {
610 let [var_e, body_e] = &mut **exprs;
611 var_e.var_sorts_to_int();
612 body_e.var_sorts_to_int();
613 }
614 Expr::IsCtor(_v, expr) => {
615 expr.var_sorts_to_int();
616 }
617 Expr::Quantifier(_, binder, expr) => {
618 for (_, sort) in binder {
619 sort.free_var_sorts_to_int();
620 }
621 expr.var_sorts_to_int();
622 }
623 Expr::WKVar(_) => {
624 unimplemented!()
625 }
626 }
627 }
628
629 pub fn free_vars(&self) -> FxIndexSet<T::Var> {
630 let mut vars = FxIndexSet::default();
631 match self {
632 Expr::Constant(_) | Expr::ThyFunc(_) => {}
633 Expr::Var(x) => {
634 vars.insert(x.clone());
635 }
636 Expr::App(func, _sort_args, args, _out_sort) => {
637 vars.extend(func.free_vars());
638 for arg in args {
639 vars.extend(arg.free_vars());
640 }
641 }
642 Expr::Neg(e) | Expr::Not(e) => {
643 vars = e.free_vars();
644 }
645 Expr::BinaryOp(_, exprs)
646 | Expr::Imp(exprs)
647 | Expr::Iff(exprs)
648 | Expr::Atom(_, exprs) => {
649 let [e1, e2] = &**exprs;
650 vars.extend(e1.free_vars());
651 vars.extend(e2.free_vars());
652 }
653 Expr::IfThenElse(exprs) => {
654 let [p, e1, e2] = &**exprs;
655 vars.extend(p.free_vars());
656 vars.extend(e1.free_vars());
657 vars.extend(e2.free_vars());
658 }
659 Expr::And(exprs) | Expr::Or(exprs) => {
660 for e in exprs {
661 vars.extend(e.free_vars());
662 }
663 }
664 Expr::Let(name, exprs) => {
665 let [var_e, body_e] = &**exprs;
668 vars.extend(var_e.free_vars());
669 let mut body_vars = body_e.free_vars();
670 body_vars.swap_remove(name);
671 vars.extend(body_vars);
672 }
673 Expr::IsCtor(_v, expr) => {
674 vars.extend(expr.free_vars());
677 }
678 Expr::Quantifier(_, binder, expr) => {
679 let mut inner = expr.free_vars();
680 for (var, _sort) in binder {
681 inner.swap_remove(var);
682 }
683 vars.extend(inner);
684 }
685 Expr::WKVar(WKVar { wkvid: _, args }) => {
686 for e in args {
687 vars.extend(e.free_vars());
688 }
689 }
690 };
691 vars
692 }
693
694 pub fn is_trivially_true(&self) -> bool {
695 matches!(self, Expr::Constant(Constant::Boolean(true)))
696 }
697
698 pub fn substitute(&self, subst: &FxIndexMap<T::Var, Self>) -> Self {
699 match self {
700 Expr::Var(v) => subst.get(v).cloned().unwrap_or_else(|| self.clone()),
701 Expr::Constant(_) | Expr::ThyFunc(_) => self.clone(),
702 Expr::App(expr, sort_args, exprs, out_sort) => {
703 Expr::App(
704 Box::new(expr.substitute(subst)),
705 sort_args.clone(),
706 exprs.iter().map(|e| e.substitute(subst)).collect_vec(),
707 out_sort.clone(),
708 )
709 }
710 Expr::Neg(expr) => Expr::Neg(Box::new(expr.substitute(subst))),
711 Expr::BinaryOp(bin_op, args) => {
712 Expr::BinaryOp(
713 *bin_op,
714 Box::new([args[0].substitute(subst), args[1].substitute(subst)]),
715 )
716 }
717 Expr::IfThenElse(args) => {
718 Expr::IfThenElse(Box::new([
719 args[0].substitute(subst),
720 args[1].substitute(subst),
721 args[2].substitute(subst),
722 ]))
723 }
724 Expr::And(exprs) => Expr::And(exprs.iter().map(|e| e.substitute(subst)).collect_vec()),
725 Expr::Or(exprs) => Expr::Or(exprs.iter().map(|e| e.substitute(subst)).collect_vec()),
726 Expr::Not(expr) => Expr::Not(Box::new(expr.substitute(subst))),
727 Expr::Imp(args) => {
728 Expr::Imp(Box::new([args[0].substitute(subst), args[1].substitute(subst)]))
729 }
730 Expr::Iff(args) => {
731 Expr::Iff(Box::new([args[0].substitute(subst), args[1].substitute(subst)]))
732 }
733 Expr::Atom(bin_rel, args) => {
734 Expr::Atom(
735 *bin_rel,
736 Box::new([args[0].substitute(subst), args[1].substitute(subst)]),
737 )
738 }
739 Expr::Let(var, args) => {
740 Expr::Let(
741 var.clone(),
742 Box::new([args[0].substitute(subst), args[1].substitute(subst)]),
743 )
744 }
745 Expr::IsCtor(var, expr) => Expr::IsCtor(var.clone(), Box::new(expr.substitute(subst))),
746 Expr::Quantifier(q, sorts, expr) => {
747 Expr::Quantifier(*q, sorts.clone(), Box::new(expr.substitute(subst)))
748 }
749 Expr::WKVar(WKVar { wkvid, args }) => {
750 Expr::WKVar(WKVar {
751 wkvid: wkvid.clone(),
752 args: args.iter().map(|e| e.substitute(subst)).collect_vec(),
753 })
754 }
755 }
756 }
757
758 pub fn wkvars_in_conj(&self) -> Vec<WKVar<T>> {
761 match self {
762 Expr::WKVar(wkvar) => vec![wkvar.clone()],
763 Expr::And(conj) => conj.iter().flat_map(|e| e.wkvars_in_conj()).collect(),
764 _ => vec![],
765 }
766 }
767
768 pub fn uncurry(&self) -> Self {
769 match self {
770 Expr::App(head, sort_args, args, out_sort) => {
771 let uncurried_head = head.uncurry();
772 let uncurried_args = args.iter().map(Expr::uncurry).collect_vec();
773 match uncurried_head {
774 Expr::App(head_head, head_sort_args, mut head_args, _) => {
775 head_args.extend(uncurried_args);
776 let sort_args = match (head_sort_args, sort_args) {
777 (Some(mut head_sort_args), Some(sort_args)) => {
778 head_sort_args.extend(sort_args.clone());
779 Some(head_sort_args)
780 }
781 _ => None,
782 };
783 Expr::App(head_head, sort_args, head_args, out_sort.clone())
784 }
785 Expr::WKVar(WKVar { wkvid, args: mut wkvar_args }) => {
786 wkvar_args.extend(uncurried_args);
787 Expr::WKVar(WKVar { wkvid, args: wkvar_args })
788 }
789 head => {
790 Expr::App(
791 Box::new(head),
792 sort_args.clone(),
793 uncurried_args,
794 out_sort.clone(),
795 )
796 }
797 }
798 }
799 Expr::Constant(_) | Expr::Var(_) | Expr::ThyFunc(_) => self.clone(),
800 Expr::Neg(expr) => Expr::Neg(Box::new(expr.uncurry())),
801 Expr::BinaryOp(bin_op, args) => {
802 Expr::BinaryOp(*bin_op, Box::new([args[0].uncurry(), args[1].uncurry()]))
803 }
804 Expr::IfThenElse(args) => {
805 Expr::IfThenElse(Box::new([
806 args[0].uncurry(),
807 args[1].uncurry(),
808 args[2].uncurry(),
809 ]))
810 }
811 Expr::And(exprs) => Expr::And(exprs.iter().map(Expr::uncurry).collect_vec()),
812 Expr::Or(exprs) => Expr::Or(exprs.iter().map(Expr::uncurry).collect_vec()),
813 Expr::Not(expr) => Expr::Not(Box::new(expr.uncurry())),
814 Expr::Imp(args) => Expr::Imp(Box::new([args[0].uncurry(), args[1].uncurry()])),
815 Expr::Iff(args) => Expr::Iff(Box::new([args[0].uncurry(), args[1].uncurry()])),
816 Expr::Atom(bin_rel, args) => {
817 Expr::Atom(*bin_rel, Box::new([args[0].uncurry(), args[1].uncurry()]))
818 }
819 Expr::Let(var, args) => {
820 Expr::Let(var.clone(), Box::new([args[0].uncurry(), args[1].uncurry()]))
821 }
822 Expr::IsCtor(var, expr) => Expr::IsCtor(var.clone(), Box::new(expr.uncurry())),
823 Expr::Quantifier(q, sorts, expr) => {
824 Expr::Quantifier(*q, sorts.clone(), Box::new(expr.uncurry()))
825 }
826 Expr::WKVar(WKVar { wkvid, args }) => {
827 Expr::WKVar(WKVar {
828 wkvid: wkvid.clone(),
829 args: args.iter().map(|e| e.uncurry()).collect_vec(),
830 })
831 }
832 }
833 }
834
835 pub fn has_wkvar_reachable_by_split(&self) -> bool {
836 if !matches!(self, Expr::Quantifier(Quantifier::Exists, ..) | Expr::Or(..) | Expr::And(..))
837 {
838 return false;
839 }
840 match self {
841 Expr::Or(exprs) => {
842 exprs.iter().any(|expr| {
843 matches!(expr, Expr::WKVar(..)) || expr.has_wkvar_reachable_by_split()
844 })
845 }
846 Expr::Quantifier(Quantifier::Exists, _sorts, expr) => {
847 !expr.wkvars_in_conj().is_empty() || expr.has_wkvar_reachable_by_split()
848 }
849 Expr::And(exprs) => exprs.iter().any(Expr::has_wkvar_reachable_by_split),
850 _ => false,
851 }
852 }
853
854 pub fn hoist_exists(&self) -> (Vec<VarSorts<T>>, Expr<T>) {
855 match self {
856 Expr::Quantifier(Quantifier::Exists, var_sorts, inner_e) => {
857 let mut vars = var_sorts.clone();
858 let (new_vars, hoisted_inner) = inner_e.hoist_exists();
859 vars.extend(new_vars);
860 (vars, hoisted_inner)
861 }
862 Expr::And(exprs) => {
863 let mut vars = vec![];
864 let expr = Expr::And(
865 exprs
866 .iter()
867 .flat_map(|expr| {
868 let (new_vars, hoisted_expr) = expr.hoist_exists();
869 vars.extend(new_vars);
870 match hoisted_expr {
871 Expr::And(exprs) => exprs,
872 expr => vec![expr],
873 }
874 })
875 .collect(),
876 );
877 (vars, expr)
878 }
879 _ => (vec![], self.clone()),
880 }
881 }
882
883 pub fn as_conjunction(self) -> Vec<Self> {
884 match self {
885 Expr::And(exprs) => exprs,
886 expr => vec![expr],
887 }
888 }
889
890 pub fn strip_wkvars(&self) -> Self {
891 match self {
892 Expr::Constant(_) | Expr::Var(_) | Expr::ThyFunc(_) => self.clone(),
893 Expr::WKVar(..) => Expr::TRUE,
894 Expr::App(head, sort_args, args, out_sort) => {
895 Expr::App(
896 Box::new(head.strip_wkvars()),
897 sort_args.clone(),
898 args.iter().map(Expr::strip_wkvars).collect(),
899 out_sort.clone(),
900 )
901 }
902 Expr::Neg(expr) => Expr::Neg(Box::new(expr.strip_wkvars())),
903 Expr::BinaryOp(bin_op, args) => {
904 Expr::BinaryOp(*bin_op, Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
905 }
906 Expr::IfThenElse(args) => {
907 Expr::IfThenElse(Box::new([
908 args[0].strip_wkvars(),
909 args[1].strip_wkvars(),
910 args[2].strip_wkvars(),
911 ]))
912 }
913 Expr::And(exprs) => Expr::And(exprs.iter().map(Expr::strip_wkvars).collect_vec()),
914 Expr::Or(exprs) => Expr::Or(exprs.iter().map(Expr::strip_wkvars).collect_vec()),
915 Expr::Not(expr) => Expr::Not(Box::new(expr.strip_wkvars())),
916 Expr::Imp(args) => {
917 Expr::Imp(Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
918 }
919 Expr::Iff(args) => {
920 Expr::Iff(Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
921 }
922 Expr::Atom(bin_rel, args) => {
923 Expr::Atom(*bin_rel, Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
924 }
925 Expr::Let(var, args) => {
926 Expr::Let(var.clone(), Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
927 }
928 Expr::IsCtor(var, expr) => Expr::IsCtor(var.clone(), Box::new(expr.strip_wkvars())),
929 Expr::Quantifier(q, sorts, expr) => {
930 Expr::Quantifier(*q, sorts.clone(), Box::new(expr.strip_wkvars()))
931 }
932 }
933 }
934
935 pub fn total_num_disjuncts(&self) -> usize {
936 match self {
937 Expr::Or(disjuncts) => {
938 disjuncts.len()
939 + disjuncts
940 .iter()
941 .map(Expr::total_num_disjuncts)
942 .sum::<usize>()
943 }
944 Expr::And(conjuncts) => conjuncts.iter().map(Expr::total_num_disjuncts).sum(),
945 _ => 0,
946 }
947 }
948}
949
950#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
951pub enum Constant<T: Types> {
952 Numeral(u128),
953 Real(T::Real),
954 Boolean(bool),
955 String(T::String),
956 BitVec(u128, u32),
957}
958
959#[derive_where(Debug, Clone, Hash)]
960pub struct Qualifier<T: Types> {
961 pub name: String,
962 pub args: Vec<QualParam<T>>,
963 pub body: Expr<T>,
964}
965
966#[derive_where(Debug, Clone, Hash)]
968pub struct Axiom<T: Types> {
969 pub name: String,
970 pub args: Vec<(T::Var, Sort<T>)>,
971 pub body: Expr<T>,
972 pub patterns: Vec<Expr<T>>,
975}
976
977#[derive_where(Debug, Clone, Hash)]
978pub struct QualParam<T: Types> {
979 pub name: T::Var,
980 pub sort: Sort<T>,
981 pub is_wildcard: bool,
982}
983
984impl<T: Types> QualParam<T> {
985 pub fn new(name: T::Var, sort: Sort<T>) -> Self {
986 Self { name, sort, is_wildcard: false }
987 }
988}
989
990#[derive(Clone, Copy, PartialEq, Eq, Hash)]
991pub enum BinOp {
992 Add,
993 Sub,
994 Mul,
995 Div,
996 Mod,
997}
998
999#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
1000pub enum Quantifier {
1001 Exists,
1002 Forall,
1003}