liquid_fixpoint/
constraint_with_env.rs1use std::collections::{HashMap, VecDeque};
2
3use derive_where::derive_where;
4use itertools::Itertools;
5
6use crate::{
7 KVarDecl, Types,
8 constraint::{Constraint, Qualifier},
9 is_constraint_satisfiable,
10 parser::ParsingTypes,
11};
12
13#[derive_where(Hash)]
14pub struct ConstraintWithEnv<T: Types> {
15 pub kvar_decls: Vec<KVarDecl<T>>,
16 pub qualifiers: Vec<Qualifier<T>>,
17 pub constraint: Constraint<T>,
18}
19
20impl ConstraintWithEnv<ParsingTypes> {
21 pub fn is_satisfiable(&self) -> bool {
22 if self.kvar_decls.is_empty() {
23 self.constraint.is_satisfiable()
24 } else {
25 self.solve_by_fusion()
26 }
27 }
28
29 pub fn uniquify(&mut self) {
30 self.constraint.uniquify();
31 }
32
33 pub fn solve_by_fusion(&self) -> bool {
34 let mut cstr = self.constraint.clone();
35 let mut dep_map = self.constraint.kvar_mappings().1;
36 let mut acyclic_kvars: Vec<String> = dep_map
37 .into_iter()
38 .filter(|(_, dependencies)| dependencies.is_empty())
39 .map(|(kvar, _)| kvar)
40 .collect();
41 while !acyclic_kvars.is_empty() {
42 cstr = cstr.elim(&acyclic_kvars);
43 dep_map = cstr.kvar_mappings().1;
44 acyclic_kvars = dep_map
45 .into_iter()
46 .filter(|(_, dependencies)| dependencies.is_empty())
47 .map(|(kvar, _)| kvar)
48 .collect();
49 }
50 ConstraintWithEnv {
51 kvar_decls: self.kvar_decls.to_vec(),
52 qualifiers: self.qualifiers.to_vec(),
53 constraint: cstr,
54 }
55 .solve_by_predicate_abstraction()
56 }
57
58 pub fn solve_by_predicate_abstraction(&self) -> bool {
59 let mut qualifiers: Vec<Qualifier<ParsingTypes>> = vec![];
60 qualifiers.extend(self.qualifiers.to_vec().into_iter());
61 let kvar_assignment = self.solve_for_kvars(&qualifiers);
62 let no_kvar_cstr = self.constraint.sub_all_kvars(&kvar_assignment);
63 is_constraint_satisfiable(&no_kvar_cstr)
64 }
65
66 pub fn compute_initial_assignments<'a>(
67 &'a self,
68 qualifiers: &'a Vec<Qualifier<ParsingTypes>>,
69 ) -> HashMap<String, Vec<(&'a Qualifier<ParsingTypes>, Vec<usize>)>> {
70 let mut assignments = HashMap::new();
71
72 for decl in &self.kvar_decls {
73 let kvar_arg_count = decl.sorts.len();
74 for qualifier in qualifiers {
75 let qualifier_arg_count = qualifier.args.len();
76 for argument_combination in (0..kvar_arg_count).combinations(qualifier_arg_count) {
77 assignments
78 .entry(decl.kvid.clone())
79 .or_insert(vec![])
80 .extend(
81 argument_combination
82 .into_iter()
83 .permutations(qualifier_arg_count)
84 .filter(|arg_permutation| {
85 type_signature_matches(arg_permutation, decl, qualifier)
86 })
87 .map(|arg_permutation| (qualifier, arg_permutation)),
88 );
89 }
90 }
91 }
92
93 assignments
94 }
95
96 pub fn solve_for_kvars<'a>(
97 &'a self,
98 qualifiers: &'a Vec<Qualifier<ParsingTypes>>,
99 ) -> HashMap<String, Vec<(&'a Qualifier<ParsingTypes>, Vec<usize>)>> {
100 let mut assignments = self.compute_initial_assignments(qualifiers);
101 let (kvars_to_fragments, _) = self.constraint.kvar_mappings();
102 let topo_order_fragments = self.constraint.topo_order_fragments();
103 let mut work_list = VecDeque::from_iter(topo_order_fragments.iter());
104 while !work_list.is_empty() {
105 if let Some(fragment) = work_list.pop_front() {
106 if let Some(kvar_name) = fragment.fragment_kvar_head() {
107 let subbed = fragment.sub_kvars_except_head(&assignments);
108 let assignment = assignments.get_mut(&kvar_name);
109 if let Some(assignment) = assignment {
110 let initial_length = assignment.len();
111 assignment.retain(|assignment| {
112 let vc = subbed.sub_head(assignment);
113 is_constraint_satisfiable(&vc)
114 });
115 if initial_length > qualifiers.len() {
116 work_list.extend(
117 fragment
118 .kvar_deps()
119 .iter()
120 .map(|kvar| kvars_to_fragments.get(kvar).unwrap().iter())
121 .flatten(),
122 );
123 }
124 }
125 }
126 }
127 }
128 assignments
129 }
130}
131
132fn type_signature_matches(
133 argument_permutation: &Vec<usize>,
134 kvar_decl: &KVarDecl<ParsingTypes>,
135 qualifier: &Qualifier<ParsingTypes>,
136) -> bool {
137 if argument_permutation.len() != qualifier.args.len() {
138 return false;
139 }
140
141 for (qs, ks) in qualifier.args.iter().map(|arg| arg.1.clone()).zip(
142 argument_permutation
143 .iter()
144 .map(|arg_idx| kvar_decl.sorts[*arg_idx].clone()),
145 ) {
146 if qs.to_string().ne(&ks.to_string()) {
147 return false;
148 }
149 }
150
151 true
152}