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)]
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
453#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
454pub enum SortCtor<T: Types> {
455 Set,
456 Map,
457 Data(T::Sort),
458}
459
460#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
461pub enum Pred<T: Types> {
462 KVar(T::KVar, Vec<Expr<T>>),
463 Expr(Expr<T>),
464}
465
466impl<T: Types> Pred<T> {
467 pub const TRUE: Self = Pred::Expr(Expr::TRUE);
468
469 pub fn is_trivially_true(&self) -> bool {
470 match self {
471 Pred::Expr(e) => e.is_trivially_true(),
472 Pred::KVar(..) => false,
473 }
474 }
475
476 pub fn is_concrete(&self) -> bool {
477 matches!(self, Pred::Expr(_))
478 }
479
480 pub fn wkvars_in_conj(&self) -> Vec<WKVar<T>> {
483 match self {
484 Pred::Expr(e) => e.wkvars_in_conj(),
485 Pred::KVar(..) => vec![],
486 }
487 }
488
489 pub fn strip_wkvars(&self) -> Self {
491 match self {
492 Pred::Expr(e) => Pred::Expr(e.strip_wkvars()),
493 Pred::KVar(..) => self.clone(),
494 }
495 }
496}
497
498#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq)]
499pub enum BinRel {
500 Eq,
501 Ne,
502 Gt,
503 Ge,
504 Lt,
505 Le,
506}
507
508impl BinRel {
509 pub const INEQUALITIES: [BinRel; 4] = [BinRel::Gt, BinRel::Ge, BinRel::Lt, BinRel::Le];
510}
511
512#[derive_where(PartialEq, Eq, Hash, Debug, Clone)]
513pub struct WKVar<T: Types> {
514 pub wkvid: T::Var,
515 pub args: Vec<Expr<T>>,
516}
517
518#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
519pub enum Expr<T: Types> {
520 Constant(Constant<T>),
521 Var(T::Var),
522 App(Box<Self>, Option<Vec<Sort<T>>>, Vec<Self>, Option<Sort<T>>),
523 Neg(Box<Self>),
524 BinaryOp(BinOp, Box<[Self; 2]>),
525 IfThenElse(Box<[Self; 3]>),
526 And(Vec<Self>),
527 Or(Vec<Self>),
528 Not(Box<Self>),
529 Imp(Box<[Self; 2]>),
530 Iff(Box<[Self; 2]>),
531 Atom(BinRel, Box<[Self; 2]>),
532 Let(T::Var, Box<[Self; 2]>),
533 ThyFunc(ThyFunc),
534 IsCtor(T::Var, Box<Self>),
535 Quantifier(Quantifier, Vec<(T::Var, Sort<T>)>, Box<Self>),
536 WKVar(WKVar<T>),
542}
543
544impl<T: Types> From<Constant<T>> for Expr<T> {
545 fn from(v: Constant<T>) -> Self {
546 Self::Constant(v)
547 }
548}
549
550impl<T: Types> Expr<T> {
551 pub const FALSE: Self = Expr::Constant(Constant::Boolean(false));
552 pub const TRUE: Self = Expr::Constant(Constant::Boolean(true));
553
554 pub const fn int(val: u128) -> Expr<T> {
555 Expr::Constant(Constant::Numeral(val))
556 }
557
558 pub fn eq(self, other: Self) -> Self {
559 Expr::Atom(BinRel::Eq, Box::new([self, other]))
560 }
561
562 pub fn and(mut exprs: Vec<Self>) -> Self {
563 if exprs.len() == 1 { exprs.remove(0) } else { Self::And(exprs) }
564 }
565
566 pub fn var_sorts_to_int(&mut self) {
567 match self {
568 Expr::Constant(_) | Expr::ThyFunc(_) | Expr::Var(_) => {}
569 Expr::App(func, sort_args, args, out_sort) => {
570 func.var_sorts_to_int();
571 for arg in args {
572 arg.var_sorts_to_int();
573 }
574 if let Some(sort_args) = sort_args {
575 for sort_arg in sort_args {
576 sort_arg.free_var_sorts_to_int();
577 }
578 }
579 if let Some(out_sort) = out_sort {
580 out_sort.free_var_sorts_to_int();
581 }
582 }
583 Expr::Neg(e) | Expr::Not(e) => {
584 e.var_sorts_to_int();
585 }
586 Expr::BinaryOp(_, exprs)
587 | Expr::Imp(exprs)
588 | Expr::Iff(exprs)
589 | Expr::Atom(_, exprs) => {
590 let [e1, e2] = &mut **exprs;
591 e1.var_sorts_to_int();
592 e2.var_sorts_to_int();
593 }
594 Expr::IfThenElse(exprs) => {
595 let [p, e1, e2] = &mut **exprs;
596 p.var_sorts_to_int();
597 e1.var_sorts_to_int();
598 e2.var_sorts_to_int();
599 }
600 Expr::And(exprs) | Expr::Or(exprs) => {
601 for e in exprs {
602 e.var_sorts_to_int();
603 }
604 }
605 Expr::Let(_, exprs) => {
606 let [var_e, body_e] = &mut **exprs;
607 var_e.var_sorts_to_int();
608 body_e.var_sorts_to_int();
609 }
610 Expr::IsCtor(_v, expr) => {
611 expr.var_sorts_to_int();
612 }
613 Expr::Quantifier(_, binder, expr) => {
614 for (_, sort) in binder {
615 sort.free_var_sorts_to_int();
616 }
617 expr.var_sorts_to_int();
618 }
619 Expr::WKVar(_) => {
620 unimplemented!()
621 }
622 }
623 }
624
625 pub fn free_vars(&self) -> FxIndexSet<T::Var> {
626 let mut vars = FxIndexSet::default();
627 match self {
628 Expr::Constant(_) | Expr::ThyFunc(_) => {}
629 Expr::Var(x) => {
630 vars.insert(x.clone());
631 }
632 Expr::App(func, _sort_args, args, _out_sort) => {
633 vars.extend(func.free_vars());
634 for arg in args {
635 vars.extend(arg.free_vars());
636 }
637 }
638 Expr::Neg(e) | Expr::Not(e) => {
639 vars = e.free_vars();
640 }
641 Expr::BinaryOp(_, exprs)
642 | Expr::Imp(exprs)
643 | Expr::Iff(exprs)
644 | Expr::Atom(_, exprs) => {
645 let [e1, e2] = &**exprs;
646 vars.extend(e1.free_vars());
647 vars.extend(e2.free_vars());
648 }
649 Expr::IfThenElse(exprs) => {
650 let [p, e1, e2] = &**exprs;
651 vars.extend(p.free_vars());
652 vars.extend(e1.free_vars());
653 vars.extend(e2.free_vars());
654 }
655 Expr::And(exprs) | Expr::Or(exprs) => {
656 for e in exprs {
657 vars.extend(e.free_vars());
658 }
659 }
660 Expr::Let(name, exprs) => {
661 let [var_e, body_e] = &**exprs;
664 vars.extend(var_e.free_vars());
665 let mut body_vars = body_e.free_vars();
666 body_vars.swap_remove(name);
667 vars.extend(body_vars);
668 }
669 Expr::IsCtor(_v, expr) => {
670 vars.extend(expr.free_vars());
673 }
674 Expr::Quantifier(_, binder, expr) => {
675 let mut inner = expr.free_vars();
676 for (var, _sort) in binder {
677 inner.swap_remove(var);
678 }
679 vars.extend(inner);
680 }
681 Expr::WKVar(WKVar { wkvid: _, args }) => {
682 for e in args {
683 vars.extend(e.free_vars());
684 }
685 }
686 };
687 vars
688 }
689
690 pub fn is_trivially_true(&self) -> bool {
691 matches!(self, Expr::Constant(Constant::Boolean(true)))
692 }
693
694 pub fn substitute(&self, subst: &FxIndexMap<T::Var, Self>) -> Self {
695 match self {
696 Expr::Var(v) => subst.get(v).cloned().unwrap_or_else(|| self.clone()),
697 Expr::Constant(_) | Expr::ThyFunc(_) => self.clone(),
698 Expr::App(expr, sort_args, exprs, out_sort) => {
699 Expr::App(
700 Box::new(expr.substitute(subst)),
701 sort_args.clone(),
702 exprs.iter().map(|e| e.substitute(subst)).collect_vec(),
703 out_sort.clone(),
704 )
705 }
706 Expr::Neg(expr) => Expr::Neg(Box::new(expr.substitute(subst))),
707 Expr::BinaryOp(bin_op, args) => {
708 Expr::BinaryOp(
709 *bin_op,
710 Box::new([args[0].substitute(subst), args[1].substitute(subst)]),
711 )
712 }
713 Expr::IfThenElse(args) => {
714 Expr::IfThenElse(Box::new([
715 args[0].substitute(subst),
716 args[1].substitute(subst),
717 args[2].substitute(subst),
718 ]))
719 }
720 Expr::And(exprs) => Expr::And(exprs.iter().map(|e| e.substitute(subst)).collect_vec()),
721 Expr::Or(exprs) => Expr::Or(exprs.iter().map(|e| e.substitute(subst)).collect_vec()),
722 Expr::Not(expr) => Expr::Not(Box::new(expr.substitute(subst))),
723 Expr::Imp(args) => {
724 Expr::Imp(Box::new([args[0].substitute(subst), args[1].substitute(subst)]))
725 }
726 Expr::Iff(args) => {
727 Expr::Iff(Box::new([args[0].substitute(subst), args[1].substitute(subst)]))
728 }
729 Expr::Atom(bin_rel, args) => {
730 Expr::Atom(
731 *bin_rel,
732 Box::new([args[0].substitute(subst), args[1].substitute(subst)]),
733 )
734 }
735 Expr::Let(var, args) => {
736 Expr::Let(
737 var.clone(),
738 Box::new([args[0].substitute(subst), args[1].substitute(subst)]),
739 )
740 }
741 Expr::IsCtor(var, expr) => Expr::IsCtor(var.clone(), Box::new(expr.substitute(subst))),
742 Expr::Quantifier(q, sorts, expr) => {
743 Expr::Quantifier(*q, sorts.clone(), Box::new(expr.substitute(subst)))
744 }
745 Expr::WKVar(WKVar { wkvid, args }) => {
746 Expr::WKVar(WKVar {
747 wkvid: wkvid.clone(),
748 args: args.iter().map(|e| e.substitute(subst)).collect_vec(),
749 })
750 }
751 }
752 }
753
754 pub fn wkvars_in_conj(&self) -> Vec<WKVar<T>> {
757 match self {
758 Expr::WKVar(wkvar) => vec![wkvar.clone()],
759 Expr::And(conj) => conj.iter().flat_map(|e| e.wkvars_in_conj()).collect(),
760 _ => vec![],
761 }
762 }
763
764 pub fn uncurry(&self) -> Self {
765 match self {
766 Expr::App(head, sort_args, args, out_sort) => {
767 let uncurried_head = head.uncurry();
768 let uncurried_args = args.iter().map(Expr::uncurry).collect_vec();
769 match uncurried_head {
770 Expr::App(head_head, head_sort_args, mut head_args, _) => {
771 head_args.extend(uncurried_args);
772 let sort_args = match (head_sort_args, sort_args) {
773 (Some(mut head_sort_args), Some(sort_args)) => {
774 head_sort_args.extend(sort_args.clone());
775 Some(head_sort_args)
776 }
777 _ => None,
778 };
779 Expr::App(head_head, sort_args, head_args, out_sort.clone())
780 }
781 Expr::WKVar(WKVar { wkvid, args: mut wkvar_args }) => {
782 wkvar_args.extend(uncurried_args);
783 Expr::WKVar(WKVar { wkvid, args: wkvar_args })
784 }
785 head => {
786 Expr::App(
787 Box::new(head),
788 sort_args.clone(),
789 uncurried_args,
790 out_sort.clone(),
791 )
792 }
793 }
794 }
795 Expr::Constant(_) | Expr::Var(_) | Expr::ThyFunc(_) => self.clone(),
796 Expr::Neg(expr) => Expr::Neg(Box::new(expr.uncurry())),
797 Expr::BinaryOp(bin_op, args) => {
798 Expr::BinaryOp(*bin_op, Box::new([args[0].uncurry(), args[1].uncurry()]))
799 }
800 Expr::IfThenElse(args) => {
801 Expr::IfThenElse(Box::new([
802 args[0].uncurry(),
803 args[1].uncurry(),
804 args[2].uncurry(),
805 ]))
806 }
807 Expr::And(exprs) => Expr::And(exprs.iter().map(Expr::uncurry).collect_vec()),
808 Expr::Or(exprs) => Expr::Or(exprs.iter().map(Expr::uncurry).collect_vec()),
809 Expr::Not(expr) => Expr::Not(Box::new(expr.uncurry())),
810 Expr::Imp(args) => Expr::Imp(Box::new([args[0].uncurry(), args[1].uncurry()])),
811 Expr::Iff(args) => Expr::Iff(Box::new([args[0].uncurry(), args[1].uncurry()])),
812 Expr::Atom(bin_rel, args) => {
813 Expr::Atom(*bin_rel, Box::new([args[0].uncurry(), args[1].uncurry()]))
814 }
815 Expr::Let(var, args) => {
816 Expr::Let(var.clone(), Box::new([args[0].uncurry(), args[1].uncurry()]))
817 }
818 Expr::IsCtor(var, expr) => Expr::IsCtor(var.clone(), Box::new(expr.uncurry())),
819 Expr::Quantifier(q, sorts, expr) => {
820 Expr::Quantifier(*q, sorts.clone(), Box::new(expr.uncurry()))
821 }
822 Expr::WKVar(WKVar { wkvid, args }) => {
823 Expr::WKVar(WKVar {
824 wkvid: wkvid.clone(),
825 args: args.iter().map(|e| e.uncurry()).collect_vec(),
826 })
827 }
828 }
829 }
830
831 pub fn has_wkvar_reachable_by_split(&self) -> bool {
832 if !matches!(self, Expr::Quantifier(Quantifier::Exists, ..) | Expr::Or(..) | Expr::And(..))
833 {
834 return false;
835 }
836 match self {
837 Expr::Or(exprs) => {
838 exprs.iter().any(|expr| {
839 matches!(expr, Expr::WKVar(..)) || expr.has_wkvar_reachable_by_split()
840 })
841 }
842 Expr::Quantifier(Quantifier::Exists, _sorts, expr) => {
843 !expr.wkvars_in_conj().is_empty() || expr.has_wkvar_reachable_by_split()
844 }
845 Expr::And(exprs) => exprs.iter().any(Expr::has_wkvar_reachable_by_split),
846 _ => false,
847 }
848 }
849
850 pub fn hoist_exists(&self) -> (Vec<VarSorts<T>>, Expr<T>) {
851 match self {
852 Expr::Quantifier(Quantifier::Exists, var_sorts, inner_e) => {
853 let mut vars = var_sorts.clone();
854 let (new_vars, hoisted_inner) = inner_e.hoist_exists();
855 vars.extend(new_vars);
856 (vars, hoisted_inner)
857 }
858 Expr::And(exprs) => {
859 let mut vars = vec![];
860 let expr = Expr::And(
861 exprs
862 .iter()
863 .flat_map(|expr| {
864 let (new_vars, hoisted_expr) = expr.hoist_exists();
865 vars.extend(new_vars);
866 match hoisted_expr {
867 Expr::And(exprs) => exprs,
868 expr => vec![expr],
869 }
870 })
871 .collect(),
872 );
873 (vars, expr)
874 }
875 _ => (vec![], self.clone()),
876 }
877 }
878
879 pub fn as_conjunction(self) -> Vec<Self> {
880 match self {
881 Expr::And(exprs) => exprs,
882 expr => vec![expr],
883 }
884 }
885
886 pub fn strip_wkvars(&self) -> Self {
887 match self {
888 Expr::Constant(_) | Expr::Var(_) | Expr::ThyFunc(_) => self.clone(),
889 Expr::WKVar(..) => Expr::TRUE,
890 Expr::App(head, sort_args, args, out_sort) => {
891 Expr::App(
892 Box::new(head.strip_wkvars()),
893 sort_args.clone(),
894 args.iter().map(Expr::strip_wkvars).collect(),
895 out_sort.clone(),
896 )
897 }
898 Expr::Neg(expr) => Expr::Neg(Box::new(expr.strip_wkvars())),
899 Expr::BinaryOp(bin_op, args) => {
900 Expr::BinaryOp(*bin_op, Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
901 }
902 Expr::IfThenElse(args) => {
903 Expr::IfThenElse(Box::new([
904 args[0].strip_wkvars(),
905 args[1].strip_wkvars(),
906 args[2].strip_wkvars(),
907 ]))
908 }
909 Expr::And(exprs) => Expr::And(exprs.iter().map(Expr::strip_wkvars).collect_vec()),
910 Expr::Or(exprs) => Expr::Or(exprs.iter().map(Expr::strip_wkvars).collect_vec()),
911 Expr::Not(expr) => Expr::Not(Box::new(expr.strip_wkvars())),
912 Expr::Imp(args) => {
913 Expr::Imp(Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
914 }
915 Expr::Iff(args) => {
916 Expr::Iff(Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
917 }
918 Expr::Atom(bin_rel, args) => {
919 Expr::Atom(*bin_rel, Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
920 }
921 Expr::Let(var, args) => {
922 Expr::Let(var.clone(), Box::new([args[0].strip_wkvars(), args[1].strip_wkvars()]))
923 }
924 Expr::IsCtor(var, expr) => Expr::IsCtor(var.clone(), Box::new(expr.strip_wkvars())),
925 Expr::Quantifier(q, sorts, expr) => {
926 Expr::Quantifier(*q, sorts.clone(), Box::new(expr.strip_wkvars()))
927 }
928 }
929 }
930
931 pub fn total_num_disjuncts(&self) -> usize {
932 match self {
933 Expr::Or(disjuncts) => {
934 disjuncts.len()
935 + disjuncts
936 .iter()
937 .map(Expr::total_num_disjuncts)
938 .sum::<usize>()
939 }
940 Expr::And(conjuncts) => conjuncts.iter().map(Expr::total_num_disjuncts).sum(),
941 _ => 0,
942 }
943 }
944}
945
946#[derive_where(PartialEq, Eq, Hash, Clone, Debug)]
947pub enum Constant<T: Types> {
948 Numeral(u128),
949 Real(T::Real),
950 Boolean(bool),
951 String(T::String),
952 BitVec(u128, u32),
953}
954
955#[derive_where(Debug, Clone, Hash)]
956pub struct Qualifier<T: Types> {
957 pub name: String,
958 pub args: Vec<QualParam<T>>,
959 pub body: Expr<T>,
960}
961
962#[derive_where(Debug, Clone, Hash)]
963pub struct QualParam<T: Types> {
964 pub name: T::Var,
965 pub sort: Sort<T>,
966 pub is_wildcard: bool,
967}
968
969impl<T: Types> QualParam<T> {
970 pub fn new(name: T::Var, sort: Sort<T>) -> Self {
971 Self { name, sort, is_wildcard: false }
972 }
973}
974
975#[derive(Clone, Copy, PartialEq, Eq, Hash)]
976pub enum BinOp {
977 Add,
978 Sub,
979 Mul,
980 Div,
981 Mod,
982}
983
984#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
985pub enum Quantifier {
986 Exists,
987 Forall,
988}