1 | % (c) 2019-2022 Lehrstuhl fuer Softwaretechnik und Programmiersprachen. | |
2 | % Heinrich Heine Universitaet Duesseldorf | |
3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
4 | ||
5 | :- module(dpllt_pred_to_sat, [predicate_to_sat/9, | |
6 | predicate_to_sat/6, | |
7 | sat_to_predicate_from_solution/3, | |
8 | remove_wd_pos_introduced_for_dpllt_keep_toplevel/2, | |
9 | get_all_top_level_wd_pos/2, | |
10 | get_amount_of_sat_variables/1, | |
11 | next_sat_var_name/1, | |
12 | reset_sat_var_id/0]). | |
13 | ||
14 | :- use_module(library(sets), [subtract/3]). | |
15 | :- use_module(library(avl)). | |
16 | :- use_module(library(lists)). | |
17 | :- use_module(wdsrc(well_def_hyps), [empty_hyps/1]). | |
18 | :- use_module(wdsrc(well_def_analyser), [compute_wd/4]). | |
19 | :- use_module(probsrc(debug)). | |
20 | :- use_module(probsrc(translate), [print_bexpr/1]). | |
21 | :- use_module(probsrc(b_ast_cleanup), [clean_up_pred/3]). | |
22 | :- use_module(probsrc(module_information), [module_info/2]). | |
23 | :- use_module(probsrc(error_manager),[add_internal_error/2]). | |
24 | :- use_module(probsrc(b_interpreter_check),[norm_pred_check/2]). | |
25 | :- use_module(probsrc(bsyntaxtree), [add_texpr_infos/3, | |
26 | find_identifier_uses/3, | |
27 | safe_create_texpr/4, | |
28 | conjunct_predicates/2, | |
29 | conjunction_to_list/2, | |
30 | disjunct_predicates/2, | |
31 | disjunction_to_list/2]). | |
32 | ||
33 | :- module_info(group, dpllt). | |
34 | :- module_info(description, 'This module provides the conversion from B predicates to SAT formulae and vice-versa to be used for DPLL(T).'). | |
35 | ||
36 | :- dynamic sat_var_id/1. | |
37 | :- volatile sat_var_id/1. | |
38 | ||
39 | sat_var_id(0). | |
40 | ||
41 | %% get_amount_of_sat_variables(-AmountOfVars). | |
42 | get_amount_of_sat_variables(AmountOfVars) :- | |
43 | sat_var_id(AmountOfVars). | |
44 | ||
45 | reset_sat_var_id :- | |
46 | retractall(sat_var_id(_)), | |
47 | asserta(sat_var_id(0)). | |
48 | ||
49 | debug_format_pred(_, _, _) :- | |
50 | debug_mode(off), | |
51 | !. | |
52 | debug_format_pred(Msg, Vars, Pred) :- | |
53 | format(Msg, Vars), | |
54 | print_bexpr(Pred), nl, !. | |
55 | ||
56 | %% predicate_to_sat(+Type, +Pred, -NewEnv, -WDPOs, -BoolFormula, -NVarAcc). | |
57 | % Same as predicate_to_sat/7 but initializing an empty environment and accumulator for variables. | |
58 | predicate_to_sat(Type, Pred, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
59 | empty_predicate_env(Env), | |
60 | predicate_to_sat(Type, [], [], Env, Pred, NewEnv, WDPOs, BoolFormula, VarAcc). | |
61 | ||
62 | %% predicate_to_sat(+Type, +VarAcc, +Env, +Pred, -NewEnv, -BoolFormula, -NVarAcc). | |
63 | % Create a boolean formula from a B predicate, e.g., return 'A=TRUE & B=TRUE' for 'x:INT & x>1'. | |
64 | % Introduces fresh unique identifiers if ReuseType is not equal to 'only_reuse'. | |
65 | % If ReuseType is 'only_reuse': do not introduce new SAT variables but skip parts that need a new SAT variable | |
66 | % (some unsat core computations might deduce new constraints and we do not want to introduce new SAT variables during CDCL). | |
67 | % Env stores pairs of B ASTs (without info field) and its assigned SAT variables. | |
68 | % Add corresponding SAT variable names to AST's info fields (returned in NewPred). | |
69 | % Each SAT variable contains a term smt_formula/1 in its info field providing the corresponding SMT formula. | |
70 | % Note: SMT formula is split on the level of conjunction, disjunction, implication and equivalence. | |
71 | predicate_to_sat(ReuseType, WDAcc, Acc, Env, Pred, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
72 | Pred = b(Expr, Type, Info), | |
73 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, Acc, Env, NewEnv, WDPOs, BoolFormula, VarAcc). | |
74 | ||
75 | ||
76 | predicate_to_sat_e(negation(b(truth,pred,Info)), _, _, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- | |
77 | !, | |
78 | EnvOut = Env, | |
79 | VarAccOut = Acc, | |
80 | NWDAcc = WDAcc, | |
81 | Falsity = b(falsity,pred,Info). | |
82 | predicate_to_sat_e(negation(b(falsity,pred,Info)), _, _, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Truth, VarAccOut) :- | |
83 | !, | |
84 | EnvOut = Env, | |
85 | VarAccOut = Acc, | |
86 | NWDAcc = WDAcc, | |
87 | Truth = b(truth,pred,Info). | |
88 | predicate_to_sat_e(truth, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Truth, VarAccOut) :- | |
89 | !, | |
90 | EnvOut = Env, | |
91 | VarAccOut = Acc, | |
92 | NWDAcc = WDAcc, | |
93 | Truth = b(truth,pred,Info). | |
94 | predicate_to_sat_e(falsity, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- | |
95 | !, | |
96 | EnvOut = Env, | |
97 | VarAccOut = Acc, | |
98 | NWDAcc = WDAcc, | |
99 | Falsity = b(falsity,pred,Info). | |
100 | predicate_to_sat_e(negation(b(negation(Pred),pred,_)), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
101 | !, | |
102 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, Pred, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
103 | predicate_to_sat_e(negation(Pred), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
104 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, Pred, boolean_false, TNewEnv, TWDPOs, TBoolFormula, TNVarAcc), | |
105 | !, | |
106 | NewEnv = TNewEnv, | |
107 | WDPOs = TWDPOs, | |
108 | BoolFormula = TBoolFormula, | |
109 | NVarAcc = TNVarAcc. | |
110 | predicate_to_sat_e(negation(Pred), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
111 | Pred = b(disjunct(A,B),pred,_), | |
112 | !, | |
113 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(A),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
114 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
115 | % conjunct_predicate/ ensures that truth and falsity are simplified (1) | |
116 | conjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
117 | predicate_to_sat_e(negation(Pred), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
118 | Pred = b(conjunct(A,B),pred,_), | |
119 | !, | |
120 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(A),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
121 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
122 | % see above comment (1) for conjunct_predicates/2 | |
123 | disjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
124 | predicate_to_sat_e(negation(Pred), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
125 | Pred = b(implication(A,B),pred,_), | |
126 | !, | |
127 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, A, NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
128 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
129 | % see (1) | |
130 | conjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
131 | predicate_to_sat_e(negation(Pred), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
132 | Pred = b(equivalence(A,B),pred,_), | |
133 | !, | |
134 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(b(implication(A,B),pred,[])),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
135 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(b(implication(B,A),pred,[])),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
136 | % see (1) | |
137 | disjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
138 | predicate_to_sat_e(conjunct(A,B), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
139 | conjunction_to_list(b(conjunct(A,B),pred,[]), PList), | |
140 | !, | |
141 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, PList, NewEnv, WDPOs, SatList, NVarAcc), | |
142 | conjunct_predicates(SatList, BoolFormula). | |
143 | /*predicate_to_sat(_, VarAcc, Env, Pred, NewEnv, BoolFormula, NVarAcc) :- | |
144 | Pred = b(disjunct(_,_),_,_), | |
145 | fetch_predicate(Pred,Env,_,SatVar), | |
146 | % equality from symmetry breaking is a disjunction | |
147 | !, | |
148 | NewEnv = Env, | |
149 | safe_create_texpr(equal(SatVar,b(boolean_true,boolean,[])), pred, [], BoolFormula), | |
150 | NVarAcc = VarAcc.*/ | |
151 | predicate_to_sat_e(disjunct(A,B), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
152 | disjunction_to_list(b(disjunct(A,B),pred,[]), PList), | |
153 | !, | |
154 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, PList, NewEnv, WDPOs, SatList, NVarAcc), | |
155 | disjunct_predicates(SatList, BoolFormula). | |
156 | /*predicate_to_sat(ReuseType, VarAcc, Env, b(negation(Pred),pred,_), NewEnv, NewPred, BoolFormula, NVarAcc) :- | |
157 | predicate_to_sat(ReuseType, VarAcc, Env, Pred, NewEnv, TNewPred, BoolFormula, NVarAcc), | |
158 | ( TNewPred \== b(truth,pred,_) | |
159 | -> safe_create_texpr(negation(TNewPred),pred,[], NewPred) | |
160 | ; safe_create_texpr(truth,pred,[], NewPred) | |
161 | ).*/ | |
162 | predicate_to_sat_e(Expr, _, _, _, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, VarAccOut) :- | |
163 | ( Expr == value(pred_true) | |
164 | ; Expr == value(pred_false) | |
165 | ), | |
166 | !, | |
167 | WDPOs = WDAcc, | |
168 | VarAccOut = VarAcc, | |
169 | safe_create_texpr(Expr, pred, [], BoolFormula), | |
170 | NewEnv = Env. | |
171 | predicate_to_sat_e(implication(Lhs,Rhs), pred, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
172 | !, | |
173 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Lhs,Rhs], NewEnv, WDPOs, NSatArgs, NVarAcc), | |
174 | NSatArgs = [NSatLhs,NSatRhs], | |
175 | safe_create_texpr(implication(NSatLhs,NSatRhs), pred, [smt_formula(b(implication(Lhs,Rhs),pred,Info))], BoolFormula). | |
176 | predicate_to_sat_e(equivalence(Lhs,Rhs), pred, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
177 | !, | |
178 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Lhs,Rhs], NewEnv, WDPOs, NSatArgs, NVarAcc), | |
179 | NSatArgs = [NSatLhs,NSatRhs], | |
180 | safe_create_texpr(equivalence(NSatLhs,NSatRhs), pred, [smt_formula(b(equivalence(Lhs,Rhs),pred,Info))], BoolFormula). | |
181 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
182 | functor(Expr, _, Arity), | |
183 | ( Arity == 2 | |
184 | ; Arity == 3 | |
185 | ), | |
186 | !, | |
187 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_true, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
188 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
189 | % formula is a singleton pred which is not splitted such as a subset | |
190 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_true, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
191 | % TO DO: if going into quantifications, we have to watch out for local identifier scopes | |
192 | % (i.e., x<7 might not be the same x<7 within a quantification if x is a local id) | |
193 | % Note that we currently do not go into quantifications so this is not an issue. | |
194 | ||
195 | map_predicate_to_sat(_, WDAcc, VarAcc, Env, [], Env, WDAcc, [], VarAcc). | |
196 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Pred|T], NewEnv, WDPOs, [BoolFormula|NT], NVarAcc) :- | |
197 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, Pred, TempEnv, TWDAcc, BoolFormula, TVarAcc), | |
198 | map_predicate_to_sat(ReuseType, TWDAcc, TVarAcc, TempEnv, T, NewEnv, WDPOs, NT, NVarAcc). | |
199 | ||
200 | negate_pred(greater_equal(A,B), less(A,B)). | |
201 | negate_pred(greater(A,B), less_equal(A,B)). | |
202 | negate_pred(less_equal(A,B), less(B,A)). | |
203 | negate_pred(less(A,B), less_equal(B,A)). | |
204 | ||
205 | negate_bool_atom(boolean_true, boolean_false). | |
206 | negate_bool_atom(boolean_false, boolean_true). | |
207 | ||
208 | % Note: BoolFormula is 'a = TRUE' or 'a = FALSE' for (negated) literal a. | |
209 | /*reuse_or_introduce_bool_var(_, VarAcc, Env, Pred, boolean_true, NewEnv, BoolFormula, NVarAcc) :- | |
210 | % ensure that the same SAT variable is used for boolean equalities such as x=TRUE & x=FALSE | |
211 | % we would usually introduce two different SAT variables for both equalities but don't want to do so for | |
212 | % boolean equalities | |
213 | Pred = b(equal(Bool,BoolId),pred,_), | |
214 | BoolId = b(identifier(BoolIdName),boolean,_), | |
215 | (Bool = b(boolean_true,boolean,[]); Bool = b(boolean_false,boolean,[])), | |
216 | fetch_predicate(b(equal(BoolPred,b(identifier(BoolIdName),boolean,[])),pred,[]),Env,_,SatVar), | |
217 | ( (Bool = b(boolean_true,boolean,_), BoolPred = b(boolean_true,boolean,_)) | |
218 | -> BoolAtom = boolean_true | |
219 | ; (Bool = b(boolean_true,boolean,_), BoolPred = b(boolean_false,boolean,_)) | |
220 | -> BoolAtom = boolean_false | |
221 | ; (Bool = b(boolean_false,boolean,_), BoolPred = b(boolean_false,boolean,_)) | |
222 | -> BoolAtom = boolean_true | |
223 | ; BoolAtom = boolean_false | |
224 | ), | |
225 | !, | |
226 | safe_create_texpr(equal(SatVar,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
227 | NewEnv = Env, | |
228 | NVarAcc = VarAcc.*/ | |
229 | reuse_or_introduce_bool_var(_, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
230 | fetch_predicate(Pred, Env, _, SatVar), | |
231 | !, | |
232 | safe_create_texpr(equal(SatVar,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
233 | NewEnv = Env, | |
234 | NWDAcc = WDAcc, | |
235 | NVarAcc = VarAcc. | |
236 | reuse_or_introduce_bool_var(_, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
237 | Pred = b(Expr,Type,Info), | |
238 | negate_pred(Expr, NExpr), | |
239 | fetch_predicate(b(NExpr,Type,Info), Env, _, SatVar), | |
240 | !, | |
241 | negate_bool_atom(BoolAtom, NBoolAtom), | |
242 | safe_create_texpr(equal(SatVar,b(NBoolAtom,boolean,[])), pred, [], BoolFormula), | |
243 | NewEnv = Env, | |
244 | NWDAcc = WDAcc, | |
245 | NVarAcc = VarAcc. | |
246 | reuse_or_introduce_bool_var(Type, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
247 | Type \== only_reuse, | |
248 | !, | |
249 | next_sat_var_name(SatVarName), | |
250 | add_wd_po_to_pred(Pred, WDAcc, true, NWDAcc, WDPred, TopLevelWdPred), | |
251 | debug_format_pred("Introduce sat var ~w for pred~n", [SatVarName], WDPred), | |
252 | safe_create_texpr(identifier(SatVarName), boolean, [], TUniqueId), | |
253 | %find_identifier_uses(Pred, [], UsedIds), | |
254 | ( ground(TopLevelWdPred) | |
255 | -> add_texpr_infos(TUniqueId, [smt_formula(WDPred),contains_top_level_wd_condition(TopLevelWdPred,Pred)], UniqueId) | |
256 | ; add_texpr_infos(TUniqueId, [smt_formula(WDPred)], UniqueId) | |
257 | ), | |
258 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv), | |
259 | safe_create_texpr(equal(UniqueId,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
260 | NVarAcc = [UniqueId|VarAcc]. | |
261 | ||
262 | next_sat_var_name(SatVarName) :- | |
263 | retract(sat_var_id(Old)), | |
264 | New is Old + 1, | |
265 | asserta(sat_var_id(New)), | |
266 | number_codes(New, NC), | |
267 | atom_codes(Index, NC), | |
268 | atom_concat('sat', Index, SatVarName). | |
269 | ||
270 | quantified_binary_expr(exists). | |
271 | quantified_binary_expr(comprehension_set). | |
272 | quantified_binary_expr(event_b_comprehension_set). | |
273 | quantified_binary_expr(lambda). | |
274 | quantified_binary_expr(general_sum). | |
275 | quantified_binary_expr(general_product). | |
276 | quantified_binary_expr(quantified_union). | |
277 | quantified_binary_expr(quantified_intersection). | |
278 | ||
279 | is_typing_pred_without_wd(b(member(Id,B),pred,_)) :- | |
280 | B \= b(domain(_),_,_), | |
281 | B \= b(seq(_),_,_), % seq typing has a wd condition | |
282 | Id = b(identifier(_),_,_). | |
283 | is_typing_pred_without_wd(b(subset(Id,B),pred,_)) :- | |
284 | B \= b(domain(_),_,_), | |
285 | B \= b(seq(_),_,_), | |
286 | Id = b(identifier(_),_,_). | |
287 | is_typing_pred_without_wd(b(subset_strict(Id,B),pred,_)) :- | |
288 | B \= b(domain(_),_,_), | |
289 | B \= b(seq(_),_,_), | |
290 | Id = b(identifier(_),_,_). | |
291 | ||
292 | clean_up_pred_cut(Pred, Clean) :- | |
293 | clean_up_pred(Pred, _, TClean), !, | |
294 | Clean = TClean. | |
295 | ||
296 | get_top_level_wd_po_no_typing(Pred, WDPo) :- | |
297 | empty_hyps(Hyps), | |
298 | find_identifier_uses(Pred, [], TopLevelIds), | |
299 | compute_wd(Pred, Hyps, [discharge_po,skip_finite_po], TWDPo), % choicepoint | |
300 | find_identifier_uses(TWDPo, [], WDIds), | |
301 | subtract(WDIds, TopLevelIds, QIds), | |
302 | QIds == [], % is top-level | |
303 | TWDPo = b(_,_,TWDInfo), | |
304 | ( member(discharged(true, _), TWDInfo) | |
305 | -> debug_format_pred('Removed discharged predicate from WD POs: ', [], TWDPo), | |
306 | fail | |
307 | ; true | |
308 | ), | |
309 | % important to use b_ast_cleanup:clean_up_pred/3 for WD POs collected by compute_wd/4 since | |
310 | % typing constraints are optimized to 'typeset' nodes, which is undone by the cleanup. | |
311 | clean_up_pred_cut(TWDPo, WDPo), | |
312 | ( is_typing_pred_without_wd(WDPo) | |
313 | -> debug_format_pred('Removed typing predicate from WD POs: ', [], WDPo), | |
314 | fail | |
315 | ; true | |
316 | ). | |
317 | ||
318 | remove_duplicate_preds(Constraints, NoDups) :- | |
319 | remove_duplicate_preds(Constraints, [], [], NoDups). | |
320 | ||
321 | remove_duplicate_preds([], _, Acc, Acc). | |
322 | remove_duplicate_preds([Pred|T], NormAcc, Acc, NoDups) :- | |
323 | norm_pred_check(Pred, NPred), | |
324 | ( memberchk(NPred, NormAcc) | |
325 | -> NAcc = Acc, | |
326 | NNormAcc = NormAcc | |
327 | ; NAcc = [Pred|Acc], | |
328 | NNormAcc = [NPred|NormAcc] | |
329 | ), | |
330 | remove_duplicate_preds(T, NNormAcc, NAcc, NoDups). | |
331 | ||
332 | get_all_top_level_wd_pos(Pred, WDPos) :- | |
333 | findall(WDPo, get_top_level_wd_po_no_typing(Pred, WDPo), TWDPos), !, | |
334 | remove_duplicate_preds(TWDPos, WDPos). | |
335 | ||
336 | % Let A be a predicate with a set of WD conditions C. We create an implication A => c for each c in C. | |
337 | % We don't use a single implication A => (c1 & c2 & .. & cn) since we have to create a CNF anyway. | |
338 | create_wd_impls([], _, Acc, Acc). | |
339 | create_wd_impls([WDPo|T], Pred, Acc, WDImpls) :- | |
340 | % don't use added info is_wd_po_for_dpllt here | |
341 | safe_create_texpr(disjunct(b(negation(Pred),pred,[]),WDPo), pred, [], WDImpl), | |
342 | create_wd_impls(T, Pred, [WDImpl|Acc], WDImpls). | |
343 | ||
344 | add_wd_impls_to_acc([], WDAcc, WDAcc). | |
345 | add_wd_impls_to_acc([WDImpl|T], WDAcc, NWDAcc) :- | |
346 | member(WDImpl, WDAcc), | |
347 | !, | |
348 | add_wd_impls_to_acc(T, WDAcc, NWDAcc). | |
349 | add_wd_impls_to_acc([WDImpl|T], WDAcc, NWDAcc) :- | |
350 | add_wd_impls_to_acc(T, [WDImpl|WDAcc], NWDAcc). | |
351 | ||
352 | %% add_wd_po_to_pred(+Pred, +WDAcc, +IsTopLevel, -NWDAcc, -WDPred, -WDPoConj). | |
353 | % Add all necessary WD POs to make +Pred well-defined for SMT solving. | |
354 | % That means, each predicate that is abstracted to a SAT variable is well-defined. | |
355 | % For quantified formulas, WD POs are nested inside a quantifier. | |
356 | add_wd_po_to_pred(Pred, WDAcc, IsTopLevel, NWDAcc, WDPred, WDPoConj) :- | |
357 | Pred = b(Expr, Type, Info), | |
358 | add_wd_po_to_pred_e(Expr, Type, Info, WDAcc, IsTopLevel, NWDAcc, WDPred, WDPoConj). | |
359 | ||
360 | % Stores top-level WD POs, not WD POs of quantified formulas since they will be abstracted as a single SAT variable on the top-level. | |
361 | % For instance, we introduce one SAT variable for a universal quantifier. We thus don't want to add the WD POs that are necessary in the quantifier | |
362 | % to our top-level WD POs. | |
363 | add_wd_po_to_pred_e(Expr, pred, Info, WDAcc, IsTopLevel, NWDAcc, WDPred, WDPoConj) :- | |
364 | functor(Expr, Functor, 2), | |
365 | (Functor == conjunct; Functor == disjunct; Functor == implication; Functor == equivalence), | |
366 | !, | |
367 | arg(1, Expr, A), | |
368 | arg(2, Expr, B), | |
369 | add_wd_po_to_pred(A, WDAcc, IsTopLevel, NWDAcc1, WDA, WDAConj), | |
370 | add_wd_po_to_pred(B, NWDAcc1, IsTopLevel, NWDAcc, WDB, WDBConj), | |
371 | functor(NExpr, Functor, 2), | |
372 | arg(1, NExpr, WDA), | |
373 | arg(2, NExpr, WDB), | |
374 | conjunct_predicates([WDAConj,WDBConj], WDPoConj), | |
375 | safe_create_texpr(NExpr, pred, Info, WDPred). | |
376 | add_wd_po_to_pred_e(if_then_else(Cond,Lhs,Rhs), pred, Info, WDAcc, IsTopLevel, NWDAcc, WDPred, WDPoConj) :- | |
377 | !, | |
378 | add_wd_po_to_pred(Cond, WDAcc, IsTopLevel, NWDAcc1, WDCond, WDPoConj1), | |
379 | add_wd_po_to_pred(Lhs, NWDAcc1, IsTopLevel, NWDAcc2, WDLhs, WDPoConj2), | |
380 | add_wd_po_to_pred(Rhs, NWDAcc2, IsTopLevel, NWDAcc, WDRhs, WDPoConj3), | |
381 | safe_create_texpr(if_then_else(WDCond,WDLhs,WDRhs), pred, Info, WDPred), | |
382 | conjunct_predicates([WDPoConj1,WDPoConj2,WDPoConj3], WDPoConj). | |
383 | add_wd_po_to_pred_e(forall(Ids,Lhs,Rhs), pred, Info, WDAcc, _, NWDAcc, WDPred, _) :- | |
384 | !, | |
385 | add_wd_po_to_pred(Rhs, WDAcc, false, NWDAcc, WDRhs, _), | |
386 | safe_create_texpr(forall(Ids,Lhs,WDRhs), pred, Info, WDPred). | |
387 | add_wd_po_to_pred_e(Expr, pred, Info, WDAcc, _, NWDAcc, WDPred, _) :- | |
388 | Expr =.. [Functor,Ids,Eqs,Body], | |
389 | (Functor == let; Functor == let_predicate), | |
390 | !, | |
391 | add_wd_po_to_pred(Body, WDAcc, false, NWDAcc, WDBody, _), | |
392 | NExpr =.. [Functor,Ids,Eqs,WDBody], | |
393 | safe_create_texpr(NExpr, pred, Info, WDPred). | |
394 | add_wd_po_to_pred_e(Expr, Type, Info, WDAcc, _, NWDAcc, WDPred, _) :- | |
395 | Expr =.. [Functor,Ids,Body], | |
396 | quantified_binary_expr(Functor), | |
397 | !, | |
398 | add_wd_po_to_pred(Body, WDAcc, false, NWDAcc, WDBody, _), | |
399 | NExpr =.. [Functor,Ids,WDBody], | |
400 | safe_create_texpr(NExpr, Type, Info, WDPred). | |
401 | add_wd_po_to_pred_e(Expr, Type, Info, WDAcc, IsTopLevel, NWDAcc, WDPred, WDPoConj) :- | |
402 | % e.g., for a = b - {some set comprehension with WD}, we want to add WD POs to the set comprehension but not the equality | |
403 | functor(Expr, Functor, 2), | |
404 | Functor \== partition, | |
405 | Expr =.. [Functor|Args], | |
406 | map_add_wd_po_to_pred(Args, WDAcc, false, NWDAcc1, WDArgs, _), | |
407 | NExpr =.. [Functor|WDArgs], | |
408 | NPred = b(NExpr,Type,Info), | |
409 | !, | |
410 | ( Type == pred, | |
411 | get_all_top_level_wd_pos(NPred, WDPos), | |
412 | WDPos \== [], | |
413 | create_wd_impls(WDPos, NPred, [], WDImpls), | |
414 | conjunct_predicates(WDPos, WDPoConj) % don't use added info is_wd_po_for_dpllt here | |
415 | -> debug_format_pred("--------------------------Add WD PO for pred~n", [], NPred), | |
416 | ( IsTopLevel == true | |
417 | -> add_wd_impls_to_acc(WDImpls, NWDAcc1, NWDAcc) | |
418 | ; NWDAcc = NWDAcc1 | |
419 | ), | |
420 | maplist(map_add_texpr_infos([is_wd_po_for_dpllt]), WDPos, NWDPos), | |
421 | conjunct_predicates(NWDPos, WDPo), | |
422 | conjunct_predicates([WDPo,NPred], WDPred) | |
423 | ; WDPred = NPred, | |
424 | NWDAcc = NWDAcc1 | |
425 | ). | |
426 | add_wd_po_to_pred_e(Expr, Type, Info, WDAcc, _, WDAcc, b(Expr,Type,Info), _). | |
427 | ||
428 | map_add_wd_po_to_pred([Arg|T], WDAcc, IsTopLevel, NWDAcc, [WDArg|TWDArgs], WDConj) :- | |
429 | add_wd_po_to_pred(Arg, WDAcc, IsTopLevel, NWDAcc1, WDArg, WDConjArg), | |
430 | map_add_wd_po_to_pred_acc(T, NWDAcc1, IsTopLevel, NWDAcc, WDConjArg, TWDArgs, WDConj). | |
431 | ||
432 | map_add_wd_po_to_pred_acc([], WDAcc, _, WDAcc, WDConjAcc, [], WDConjAcc). | |
433 | map_add_wd_po_to_pred_acc([Arg|T], WDAcc, IsTopLevel, NWDAcc, WDConjAcc, [WDArg|TWDArgs], WDConj) :- | |
434 | add_wd_po_to_pred(Arg, WDAcc, IsTopLevel, NWDAcc1, WDArg, WDConjArg), | |
435 | ( ground(WDConjArg) | |
436 | -> safe_create_texpr(conjunct(WDConjArg,WDConjAcc),pred,[],NWDConjAcc) | |
437 | ; NWDConjAcc = WDConjAcc | |
438 | ), | |
439 | map_add_wd_po_to_pred_acc(T, NWDAcc1, IsTopLevel, NWDAcc, NWDConjAcc, TWDArgs, WDConj). | |
440 | % ---------------- | |
441 | ||
442 | ||
443 | quantified_expr(forall(Ids,Lhs,Rhs), forall, Ids, [Lhs,Rhs]). | |
444 | quantified_expr(exists(Ids,Body), exists, Ids, [Body]). | |
445 | quantified_expr(comprehension_set(Ids,Body), comprehension_set, Ids, [Body]). | |
446 | quantified_expr(event_b_comprehension_set(Ids,Body), event_b_comprehension_set, Ids, [Body]). | |
447 | quantified_expr(lambda(Ids,Body), lambda, Ids, [Body]). | |
448 | quantified_expr(general_sum(Ids,Body), general_sum, Ids, [Body]). | |
449 | quantified_expr(general_product(Ids,Body), general_product, Ids, [Body]). | |
450 | quantified_expr(quantified_union(Ids,Body), quantified_union, Ids, [Body]). | |
451 | quantified_expr(quantified_intersection(Ids,Body), quantified_intersection, Ids, [Body]). | |
452 | ||
453 | %% remove_wd_pos_introduced_for_dpllt_keep_toplevel(+Conj, -NConj). | |
454 | % We possibly add WD POs which have to be removed prior to predicate_to_sat/9 in order to abstract constraints to the same SAT variable. | |
455 | remove_wd_pos_introduced_for_dpllt_keep_toplevel(Conj, NConj) :- | |
456 | remove_wd_pos_introduced_for_dpllt(false, Conj, NConj). | |
457 | ||
458 | %% remove_wd_pos_introduced_for_dpllt(+Remove, +Conj, -NConj). | |
459 | % Remove WD POs introduced for dpllt if +Remove is true. | |
460 | remove_wd_pos_introduced_for_dpllt(Remove, Conj, NConj) :- | |
461 | conjunction_to_list(Conj, List), | |
462 | remove_wd_pos_introduced_for_dpllt_l(Remove, List, NList), | |
463 | conjunct_predicates(NList, NConj). | |
464 | ||
465 | remove_wd_pos_introduced_for_dpllt_l(_, [], []). | |
466 | remove_wd_pos_introduced_for_dpllt_l(Remove, [b(negation(Pred),pred,NInfo)|T], [Out|NT]) :- | |
467 | !, | |
468 | remove_wd_pos_introduced_for_dpllt(true, Pred, NPred), | |
469 | Out = b(negation(NPred),pred,NInfo), | |
470 | remove_wd_pos_introduced_for_dpllt_l(Remove, T, NT). | |
471 | remove_wd_pos_introduced_for_dpllt_l(Remove, [Pred|T], [Out|NT]) :- | |
472 | Pred = b(Expr,Type,Info), | |
473 | quantified_expr(Expr, Functor, Ids, Subs), | |
474 | !, | |
475 | maplist(remove_wd_pos_introduced_for_dpllt(true), Subs, NSubs), | |
476 | NExpr =.. [Functor,Ids|NSubs], | |
477 | Out = b(NExpr,Type,Info), | |
478 | remove_wd_pos_introduced_for_dpllt_l(Remove, T, NT). | |
479 | remove_wd_pos_introduced_for_dpllt_l(Remove, [Pred|T], Out) :- | |
480 | Pred = b(_,_,Info), | |
481 | memberchk(is_wd_po_for_dpllt, Info), | |
482 | !, | |
483 | ( Remove == true | |
484 | -> Out = NT, | |
485 | debug_format_pred("-----------------------removed wd po from unsat core: ", [], Pred) | |
486 | ; Out = [Pred|NT] | |
487 | ), | |
488 | remove_wd_pos_introduced_for_dpllt_l(Remove, T, NT). | |
489 | remove_wd_pos_introduced_for_dpllt_l(Remove, [Pred|T], [Out|NT]) :- | |
490 | Pred = b(Expr,Type,Info), | |
491 | functor(Expr, Functor, 2), | |
492 | !, | |
493 | arg(1, Expr, Arg1), | |
494 | arg(2, Expr, Arg2), | |
495 | remove_wd_pos_introduced_for_dpllt(Remove, Arg1, NArg1), | |
496 | remove_wd_pos_introduced_for_dpllt(Remove, Arg2, NArg2), | |
497 | functor(NExpr, Functor, 2), | |
498 | arg(1, NExpr, NArg1), | |
499 | arg(2, NExpr, NArg2), | |
500 | Out = b(NExpr,Type,Info), | |
501 | remove_wd_pos_introduced_for_dpllt_l(Remove, T, NT). | |
502 | remove_wd_pos_introduced_for_dpllt_l(Remove, [Pred|T], [Pred|NT]) :- | |
503 | remove_wd_pos_introduced_for_dpllt_l(Remove, T, NT). | |
504 | ||
505 | map_add_texpr_infos(ToBeAdded, Ast, NAst) :- | |
506 | add_texpr_infos(Ast, ToBeAdded, NAst). | |
507 | ||
508 | % managing link from predicates to SAT variables | |
509 | ||
510 | empty_predicate_env(E) :- empty_avl(E). | |
511 | ||
512 | % TO DO: maybe we should also store SatVarName? | |
513 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv) :- (var(Env) ; \+ is_avl(Env)),!, | |
514 | add_internal_error('Illegal env:',register_predicate(Pred,WDPred,Env,UniqueId,NewEnv)), | |
515 | NewEnv=Env. | |
516 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv) :- %print('storing: '), writeq(WDPred),nl, | |
517 | norm_pred_check(Pred,NPred), | |
518 | avl_store(NPred,Env,pred2satvar(WDPred,UniqueId),NewEnv). | |
519 | ||
520 | fetch_predicate(Pred,Env,StoredPred,SatVar) :- (var(Env) ; \+ is_avl(Env)),!, | |
521 | add_internal_error('Illegal env:',fetch_predicate(Pred,Env,StoredPred,SatVar)), fail. | |
522 | fetch_predicate(Pred,Env,StoredPred,SatVar) :- | |
523 | norm_pred_check(Pred,NPred), | |
524 | avl_fetch(NPred,Env,pred2satvar(StoredPred,SatVar)), !. | |
525 | %fetch_predicate(Pred,_,_,_SatVar) :- print('not found: '), print_bexpr(Pred),nl,fail. | |
526 | ||
527 | % --------------- | |
528 | ||
529 | ||
530 | %% sat_to_predicate_from_solution(+SatBindings, +SatVars, -Conjunction). | |
531 | % Create conjunction of SAT bindings using their corresponding SMT formulae | |
532 | % which are stored in the bool variables' information fields. | |
533 | sat_to_predicate_from_solution([], _, b(truth,pred,[])). | |
534 | sat_to_predicate_from_solution([Binding|T], SatVars, Conjunction) :- | |
535 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars), | |
536 | !, | |
537 | sat_to_predicate_from_solution(T, SMT, RestSatVars, Conjunction). | |
538 | sat_to_predicate_from_solution([_|T], SatVars, Conjunction) :- | |
539 | % skip: binding might be a variable if instantiation is not required | |
540 | sat_to_predicate_from_solution(T, SatVars, Conjunction). | |
541 | ||
542 | sat_to_predicate_from_solution([], SmtAcc, _, SmtAcc). | |
543 | sat_to_predicate_from_solution([Binding|T], SmtAcc, SatVars, Conjunction) :- | |
544 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars), | |
545 | !, | |
546 | safe_create_texpr(conjunct(SMT,SmtAcc), pred, [], NewSmtAcc), | |
547 | sat_to_predicate_from_solution(T, NewSmtAcc, RestSatVars, Conjunction). | |
548 | sat_to_predicate_from_solution([_|T], SmtAcc, SatVars, Conjunction) :- | |
549 | sat_to_predicate_from_solution(T, SmtAcc, SatVars, Conjunction). | |
550 | ||
551 | get_var_and_value_from_binding(bind(SatVarName,Value), SatVarName, Value). | |
552 | get_var_and_value_from_binding(binding(SatVarName,Value,_), SatVarName, Value). | |
553 | ||
554 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars) :- | |
555 | ground(Binding), | |
556 | get_var_and_value_from_binding(Binding, SatVarName, Value), | |
557 | !, | |
558 | select(b(identifier(SatVarName),_,Info), SatVars, RestSatVars), | |
559 | member(smt_formula(TSMT), Info),!, | |
560 | ( Value == pred_true | |
561 | -> SMT = TSMT | |
562 | ; Value == pred_false, | |
563 | TSMT = b(_,_,TSMTInfo), | |
564 | safe_create_texpr(negation(TSMT), pred, TSMTInfo, SMT) | |
565 | ). | |
566 | /*get_smt_formula_from_binding(Binding, _, _, _) :- | |
567 | add_error(get_smt_formula_from_binding, 'SAT binding not ground:', [Binding]), | |
568 | fail.*/ |