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 | get_amount_of_sat_variables/1, | |
9 | next_sat_var_name/1, | |
10 | reset_sat_var_id/0]). | |
11 | ||
12 | :- use_module(library(sets), [subtract/3]). | |
13 | :- use_module(library(avl)). | |
14 | :- use_module(library(lists)). | |
15 | :- use_module(wdsrc(well_def_hyps), [empty_hyps/1,push_hyps/4]). | |
16 | :- use_module(wdsrc(well_def_analyser), [compute_wd/4]). | |
17 | :- use_module(probsrc(debug)). | |
18 | :- use_module(probsrc(translate), [print_bexpr/1]). | |
19 | :- use_module(probsrc(preferences), [get_preference/2]). | |
20 | :- use_module(probsrc(b_ast_cleanup), [clean_up_pred/3]). | |
21 | :- use_module(probsrc(module_information), [module_info/2]). | |
22 | :- use_module(probsrc(error_manager),[add_internal_error/2,add_error_fail/3]). | |
23 | :- use_module(probsrc(b_interpreter_check),[norm_pred_check/2]). | |
24 | :- use_module(probsrc(bsyntaxtree), [add_texpr_infos/3, | |
25 | find_identifier_uses/3, | |
26 | safe_create_texpr/4, | |
27 | conjunct_predicates/2, | |
28 | conjunction_to_list/2, | |
29 | disjunct_predicates/2, | |
30 | disjunction_to_list/2]). | |
31 | :- use_module(cdclt_solver('cdclt_preprocessing')). | |
32 | :- use_module(cdclt_solver('cdclt_settings')). | |
33 | :- use_module(extension('banditfuzz/welldef'), [ensure_wd/2]). | |
34 | ||
35 | :- module_info(group, cdclt). | |
36 | :- module_info(description, 'This module provides the conversion from B predicates to SAT formulae and vice-versa to be used for CDCL(T).'). | |
37 | ||
38 | :- dynamic sat_var_id/1. | |
39 | ||
40 | sat_var_id(0). | |
41 | ||
42 | %% get_amount_of_sat_variables(-AmountOfVars). | |
43 | get_amount_of_sat_variables(AmountOfVars) :- | |
44 | sat_var_id(AmountOfVars). | |
45 | ||
46 | %% reset_sat_var_id. | |
47 | reset_sat_var_id :- | |
48 | retractall(sat_var_id(_)), | |
49 | asserta(sat_var_id(0)). | |
50 | ||
51 | debug_format_pred(_, _, _) :- | |
52 | print_logs(false), | |
53 | !. | |
54 | debug_format_pred(Msg, Vars, Pred) :- | |
55 | format(Msg, Vars), | |
56 | print_bexpr(Pred), nl, !. | |
57 | ||
58 | %% predicate_to_sat(+Type, +Pred, -NewEnv, -WDPOs, -BoolFormula, -NVarAcc). | |
59 | % Same as predicate_to_sat/9 but initializing an empty environment and accumulator for variables. | |
60 | predicate_to_sat(Type, Pred, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
61 | empty_predicate_env(Env), | |
62 | predicate_to_sat(Type, [], [], Env, Pred, NewEnv, WDPOs, BoolFormula, VarAcc). | |
63 | ||
64 | %% predicate_to_sat(+ReuseType, +WDAcc, +Type, +VarAcc, +Env, +Pred, -NewEnv, -BoolFormula, -NVarAcc). | |
65 | % Create a boolean formula from a B predicate, e.g., return 'A=TRUE & B=TRUE' for 'x:INT & x>1'. | |
66 | % Introduces fresh unique identifiers if ReuseType is not equal to 'only_reuse'. | |
67 | % If ReuseType is 'only_reuse': do not introduce new SAT variables but skip parts that need a new SAT variable | |
68 | % (some unsat core computations might deduce new constraints and we do not want to introduce new SAT variables during CDCL). | |
69 | % Env stores pairs of B ASTs (without info field) and its assigned SAT variables. | |
70 | % Add corresponding SAT variable names to AST's info fields (returned in NewPred). | |
71 | % Each SAT variable contains a term smt_formula/1 in its info field providing the corresponding SMT formula. | |
72 | % Note: SMT formula is split on the level of conjunction, disjunction, implication and equivalence. | |
73 | predicate_to_sat(ReuseType, WDAcc, Acc, Env, Pred, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
74 | Pred = b(Expr, Type, Info), | |
75 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, Acc, Env, NewEnv, WDPOs, BoolFormula, VarAcc). | |
76 | ||
77 | %predicate_to_sat_e(E, _, _, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- functor(E,F,N),print(F/N),nl,nl,fail. | |
78 | predicate_to_sat_e(negation(Expr), _, _, ReuseType, WDAcc, Acc, Env, NewEnv, WDPOs, BoolFormula, VarAcc) :- | |
79 | predicate_to_sat_neg(Expr, ReuseType, WDAcc, Acc, Env, NewEnv, WDPOs, BoolFormula, VarAcc). | |
80 | predicate_to_sat_e(truth, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Truth, VarAccOut) :- | |
81 | !, | |
82 | EnvOut = Env, | |
83 | VarAccOut = Acc, | |
84 | NWDAcc = WDAcc, | |
85 | Truth = b(truth,pred,Info). | |
86 | predicate_to_sat_e(falsity, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- | |
87 | !, | |
88 | EnvOut = Env, | |
89 | VarAccOut = Acc, | |
90 | NWDAcc = WDAcc, | |
91 | Falsity = b(falsity,pred,Info). | |
92 | ||
93 | predicate_to_sat_e(conjunct(A,B), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
94 | conjunction_to_list(b(conjunct(A,B),pred,[]), PList), | |
95 | !, | |
96 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, PList, NewEnv, WDPOs, SatList, NVarAcc), | |
97 | conjunct_predicates(SatList, BoolFormula). | |
98 | /*predicate_to_sat(_, VarAcc, Env, Pred, NewEnv, BoolFormula, NVarAcc) :- | |
99 | Pred = b(disjunct(_,_),_,_), | |
100 | fetch_predicate(Pred,Env,_,SatVar), | |
101 | % equality from symmetry breaking is a disjunction | |
102 | !, | |
103 | NewEnv = Env, | |
104 | safe_create_texpr(equal(SatVar,b(boolean_true,boolean,[])), pred, [], BoolFormula), | |
105 | NVarAcc = VarAcc.*/ | |
106 | predicate_to_sat_e(disjunct(A,B), _, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
107 | disjunction_to_list(b(disjunct(A,B),pred,[]), PList), | |
108 | !, | |
109 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, PList, NewEnv, WDPOs, SatList, NVarAcc), | |
110 | disjunct_predicates(SatList, BoolFormula). | |
111 | /*predicate_to_sat(ReuseType, VarAcc, Env, b(negation(Pred),pred,_), NewEnv, NewPred, BoolFormula, NVarAcc) :- | |
112 | predicate_to_sat(ReuseType, VarAcc, Env, Pred, NewEnv, TNewPred, BoolFormula, NVarAcc), | |
113 | ( TNewPred \== b(truth,pred,_) | |
114 | -> safe_create_texpr(negation(TNewPred),pred,[], NewPred) | |
115 | ; safe_create_texpr(truth,pred,[], NewPred) | |
116 | ).*/ | |
117 | predicate_to_sat_e(Expr, _, _, _, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, VarAccOut) :- | |
118 | ( Expr == value(pred_true) | |
119 | ; Expr == value(pred_false) | |
120 | ), | |
121 | !, | |
122 | WDPOs = WDAcc, | |
123 | VarAccOut = VarAcc, | |
124 | safe_create_texpr(Expr, pred, [], BoolFormula), | |
125 | NewEnv = Env. | |
126 | predicate_to_sat_e(implication(Lhs,Rhs), pred, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
127 | !, | |
128 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Lhs,Rhs], NewEnv, WDPOs, NSatArgs, NVarAcc), | |
129 | NSatArgs = [NSatLhs,NSatRhs], | |
130 | safe_create_texpr(implication(NSatLhs,NSatRhs), pred, [smt_formula(b(implication(Lhs,Rhs),pred,Info))], BoolFormula). | |
131 | predicate_to_sat_e(equivalence(Lhs,Rhs), pred, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
132 | !, | |
133 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Lhs,Rhs], NewEnv, WDPOs, NSatArgs, NVarAcc), | |
134 | NSatArgs = [NSatLhs,NSatRhs], | |
135 | safe_create_texpr(equivalence(NSatLhs,NSatRhs), pred, [smt_formula(b(equivalence(Lhs,Rhs),pred,Info))], BoolFormula). | |
136 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
137 | functor(Expr, _, Arity), | |
138 | ( Arity == 2 | |
139 | ; Arity == 3 | |
140 | ), | |
141 | !, | |
142 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_true, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
143 | predicate_to_sat_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
144 | % formula is a singleton pred which is not splitted such as a subset | |
145 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_true, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
146 | % TO DO: if going into quantifications, we have to watch out for local identifier scopes | |
147 | % (i.e., x<7 might not be the same x<7 within a quantification if x is a local id) | |
148 | % Note that we currently do not go into quantifications so this is not an issue. | |
149 | ||
150 | predicate_to_sat_neg(Ast, ReuseType, WDAcc, Acc, Env, EnvOut, NWDAcc, NAst, VarAccOut) :- | |
151 | Ast = b(Expr,Type,Info), | |
152 | predicate_to_sat_neg_e(Expr, Type, Info, ReuseType, WDAcc, Acc, Env, EnvOut, NWDAcc, NAst, VarAccOut). | |
153 | ||
154 | predicate_to_sat_neg_e(truth, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Falsity, VarAccOut) :- | |
155 | !, | |
156 | EnvOut = Env, VarAccOut = Acc, | |
157 | NWDAcc = WDAcc, | |
158 | Falsity = b(falsity,pred,Info). | |
159 | predicate_to_sat_neg_e(falsity, pred, Info, _, WDAcc, Acc, Env, EnvOut, NWDAcc, Truth, VarAccOut) :- | |
160 | !, | |
161 | EnvOut = Env, VarAccOut = Acc, | |
162 | NWDAcc = WDAcc, | |
163 | Truth = b(truth,pred,Info). | |
164 | predicate_to_sat_neg_e(negation(Pred), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
165 | !, | |
166 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, Pred, NewEnv, WDPOs, BoolFormula, NVarAcc). | |
167 | predicate_to_sat_neg_e(Expr, Type, Info, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
168 | reuse_or_introduce_bool_var(ReuseType, WDAcc, VarAcc, Env, b(Expr,Type,Info), boolean_false, TNewEnv, TWDPOs, TBoolFormula, TNVarAcc), | |
169 | !, | |
170 | NewEnv = TNewEnv, | |
171 | WDPOs = TWDPOs, | |
172 | BoolFormula = TBoolFormula, | |
173 | NVarAcc = TNVarAcc. | |
174 | predicate_to_sat_neg_e(disjunct(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
175 | !, | |
176 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(A),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
177 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
178 | % conjunct_predicate/ ensures that truth and falsity are simplified (1) | |
179 | conjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
180 | predicate_to_sat_neg_e(conjunct(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
181 | !, | |
182 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(A),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
183 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
184 | % see above comment (1) for conjunct_predicates/2 | |
185 | disjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
186 | predicate_to_sat_neg_e(implication(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
187 | !, | |
188 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, A, NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
189 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(B),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
190 | % see (1) | |
191 | conjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
192 | predicate_to_sat_neg_e(equivalence(A,B), pred, _, ReuseType, WDAcc, VarAcc, Env, NewEnv, WDPOs, BoolFormula, NVarAcc) :- | |
193 | !, | |
194 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, b(negation(b(implication(A,B),pred,[])),pred,[]), NewEnv1, WDAcc1, ABoolFormula, NVarAcc1), | |
195 | predicate_to_sat(ReuseType, WDAcc1, NVarAcc1, NewEnv1, b(negation(b(implication(B,A),pred,[])),pred,[]), NewEnv, WDPOs, BBoolFormula, NVarAcc), | |
196 | % see (1) | |
197 | disjunct_predicates([ABoolFormula,BBoolFormula], BoolFormula). | |
198 | ||
199 | map_predicate_to_sat(_, WDAcc, VarAcc, Env, [], Env, WDAcc, BoolFormulas, VarAcc) :- !, BoolFormulas=[]. | |
200 | map_predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, [Pred|T], NewEnv, WDPOs, [BoolFormula|NT], NVarAcc) :- | |
201 | predicate_to_sat(ReuseType, WDAcc, VarAcc, Env, Pred, TempEnv, TWDAcc, BoolFormula, TVarAcc), | |
202 | map_predicate_to_sat(ReuseType, TWDAcc, TVarAcc, TempEnv, T, NewEnv, WDPOs, NT, NVarAcc). | |
203 | ||
204 | negate_pred(greater_equal(A,B), less(A,B)). | |
205 | negate_pred(greater(A,B), less_equal(A,B)). | |
206 | negate_pred(less_equal(A,B), less(B,A)). | |
207 | negate_pred(less(A,B), less_equal(B,A)). | |
208 | ||
209 | negate_bool_atom(boolean_true, boolean_false). | |
210 | negate_bool_atom(boolean_false, boolean_true). | |
211 | ||
212 | % Note: BoolFormula is 'a = TRUE' or 'a = FALSE' for (negated) literal a. | |
213 | /*reuse_or_introduce_bool_var(_, VarAcc, Env, Pred, boolean_true, NewEnv, BoolFormula, NVarAcc) :- | |
214 | % ensure that the same SAT variable is used for boolean equalities such as x=TRUE & x=FALSE | |
215 | % we would usually introduce two different SAT variables for both equalities but don't want to do so for | |
216 | % boolean equalities | |
217 | Pred = b(equal(Bool,BoolId),pred,_), | |
218 | BoolId = b(identifier(BoolIdName),boolean,_), | |
219 | (Bool = b(boolean_true,boolean,[]); Bool = b(boolean_false,boolean,[])), | |
220 | fetch_predicate(b(equal(BoolPred,b(identifier(BoolIdName),boolean,[])),pred,[]),Env,_,SatVar), | |
221 | ( (Bool = b(boolean_true,boolean,_), BoolPred = b(boolean_true,boolean,_)) | |
222 | -> BoolAtom = boolean_true | |
223 | ; (Bool = b(boolean_true,boolean,_), BoolPred = b(boolean_false,boolean,_)) | |
224 | -> BoolAtom = boolean_false | |
225 | ; (Bool = b(boolean_false,boolean,_), BoolPred = b(boolean_false,boolean,_)) | |
226 | -> BoolAtom = boolean_true | |
227 | ; BoolAtom = boolean_false | |
228 | ), | |
229 | !, | |
230 | safe_create_texpr(equal(SatVar,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
231 | NewEnv = Env, | |
232 | NVarAcc = VarAcc.*/ | |
233 | reuse_or_introduce_bool_var(_, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
234 | fetch_predicate(Pred, Env, _, SatVar), | |
235 | !, | |
236 | safe_create_texpr(equal(SatVar,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
237 | NewEnv = Env, | |
238 | NWDAcc = WDAcc, | |
239 | NVarAcc = VarAcc. | |
240 | reuse_or_introduce_bool_var(_, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
241 | Pred = b(Expr,Type,Info), | |
242 | negate_pred(Expr, NExpr), | |
243 | fetch_predicate(b(NExpr,Type,Info), Env, _, SatVar), | |
244 | !, | |
245 | negate_bool_atom(BoolAtom, NBoolAtom), | |
246 | safe_create_texpr(equal(SatVar,b(NBoolAtom,boolean,[])), pred, [], BoolFormula), | |
247 | NewEnv = Env, | |
248 | NWDAcc = WDAcc, | |
249 | NVarAcc = VarAcc. | |
250 | reuse_or_introduce_bool_var(Type, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
251 | Type == normal, | |
252 | !, | |
253 | next_sat_var_name(SatVarName), | |
254 | debug_format_pred("Introduce sat var ~w for pred~n", [SatVarName], Pred), | |
255 | safe_create_texpr(identifier(SatVarName), boolean, [], TUniqueId), | |
256 | add_texpr_infos(TUniqueId, [smt_formula(Pred)], UniqueId), | |
257 | register_predicate(Pred,Pred,Env,UniqueId,NewEnv), | |
258 | safe_create_texpr(equal(UniqueId,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
259 | NWDAcc = WDAcc, | |
260 | NVarAcc = [UniqueId|VarAcc]. | |
261 | reuse_or_introduce_bool_var(Type, WDAcc, VarAcc, Env, Pred, BoolAtom, NewEnv, NWDAcc, BoolFormula, NVarAcc) :- | |
262 | Type == normal_make_wd, | |
263 | !, | |
264 | next_sat_var_name(SatVarName), | |
265 | ensure_wd(Pred, WDPred), | |
266 | collect_toplevel_wd_preds(WDPred, TopLevelWdPred, WDAcc, NWDAcc), | |
267 | debug_format_pred("Introduce sat var ~w for pred~n", [SatVarName], WDPred), | |
268 | safe_create_texpr(identifier(SatVarName), boolean, [], TUniqueId), | |
269 | %find_identifier_uses(Pred, [], UsedIds), | |
270 | ( TopLevelWdPred \= b(truth,_,_) | |
271 | -> add_texpr_infos(TUniqueId, [smt_formula(WDPred),contains_top_level_wd_condition(TopLevelWdPred,Pred)], UniqueId) | |
272 | ; add_texpr_infos(TUniqueId, [smt_formula(WDPred)], UniqueId) | |
273 | ), | |
274 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv), | |
275 | safe_create_texpr(equal(UniqueId,b(BoolAtom,boolean,[])), pred, [], BoolFormula), | |
276 | NVarAcc = [UniqueId|VarAcc]. | |
277 | reuse_or_introduce_bool_var(Type, _, _, _, Pred, _, _, _, _, _) :- | |
278 | Type == only_reuse, | |
279 | 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]). | |
280 | ||
281 | collect_toplevel_wd_preds(b(Node,Type,Info), TopLevelWdPred, WDAcc, NWDAcc) :- | |
282 | collect_toplevel_wd_preds_e(Node, Type, Info, TopLevelWdPred, WDAcc, NWDAcc). | |
283 | ||
284 | collect_toplevel_wd_preds_e(conjunct(A,B), _, Info, A, WDAcc, NWDAcc) :- | |
285 | member(fuzzed_with_wd_po_included, Info), | |
286 | conjunction_to_list(A, WDPOs), | |
287 | create_wd_impls(WDPOs, B, [], WDImpls), | |
288 | add_wd_impls_to_acc(WDImpls, WDAcc, NWDAcc). | |
289 | collect_toplevel_wd_preds_e(Node, _, _, TopLevelWdPred, WDAcc, NWDAcc) :- | |
290 | Node =.. [_,A,B], | |
291 | collect_toplevel_wd_preds(A, TopLevelWdPred1, WDAcc, NWDAcc1), | |
292 | collect_toplevel_wd_preds(B, TopLevelWdPred2, NWDAcc1, NWDAcc), | |
293 | safe_create_texpr(conjunct(TopLevelWdPred1,TopLevelWdPred2), pred, [], TopLevelWdPred). | |
294 | collect_toplevel_wd_preds_e(_, _, _, b(truth,pred,[]), WDAcc, WDAcc). | |
295 | ||
296 | next_sat_var_name(SatVarName) :- | |
297 | retract(sat_var_id(Old)), | |
298 | New is Old + 1, | |
299 | asserta(sat_var_id(New)), | |
300 | number_codes(New, NC), | |
301 | atom_codes(Index, NC), | |
302 | atom_concat('sat', Index, SatVarName). | |
303 | ||
304 | % 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. | |
305 | % We don't use a single implication A => (c1 & c2 & .. & cn) since we have to create a CNF anyway. | |
306 | create_wd_impls([], _, Acc, Acc). | |
307 | create_wd_impls([WDPo|T], Pred, Acc, WDImpls) :- | |
308 | % don't use added info is_wd_po_for_cdclt here | |
309 | NegP = b(negation(Pred),pred,[]), | |
310 | safe_create_texpr(disjunct(NegP,WDPo), pred, [], WDImpl1), | |
311 | safe_create_texpr(disjunct(WDPo,NegP), pred, [], WDImpl2), | |
312 | create_wd_impls(T, Pred, [WDImpl1,WDImpl2|Acc], WDImpls). | |
313 | ||
314 | add_wd_impls_to_acc([], WDAcc, WDAcc). | |
315 | add_wd_impls_to_acc([WDImpl|T], WDAcc, NWDAcc) :- | |
316 | member(WDImpl, WDAcc), | |
317 | !, | |
318 | add_wd_impls_to_acc(T, WDAcc, NWDAcc). | |
319 | add_wd_impls_to_acc([WDImpl|T], WDAcc, NWDAcc) :- | |
320 | add_wd_impls_to_acc(T, [WDImpl|WDAcc], NWDAcc). | |
321 | ||
322 | % managing link from predicates to SAT variables | |
323 | ||
324 | empty_predicate_env(E) :- empty_avl(E). | |
325 | ||
326 | % TO DO: maybe we should also store SatVarName? | |
327 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv) :- | |
328 | ( var(Env) | |
329 | ; \+ is_avl(Env) | |
330 | ), | |
331 | !, | |
332 | add_internal_error('Illegal env:', register_predicate(Pred,WDPred,Env,UniqueId,NewEnv)), | |
333 | NewEnv = Env. | |
334 | register_predicate(Pred,WDPred,Env,UniqueId,NewEnv) :- %print('storing: '), writeq(WDPred),nl, | |
335 | norm_pred_check(Pred, NPred), | |
336 | avl_store(NPred,Env,pred2satvar(WDPred,UniqueId),NewEnv). | |
337 | ||
338 | fetch_predicate(Pred,Env,StoredPred,SatVar) :- (var(Env) ; \+ is_avl(Env)),!, | |
339 | add_internal_error('Illegal env:',fetch_predicate(Pred,Env,StoredPred,SatVar)), fail. | |
340 | fetch_predicate(Pred,Env,StoredPred,SatVar) :- | |
341 | norm_pred_check(Pred, NPred), | |
342 | avl_fetch(NPred,Env,pred2satvar(StoredPred,SatVar)), !. | |
343 | %fetch_predicate(Pred,_,_,_SatVar) :- print('not found: '), print_bexpr(Pred),nl,fail. | |
344 | ||
345 | % --------------- | |
346 | ||
347 | ||
348 | %% sat_to_predicate_from_solution(+SatBindings, +SatVars, -Conjunction). | |
349 | % Create conjunction of SAT bindings using their corresponding SMT formulae | |
350 | % which are stored in the bool variables' information fields. | |
351 | sat_to_predicate_from_solution([], _, b(truth,pred,[])). | |
352 | sat_to_predicate_from_solution([Binding|T], SatVars, Conjunction) :- | |
353 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars), | |
354 | !, | |
355 | sat_to_predicate_from_solution(T, SMT, RestSatVars, Conjunction). | |
356 | sat_to_predicate_from_solution([_|T], SatVars, Conjunction) :- | |
357 | % skip: binding might be a variable if instantiation is not required | |
358 | sat_to_predicate_from_solution(T, SatVars, Conjunction). | |
359 | ||
360 | sat_to_predicate_from_solution([], SmtAcc, _, SmtAcc). | |
361 | sat_to_predicate_from_solution([Binding|T], SmtAcc, SatVars, Conjunction) :- | |
362 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars), | |
363 | !, | |
364 | safe_create_texpr(conjunct(SMT,SmtAcc), pred, [], NewSmtAcc), | |
365 | sat_to_predicate_from_solution(T, NewSmtAcc, RestSatVars, Conjunction). | |
366 | sat_to_predicate_from_solution([_|T], SmtAcc, SatVars, Conjunction) :- | |
367 | sat_to_predicate_from_solution(T, SmtAcc, SatVars, Conjunction). | |
368 | ||
369 | get_var_and_value_from_binding(bind(SatVarName,Value), SatVarName, Value). | |
370 | get_var_and_value_from_binding(binding(SatVarName,Value,_), SatVarName, Value). | |
371 | ||
372 | get_smt_formula_from_binding(Binding, SatVars, SMT, RestSatVars) :- | |
373 | ground(Binding), | |
374 | get_var_and_value_from_binding(Binding, SatVarName, Value), | |
375 | !, | |
376 | select(b(identifier(SatVarName),_,Info), SatVars, RestSatVars), | |
377 | member(smt_formula(TSMT), Info),!, | |
378 | ( Value == pred_true | |
379 | -> SMT = TSMT | |
380 | ; Value == pred_false, | |
381 | TSMT = b(_,_,TSMTInfo), | |
382 | safe_create_texpr(negation(TSMT), pred, TSMTInfo, SMT) | |
383 | ). | |
384 | /*get_smt_formula_from_binding(Binding, _, _, _) :- | |
385 | add_error(get_smt_formula_from_binding, 'SAT binding not ground:', [Binding]), | |
386 | fail.*/ |