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(cdclt_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_cdclt_keep_toplevel/2, | |
9 | get_all_top_level_wd_pos/2, | |
10 | add_wd_pos_to_pred/8, | |
11 | get_amount_of_sat_variables/1, | |
12 | next_sat_var_name/1, | |
13 | reset_sat_var_id/0]). | |
14 | ||
15 | :- use_module(library(sets), [subtract/3]). | |
16 | :- use_module(library(avl)). | |
17 | :- use_module(library(lists)). | |
18 | :- use_module(wdsrc(well_def_hyps), [empty_hyps/1,push_hyps/4]). | |
19 | :- use_module(wdsrc(well_def_analyser), [compute_wd/4]). | |
20 | :- use_module(probsrc(debug)). | |
21 | :- use_module(probsrc(translate), [print_bexpr/1]). | |
22 | :- use_module(probsrc(preferences), [get_preference/2]). | |
23 | :- use_module(probsrc(b_ast_cleanup), [clean_up_pred/3]). | |
24 | :- use_module(probsrc(module_information), [module_info/2]). | |
25 | :- use_module(probsrc(error_manager),[add_internal_error/2,add_error_fail/3]). | |
26 | :- use_module(probsrc(b_interpreter_check),[norm_pred_check/2]). | |
27 | :- use_module(probsrc(bsyntaxtree), [add_texpr_infos/3, | |
28 | find_identifier_uses/3, | |
29 | safe_create_texpr/4, | |
30 | conjunct_predicates/2, | |
31 | conjunction_to_list/2, | |
32 | disjunct_predicates/2, | |
33 | disjunction_to_list/2]). | |
34 | :- use_module(cdclt_solver('cdclt_preprocessing')). | |
35 | :- use_module(cdclt_solver('cdclt_settings')). | |
36 | ||
37 | :- module_info(group, cdclt). | |
38 | :- module_info(description, 'This module provides the conversion from B predicates to SAT formulae and vice-versa to be used for CDCL(T).'). | |
39 | ||
40 | :- dynamic sat_var_id/1. | |
41 | ||
42 | sat_var_id(0). | |
43 | ||
44 | %% get_amount_of_sat_variables(-AmountOfVars). | |
45 | get_amount_of_sat_variables(AmountOfVars) :- | |
46 | sat_var_id(AmountOfVars). | |
47 | ||
48 | %% reset_sat_var_id. | |
49 | reset_sat_var_id :- | |
50 | retractall(sat_var_id(_)), | |
51 | asserta(sat_var_id(0)). | |
52 | ||
53 | debug_format_pred(_, _, _) :- | |
54 | print_logs(false), | |
55 | !. | |
56 | debug_format_pred(Msg, Vars, Pred) :- | |
57 | format(Msg, Vars), | |
58 | print_bexpr(Pred), nl, !. | |
59 | ||
60 | %% predicate_to_sat(+Type, +Pred, -NewEnv, -WDPOs, -BoolFormula, -NVarAcc). | |
61 | % Same as predicate_to_sat/9 but initializing an empty environment and accumulator for variables. | |
62 | predicate_to_sat(Type, Pred, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
63 | empty_predicate_env(Env), | |
64 | predicate_to_sat(Type, [], [], Env, Pred, NewEnv, WDPOs, BoolFormula, VarAcc). | |
65 | ||
66 | %% predicate_to_sat(+ReuseType, +WDAcc, +Type, +VarAcc, +Env, +Pred, -NewEnv, -BoolFormula, -NVarAcc). | |
67 | % Create a boolean formula from a B predicate, e.g., return 'A=TRUE & B=TRUE' for 'x:INT & x>1'. | |
68 | % Introduces fresh unique identifiers if ReuseType is not equal to 'only_reuse'. | |
69 | % If ReuseType is 'only_reuse': do not introduce new SAT variables but skip parts that need a new SAT variable | |
70 | % (some unsat core computations might deduce new constraints and we do not want to introduce new SAT variables during CDCL). | |
71 | % Env stores pairs of B ASTs (without info field) and its assigned SAT variables. | |
72 | % Add corresponding SAT variable names to AST's info fields (returned in NewPred). | |
73 | % Each SAT variable contains a term smt_formula/1 in its info field providing the corresponding SMT formula. | |
74 | % Note: SMT formula is split on the level of conjunction, disjunction, implication and equivalence. | |
75 | predicate_to_sat(ReuseType, WDAcc, Acc, Env, Pred, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
76 | Pred = b(Expr, Type, Info), | |
77 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, Acc, Env, NewEnv, WDPOs, BoolFormula, VarAcc). | |
78 | ||
79 | %predicate_to_sat_e(E, _, _, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- functor(E,F,N),print(F/N),nl,nl,fail. | |
80 | predicate_to_sat_e(negation(Expr), _, _, ReuseType, WDAcc, Acc, Env, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
81 | predicate_to_sat_neg(Expr, ReuseType, WDAcc, Acc, Env, NewEnv, WDPOs, BoolFormula, VarAcc). | |
82 | predicate_to_sat_e(truth, 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(falsity, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- | |
89 | !, | |
90 | EnvOut = Env, | |
91 | VarAccOut = Acc, | |
92 | NWDAcc = WDAcc, | |
93 | Falsity = b(falsity,pred,Info). | |
94 | ||
95 | predicate_to_sat_e(conjunct(A,B), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
96 | conjunction_to_list(b(conjunct(A,B),pred,[]), PList), | |
97 | !, | |
98 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, PList, NewEnv, WDPOs, SatList, NVarAcc), | |
99 | conjunct_predicates(SatList, BoolFormula). | |
100 | /*predicate_to_sat(_, VarAcc, Env, Pred, NewEnv, BoolFormula, NVarAcc) :- | |
101 | Pred = b(disjunct(_,_),_,_), | |
102 | fetch_predicate(Pred,Env,_,SatVar), | |
103 | % equality from symmetry breaking is a disjunction | |
104 | !, | |
105 | NewEnv = Env, | |
106 | safe_create_texpr(equal(SatVar,b(boolean_true,boolean,[])), pred, [], BoolFormula), | |
107 | NVarAcc = VarAcc.*/ | |
108 | predicate_to_sat_e(disjunct(A,B), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
109 | disjunction_to_list(b(disjunct(A,B),pred,[]), PList), | |
110 | !, | |
111 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, PList, NewEnv, WDPOs, SatList, NVarAcc), | |
112 | disjunct_predicates(SatList, BoolFormula). | |
113 | /*predicate_to_sat(ReuseType, VarAcc, Env, b(negation(Pred),pred,_), NewEnv, NewPred, BoolFormula, NVarAcc) :- | |
114 | predicate_to_sat(ReuseType, VarAcc, Env, Pred, NewEnv, TNewPred, BoolFormula, NVarAcc), | |
115 | ( TNewPred \== b(truth,pred,_) | |
116 | -> safe_create_texpr(negation(TNewPred),pred,[], NewPred) | |
117 | ; safe_create_texpr(truth,pred,[], NewPred) | |
118 | ).*/ | |
119 | predicate_to_sat_e(Expr, _, _, _, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, VarAccOut) :- | |
120 | ( Expr == value(pred_true) | |
121 | ; Expr == value(pred_false) | |
122 | ), | |
123 | !, | |
124 | WDPOs = WDAcc, | |
125 | VarAccOut = VarAcc, | |
126 | safe_create_texpr(Expr, pred, [], BoolFormula), | |
127 | NewEnv = Env. | |
128 | predicate_to_sat_e(implication(Lhs,Rhs), pred, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
129 | !, | |
130 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Lhs,Rhs], NewEnv, WDPOs, NSatArgs, NVarAcc), | |
131 | NSatArgs = [NSatLhs,NSatRhs], | |
132 | safe_create_texpr(implication(NSatLhs,NSatRhs), pred, [smt_formula(b(implication(Lhs,Rhs),pred,Info))], BoolFormula). | |
133 | predicate_to_sat_e(equivalence(Lhs,Rhs), pred, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
134 | !, | |
135 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Lhs,Rhs], NewEnv, WDPOs, NSatArgs, NVarAcc), | |
136 | NSatArgs = [NSatLhs,NSatRhs], | |
137 | safe_create_texpr(equivalence(NSatLhs,NSatRhs), pred, [smt_formula(b(equivalence(Lhs,Rhs),pred,Info))], BoolFormula). | |
138 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
139 | functor(Expr, _, Arity), | |
140 | ( Arity == 2 | |
141 | ; Arity == 3 | |
142 | ), | |
143 | !, | |
144 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_true, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
145 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
146 | % formula is a singleton pred which is not splitted such as a subset | |
147 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_true, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
148 | % TO DO: if going into quantifications, we have to watch out for local identifier scopes | |
149 | % (i.e., x<7 might not be the same x<7 within a quantification if x is a local id) | |
150 | % Note that we currently do not go into quantifications so this is not an issue. | |
151 | ||
152 | predicate_to_sat_neg(Ast, ReuseType, WDAcc, Acc, Env, EnvOut, NWDAcc, NAst, VarAccOut) :- | |
153 | Ast = b(Expr,Type,Info), | |
154 | predicate_to_sat_neg_e(Expr, Type, Info, ReuseType, WDAcc, Acc, Env, EnvOut, NWDAcc, NAst, VarAccOut). | |
155 | ||
156 | predicate_to_sat_neg_e(truth, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- | |
157 | !, | |
158 | EnvOut = Env, VarAccOut = Acc, | |
159 | NWDAcc = WDAcc, | |
160 | Falsity = b(falsity,pred,Info). | |
161 | predicate_to_sat_neg_e(falsity, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Truth, VarAccOut) :- | |
162 | !, | |
163 | EnvOut = Env, VarAccOut = Acc, | |
164 | NWDAcc = WDAcc, | |
165 | Truth = b(truth,pred,Info). | |
166 | predicate_to_sat_neg_e(negation(Pred), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
167 | !, | |
168 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, Pred, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
169 | predicate_to_sat_neg_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
170 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_false, TNewEnv, TWDPOs, TBoolFormula, TNVarAcc), | |
171 | !, | |
172 | NewEnv = TNewEnv, | |
173 | WDPOs = TWDPOs, | |
174 | BoolFormula = TBoolFormula, | |
175 | NVarAcc = TNVarAcc. | |
176 | predicate_to_sat_neg_e(disjunct(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
177 | !, | |
178 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(A),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
179 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
180 | % conjunct_predicate/ ensures that truth and falsity are simplified (1) | |
181 | conjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
182 | predicate_to_sat_neg_e(conjunct(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
183 | !, | |
184 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(A),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
185 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
186 | % see above comment (1) for conjunct_predicates/2 | |
187 | disjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
188 | predicate_to_sat_neg_e(implication(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
189 | !, | |
190 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, A, NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
191 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
192 | % see (1) | |
193 | conjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
194 | predicate_to_sat_neg_e(equivalence(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
195 | !, | |
196 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(b(implication(A,B),pred,[])),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
197 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(b(implication(B,A),pred,[])),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
198 | % see (1) | |
199 | disjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
200 | ||
201 | map_predicate_to_sat(_, WDAcc, VarAcc, Env, [], Env, WDAcc, BoolFormulas, VarAcc) :- !, BoolFormulas=[]. | |
202 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Pred|T], NewEnv, WDPOs, [BoolFormula|NT], NVarAcc) :- | |
203 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, Pred, TempEnv, TWDAcc, BoolFormula, TVarAcc), | |
204 | map_predicate_to_sat(ReuseType, TWDAcc, TVarAcc, TempEnv, T, NewEnv, WDPOs, NT, NVarAcc). | |
205 | ||
206 | negate_pred(greater_equal(A,B), less(A,B)). | |
207 | negate_pred(greater(A,B), less_equal(A,B)). | |
208 | negate_pred(less_equal(A,B), less(B,A)). | |
209 | negate_pred(less(A,B), less_equal(B,A)). | |
210 | ||
211 | negate_bool_atom(boolean_true, boolean_false). | |
212 | negate_bool_atom(boolean_false, boolean_true). | |
213 | ||
214 | % Note: BoolFormula is 'a = TRUE' or 'a = FALSE' for (negated) literal a. | |
215 | /*reuse_or_introduce_bool_var(_, VarAcc, Env, Pred, boolean_true, NewEnv, BoolFormula, NVarAcc) :- | |
216 | % ensure that the same SAT variable is used for boolean equalities such as x=TRUE & x=FALSE | |
217 | % we would usually introduce two different SAT variables for both equalities but don't want to do so for | |
218 | % boolean equalities | |
219 | Pred = b(equal(Bool,BoolId),pred,_), | |
220 | BoolId = b(identifier(BoolIdName),boolean,_), | |
221 | (Bool = b(boolean_true,boolean,[]); Bool = b(boolean_false,boolean,[])), | |
222 | fetch_predicate(b(equal(BoolPred,b(identifier(BoolIdName),boolean,[])),pred,[]),Env,_,SatVar), | |
223 | ( (Bool = b(boolean_true,boolean,_), BoolPred = b(boolean_true,boolean,_)) | |
224 | -> BoolAtom = boolean_true | |
225 | ; (Bool = b(boolean_true,boolean,_), BoolPred = b(boolean_false,boolean,_)) | |
226 | -> BoolAtom = boolean_false | |
227 | ; (Bool = b(boolean_false,boolean,_), BoolPred = b(boolean_false,boolean,_)) | |
228 | -> BoolAtom = boolean_true | |
229 | ; BoolAtom = boolean_false | |
230 | ), | |
231 | !, | |
232 | safe_create_texpr(equal(SatVar,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
233 | NewEnv = Env, | |
234 | NVarAcc = VarAcc.*/ | |
235 | reuse_or_introduce_bool_var(_, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
236 | fetch_predicate(Pred, Env, _, SatVar), | |
237 | !, | |
238 | safe_create_texpr(equal(SatVar,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
239 | NewEnv = Env, | |
240 | NWDAcc = WDAcc, | |
241 | NVarAcc = VarAcc. | |
242 | reuse_or_introduce_bool_var(_, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
243 | Pred = b(Expr,Type,Info), | |
244 | negate_pred(Expr, NExpr), | |
245 | fetch_predicate(b(NExpr,Type,Info), Env, _, SatVar), | |
246 | !, | |
247 | negate_bool_atom(BoolAtom, NBoolAtom), | |
248 | safe_create_texpr(equal(SatVar,b(NBoolAtom,boolean,[])), pred, [], BoolFormula), | |
249 | NewEnv = Env, | |
250 | NWDAcc = WDAcc, | |
251 | NVarAcc = VarAcc. | |
252 | reuse_or_introduce_bool_var(Type, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
253 | Type \== only_reuse, | |
254 | !, | |
255 | next_sat_var_name(SatVarName), | |
256 | add_wd_pos_to_pred(Pred, [], WDAcc, true, true, NWDAcc, WDPred, TopLevelWdPred), | |
257 | debug_format_pred("Introduce sat var ~w for pred~n", [SatVarName], WDPred), | |
258 | safe_create_texpr(identifier(SatVarName), boolean, [], TUniqueId), | |
259 | %find_identifier_uses(Pred, [], UsedIds), | |
260 | ( ground(TopLevelWdPred) | |
261 | -> add_texpr_infos(TUniqueId, [smt_formula(WDPred),contains_top_level_wd_condition(TopLevelWdPred,Pred)], UniqueId) | |
262 | ; add_texpr_infos(TUniqueId, [smt_formula(WDPred)], UniqueId) | |
263 | ), | |
264 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv), | |
265 | safe_create_texpr(equal(UniqueId,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
266 | NVarAcc = [UniqueId|VarAcc]. | |
267 | reuse_or_introduce_bool_var(Type, _, _, _, Pred, _, _, _, _, _) :- | |
268 | Type == only_reuse, | |
269 | add_error_fail(reuse_or_introduce_bool_var, 'Missing SAT variable for SMT constraint. b_interpreter_check:norm_pred_check/2 might be inconsistent.', [Pred]). | |
270 | ||
271 | next_sat_var_name(SatVarName) :- | |
272 | retract(sat_var_id(Old)), | |
273 | New is Old + 1, | |
274 | asserta(sat_var_id(New)), | |
275 | number_codes(New, NC), | |
276 | atom_codes(Index, NC), | |
277 | atom_concat('sat', Index, SatVarName). | |
278 | ||
279 | quantified_binary_expr(exists). | |
280 | quantified_binary_expr(comprehension_set). | |
281 | ||
282 | quantified_ternary_expr_nonpred_body(lambda). | |
283 | quantified_ternary_expr_nonpred_body(general_sum). | |
284 | quantified_ternary_expr_nonpred_body(general_product). | |
285 | quantified_ternary_expr_nonpred_body(quantified_union). | |
286 | quantified_ternary_expr_nonpred_body(quantified_intersection). | |
287 | ||
288 | is_typing_pred_without_wd(b(member(Id,B),pred,_)) :- | |
289 | B \= b(domain(_),_,_), | |
290 | B \= b(empty_set,_,_), | |
291 | B \= b(value([]),_,_), | |
292 | B \= b(seq(_),_,_), % seq typing has a wd condition | |
293 | B \= b(seq1(_),_,_), | |
294 | Id = b(identifier(_),_,_). | |
295 | is_typing_pred_without_wd(b(subset(Id,B),pred,_)) :- | |
296 | B \= b(domain(_),_,_), | |
297 | B \= b(empty_set,_,_), | |
298 | B \= b(value([]),_,_), | |
299 | B \= b(seq(_),_,_), | |
300 | B \= b(seq1(_),_,_), | |
301 | Id = b(identifier(_),_,_). | |
302 | is_typing_pred_without_wd(b(subset_strict(Id,B),pred,_)) :- | |
303 | B \= b(domain(_),_,_), | |
304 | B \= b(empty_set,_,_), | |
305 | B \= b(value([]),_,_), | |
306 | B \= b(seq(_),_,_), | |
307 | B \= b(seq1(_),_,_), | |
308 | Id = b(identifier(_),_,_). | |
309 | % from rewriting let-expressions | |
310 | is_typing_pred_without_wd(b(member(b(comprehension_set([b(identifier('_zzzz_unary'),boolean,[]),b(identifier('_zzzz_binary'),integer,[])],_),_,_),_),pred,_)). | |
311 | is_typing_pred_without_wd(b(exists([b(identifier('_zzzz_binary'),integer,_)],_),pred,_)). | |
312 | ||
313 | clean_up_and_preprocess(Pred, Clean) :- | |
314 | clean_up_pred(Pred, _, TClean), | |
315 | remove_wd_pos_introduced_for_cdclt(true, TClean, TTClean), % there can be an added WD condition inside a WD condition for nested expressions; cleaning infos would work here too | |
316 | get_preference(cdclt_use_idl_theory_solver, RewriteToIdl), % possibly rewrite WD condition to IDL | |
317 | preprocess_predicate(false, RewriteToIdl, TTClean, LiftedPred, _, _), | |
318 | !, | |
319 | rewrite_emptyset(LiftedPred, TTTClean), | |
320 | rewrite_falsity_or_truth(TTTClean, Clean). | |
321 | ||
322 | %% rewrite_falsity_or_truth(+In, -Out). | |
323 | % Static contradictions or truths might be rewritten to falsity or truth. | |
324 | % This is a problem if the predicate is added inside a quantified formula since the | |
325 | % WD condition will then be found for the top-level predicate and will be added outside the quantified formula. | |
326 | % For instance, PI(id1).(-1 >= 0 |3 ** -1) where the WD condition is -1 >= 0. | |
327 | rewrite_falsity_or_truth(b(TruthOrFalsity,Type,Info), Clean) :- | |
328 | ( TruthOrFalsity == truth | |
329 | ; TruthOrFalsity == falsity | |
330 | ), | |
331 | select(was(Expr), Info, NInfo), | |
332 | !, | |
333 | Clean = b(Expr,Type,NInfo). | |
334 | rewrite_falsity_or_truth(Clean, Clean). | |
335 | ||
336 | rewrite_emptyset(b(negation(b(equal(A,b(empty_set,Type,Info)),pred,Info2)),pred,Info3), Out) :- | |
337 | % important if we use b_compile on the full predicate in cdclt_solver.pl | |
338 | % since empty_set is compiled to value([]) | |
339 | !, | |
340 | Out = b(negation(b(equal(A,b(value([]),Type,Info)),pred,Info2)),pred,Info3). | |
341 | rewrite_emptyset(Out, Out). | |
342 | ||
343 | get_top_level_wd_po_no_typing(Pred, Hypotheses, WDPo) :- | |
344 | empty_hyps(IHyps), | |
345 | ( Hypotheses == [] | |
346 | -> Hyps = IHyps | |
347 | ; push_hyps(IHyps, Hypotheses, [], Hyps) | |
348 | ), | |
349 | find_identifier_uses(Pred, [], TopLevelIds), | |
350 | compute_wd(Pred, Hyps, [discharge_po], TWDPo), % choicepoint | |
351 | TWDPo \= b(unknown_truth_value(_),_,_), % e.g., from external predicate calls such as RPOW | |
352 | find_identifier_uses(TWDPo, [], WDIds), | |
353 | subtract(WDIds, TopLevelIds, QIds), | |
354 | QIds == [], % is top-level | |
355 | TWDPo = b(_,_,TWDInfo), | |
356 | ( member(discharged(true, _), TWDInfo) | |
357 | -> debug_format_pred('Removed discharged predicate from WD POs: ', [], TWDPo), | |
358 | fail | |
359 | ; true | |
360 | ), | |
361 | % important to use b_ast_cleanup:clean_up_pred/3 for WD POs collected by compute_wd/4 since | |
362 | % typing constraints are optimized to 'typeset' nodes, which is undone by the cleanup. | |
363 | clean_up_and_preprocess(TWDPo, TTWDPo), | |
364 | ( is_typing_pred_without_wd(TTWDPo) | |
365 | -> debug_format_pred('Removed typing predicate from WD POs: ', [], TTWDPo), | |
366 | fail | |
367 | ; % WD POs might be conjunctions | |
368 | conjunction_to_list(TTWDPo, WDPo) | |
369 | ). | |
370 | ||
371 | remove_duplicate_preds(Constraints, NoDups) :- | |
372 | remove_duplicate_preds(Constraints, [], NoDups). | |
373 | ||
374 | remove_duplicate_preds([], _, []). | |
375 | remove_duplicate_preds([Pred|T], NormAcc, NoDups) :- | |
376 | norm_pred_check(Pred, NPred), | |
377 | ( memberchk(NPred, NormAcc) | |
378 | -> NoDups = NT, | |
379 | NNormAcc = NormAcc | |
380 | ; NoDups = [Pred|NT], | |
381 | NNormAcc = [NPred|NormAcc] | |
382 | ), | |
383 | remove_duplicate_preds(T, NNormAcc, NT). | |
384 | ||
385 | %% get_all_top_level_wd_pos(+Pred, -WDPos). | |
386 | get_all_top_level_wd_pos(Pred, WDPos) :- | |
387 | get_all_top_level_wd_pos(Pred, [], WDPos). | |
388 | ||
389 | %% get_all_top_level_wd_pos(+Pred, +Hypotheses, -WDPos). | |
390 | get_all_top_level_wd_pos(Pred, Hypotheses, WDPos) :- | |
391 | findall(WDPo, get_top_level_wd_po_no_typing(Pred, Hypotheses, WDPo), TWDPos), !, | |
392 | append(TWDPos, TTWDPos), | |
393 | remove_duplicate_preds(TTWDPos, WDPos). | |
394 | ||
395 | % Let A be a predicate with a set of WD conditions C. We create an implication A => c & not(c) => not(A) for each c in C. | |
396 | % We don't use a single implication A => (c1 & c2 & .. & cn) since we have to create a CNF anyway. | |
397 | create_wd_impls([], _, Acc, Acc). | |
398 | create_wd_impls([WDPo|T], Pred, Acc, WDImpls) :- | |
399 | % don't use added info is_wd_po_for_cdclt here | |
400 | NegP = b(negation(Pred),pred,[]), | |
401 | safe_create_texpr(disjunct(NegP,WDPo), pred, [], WDImpl1), | |
402 | safe_create_texpr(disjunct(WDPo,NegP), pred, [], WDImpl2), | |
403 | create_wd_impls(T, Pred, [WDImpl1,WDImpl2|Acc], WDImpls). | |
404 | ||
405 | add_wd_impls_to_acc([], WDAcc, WDAcc). | |
406 | add_wd_impls_to_acc([WDImpl|T], WDAcc, NWDAcc) :- | |
407 | member(WDImpl, WDAcc), | |
408 | !, | |
409 | add_wd_impls_to_acc(T, WDAcc, NWDAcc). | |
410 | add_wd_impls_to_acc([WDImpl|T], WDAcc, NWDAcc) :- | |
411 | add_wd_impls_to_acc(T, [WDImpl|WDAcc], NWDAcc). | |
412 | ||
413 | %% add_wd_pos_to_pred(+Pred, +Hyps, +WDAcc, +IsTopLevel, +AddToTopLevel, -NWDAcc, -WDPred, -WDPoConj). | |
414 | % Add all necessary WD POs to make +Pred well-defined for SMT solving. | |
415 | % That means, each predicate that is abstracted to a SAT variable is well-defined. | |
416 | % For quantified formulas, WD POs are nested inside a quantifier. | |
417 | % Only add WD POs to WDAcc if +IsTopLevel is true. | |
418 | % Note: let-expressions and if-then-else expressions have to be rewritten beforehand | |
419 | add_wd_pos_to_pred(Pred, Hyps, WDAcc, IsTopLevel, AddToTopLevel, NWDAcc, WDPred, WDPoConj) :- | |
420 | Pred = b(Expr, Type, Info), | |
421 | add_wd_pos_to_pred_e(Expr, Type, Info, Hyps, WDAcc, IsTopLevel, AddToTopLevel, NWDAcc, WDPred, WDPoConj). | |
422 | ||
423 | % 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. | |
424 | % 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 | |
425 | % to our top-level WD POs. | |
426 | add_wd_pos_to_pred_e(conjunct(A,B), pred, Info, Hyps, WDAcc, IsTopLevel, true, NWDAcc, WDPred, WDPoConj) :- | |
427 | !, | |
428 | add_wd_pos_to_pred(A, Hyps, WDAcc, IsTopLevel, true, NWDAcc1, WDA, WDAConj), | |
429 | NHyps = [WDA|Hyps], | |
430 | add_wd_pos_to_pred(B, NHyps, NWDAcc1, IsTopLevel, true, NWDAcc, WDB, WDBConj), | |
431 | NExpr = conjunct(WDA,WDB), | |
432 | conjunct_predicates([WDAConj,WDBConj], WDPoConj), | |
433 | safe_create_texpr(NExpr, pred, Info, WDPred). | |
434 | add_wd_pos_to_pred_e(Expr, pred, Info, Hyps, WDAcc, IsTopLevel, true, NWDAcc, WDPred, WDPoConj) :- | |
435 | functor(Expr, Functor, 2), | |
436 | (Functor == disjunct; Functor == implication; Functor == equivalence), | |
437 | !, | |
438 | arg(1, Expr, A), | |
439 | arg(2, Expr, B), | |
440 | add_wd_pos_to_pred(A, Hyps, WDAcc, IsTopLevel, true, NWDAcc1, WDA, WDAConj), | |
441 | add_wd_pos_to_pred(B, Hyps, NWDAcc1, IsTopLevel, true, NWDAcc, WDB, WDBConj), | |
442 | functor(NExpr, Functor, 2), | |
443 | arg(1, NExpr, WDA), | |
444 | arg(2, NExpr, WDB), | |
445 | conjunct_predicates([WDAConj,WDBConj], WDPoConj), | |
446 | safe_create_texpr(NExpr, pred, Info, WDPred). | |
447 | add_wd_pos_to_pred_e(negation(Pred), pred, Info, Hyps, WDAcc, IsTopLevel, _, NWDAcc, WDNeg, WDPoConj) :- | |
448 | !, | |
449 | add_wd_pos_to_pred(Pred, Hyps, WDAcc, IsTopLevel, true, NWDAcc, WDPred, WDPoConj), | |
450 | WDNeg = b(negation(WDPred),pred,Info). | |
451 | add_wd_pos_to_pred_e(if_then_else(Cond,Lhs,Rhs), pred, Info, Hyps, WDAcc, IsTopLevel, true, NWDAcc, WDPred, WDPoConj) :- | |
452 | !, | |
453 | add_wd_pos_to_pred(Cond, Hyps, WDAcc, IsTopLevel, true, NWDAcc1, WDCond, WDPoConj1), | |
454 | add_wd_pos_to_pred(Lhs, Hyps, NWDAcc1, IsTopLevel, true, NWDAcc2, WDLhs, WDPoConj2), | |
455 | add_wd_pos_to_pred(Rhs, Hyps, NWDAcc2, IsTopLevel, true, NWDAcc, WDRhs, WDPoConj3), | |
456 | safe_create_texpr(if_then_else(WDCond,WDLhs,WDRhs), pred, Info, WDPred), | |
457 | conjunct_predicates([WDPoConj1,WDPoConj2,WDPoConj3], WDPoConj). | |
458 | add_wd_pos_to_pred_e(Expr, Type, Info, Hyps, WDAcc, _, _, NWDAcc, WDPred, _) :- | |
459 | Expr =.. [Functor,Ids,Lhs,Rhs], | |
460 | ( Functor == forall; Functor == event_b_comprehension_set), | |
461 | !, | |
462 | add_wd_pos_to_pred(Rhs, Hyps, WDAcc, false, true, NWDAcc, WDRhs, _), | |
463 | NExpr =.. [Functor,Ids,Lhs,WDRhs], | |
464 | safe_create_texpr(NExpr, Type, Info, WDPred). | |
465 | add_wd_pos_to_pred_e(Expr, Type, Info, Hyps, WDAcc, _, _, NWDAcc, WDPred, _) :- | |
466 | Expr =.. [Functor,Ids,Lhs,Rhs], | |
467 | quantified_ternary_expr_nonpred_body(Functor), | |
468 | !, | |
469 | % get WD POs from RHS expression but add to LHS predicate | |
470 | get_all_top_level_wd_pos(Rhs, [Lhs|Hyps], WDPos), | |
471 | maplist(map_add_texpr_infos([is_wd_po_for_cdclt]), WDPos, NWDPos), | |
472 | conjunct_predicates(NWDPos, WDPoConj), | |
473 | safe_create_texpr(conjunct(WDPoConj,Lhs), pred, [], WDLhs), | |
474 | NExpr =.. [Functor,Ids,WDLhs,Rhs], | |
475 | % don't add to WDAcc since it's not at the top-level | |
476 | NWDAcc = WDAcc, | |
477 | safe_create_texpr(NExpr, Type, Info, WDPred). | |
478 | add_wd_pos_to_pred_e(Expr, pred, Info, Hyps, WDAcc, _, _, NWDAcc, WDPred, _) :- | |
479 | Expr =.. [Functor,Ids,Eqs,Body], | |
480 | (Functor == let; Functor == let_predicate), | |
481 | !, | |
482 | add_wd_pos_to_pred(Body, Hyps, WDAcc, false, true, NWDAcc, WDBody, _), | |
483 | NExpr =.. [Functor,Ids,Eqs,WDBody], | |
484 | safe_create_texpr(NExpr, pred, Info, WDPred). | |
485 | add_wd_pos_to_pred_e(Expr, Type, Info, Hyps, WDAcc, _, _, NWDAcc, WDPred, _) :- | |
486 | Expr =.. [Functor,Ids,Body], | |
487 | quantified_binary_expr(Functor), | |
488 | !, | |
489 | add_wd_pos_to_pred(Body, Hyps, WDAcc, false, true, NWDAcc, WDBody, _), | |
490 | NExpr =.. [Functor,Ids,WDBody], | |
491 | safe_create_texpr(NExpr, Type, Info, WDPred). | |
492 | add_wd_pos_to_pred_e(Expr, Type, Info, Hyps, WDAcc, IsTopLevel, true, NWDAcc, WDAst, WDPoConj) :- | |
493 | % e.g., for a = b - {some set comprehension with WD}, we want to add WD POs to the set comprehension but not the equality | |
494 | functor(Expr, Functor, _), | |
495 | Functor \== identifier, | |
496 | Functor \== integer, | |
497 | Functor \== value, | |
498 | Functor \== string, | |
499 | Functor \== partition, | |
500 | Functor \== external_pred_call, | |
501 | Expr =.. [Functor|Args], | |
502 | map_add_wd_pos_to_pred(Args, Hyps, WDAcc, false, true, NWDAcc1, WDArgs, _), | |
503 | NExpr =.. [Functor|WDArgs], | |
504 | Ast = b(Expr,Type,Info), | |
505 | NAst = b(NExpr,Type,Info), | |
506 | !, | |
507 | top_level_wd_post_processing(Type, Hyps, Ast, NAst, NWDAcc1, IsTopLevel, NWDAcc, WDAst, WDPoConj). | |
508 | add_wd_pos_to_pred_e(Expr, Type, Info, _, WDAcc, _, _, WDAcc, b(Expr,Type,Info), _). | |
509 | ||
510 | %% top_level_wd_post_processing(+Type, +Hyps, +Ast, +NAst, +WDAcc, +IsTopLevel, -NWDAcc, -WDAst). | |
511 | % Create top-level WD implications and WD PO conjunction if is predicate. | |
512 | % Only add WD POs to WDAcc if +IsTopLevel is true. | |
513 | top_level_wd_post_processing(pred, Hyps, Ast, NAst, WDAcc, IsTopLevel, NWDAcc, WDAst, WDPoConj) :- | |
514 | get_all_top_level_wd_pos(NAst, Hyps, WDPos), | |
515 | WDPos \== [], | |
516 | create_wd_impls(WDPos, Ast, [], WDImpls), % use Ast here, not NAst where WD POs have potentially been added | |
517 | conjunct_predicates(WDPos, WDPoConj), % don't use added info is_wd_po_for_cdclt here | |
518 | !, | |
519 | debug_format_pred("--------------------------Add WD PO for AST~n", [], NAst), | |
520 | ( IsTopLevel == true | |
521 | -> add_wd_impls_to_acc(WDImpls, WDAcc, NWDAcc) | |
522 | ; NWDAcc = WDAcc | |
523 | ), | |
524 | maplist(map_add_texpr_infos([is_wd_po_for_cdclt]), WDPos, NWDPos), | |
525 | conjunct_predicates(NWDPos, WDPo), | |
526 | conjunct_predicates([WDPo,NAst], WDAst). | |
527 | top_level_wd_post_processing(_, _, _, NAst, WDAcc, _, WDAcc, NAst, _). | |
528 | ||
529 | map_add_wd_pos_to_pred([Arg|T], Hyps, WDAcc, IsTopLevel, AddToTopLevel, NWDAcc, [WDArg|TWDArgs], WDConj) :- | |
530 | add_wd_pos_to_pred(Arg, Hyps, WDAcc, IsTopLevel, AddToTopLevel, NWDAcc1, WDArg, WDConjArg), | |
531 | map_add_wd_po_to_pred_acc(T, Hyps, NWDAcc1, IsTopLevel, AddToTopLevel, NWDAcc, WDConjArg, TWDArgs, WDConj). | |
532 | ||
533 | map_add_wd_po_to_pred_acc([], _, WDAcc, _, _, WDAcc, WDConjAcc, [], WDConjAcc). | |
534 | map_add_wd_po_to_pred_acc([Arg|T], Hyps, WDAcc, IsTopLevel, AddToTopLevel, NWDAcc, WDConjAcc, [WDArg|TWDArgs], WDConj) :- | |
535 | add_wd_pos_to_pred(Arg, Hyps, WDAcc, IsTopLevel, AddToTopLevel, NWDAcc1, WDArg, WDConjArg), | |
536 | ( ground(WDConjArg) | |
537 | -> safe_create_texpr(conjunct(WDConjArg,WDConjAcc),pred,[],NWDConjAcc) | |
538 | ; NWDConjAcc = WDConjAcc | |
539 | ), | |
540 | map_add_wd_po_to_pred_acc(T, Hyps, NWDAcc1, IsTopLevel, AddToTopLevel, NWDAcc, NWDConjAcc, TWDArgs, WDConj). | |
541 | % ---------------- | |
542 | ||
543 | ||
544 | quantified_expr(forall(Ids,Lhs,Rhs), forall, Ids, [Lhs,Rhs]). | |
545 | quantified_expr(exists(Ids,Body), exists, Ids, [Body]). | |
546 | quantified_expr(comprehension_set(Ids,Body), comprehension_set, Ids, [Body]). | |
547 | quantified_expr(event_b_comprehension_set(Ids,T,Body), event_b_comprehension_set, Ids, [T,Body]). | |
548 | quantified_expr(lambda(Ids,Pred,Body), lambda, Ids, [Pred,Body]). | |
549 | quantified_expr(general_sum(Ids,Pred,Body), general_sum, Ids, [Pred,Body]). | |
550 | quantified_expr(general_product(Ids,Pred,Body), general_product, Ids, [Pred,Body]). | |
551 | quantified_expr(quantified_union(Ids,Pred,Body), quantified_union, Ids, [Pred,Body]). | |
552 | quantified_expr(quantified_intersection(Ids,Pred,Body), quantified_intersection, Ids, [Pred,Body]). | |
553 | ||
554 | %% remove_wd_pos_introduced_for_cdclt_keep_toplevel(+Conj, -NConj). | |
555 | % 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. | |
556 | remove_wd_pos_introduced_for_cdclt_keep_toplevel(Conj, NConj) :- | |
557 | remove_wd_pos_introduced_for_cdclt(false, Conj, NConj). | |
558 | ||
559 | %% remove_wd_pos_introduced_for_cdclt(+Remove, +Conj, -NConj). | |
560 | % Remove WD POs introduced for cdclt if +Remove is true. | |
561 | remove_wd_pos_introduced_for_cdclt(Remove, Conj, NConj) :- | |
562 | conjunction_to_list(Conj, List), | |
563 | !, | |
564 | remove_wd_pos_introduced_for_cdclt_l(Remove, List, NList), | |
565 | conjunct_predicates(NList, NConj). | |
566 | remove_wd_pos_introduced_for_cdclt(_, Node, Node). | |
567 | ||
568 | % TODO: first argument indexing | |
569 | remove_wd_pos_introduced_for_cdclt_l(_, [], []). | |
570 | remove_wd_pos_introduced_for_cdclt_l(Remove, [Pred|T], Out) :- | |
571 | Pred = b(_,_,Info), | |
572 | memberchk(is_wd_po_for_cdclt, Info), | |
573 | !, | |
574 | ( ( Remove == true | |
575 | ; % disjunction only occurs for WD condition x/=0 of y/x if IDL solver is used | |
576 | % inequality results in disjunction but conflict has to be conjunction | |
577 | % so remove this WD condition in this specific case | |
578 | Pred = b(disjunct(_,_),_,_) | |
579 | ) | |
580 | -> Out = NT, | |
581 | debug_format_pred("-----------------------removed wd po from unsat core: ", [], Pred) | |
582 | ; Out = [Pred|NT] | |
583 | ), | |
584 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
585 | remove_wd_pos_introduced_for_cdclt_l(Remove, [b(negation(Pred),pred,NInfo)|T], [Out|NT]) :- | |
586 | !, | |
587 | remove_wd_pos_introduced_for_cdclt(true, Pred, NPred), | |
588 | safe_create_texpr(negation(NPred), pred, NInfo, Out), | |
589 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
590 | remove_wd_pos_introduced_for_cdclt_l(Remove, [b(convert_bool(Pred),boolean,NInfo)|T], [Out|NT]) :- | |
591 | !, | |
592 | remove_wd_pos_introduced_for_cdclt(true, Pred, NPred), | |
593 | safe_create_texpr(convert_bool(NPred), boolean, NInfo, Out), | |
594 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
595 | remove_wd_pos_introduced_for_cdclt_l(Remove, [Pred|T], [Out|NT]) :- | |
596 | Pred = b(Expr,Type,Info), | |
597 | Expr =.. [Functor,Ids,Eqs,Body], | |
598 | (Functor == let; Functor == let_predicate; Functor == lazy_let_pred), | |
599 | !, | |
600 | remove_wd_pos_introduced_for_cdclt(true, Body, NBody), | |
601 | NExpr =.. [Functor,Ids,Eqs,NBody], | |
602 | safe_create_texpr(NExpr, Type, Info, Out), | |
603 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
604 | remove_wd_pos_introduced_for_cdclt_l(Remove, [Pred|T], [Out|NT]) :- | |
605 | Pred = b(Expr,Type,Info), | |
606 | quantified_expr(Expr, Functor, Ids, Subs), | |
607 | !, | |
608 | maplist(remove_wd_pos_introduced_for_cdclt(true), Subs, NSubs), | |
609 | NExpr =.. [Functor,Ids|NSubs], | |
610 | safe_create_texpr(NExpr, Type, Info, Out), | |
611 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
612 | remove_wd_pos_introduced_for_cdclt_l(Remove, [Pred|T], [Out|NT]) :- | |
613 | Pred = b(Expr,Type,Info), | |
614 | functor(Expr, Functor, 1), | |
615 | !, | |
616 | arg(1, Expr, Arg), | |
617 | remove_wd_pos_introduced_for_cdclt(Remove, Arg, NArg), | |
618 | functor(NExpr, Functor, 1), | |
619 | arg(1, NExpr, NArg), | |
620 | Out = b(NExpr,Type,Info), | |
621 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
622 | remove_wd_pos_introduced_for_cdclt_l(Remove, [Pred|T], [Out|NT]) :- | |
623 | Pred = b(Expr,Type,Info), | |
624 | functor(Expr, Functor, 2), | |
625 | Functor \== external_pred_call, | |
626 | Functor \== partition, | |
627 | !, | |
628 | arg(1, Expr, Arg1), | |
629 | arg(2, Expr, Arg2), | |
630 | remove_wd_pos_introduced_for_cdclt(Remove, Arg1, NArg1), | |
631 | remove_wd_pos_introduced_for_cdclt(Remove, Arg2, NArg2), | |
632 | functor(NExpr, Functor, 2), | |
633 | arg(1, NExpr, NArg1), | |
634 | arg(2, NExpr, NArg2), | |
635 | Out = b(NExpr,Type,Info), | |
636 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
637 | remove_wd_pos_introduced_for_cdclt_l(Remove, [Pred|T], [Pred|NT]) :- | |
638 | remove_wd_pos_introduced_for_cdclt_l(Remove, T, NT). | |
639 | ||
640 | map_add_texpr_infos(ToBeAdded, Ast, NAst) :- | |
641 | add_texpr_infos(Ast, ToBeAdded, NAst). | |
642 | ||
643 | % managing link from predicates to SAT variables | |
644 | ||
645 | empty_predicate_env(E) :- empty_avl(E). | |
646 | ||
647 | % TO DO: maybe we should also store SatVarName? | |
648 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv) :- | |
649 | ( var(Env) | |
650 | ; \+ is_avl(Env) | |
651 | ), | |
652 | !, | |
653 | add_internal_error('Illegal env:', register_predicate(Pred,WDPred,Env,UniqueId,NewEnv)), | |
654 | NewEnv = Env. | |
655 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv) :- %print('storing: '), writeq(WDPred),nl, | |
656 | norm_pred_check(Pred, NPred), | |
657 | avl_store(NPred,Env,pred2satvar(WDPred,UniqueId),NewEnv). | |
658 | ||
659 | fetch_predicate(Pred,Env,StoredPred,SatVar) :- (var(Env) ; \+ is_avl(Env)),!, | |
660 | add_internal_error('Illegal env:',fetch_predicate(Pred,Env,StoredPred,SatVar)), fail. | |
661 | fetch_predicate(Pred,Env,StoredPred,SatVar) :- | |
662 | norm_pred_check(Pred, NPred), | |
663 | avl_fetch(NPred,Env,pred2satvar(StoredPred,SatVar)), !. | |
664 | %fetch_predicate(Pred,_,_,_SatVar) :- print('not found: '), print_bexpr(Pred),nl,fail. | |
665 | ||
666 | % --------------- | |
667 | ||
668 | ||
669 | %% sat_to_predicate_from_solution(+SatBindings, +SatVars, -Conjunction). | |
670 | % Create conjunction of SAT bindings using their corresponding SMT formulae | |
671 | % which are stored in the bool variables' information fields. | |
672 | sat_to_predicate_from_solution([], _, b(truth,pred,[])). | |
673 | sat_to_predicate_from_solution([Binding|T], SatVars, Conjunction) :- | |
674 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars), | |
675 | !, | |
676 | sat_to_predicate_from_solution(T, SMT, RestSatVars, Conjunction). | |
677 | sat_to_predicate_from_solution([_|T], SatVars, Conjunction) :- | |
678 | % skip: binding might be a variable if instantiation is not required | |
679 | sat_to_predicate_from_solution(T, SatVars, Conjunction). | |
680 | ||
681 | sat_to_predicate_from_solution([], SmtAcc, _, SmtAcc). | |
682 | sat_to_predicate_from_solution([Binding|T], SmtAcc, SatVars, Conjunction) :- | |
683 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars), | |
684 | !, | |
685 | safe_create_texpr(conjunct(SMT,SmtAcc), pred, [], NewSmtAcc), | |
686 | sat_to_predicate_from_solution(T, NewSmtAcc, RestSatVars, Conjunction). | |
687 | sat_to_predicate_from_solution([_|T], SmtAcc, SatVars, Conjunction) :- | |
688 | sat_to_predicate_from_solution(T, SmtAcc, SatVars, Conjunction). | |
689 | ||
690 | get_var_and_value_from_binding(bind(SatVarName,Value), SatVarName, Value). | |
691 | get_var_and_value_from_binding(binding(SatVarName,Value,_), SatVarName, Value). | |
692 | ||
693 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars) :- | |
694 | ground(Binding), | |
695 | get_var_and_value_from_binding(Binding, SatVarName, Value), | |
696 | !, | |
697 | select(b(identifier(SatVarName),_,Info), SatVars, RestSatVars), | |
698 | member(smt_formula(TSMT), Info),!, | |
699 | ( Value == pred_true | |
700 | -> SMT = TSMT | |
701 | ; Value == pred_false, | |
702 | TSMT = b(_,_,TSMTInfo), | |
703 | safe_create_texpr(negation(TSMT), pred, TSMTInfo, SMT) | |
704 | ). | |
705 | /*get_smt_formula_from_binding(Binding, _, _, _) :- | |
706 | add_error(get_smt_formula_from_binding, 'SAT binding not ground:', [Binding]), | |
707 | fail.*/ |