1 | % (c) 2019-2024 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_sat_solver, [b_to_cnf_safe/3, | |
6 | create_solver_state/1, | |
7 | sat/3, | |
8 | sat/4, | |
9 | sat/5, | |
10 | restarts/1, | |
11 | is_backjumping/0, | |
12 | announce_bt_from_smt_solution/0, | |
13 | store_idl_unsat_core/1, | |
14 | log_theory_propagation_sat_stack/4, | |
15 | set_variable_references_in_clauses/3, | |
16 | remove_idl_unsat_core/0, | |
17 | unit_propagate_cnf/4, | |
18 | get_bindings_from_ids/6, | |
19 | portray_cnf/1, | |
20 | cnf_to_smt/2, | |
21 | clear_pending_theory_propagations/0, | |
22 | unfixed_deferred_set_error_occurred/0, | |
23 | severe_error_occurred/0, | |
24 | assignment_timeout_occurred/0, | |
25 | log_det_theory_timeout/1, | |
26 | sat_bindings_to_smt_formula/2]). | |
27 | ||
28 | :- meta_predicate asserta_once(0). | |
29 | :- meta_predicate retract_if_exists(0). | |
30 | :- meta_predicate retract_once(0). | |
31 | :- meta_predicate bt_asserta(0). | |
32 | :- meta_predicate bt_retract(0). | |
33 | ||
34 | :- use_module(library(lists)). | |
35 | :- use_module(library(sets), [subtract/3]). | |
36 | :- use_module(library(heaps)). | |
37 | :- use_module(library(ordsets)). | |
38 | :- use_module(library(timeout)). | |
39 | :- use_module(library(samsort)). | |
40 | :- use_module(library(plunit)). | |
41 | ||
42 | :- use_module(smt_solvers_interface(ast_optimizer_for_smt)). | |
43 | :- use_module(cdclt_solver('cdclt_stats')). | |
44 | :- use_module(cdclt_solver('cdclt_pred_to_sat')). | |
45 | :- use_module(cdclt_solver('cdclt_settings')). | |
46 | :- use_module(cdclt_solver('symmetry_check/sat_symmetry_breaking')). | |
47 | :- use_module(probsrc(b_global_sets), [list_contains_unfixed_deferred_set_id/1]). | |
48 | :- use_module(probsrc(bsyntaxtree),[get_texpr_expr/2, | |
49 | find_typed_identifier_uses/3, | |
50 | safe_create_texpr/4, | |
51 | create_texpr/4, | |
52 | disjunct_predicates/2, | |
53 | conjunct_predicates/2, | |
54 | conjunction_to_list/2]). | |
55 | :- use_module(probsrc(debug)). | |
56 | :- use_module(probsrc(preferences), [temporary_set_preference/3, | |
57 | reset_temporary_preference/2]). | |
58 | :- use_module(probsrc(error_manager), [add_internal_error/2, | |
59 | add_error_fail/3, | |
60 | check_error_occured/2, | |
61 | error_occurred_in_error_scope/0]). | |
62 | :- use_module(probsrc(translate), [translate_bexpression/2]). | |
63 | :- use_module(extrasrc(unsat_cores), [unsat_core_with_fixed_conjuncts/3, | |
64 | unsat_chr_core_list_with_auto_time_limit/5]). | |
65 | :- use_module(probsrc(module_information), [module_info/2]). | |
66 | :- use_module(extension('banditfuzz/welldef')). | |
67 | ||
68 | :- use_module(extension('fibonacci_heap/fibonacci_heap')). | |
69 | %:- use_module(probsrc(tools_portability), [exists_source/1]). | |
70 | ||
71 | :- module_info(group, cdclt). | |
72 | :- module_info(description,'This module provides the SAT solver for CDCL(T) implementing CDCL with backjumping and further improvements.'). | |
73 | ||
74 | :- dynamic solver_name/1, backjump_clause/6, backjump_level/1, conflict_stats/3, saved_phase/2, restarts/1, | |
75 | bt_from_smt_solution/0, is_restart/0, exclude_sat_solution_clause/1, total_lbd_sum/1, recent_lbds_dl/2, recent_stack_sizes_dl/2, luby_counter/1, | |
76 | amount_clause_reductions/1, amount_learned_clauses/1, idl_unsat_core/1, pending_theory_prop/2, unfixed_deferred_set_error/0, assignment_count_on_cur_level/1, | |
77 | glue_level/3, glue_clauses/1, allow_partial_model/0, assignment_timeout_occurred/0. | |
78 | ||
79 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
80 | % A sat solver utilising delay declaration to implement watched literals. | |
81 | % Authors: Jacob Howe and Andy King | |
82 | % | |
83 | % Extended for CDCL(T) with first UIP conflict-driven clause learning, | |
84 | % theory propagation, branching heuristics, phase saving for rapid restarts, | |
85 | % learned clause reduction, clause minimization, random restarts, and static SMT symmetry breaking. | |
86 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
87 | ||
88 | % possible improvements: | |
89 | % (- FirstNewCutscheme (cf. https://www.aaai.org/Papers/JAIR/Vol22/JAIR-2210.pdf)) | |
90 | % [] improve implying constraint detection (e.g., :cdclt x > y & gt : {x+1} & y > gt) | |
91 | % -> might be overkill at some point | |
92 | % [] clause minimization (cf. Definition 9, "Towards Understanding and Harnessing the Potential of Clause Learning") | |
93 | % [] check out "Advances in Symmetry Breaking for SAT Modulo Theories" by Dinliwal et al. for static SMT symmetry breaking | |
94 | ||
95 | %:- if(exists_source(library(mutdict))). | |
96 | %:- use_module(library(mutdict)). | |
97 | %:- else. | |
98 | % mutdict throws a segmentation fault in SICStus 4.8.0, don't use it until the bug is fixed | |
99 | :- use_module(library(avl)). | |
100 | mutdict_empty(Dict) :- | |
101 | get_mutable(Avl, Dict), | |
102 | empty_avl(Avl). | |
103 | ||
104 | new_mutdict(Dict) :- | |
105 | empty_avl(Avl), | |
106 | create_mutable(Avl, Dict). | |
107 | ||
108 | mutdict_put(Dict, Key, Value) :- | |
109 | get_mutable(Avl, Dict), | |
110 | avl_store(Key, Avl, Value, NewAvl), | |
111 | update_mutable(NewAvl, Dict). | |
112 | ||
113 | mutdict_get(Dict, Key, Value) :- | |
114 | get_mutable(Avl, Dict), | |
115 | avl_fetch(Key, Avl, Value). | |
116 | ||
117 | mutdict_keys(Dict, Keys) :- | |
118 | get_mutable(Avl, Dict), | |
119 | avl_domain(Avl, Keys). | |
120 | ||
121 | mutdict_update(Dict, Key, OldValue, NewValue) :- | |
122 | get_mutable(Avl, Dict), | |
123 | avl_change(Key, Avl, OldValue, NewAvl, NewValue), | |
124 | update_mutable(NewAvl, Dict). | |
125 | ||
126 | mutdict_delete(Dict, Key) :- | |
127 | get_mutable(Avl, Dict), | |
128 | avl_delete(Key, Avl, _, NewAvl), | |
129 | update_mutable(NewAvl, Dict). | |
130 | ||
131 | mutdict_items(Dict, Items) :- | |
132 | get_mutable(Avl, Dict), | |
133 | avl_to_list(Avl, Items). | |
134 | ||
135 | %mutdict_values(Dict, Values) :- | |
136 | % get_mutable(Avl, Dict), | |
137 | % avl_range(Avl, Values). | |
138 | %:- endif. | |
139 | ||
140 | pretty_print_clause([], []). | |
141 | pretty_print_clause([_-Pol-Var-Name|T], [Pol-Var-Name|NT]) :- | |
142 | pretty_print_clause(T, NT). | |
143 | ||
144 | pretty_print_vars([], []). | |
145 | pretty_print_vars([strip-Var|T], [NVar|NT]) :- | |
146 | !, | |
147 | pretty_print_clause(Var, NVar), | |
148 | pretty_print_vars(T, NT). | |
149 | pretty_print_vars([Var|T], [Var|NT]) :- | |
150 | pretty_print_vars(T, NT). | |
151 | ||
152 | debug_format_sat(_, _) :- | |
153 | print_logs(false), | |
154 | !. | |
155 | debug_format_sat(Msg, Vars) :- | |
156 | append(Msg, " (CDCL(T) SAT Solver)~n", NCodes), | |
157 | atom_codes(NMsg, NCodes), | |
158 | pretty_print_vars(Vars, NVars), | |
159 | format(NMsg, NVars), !. | |
160 | ||
161 | debug_format_sat(_, _, _) :- | |
162 | print_logs(false), | |
163 | !. | |
164 | debug_format_sat(Msg, Vars, Pred) :- | |
165 | format(Msg, Vars), | |
166 | translate:print_bexpr(Pred), nl, !. | |
167 | ||
168 | unfixed_deferred_set_error_occurred :- | |
169 | unfixed_deferred_set_error. | |
170 | ||
171 | assignment_count_on_cur_level(0). | |
172 | ||
173 | reset_assignment_count_on_level :- | |
174 | retract(assignment_count_on_cur_level(Old)), | |
175 | asserta(assignment_count_on_cur_level(0)), | |
176 | ( true | |
177 | ; retract(assignment_count_on_cur_level(_)), | |
178 | asserta(assignment_count_on_cur_level(Old)), | |
179 | fail | |
180 | ). | |
181 | ||
182 | get_next_assignment_count_on_level(NCount) :- | |
183 | retract(assignment_count_on_cur_level(Count)), | |
184 | NCount is Count + 1, | |
185 | asserta(assignment_count_on_cur_level(NCount)), | |
186 | ( true | |
187 | ; retract(assignment_count_on_cur_level(_)), | |
188 | asserta(assignment_count_on_cur_level(Count)), | |
189 | fail | |
190 | ). | |
191 | ||
192 | clear_pending_theory_propagations :- | |
193 | retractall_once(pending_theory_prop(_,_)). | |
194 | ||
195 | % this is just to replay the same order as is propagated to ProB using coroutines | |
196 | plvar_sort(_-(_-_-_-(_,(DLevel1,ACount1),_,_)), _-(_-_-_-(_,(DLevel2,ACount2),_,_))) :- | |
197 | ground(DLevel1), ground(DLevel2), | |
198 | ( DLevel1 < DLevel2 | |
199 | -> true | |
200 | ; DLevel1 == DLevel2 | |
201 | -> ACount1 < ACount2 | |
202 | ; fail | |
203 | ). | |
204 | ||
205 | sat_bindings_to_smt_formula(PlVars, SmtFormula) :- | |
206 | mutdict_items(PlVars, PlItems), | |
207 | samsort(plvar_sort, PlItems, SPlItems), | |
208 | sat_bindings_to_smt_formula_aux(SPlItems, b(truth,pred,[]), SmtFormula). | |
209 | ||
210 | sat_bindings_to_smt_formula_aux([], Acc, Acc). | |
211 | sat_bindings_to_smt_formula_aux([_-(PrologVar-_-TTheoryConstraint-_)|T], Acc, SmtFormula) :- | |
212 | ground(PrologVar), | |
213 | !, | |
214 | get_smt_formula_for_sat_pol(TTheoryConstraint, PrologVar, TheoryConstraint), | |
215 | safe_create_texpr(conjunct(Acc,TheoryConstraint), pred, [], NAcc), | |
216 | sat_bindings_to_smt_formula_aux(T, NAcc, SmtFormula). | |
217 | sat_bindings_to_smt_formula_aux([_|T], Acc, SmtFormula) :- | |
218 | sat_bindings_to_smt_formula_aux(T, Acc, SmtFormula). | |
219 | ||
220 | %% get_bindings_from_ids(+SatVars, -StackBindings, -SatBindings, -SatVarNames, -IdPrologVarTuples, -PrologSatVarTriple). | |
221 | % Given a set of boolean B identifiers. Create a list of bindings containing terms bind/2 | |
222 | % and a list of tuples of B identifier and corresponding Prolog variable used for sat solving. | |
223 | % StackBindings contain the bind/2 terms as well as the StackInfo in order to unify Prolog variables in b_to_cnf_safe/3. | |
224 | get_bindings_from_ids(SatVars, StackBindings, SatBindings, SatVarNames, IdPrologVarTuples, PrologSatVarTriple) :- | |
225 | new_mutdict(EmptyDict), | |
226 | get_bindings_from_ids_acc(SatVars, [], [], [], [], EmptyDict, StackBindings, SatBindings, SatVarNames, IdPrologVarTuples, PrologSatVarTriple), !. | |
227 | ||
228 | get_bindings_from_ids_acc([], AccStackBindings, AccBindings, AccNames, AccTuples, AccPlVars, AccStackBindings, AccBindings, AccNames, AccTuples, AccPlVars). | |
229 | get_bindings_from_ids_acc([b(identifier(Name),IdType,IdInfo)|T], AccStackBindings, AccBindings, AccNames, AccTuples, AccPlVars, StackBindings, SatBindings, SatVarNames, IdPrologVarTuples, PrologSatVarTriple) :- | |
230 | NewAccBindings = [bind(Name,PrologVar)|AccBindings], | |
231 | % we add Prolog variables for stack infos to each var so that we do not have to maintain a genuine stack | |
232 | StackInfo = (_PropType, _Level, _Pol, _OriginalClause), | |
233 | NewAccStackBindings = [bind(Name,PrologVar)-StackInfo|AccStackBindings], | |
234 | NewAccTuples = [(b(identifier(Name),IdType,IdInfo),PrologVar,StackInfo)|AccTuples], | |
235 | !, | |
236 | ( member(smt_formula(SmtFormula), IdInfo) | |
237 | -> mutdict_put(AccPlVars, Name, PrologVar-Name-SmtFormula-StackInfo) | |
238 | ; % plain SAT variable which is not reified with a theory solver, e.g., introduced by CNF optimization rewriting | |
239 | OptEq = b(equal(b(identifier(Name),boolean,[]),b(boolean_true,boolean,[])),pred,[]), | |
240 | mutdict_put(AccPlVars, Name, PrologVar-Name-OptEq-StackInfo) | |
241 | ), | |
242 | get_bindings_from_ids_acc(T, NewAccStackBindings, NewAccBindings, [Name|AccNames], NewAccTuples, AccPlVars, StackBindings, SatBindings, SatVarNames, IdPrologVarTuples, PrologSatVarTriple). | |
243 | get_bindings_from_ids_acc([_|T], AccStackBindings, AccBindings, AccNames, AccTuples, AccPlVars, StackBindings, SatBindings, SatVarNames, IdPrologVarTuples, PrologSatVarTriple) :- | |
244 | get_bindings_from_ids_acc(T, AccStackBindings, AccBindings, AccNames, AccTuples, AccPlVars, StackBindings, SatBindings, SatVarNames, IdPrologVarTuples, PrologSatVarTriple). | |
245 | ||
246 | %% sat(+SolverName, +SolverEnv, +Clauses). | |
247 | % SolverEnv is a list [sat_vars:_, sat_varnames:_, sat_bindings:_, t2b_env:_, pl_vars:_]. | |
248 | % sat_vars are boolean b/3 identifier ASTs for corresponding SAT variables in Clauses. | |
249 | % sat_bindings is a list of terms bind/2 as used by the ProB constraint solver. | |
250 | % t2b_env is the environment mapping SAT variable names and theory formulae used to | |
251 | % translate B predicates to SAT. | |
252 | % pl_vars is a dict of tuples PrologVar-SatVarName-SmtFormula-StackInfo. | |
253 | sat(SolverName, SolverEnv, Clauses) :- | |
254 | debug_format_sat("Start SAT solving with solver ~w ", [SolverName]), | |
255 | init_dynamic_solver_state(SolverName), | |
256 | create_solver_state(StateMutable), | |
257 | get_from_solver_env(SolverEnv, binary_clause_vars, VarsFromBinaryClauses), | |
258 | init_decision_heuristic(StateMutable, VarsFromBinaryClauses, Clauses), | |
259 | sat_stateful_pre(SolverEnv, StateMutable, Clauses). | |
260 | ||
261 | %% sat(+SolverName, +SolverEnv, +StateMutable, +Clauses). | |
262 | sat(SolverName, SolverEnv, StateMutable, Clauses) :- | |
263 | sat(SolverName, SolverEnv, StateMutable, Clauses, []). | |
264 | ||
265 | %% sat(+SolverName, +SolverEnv, +StateMutable, +Clauses, +Options). | |
266 | % Options: | |
267 | % allow_partial_model: only for SMT solving: possibly does not assign all SAT variables, | |
268 | % but the reification with ProB ensures that all coroutines are triggered | |
269 | sat(SolverName, SolverEnv, StateMutable, Clauses, Options) :- | |
270 | debug_format_sat("Start SAT solving with solver ~w ", [SolverName]), | |
271 | init_dynamic_solver_state(SolverName), | |
272 | ( memberchk(allow_partial_model, Options) | |
273 | -> asserta(allow_partial_model) | |
274 | ; true | |
275 | ), | |
276 | get_from_solver_env(SolverEnv, binary_clause_vars, VarsFromBinaryClauses), | |
277 | init_decision_heuristic(StateMutable, VarsFromBinaryClauses, Clauses), | |
278 | sat_stateful_pre(SolverEnv, StateMutable, Clauses). | |
279 | ||
280 | % Wrapper for sat_stateful_restart_cp/3 to enable backjumping to level 0 several times. | |
281 | sat_stateful_pre(SolverEnv, StateMutable, Clauses) :- | |
282 | \+ severe_error_occurred, | |
283 | sat_stateful_restart_cp(SolverEnv, StateMutable, Clauses). | |
284 | ||
285 | sat_stateful_restart_cp(SolverEnv, StateMutable, Clauses) :- | |
286 | ( sat_stateful(SolverEnv, StateMutable, Clauses) | |
287 | ; % we either learned a unit-clause from conflict analysis or randomly restart | |
288 | % in both cases, we learn all asserted backjump clauses | |
289 | retract(backjump_level(0)), | |
290 | ( retract(is_restart) | |
291 | -> debug_format_sat("backjump to level 0 random restart", []), | |
292 | backjump_clause(LearnFromLevel,_,_,_,_,_) | |
293 | ; debug_format_sat("backjump to level 0", []), | |
294 | LearnFromLevel = 0 | |
295 | ), | |
296 | learn_backjump_clause(LearnFromLevel, SolverEnv, StateMutable), | |
297 | sat_stateful_pre(SolverEnv, StateMutable, Clauses) | |
298 | ). | |
299 | ||
300 | %% sat_stateful(+Clauses, +StateMutable, +Clauses). | |
301 | % CDCL with first UIP conflict-driven clause learning, two-watched literals, EVSIDS branching heuristic, | |
302 | % random glucose restarts, and phase saving for rapid restarts. | |
303 | % See create_solver_state/1 for variable StateMutable. | |
304 | sat_stateful(SolverEnv, StateMutable, Clauses) :- | |
305 | problem_setup(SolverEnv, StateMutable, Clauses), | |
306 | %static_sat_symmetry_breaking(Clauses, SolverEnv, CurLevelMut, NewSolverEnv), | |
307 | elim_vars(SolverEnv, StateMutable). | |
308 | ||
309 | %% elim_vars(+SolverEnv, +StateMutable). | |
310 | elim_vars(SolverEnv, StateMutable) :- | |
311 | \+ severe_error_occurred, | |
312 | get_full_state(StateMutable, cur_level, CurLevel), | |
313 | NextLevel is CurLevel + 1, | |
314 | reset_assignment_count_on_level, | |
315 | ( % solution found | |
316 | fibonacci_heap:is_empty | |
317 | -> true | |
318 | ; elim_vars_from_asserted_heuristic_rapid_restart(SolverEnv, StateMutable, NextLevel) | |
319 | ). | |
320 | ||
321 | learn_backjump_clause(CurLevel, SolverEnv, StateMutable) :- | |
322 | retract(backjump_clause(BjLevel, BjClause, _, BjSatVars, UsedVars, AC)), | |
323 | ( CurLevel == BjLevel | |
324 | -> true | |
325 | ; add_error_fail(learn_backjump_clause, 'Inconsistent backjump level: ', [BjLevel,CurLevel]) | |
326 | ), | |
327 | get_from_solver_env(SolverEnv, pl_vars, PlVars), | |
328 | set_variable_references_in_clause(PlVars, BjClause, BjClauseRef), | |
329 | clause_setup(SolverEnv, StateMutable, BjClauseRef), | |
330 | update_heuristic_scores_for_vars(BjSatVars, AC), | |
331 | ( bump_scores_for_bj_clause_only(true) | |
332 | ; % additionally bump scores for all variables used during conflict analysis | |
333 | bump_scores_for_bj_clause_only(false), | |
334 | update_heuristic_scores_for_vars(UsedVars, AC) | |
335 | ), !. | |
336 | ||
337 | possibly_backjump(_, _, _). | |
338 | possibly_backjump(SolverEnv, StateMutable, NextLevel) :- | |
339 | % backjumping to a level other than 0; skip for restart since we then backjump to level 0 | |
340 | \+ is_restart, | |
341 | backjump_level(C), | |
342 | debug_format_sat("Current level is ~w and bj level is ~w", [NextLevel,C]), | |
343 | C == NextLevel, | |
344 | retract(backjump_level(C)), | |
345 | debug_format_sat("~nbackjump branch prop level ~w", [NextLevel]), | |
346 | learn_backjump_clause(C, SolverEnv, StateMutable), | |
347 | possibly_bump_glue_variable_scores(NextLevel), | |
348 | possibly_backjump(SolverEnv, StateMutable, NextLevel). | |
349 | ||
350 | possibly_bump_glue_variable_scores(CurLevel) :- | |
351 | ( ( glue_bumping(true), | |
352 | glue_clauses(GC), | |
353 | GC \== 0 | |
354 | ) | |
355 | -> bump_glue_variable_scores(GC, CurLevel) | |
356 | ; true | |
357 | ). | |
358 | ||
359 | bump_glue_variable_scores(GC, CurLevel) :- | |
360 | ( bt_retract(glue_level(GlueVar,GlueLevel,AlreadyBumped)) | |
361 | -> ( ( \+ AlreadyBumped, | |
362 | GlueLevel > CurLevel | |
363 | ) | |
364 | -> fibonacci_heap:get_priority_of(GlueVar, Score), | |
365 | bump_glue_variable_score(Score, GlueVar, GlueLevel, GC), | |
366 | bump_glue_variable_scores(GC, CurLevel), | |
367 | bt_asserta(glue_level(GlueVar,GlueLevel,true)) | |
368 | ; bump_glue_variable_scores(GC, CurLevel), | |
369 | bt_asserta(glue_level(GlueVar,GlueLevel,AlreadyBumped)) | |
370 | ) | |
371 | ; true | |
372 | ). | |
373 | ||
374 | bump_glue_variable_score(Score, SatVarName, GlueLevel, GC) :- | |
375 | GlueBump is Score * (GlueLevel/GC), | |
376 | NScore is Score + GlueBump, | |
377 | fibonacci_heap:update_bt(SatVarName, NScore). | |
378 | ||
379 | %% elim_vars_from_asserted_heuristic_rapid_restart(+SolverEnv, +StateMutable, +NextLevel). | |
380 | elim_vars_from_asserted_heuristic_rapid_restart(SolverEnv, StateMutable, NextLevel) :- | |
381 | \+ backjump_level(_), | |
382 | \+ idl_unsat_core(_), | |
383 | get_sat_var_with_max_heuristic(SatVarName, MaxScore), | |
384 | get_from_solver_env(SolverEnv, pl_vars, PlVars), | |
385 | mutdict_get(PlVars, SatVarName, Var-SatVarName-_-StackInfo), % we need the variable's references | |
386 | debug_format_sat("Max heuristic value with score ~w is ~w", [MaxScore,SatVarName]), | |
387 | possibly_backjump(SolverEnv, StateMutable, NextLevel), | |
388 | ( saved_phase(SatVarName, SavedPol) | |
389 | -> % restore phase/polarity from cache for rapid restart | |
390 | SelectedPol = SavedPol, | |
391 | retract(saved_phase(SatVarName, _)), % don't undo when backtracking | |
392 | debug_format_sat("Restore phase of ~w", [SatVarName]) | |
393 | ; % uninformed phase/polarity selection: start with truth | |
394 | SelectedPol = pred_true | |
395 | ), | |
396 | elim_var_for_phase(SatVarName, StackInfo, SelectedPol, Var, SolverEnv, StateMutable, NextLevel). | |
397 | ||
398 | %% elim_var_for_phase(+SatVarName, +StackInfo, +SavedPol, +Var, +SolverEnv, +StateMutable, +NextLevel). | |
399 | elim_var_for_phase(SatVarName, StackInfo, SavedPol, Var, SolverEnv, StateMutable, NextLevel) :- | |
400 | ( ground(Var) | |
401 | -> add_error_fail(elim_var_for_phase, 'Decision variable is already ground: probably an error in the decision heuristic.', [SatVarName]) | |
402 | ; true | |
403 | ), | |
404 | update_full_state(StateMutable, cur_level, NextLevel), | |
405 | get_next_assignment_count_on_level(ACount), | |
406 | ( StackInfo = (branch,(NextLevel,ACount),SavedPol,_OriginalClause), | |
407 | bt_log_sat_stack(StateMutable, SatVarName, SavedPol), | |
408 | debug_format_sat("Decide variable ~w with polarity ~w on level ~w", [SatVarName,SavedPol,NextLevel]), | |
409 | log_boolean_decision, | |
410 | Var = SavedPol | |
411 | ; \+ backjump_level(_), | |
412 | \+ severe_error_occurred, | |
413 | negate_polarity(SavedPol, NegSavedPol), | |
414 | StackInfo = (branch,(NextLevel,ACount),NegSavedPol,_OriginalClause), | |
415 | bt_log_sat_stack(StateMutable, SatVarName, NegSavedPol), | |
416 | debug_format_sat("Decide variable ~w with polarity ~w on level ~w", [SatVarName,NegSavedPol,NextLevel]), | |
417 | log_boolean_decision, | |
418 | Var = NegSavedPol | |
419 | ), | |
420 | elim_vars(SolverEnv, StateMutable). | |
421 | ||
422 | %% checkout_sat_variable(+SatVarName, +OriginalClause). | |
423 | % Remove a SAT variable's information if it has been propagated. | |
424 | checkout_sat_variable(SatVarName, OriginalClause) :- | |
425 | delete_from_heuristic(SatVarName), | |
426 | retract_if_exists(saved_phase(SatVarName, _)), | |
427 | ( allow_partial_model | |
428 | -> worsen_scores_for_vars_in_clause(OriginalClause) | |
429 | ; true | |
430 | ). | |
431 | ||
432 | worsen_scores_for_vars_in_clause([]). | |
433 | worsen_scores_for_vars_in_clause([_-_-_-SatVarName|T]) :- | |
434 | ( fibonacci_heap:get_priority_of_silent_fail(SatVarName, Score) | |
435 | -> ( Score > 1, | |
436 | fibonacci_heap:dec_priority_of_bt(SatVarName, 1) | |
437 | ; Score =< 1, | |
438 | fibonacci_heap:delete_elm_bt(SatVarName) | |
439 | ), | |
440 | worsen_scores_for_vars_in_clause(T) | |
441 | ; worsen_scores_for_vars_in_clause(T) | |
442 | ). | |
443 | ||
444 | problem_setup(_, _, []). | |
445 | problem_setup(SolverEnv, StateMutable, [Clause|Clauses]) :- | |
446 | clause_setup(SolverEnv, StateMutable, Clause), | |
447 | problem_setup(SolverEnv, StateMutable, Clauses). | |
448 | ||
449 | clause_setup(SolverEnv, StateMutable, Clause) :- | |
450 | Clause = [StackInfo-Pol-Var-SatVarName|Triples], | |
451 | set_watch(SolverEnv, StateMutable, Clause, Triples, Var, Pol, SatVarName, StackInfo). | |
452 | ||
453 | set_polarity_of_var_explicitly(_, _, [], []). | |
454 | set_polarity_of_var_explicitly(SatVarName, Pol, [CPol-CVar-CName|T], ConflictClause) :- | |
455 | var(CVar), | |
456 | SatVarName == CName, | |
457 | !, | |
458 | ConflictClause = [CPol-Pol-CName|T]. | |
459 | set_polarity_of_var_explicitly(SatVarName, Pol, [Triple|T], [Triple|NT]) :- | |
460 | set_polarity_of_var_explicitly(SatVarName, Pol, T, NT). | |
461 | ||
462 | set_watch(_, _, OriginalClause, [], Var, Pol, SatVarName, _) :- | |
463 | Var == Pol, | |
464 | checkout_sat_variable(SatVarName, OriginalClause). | |
465 | set_watch(SolverEnv, StateMutable, OriginalClause, [], Var, Pol, _, _) :- | |
466 | ground(Var), | |
467 | Var \== Pol, | |
468 | \+ severe_error_occurred, | |
469 | \+ backjump_level(_), | |
470 | debug_format_sat("sat conflict", []), | |
471 | clause_learning(true), | |
472 | possibly_bt_from_smt_solution(SolverEnv,StateMutable, _, _), | |
473 | get_full_state(StateMutable, current_stack_size, StackSize), | |
474 | get_full_state(StateMutable, cur_level, CurLevel), | |
475 | assignment_count_on_cur_level(ACount), | |
476 | ACount \== 1, % at least one unit-propagation for CDCL, otherwise just backtrack to the last decision | |
477 | compute_and_assert_backjump_clause(SolverEnv, StateMutable, StackSize, CurLevel, OriginalClause), | |
478 | fail. | |
479 | set_watch(SolverEnv, StateMutable, OriginalClause, [], Var, Pol, SatVarName, StackInfo) :- | |
480 | var(Var), | |
481 | \+ severe_error_occurred, | |
482 | \+ backjump_level(_), | |
483 | get_full_state(StateMutable, cur_level, CurLevel), | |
484 | debug_format_sat("unit propagation of ~w with polarity ~w on level ~w due to clause ~w", [SatVarName,Pol,CurLevel,strip-OriginalClause]), | |
485 | %translate:print_bexpr(TheoryFormula),nl, | |
486 | get_next_assignment_count_on_level(ACount), | |
487 | StackInfo = (unit,(CurLevel,ACount),Pol,OriginalClause), | |
488 | bt_log_sat_stack(StateMutable, SatVarName, Pol), | |
489 | log_unit_propagation, | |
490 | ( checkout_sat_variable(SatVarName, OriginalClause), | |
491 | Var = Pol, | |
492 | ( true | |
493 | ; % remove idl unsat core from higher decision level when backtracking | |
494 | remove_idl_unsat_core, | |
495 | fail | |
496 | ) | |
497 | ; % theory conflict: if Var = Pol triggered a SAT conflict instead, | |
498 | % a backjump clause has been computed and backjump_level/1 is asserted | |
499 | clause_learning(true), | |
500 | \+ severe_error_occurred, | |
501 | \+ backjump_level(_), % skip when backjumping | |
502 | get_last_decision_level(StateMutable, LastDLevel), % skip if no decision so far | |
503 | LastDLevel > 0, % just backtrack if last decision level is 1 or 0 | |
504 | possibly_bt_from_smt_solution(SolverEnv,StateMutable, SatVarName, Pol), | |
505 | ( learn_idl_core(StateMutable, SolverEnv, SatVarName, Pol) | |
506 | -> true | |
507 | ; debug_format_sat("theory conflict on level ~w", [CurLevel]), | |
508 | get_conflict_clause_for_theory_conflict(SolverEnv, SatVarName, Pol, SolverEnv, TConflictClause), | |
509 | % explicitly set the polarity which failed to be assigned above in line 414 for conflict analysis (possibly part of the unsat core) | |
510 | set_polarity_of_var_explicitly(SatVarName, Pol, TConflictClause, ConflictClause), | |
511 | ( ConflictClause = [SStackInfo-CPol-SingletonVar-SingletonName] | |
512 | -> % singleton theory conflict: backjump to level 0 | |
513 | debug_format_sat("backjump to level 0 after finding singleton theory conflict for SAT variable ~w", [SingletonName]), | |
514 | ( ground(SingletonVar) | |
515 | -> negate_polarity(SingletonVar, NSingletonPol) | |
516 | ; % static WD PO theory contradiction | |
517 | debug_format_sat("Force static theory conflict of WD condition to be false for ~w.", [SingletonName]), | |
518 | NSingletonPol = CPol | |
519 | ), | |
520 | BjClause = [SStackInfo-NSingletonPol-SingletonVar-SingletonName], | |
521 | debug_format_sat("learn unit clause ~w", [strip-BjClause]), | |
522 | BjLevel = 0, | |
523 | compute_lbd_score(BjClause, LbdScore), | |
524 | count_found_conflict(NewTotal, _, _), | |
525 | asserta(backjump_clause(BjLevel, BjClause, LbdScore, [SingletonName], [], NewTotal)), | |
526 | asserta(backjump_level(BjLevel)) | |
527 | ; get_maximum_decision_level(ConflictClause, ConflictLevel), | |
528 | % it can be the case that ProB first recognizes unsatisfiable after grounding waitflags; the last decision level is then not necessarily the conflict level | |
529 | debug_format_sat("theory conflict on level ~w after unsat core computation", [ConflictLevel]), | |
530 | get_full_state(StateMutable, current_stack_size, StackSize), | |
531 | compute_and_assert_backjump_clause_get_level(SolverEnv, StateMutable, StackSize, ConflictLevel, ConflictClause, _BjLevel) | |
532 | ) | |
533 | ), | |
534 | fail | |
535 | ). | |
536 | set_watch(SolverEnv, StateMutable, OriginalClause, [StackInfo2-Pol2-Var2-Name2|Triples], Var1, Pol1, Name1, StackInfo1):- | |
537 | \+ backjump_level(_), | |
538 | watch(SolverEnv, StateMutable, OriginalClause, StackInfo1, Var1, Pol1, Name1, StackInfo2, Var2, Pol2, Name2, Triples). | |
539 | ||
540 | :- block watch(?, ?, ?, ?, -, ?, ?, ?, -, ?, ?, ?). | |
541 | watch(SolverEnv, StateMutable, OriginalClause, StackInfo1, Var1, Pol1, Name1, StackInfo2, Var2, Pol2, Name2, Triples) :- | |
542 | ( nonvar(Var1) | |
543 | -> update_watch(SolverEnv, StateMutable, OriginalClause, StackInfo1, Var1, Pol1, Name1, StackInfo2, Var2, Pol2, Name2, Triples) | |
544 | ; update_watch(SolverEnv, StateMutable, OriginalClause, StackInfo2, Var2, Pol2, Name2, StackInfo1, Var1, Pol1, Name1, Triples) | |
545 | ). | |
546 | ||
547 | update_watch(SolverEnv, StateMutable, OriginalClause, _, Var1, Pol1, Name1, StackInfo2, Var2, Pol2, Name2, Triples) :- | |
548 | ( Var1 == Pol1 | |
549 | -> checkout_sat_variable(Name1, OriginalClause) | |
550 | ; set_watch(SolverEnv, StateMutable, OriginalClause, Triples, Var2, Pol2, Name2, StackInfo2) | |
551 | ). | |
552 | ||
553 | retract_once(Assertion) :- | |
554 | retract(Assertion), | |
555 | !. | |
556 | ||
557 | severe_error_occurred :- | |
558 | error_occurred_in_error_scope, | |
559 | check_error_occured(ErrorName, _), | |
560 | ErrorName \= warning(_), | |
561 | ErrorName \== clpfd_overflow, | |
562 | ErrorName \== smt_symmetry_breaking, | |
563 | ErrorName \== well_definedness_error, | |
564 | ErrorName \== smt_solvers_interface, | |
565 | ErrorName \== internal_error(smt_solvers_interface). | |
566 | ||
567 | %% is_backjumping. | |
568 | is_backjumping :- | |
569 | backjump_level(_). | |
570 | ||
571 | assert_update_pending_theory_propagation(SatVarName, Pol) :- | |
572 | retract(pending_theory_prop(SatVarName,_)), | |
573 | !, | |
574 | asserta(pending_theory_prop(SatVarName,Pol)). | |
575 | assert_update_pending_theory_propagation(SatVarName, Pol) :- | |
576 | asserta(pending_theory_prop(SatVarName,Pol)). | |
577 | ||
578 | % We use a time limit in b_interpreter:b_convert_bool_timeout/7 which is observed here. | |
579 | % It can be the case that ProB/CLP(FD) exceeds the predefined global time limit | |
580 | % when assigning a SAT variable in the deterministic propagation phase (b_convert_bool). | |
581 | % Simply setting a time limit on the SAT variable's unification in the SAT solver is not possible | |
582 | % since CDCL etc. would also be affected by this time limit due to coroutines. | |
583 | :- block log_det_theory_timeout(-). | |
584 | log_det_theory_timeout(TORes) :- | |
585 | ( TORes == time_out | |
586 | -> asserta(assignment_timeout_occurred) | |
587 | ; true | |
588 | ). | |
589 | ||
590 | %% log_theory_propagation_sat_stack(+StateMutable, +SatVarName, +SatPrologVar, +StackInfo). | |
591 | log_theory_propagation_sat_stack(StateMutable, SatVarName, SatPrologVar, StackInfo) :- | |
592 | get_full_state(StateMutable, cur_level, CurLevel), | |
593 | log_theory_propagation, | |
594 | !, | |
595 | debug_format_sat("Theory propagation of ~w with polarity ~w", [SatVarName,SatPrologVar]), | |
596 | ( SatPrologVar == pred_true -> Pol = pred_true; Pol = pred_false), | |
597 | assert_update_pending_theory_propagation(SatVarName, Pol), | |
598 | % explanation (OriginalClause) is computed lazily for conflict analysis if necessary, see explain_theory_propagation/5 | |
599 | get_next_assignment_count_on_level(ACount), | |
600 | StackInfo = (theory,(CurLevel,ACount),Pol,_), | |
601 | bt_log_sat_stack(StateMutable, SatVarName, Pol). | |
602 | ||
603 | %% learn_idl_core(+StateMutable, +SolverEnv, +LastSatVarName, +FailedPol). | |
604 | learn_idl_core(StateMutable, SolverEnv, LastSatVarName, FailedPol) :- | |
605 | retract(idl_unsat_core(Core)), | |
606 | remove_idl_unsat_core, | |
607 | !, | |
608 | get_from_solver_env(SolverEnv, pl_vars, PlVars), | |
609 | get_conflict_clause_from_unsat_core(Core, SolverEnv, TConflictClause), | |
610 | % explicitly assign the polarity which was undone due to the conflict | |
611 | set_polarity_of_var_explicitly(LastSatVarName, FailedPol, TConflictClause, TTConflictClause), | |
612 | set_variable_references_in_clause(PlVars, TTConflictClause, ConflictClause), | |
613 | get_full_state(StateMutable, current_stack_size, StackSize), | |
614 | get_full_state(StateMutable, cur_level, CurLevel), | |
615 | compute_and_assert_backjump_clause(SolverEnv, StateMutable, StackSize, CurLevel, ConflictClause). | |
616 | ||
617 | save_phase(SatVarName, Pol) :- | |
618 | (retract(saved_phase(SatVarName, _)), !; true), | |
619 | asserta(saved_phase(SatVarName, Pol)). | |
620 | ||
621 | % Log variable assignments. | |
622 | % Effect is undone when backtracking. Cache phase when backtracking and unassigning a variable. | |
623 | bt_log_sat_stack(StateMutable, SatVarName, Pol) :- | |
624 | increase_stack_size(StateMutable), | |
625 | ( true | |
626 | ; save_phase(SatVarName, Pol), | |
627 | fail | |
628 | ). | |
629 | ||
630 | increase_stack_size(StateMutable) :- | |
631 | get_full_state(StateMutable, current_stack_size, Old), | |
632 | New is Old + 1, !, | |
633 | update_full_state(StateMutable, current_stack_size, New). | |
634 | ||
635 | %% possibly_bt_from_smt_solution(+SolverEnv,+StateMutable, +SatVarName, +Pol). | |
636 | % Backtracking from an SMT solution which should not be handled as a theory conflict. | |
637 | possibly_bt_from_smt_solution(SolverEnv,StateMutable, SatVarName, Pol) :- | |
638 | retract(bt_from_smt_solution), | |
639 | !, | |
640 | ( ground(SatVarName) | |
641 | -> get_complete_theory_lemma_fixed_binding(SolverEnv, SatVarName, Pol, TheoryLemmaClause) | |
642 | ; get_complete_theory_lemma(SolverEnv, TheoryLemmaClause) | |
643 | ), | |
644 | % backjump to the last decision level without computing a conflict clause | |
645 | % but excluding the last SAT solution when backtracking after finding an SMT solution | |
646 | get_last_decision_level(StateMutable, Level), | |
647 | asserta(exclude_sat_solution_clause(TheoryLemmaClause)), | |
648 | asserta(backjump_level(Level)), | |
649 | fail. | |
650 | possibly_bt_from_smt_solution(_,_, _, _). | |
651 | ||
652 | % Just wrap with negation but prevent double negation. | |
653 | negate_smt_formula(b(negation(Smt),pred,_), NegSmt) :- | |
654 | !, | |
655 | NegSmt = Smt. | |
656 | negate_smt_formula(Smt, b(negation(Smt),pred,[])). | |
657 | ||
658 | % iterate over all Prolog variables to find the propagated literals: usually a stack is used but we store stack infos besides each | |
659 | % variable in the clauses; explanation of theory propagations is rare and maintaining a genuine stack is more expensive | |
660 | get_propagated_sat_vars([], _, []). | |
661 | get_propagated_sat_vars([SatVarName-(_-_-_-(_,(Level,_ACount),Pol,_))|T], TheoryPropLevel, SatVarNameTuples) :- | |
662 | ground(Level), | |
663 | Level < TheoryPropLevel, | |
664 | !, | |
665 | SatVarNameTuples = [(SatVarName-Pol)|NT], | |
666 | get_propagated_sat_vars(T, TheoryPropLevel, NT). | |
667 | get_propagated_sat_vars([_|T], TheoryPropLevel, NT) :- | |
668 | get_propagated_sat_vars(T, TheoryPropLevel, NT). | |
669 | ||
670 | %% explain_theory_propagation(+SolverEnv, +TheoryPropSatVar, +TheoryPropLevel, +TheoryPropPol, -ExplainingClause). | |
671 | explain_theory_propagation(SolverEnv, TheoryPropSatVar, _, _, ExplainingClause) :- | |
672 | minimize_theory_explanations(false), | |
673 | !, | |
674 | debug_format_sat("Use complete lemma for theory explanation of ~w", [TheoryPropSatVar]), | |
675 | get_from_solver_env(SolverEnv, sat_bindings, SatBindings), | |
676 | get_clause_from_ground_bindings(SatBindings, _, _, [], TExplainingClause), | |
677 | get_from_solver_env(SolverEnv, pl_vars, PlVars), | |
678 | set_variable_references_in_clause(PlVars, TExplainingClause, ExplainingClause), | |
679 | debug_format_sat("finished explanation.", []). | |
680 | explain_theory_propagation(SolverEnv, TheoryPropSatVar, TheoryPropLevel, TheoryPropPol, ExplainingClause) :- | |
681 | debug_format_sat("Explain theory propagation of ~w", [TheoryPropSatVar]), | |
682 | get_from_solver_env(SolverEnv, pl_vars, PlVars), | |
683 | mutdict_items(PlVars, PlVarsList), | |
684 | get_propagated_sat_vars(PlVarsList, TheoryPropLevel, SatVarNameTuples), | |
685 | get_from_solver_env(SolverEnv, sat_vars, SatVars), | |
686 | get_smt_formula_from_vars_for_sat_pol(SatVars, TheoryPropSatVar, TheoryPropPol, SmtFormula), | |
687 | negate_smt_formula(SmtFormula, NegSmt), | |
688 | debug_format_sat("Compute unsat core for explanation: ", [], NegSmt), | |
689 | get_explanation_candidate_formula(SatVars, SatVarNameTuples, CandidateFormula), | |
690 | ( SatVarNameTuples = [_] | |
691 | -> safe_create_texpr(conjunct(CandidateFormula,NegSmt), pred, [], UnsatCore) | |
692 | ; temporary_set_preference(time_out, 25, Change1), | |
693 | temporary_set_preference(unsat_core_algorithm, linear, Change2), | |
694 | call_cleanup(unsat_core_with_fixed_conjuncts(CandidateFormula, NegSmt, TTUnsatCore), | |
695 | (reset_temporary_preference(unsat_core_algorithm, Change2), | |
696 | reset_temporary_preference(time_out, Change1))), | |
697 | safe_create_texpr(conjunct(TTUnsatCore,NegSmt), pred, [], TUnsatCore), | |
698 | ( strip_pos_keep_toplevel_conj(TUnsatCore, UnsatCore) | |
699 | -> true | |
700 | ; add_error_fail(strip_pos_keep_toplevel_conj, 'Removing WD POs for CDCL(T) failed for explaining theory propagation.', [unsat_core_with_wd:TUnsatCore]) | |
701 | ) | |
702 | ), | |
703 | get_from_solver_env(SolverEnv, t2b_env, T2BEnv), | |
704 | debug_format_sat("Computed unsat core for explanation: ", [], UnsatCore), | |
705 | ( | |
706 | ( | |
707 | predicate_to_sat(only_reuse, [], SatVars, T2BEnv, UnsatCore, _NewEnv, _, UnsatCoreSat, _NewSatVars), | |
708 | sat_conj_negate_to_clause(UnsatCoreSat, TExplainingClause) | |
709 | ) | |
710 | -> true | |
711 | ; add_error_fail(sat_conj_negate_to_clause, 'Explaining theory propagation failed: Explanation cannot be transformed to SAT.', [unsat_core:UnsatCore]) | |
712 | ), | |
713 | debug_format_sat("finished explanation.", []), | |
714 | set_variable_references_in_clause(PlVars, TExplainingClause, TTExplainingClause), | |
715 | sort(TTExplainingClause, ExplainingClause). | |
716 | ||
717 | get_explanation_candidate_formula(SatVars, [SatVarName-Pol|T], CandidateFormula) :- | |
718 | get_smt_formula_from_vars_for_sat_pol(SatVars, SatVarName, Pol, SmtFormula), | |
719 | !, | |
720 | get_explanation_candidate_formula_acc(SatVars, T, SmtFormula, CandidateFormula). | |
721 | get_explanation_candidate_formula(SatVars, [_|T], CandidateFormula) :- | |
722 | % can be artificial SAT variable introduced by cnf rewriting | |
723 | get_explanation_candidate_formula(SatVars, T, CandidateFormula). | |
724 | ||
725 | get_explanation_candidate_formula_acc(_, [], Acc, Acc). | |
726 | get_explanation_candidate_formula_acc(SatVars, [SatVarName-Pol|T], Acc, CandidateFormula) :- | |
727 | get_smt_formula_from_vars_for_sat_pol(SatVars, SatVarName, Pol, SmtFormula), | |
728 | !, | |
729 | safe_create_texpr(conjunct(SmtFormula,Acc), pred, [], NAcc), | |
730 | get_explanation_candidate_formula_acc(SatVars, T, NAcc, CandidateFormula). | |
731 | get_explanation_candidate_formula_acc(SatVars, [_|T], Acc, CandidateFormula) :- | |
732 | get_explanation_candidate_formula_acc(SatVars, T, Acc, CandidateFormula). | |
733 | ||
734 | get_smt_formula_from_vars_for_sat_pol(SatVars, SatVarName, Pol, SmtFormula) :- | |
735 | memberchk(b(identifier(SatVarName),_,Info), SatVars), | |
736 | member(smt_formula(TSmtFormula), Info), | |
737 | get_smt_formula_for_sat_pol(TSmtFormula, Pol, SmtFormula). | |
738 | ||
739 | get_smt_formula_for_sat_pol(TSmtFormula, Pol, SmtFormula) :- | |
740 | ( Pol == pred_true | |
741 | -> SmtFormula = TSmtFormula | |
742 | ; TSmtFormula = b(negation(SmtFormula),pred,[]) | |
743 | -> true | |
744 | ; TSmtFormula = b(_,_,Info), | |
745 | SmtFormula = b(negation(TSmtFormula),pred,Info) | |
746 | ). | |
747 | ||
748 | %% get_sat_var_with_max_heuristic(-SatVarName, -MaxScore). | |
749 | get_sat_var_with_max_heuristic(SatVarName, MaxScore) :- | |
750 | %\+ fibonacci_heap:is_empty, | |
751 | ( print_logs(true) | |
752 | -> fibonacci_heap:get_max_priority(MaxScore) | |
753 | ; MaxScore = -1 | |
754 | ), | |
755 | fibonacci_heap:get_and_remove_max_value_bt(SatVarName). | |
756 | ||
757 | retract_if_exists(Assertion) :- | |
758 | ( cdclt_sat_solver:Assertion | |
759 | -> retract(cdclt_sat_solver:Assertion) | |
760 | ; true | |
761 | ). | |
762 | ||
763 | % Periodically decay heuristic scores for VSIDS heuristic. | |
764 | % Not undone when backtracking. | |
765 | possibly_decay_heuristic_values :- | |
766 | decision_heuristic(vsids), | |
767 | conflict_stats(total(AC), _, _), | |
768 | AC \== 0, | |
769 | vsids_decay_frequency(I), | |
770 | C is AC mod I, | |
771 | C == 0, | |
772 | debug_format_sat("~nDecay heuristic scores", []), | |
773 | !, | |
774 | vsids_decay_value(Val), | |
775 | decay_heuristic_values(Val). | |
776 | possibly_decay_heuristic_values. | |
777 | ||
778 | %% decay_heuristic_values(+DecayValue). | |
779 | % Not undone when backtracking. | |
780 | decay_heuristic_values(DecayValue) :- | |
781 | Decay is (1/DecayValue), | |
782 | fibonacci_heap:mult_priority_of_all(Decay). | |
783 | ||
784 | %% init_decision_heuristic(+StateMutable, +VarsFromBinaryClauses, +Clauses). | |
785 | % Each variable is initially assigned the number of its occurrences in all clauses as its score. | |
786 | % Variable scores are not split for polarities. | |
787 | init_decision_heuristic(StateMutable, VarsFromBinaryClauses, Clauses) :- | |
788 | count_var_occurrences_in_clauses(Clauses, VarScoreTuples), | |
789 | binary_boost_factor(BoostFactor), | |
790 | add_heuristic_tuples(StateMutable, BoostFactor, VarsFromBinaryClauses, VarScoreTuples). | |
791 | ||
792 | add_heuristic_tuples(_, _, _, []). | |
793 | add_heuristic_tuples(StateMutable, BoostFactor, VarsFromBinaryClauses, [SatVarName-Score|T]) :- | |
794 | ( select(SatVarName, VarsFromBinaryClauses, TVarsFromBinaryClauses) | |
795 | -> NScore is Score * BoostFactor | |
796 | ; NScore = Score, | |
797 | TVarsFromBinaryClauses = VarsFromBinaryClauses | |
798 | ), | |
799 | fibonacci_heap:push(NScore, SatVarName), | |
800 | add_heuristic_tuples(StateMutable, BoostFactor, TVarsFromBinaryClauses, T). | |
801 | ||
802 | count_var_occurrences_in_clauses(Clauses, DictItems) :- | |
803 | new_mutdict(Dict), | |
804 | count_var_occurrences_dict(Dict, Clauses), !, | |
805 | mutdict_items(Dict, DictItems), !. | |
806 | ||
807 | count_var_occurrences_dict(_, []). | |
808 | count_var_occurrences_dict(Dict, [Clause|T]) :- | |
809 | count_var_occurrences_from_clause_dict(Dict, Clause), | |
810 | count_var_occurrences_dict(Dict, T). | |
811 | ||
812 | count_var_occurrences_from_clause_dict(_, []). | |
813 | count_var_occurrences_from_clause_dict(Dict, [_-_-Pol-SatVarName|T]) :- | |
814 | var(Pol), % skip variables that are already propagated by deterministic unit propagation | |
815 | !, | |
816 | ( mutdict_get(Dict, SatVarName, Score) | |
817 | -> Score1 is Score + 1, | |
818 | mutdict_update(Dict, SatVarName, _, Score1) | |
819 | ; mutdict_put(Dict, SatVarName, 1) | |
820 | ), | |
821 | count_var_occurrences_from_clause_dict(Dict, T). | |
822 | count_var_occurrences_from_clause_dict(Dict, [_|T]) :- | |
823 | count_var_occurrences_from_clause_dict(Dict, T). | |
824 | ||
825 | update_heuristic_scores_for_vars(UsedVars, AC) :- | |
826 | decision_heuristic(Type), | |
827 | update_heuristic_scores(AC, Type, UsedVars). | |
828 | ||
829 | %% update_heuristic_scores(+AmountOfConflitsAtLevel, +Type, +SatVarNames). | |
830 | % Type is either vsids, evsids, vmtf or acids. | |
831 | % SatVarNames are the variable names occurring in learned clauses. | |
832 | update_heuristic_scores(_, _, []). | |
833 | update_heuristic_scores(TotalConflicts, Type, [SatVarName|T]) :- | |
834 | ( fibonacci_heap:get_priority_of_silent_fail(SatVarName, OldScore) | |
835 | -> bump_heuristic_score_for_type(Type, TotalConflicts, OldScore, NewScore), | |
836 | fibonacci_heap:update(SatVarName, NewScore), | |
837 | update_heuristic_scores(TotalConflicts, Type, T) | |
838 | ; % SAT variable has already been propagated. | |
839 | % For instance, this is the case when learning a clause on a level greater zero while | |
840 | % a specific SAT variable of this clause has already been propagated on a previous level. | |
841 | update_heuristic_scores(TotalConflicts, Type, T) | |
842 | ). | |
843 | ||
844 | % v_s + 1 | |
845 | bump_heuristic_score_for_type(vsids, _, OldScore, NewScore) :- | |
846 | NewScore is OldScore + 1. | |
847 | % k | |
848 | bump_heuristic_score_for_type(vmtf, TotalConflicts, _, NewScore) :- | |
849 | NewScore is TotalConflicts. | |
850 | % (v_s + k) / 2 | |
851 | bump_heuristic_score_for_type(acids, TotalConflicts, OldScore, NewScore) :- | |
852 | NewScore is (OldScore + TotalConflicts) / 2. | |
853 | % v_s + f^(-k), where f is evsids_f_value/1 and it is/was the k-th conflict when finding this clause via conflict analysis | |
854 | bump_heuristic_score_for_type(evsids, TotalConflicts, OldScore, NewScore) :- | |
855 | evsids_f_value(FVal), | |
856 | catch(NewScore is OldScore + FVal**(-TotalConflicts), error(evaluation_error(float_overflow),_), NewScore = 1.35743634973696E+308). | |
857 | ||
858 | % Literal Block Distance (LBD) as defined in "Predicting Learnt Clauses Quality in Modern SAT Solvers", | |
859 | % i.e., the amount of different decision levels in a clause. | |
860 | compute_lbd_score(BjClause, LbdScore) :- | |
861 | compute_lbd_score(BjClause, [], LbdScore). | |
862 | ||
863 | compute_lbd_score([], Acc, LbdScore) :- | |
864 | length(Acc, LbdScore). | |
865 | compute_lbd_score([(_,(Level,_),_,_)-_-_-_|T], Acc, LbdScore) :- | |
866 | !, | |
867 | ord_add_element(Acc, Level, NewAcc), | |
868 | compute_lbd_score(T, NewAcc, LbdScore). | |
869 | ||
870 | %% count_found_conflict(-NewTotal, -NewSinceRestart, -NewSinceReduction). | |
871 | count_found_conflict(Total1, SRes1, SRed1) :- | |
872 | log_conflict, | |
873 | retract(conflict_stats(total(Total), since_restart(SRes), since_reduction(SRed))), | |
874 | Total1 is Total + 1, | |
875 | SRes1 is SRes + 1, | |
876 | SRed1 is SRed + 1, | |
877 | asserta(conflict_stats(total(Total1), since_restart(SRes1), since_reduction(SRed1))). | |
878 | ||
879 | %% compute_and_assert_backjump_clause(+SolverEnv, +StateMutable, +StackSize, +ConflictClause). | |
880 | compute_and_assert_backjump_clause(SolverEnv, StateMutable, StackSize, ConflictLevel, ConflictClause) :- | |
881 | compute_and_assert_backjump_clause_get_level(SolverEnv, StateMutable, StackSize, ConflictLevel, ConflictClause, _). | |
882 | ||
883 | cnf_to_smt(BoolPred, Smt) :- | |
884 | BoolPred = b(Expr,_,_), | |
885 | cnf_to_smt_e(Expr, Smt). | |
886 | ||
887 | cnf_to_smt_e(falsity, b(falsity,pred,[])). | |
888 | cnf_to_smt_e(truth, b(truth,pred,[])). | |
889 | cnf_to_smt_e(conjunct(A,B), Smt) :- | |
890 | cnf_to_smt(A, NA), | |
891 | cnf_to_smt(B, NB), | |
892 | safe_create_texpr(conjunct(NA,NB), pred, [], Smt). | |
893 | cnf_to_smt_e(disjunct(A,B), Smt) :- | |
894 | cnf_to_smt(A, NA), | |
895 | cnf_to_smt(B, NB), | |
896 | safe_create_texpr(disjunct(NA,NB), pred, [], Smt). | |
897 | cnf_to_smt_e(equal(b(identifier(_),_,Info),b(BoolExpr,boolean,_)), Smt) :- | |
898 | member(smt_formula(TSmt), Info), | |
899 | ( BoolExpr == boolean_true | |
900 | -> Smt = TSmt | |
901 | ; safe_create_texpr(negation(TSmt), pred, [], Smt) | |
902 | ). | |
903 | ||
904 | /*cnf_to_smt([], _, Acc, SmtFromCnf) :- | |
905 | conjunct_predicates(Acc, SmtFromCnf). | |
906 | cnf_to_smt([Clause|T], PrologSatVarTriple, Acc, SmtFromCnf) :- | |
907 | clause_to_smt(PrologSatVarTriple, Clause, SmtClause), | |
908 | cnf_to_smt(T, PrologSatVarTriple, [SmtClause|Acc], SmtFromCnf).*/ | |
909 | ||
910 | %clause_to_smt(PlVars, Clause, SmtFormula) :- | |
911 | % clause_to_smt(PlVars, Clause, [], SmtFormula). | |
912 | % | |
913 | %clause_to_smt(_, [], Acc, SmtFormula) :- | |
914 | % disjunct_predicates(Acc, SmtFormula). | |
915 | %clause_to_smt(PlVars, [_-Pol-_-SatVarName|T], Acc, SmtClause) :- | |
916 | % mutdict_get(PlVars, SatVarName, _-SatVarName-TSmtFormula-_), | |
917 | % !, | |
918 | % get_smt_formula_for_sat_pol(TSmtFormula, Pol, SmtFormula), | |
919 | % clause_to_smt(PlVars, T, [SmtFormula|Acc], SmtClause). | |
920 | %clause_to_smt(_, [_-_-SatVarName|_], _, _) :- | |
921 | % add_error_fail(clause_to_smt, 'Unknown SAT variable.', [SatVarName]). | |
922 | ||
923 | bump_glue_levels([]). | |
924 | bump_glue_levels([_-_-_-SatVarName|T]) :- | |
925 | ( retract(glue_level(SatVarName, GlueLevel,AlreadyBumped)) | |
926 | -> NGlueLevel is GlueLevel + 1 | |
927 | ; NGlueLevel = 1, | |
928 | AlreadyBumped = false | |
929 | ), | |
930 | asserta(glue_level(SatVarName,NGlueLevel,AlreadyBumped)), | |
931 | bump_glue_levels(T). | |
932 | ||
933 | %% compute_and_assert_backjump_clause_get_level(+SolverEnv, +StateMutable, +StackSize, +ConflictLevel, +ConflictClause, -BjLevel). | |
934 | compute_and_assert_backjump_clause_get_level(SolverEnv, StateMutable, StackSize, ConflictLevel, ConflictClause, BjLevel) :- | |
935 | get_last_decision_level(StateMutable, _), | |
936 | %possibly_discard_learned_clauses, % TODO: adapt to new bj clause handling; yet, forgetting clauses has not shown to be beneficial so far | |
937 | debug_format_sat("~nConflict clause is ~w", [strip-ConflictClause]), | |
938 | debug_format_sat("~nStart CDCL..", []), | |
939 | ( ( | |
940 | get_backjump_clause_conflict_resolution(SolverEnv, StateMutable, ConflictLevel, ConflictClause, BjClause, BjLevel, BjSatVars, UsedVars), | |
941 | BjLevel \== -1 | |
942 | ) | |
943 | ; add_error_fail(compute_and_assert_backjump_clause_get_level, 'SMT solver\'s conflict resolution failed', []) | |
944 | ), | |
945 | debug_format_sat("done.", []), | |
946 | debug_format_sat("Backjump clause is ~w", [strip-BjClause]), | |
947 | debug_format_sat("Backjump level is ~w", [BjLevel]), | |
948 | compute_lbd_score(BjClause, LbdScore), | |
949 | debug_format_sat("LBD Score is ~w", [LbdScore]), | |
950 | ( ( glue_bumping(true), | |
951 | LbdScore == 2 | |
952 | ) | |
953 | -> retract(glue_clauses(Old)), | |
954 | New is Old + 1, | |
955 | asserta(glue_clauses(New)), | |
956 | bump_glue_levels(BjClause) | |
957 | ; true | |
958 | ), | |
959 | count_found_conflict(NewTotal, NewSinceRestart, _), | |
960 | asserta(backjump_clause(BjLevel, BjClause, LbdScore, BjSatVars, UsedVars, NewTotal)), | |
961 | asserta(backjump_level(BjLevel)), | |
962 | store_recent_stack_size(StackSize), | |
963 | count_learned_clause, | |
964 | possibly_decay_heuristic_values, | |
965 | ( \+ clear_lbd_values_or_fail(StateMutable), | |
966 | BjLevel \== 0 | |
967 | -> store_recent_lbd_score(LbdScore), | |
968 | update_total_lbd_sum(LbdScore), | |
969 | (random_restart(NewTotal, NewSinceRestart), !; true) | |
970 | ; true | |
971 | ), !. | |
972 | ||
973 | count_learned_clause :- | |
974 | retract(amount_learned_clauses(Old)), | |
975 | New is Old + 1, | |
976 | asserta(amount_learned_clauses(New)). | |
977 | ||
978 | %% store_recent_lbd_score(+LbdScore). | |
979 | % The stored list of recent LBDs is a difference list and we insert at the end of the list. | |
980 | % The first LBD is thus the oldest one and removed when exceeding the maximum size | |
981 | % defined by recent_lbd_threshold/1. | |
982 | store_recent_lbd_score(LbdScore) :- | |
983 | retract(recent_lbds_dl(Lbds-Diff, Amount)), | |
984 | glucose_restart_recent_lbds_threshold(Thresh), | |
985 | Diff = [LbdScore|NDiff], | |
986 | ( Amount < Thresh | |
987 | -> Amount1 is Amount + 1, | |
988 | asserta(recent_lbds_dl(Lbds-NDiff, Amount1)) | |
989 | ; Lbds = [_|RLbds], | |
990 | asserta(recent_lbds_dl(RLbds-NDiff, Amount)) | |
991 | ). | |
992 | ||
993 | store_recent_stack_size(StackSize) :- | |
994 | retract(recent_stack_sizes_dl(StackSizes-Diff, Amount)), | |
995 | glucose_restart_trail_threshold(Thresh), | |
996 | Diff = [StackSize|NDiff], | |
997 | ( Amount < Thresh | |
998 | -> Amount1 is Amount + 1, | |
999 | asserta(recent_stack_sizes_dl(StackSizes-NDiff, Amount1)) | |
1000 | ; StackSizes = [_|RStackSizes], | |
1001 | asserta(recent_stack_sizes_dl(RStackSizes-NDiff, Amount)) | |
1002 | ). | |
1003 | ||
1004 | %% update_total_lbd_sum(+LbdScore). | |
1005 | update_total_lbd_sum(LbdScore) :- | |
1006 | retract(total_lbd_sum(Old)), | |
1007 | New is Old + LbdScore, | |
1008 | asserta(total_lbd_sum(New)). | |
1009 | ||
1010 | %% random_restart(+AmountOfConflicts, +AmountOfConflictsSinceRestart). | |
1011 | % "Randomly" restart after an amount of conflicts since the last restart. | |
1012 | random_restart(_AC, ACR) :- | |
1013 | restart_policy(luby), | |
1014 | random_luby_restart(ACR), !. | |
1015 | random_restart(AC, _ACR) :- | |
1016 | restart_policy(glucose), | |
1017 | random_glucose_restart(AC), !. | |
1018 | ||
1019 | do_random_restart :- | |
1020 | log_restart, | |
1021 | retract(restarts(OldR)), | |
1022 | NewR is OldR + 1, | |
1023 | asserta(restarts(NewR)), | |
1024 | retract(backjump_level(_)), | |
1025 | asserta(backjump_level(0)), | |
1026 | retract(conflict_stats(total(Total), _, since_reduction(SRed))), | |
1027 | asserta(conflict_stats(total(Total), since_restart(0), since_reduction(SRed))), | |
1028 | asserta_once(is_restart), | |
1029 | debug_format_sat("~nRandom restart", []). | |
1030 | ||
1031 | %% random_glucose_restart(+AmountOfConflicts). | |
1032 | % Restart search if recent_lbds_dl/2 contains exactly glucose_restart_recent_lbds_threshold/1 amount | |
1033 | % of most recent LBDs and RecentAvg * Proportion > TotalAvg is satisfied, i.e., the recently learned clauses' | |
1034 | % LBDs got too large. | |
1035 | random_glucose_restart(AC) :- | |
1036 | total_lbd_sum(TotalLbdSum), | |
1037 | TotalAvg is TotalLbdSum / AC, | |
1038 | recent_lbds_dl(RLbds-[], LbdAmount), | |
1039 | glucose_restart_recent_lbds_threshold(LbdThresh), | |
1040 | LbdAmount == LbdThresh, % queue of recent LBDs is full | |
1041 | sumlist(RLbds, RSum), | |
1042 | RecentAvg is RSum / LbdAmount, | |
1043 | glucose_restart_margin_ratio(Proportion), | |
1044 | debug_format_sat("~nTotalAvg: ~w~nRecentAvg: ~w", [TotalAvg,RecentAvg]), | |
1045 | ( RecentAvg * Proportion > TotalAvg | |
1046 | -> do_random_restart, | |
1047 | clear_recent_lbds_state | |
1048 | ; true | |
1049 | ). | |
1050 | ||
1051 | % Favor SAT instances too by possibly clearing the recent LBD queue. | |
1052 | % Assumption: The queue of recent LBDs is full. | |
1053 | clear_lbd_values_or_fail(StateMutable) :- | |
1054 | glucose_restart_trail_threshold(TrailThresh), | |
1055 | glucose_restart_stack_avg_factor(StackSizeFactor), | |
1056 | recent_stack_sizes_dl(StackSizes-[], AmountStackSizes), | |
1057 | AmountStackSizes == TrailThresh, % queue of recent stack sizes on conflict is full | |
1058 | get_full_state(StateMutable, current_stack_size, StackSize), | |
1059 | sumlist(StackSizes, SSum), | |
1060 | StackSizesAvg is SSum / AmountStackSizes, | |
1061 | StackSize > StackSizeFactor * StackSizesAvg, | |
1062 | clear_recent_lbds_state. | |
1063 | ||
1064 | clear_recent_lbds_state :- | |
1065 | retract(recent_lbds_dl(_, _)), | |
1066 | asserta(recent_lbds_dl(Diff-Diff, 0)). | |
1067 | ||
1068 | %% random_luby_restart(+AmountOfConflictsSinceRestart). | |
1069 | % The amount of conflicts when to restart is defined by the Luby sequence, | |
1070 | % i.e., 1,1,2,1,1,2,4,1,1,2,1,1,2,4,8,.. etc., (cf. "Optimal speedup of Las Vegas algorithms") | |
1071 | % using a unit length of 32 (see luby_counter/1). | |
1072 | random_luby_restart(ACR) :- | |
1073 | restart_policy(luby), | |
1074 | get_next_luby_value(Luby), | |
1075 | !, | |
1076 | ( ACR == Luby | |
1077 | -> retract_once(luby_counter(_)), | |
1078 | do_random_restart | |
1079 | ; true | |
1080 | ). | |
1081 | random_luby_restart(_) :- | |
1082 | add_error_fail(random_restart, 'No more values in predefined Luby sequence', []). | |
1083 | ||
1084 | get_next_luby_value(LubyValue) :- | |
1085 | luby_counter(Luby), | |
1086 | luby_restart_unit_length(UnitLength), | |
1087 | LubyValue is UnitLength * Luby, | |
1088 | !. | |
1089 | ||
1090 | %% get_sat_solution_exclusion_clauses(+PlVars, -ExclClausesNoRef). | |
1091 | % We exclude SAT solutions when backtracking from finding an SMT solution to find a different assignment. | |
1092 | /*get_sat_solution_exclusion_clauses(PlVars, ExclClausesNoRef) :- | |
1093 | findall(ExclClause, | |
1094 | (exclude_sat_solution_clause(TExclClause), set_variable_references_in_clause(PlVars, TExclClause, ExclClause)), | |
1095 | ExclClausesNoRef), !.*/ | |
1096 | ||
1097 | %% set_variable_references_in_clauses(+PlVars, +Clauses, -RefClauses). | |
1098 | set_variable_references_in_clauses(_, [], []). | |
1099 | set_variable_references_in_clauses(PlVars, [Clause|T], [RefClause|NT]) :- | |
1100 | set_variable_references_in_clause(PlVars, Clause, RefClause), | |
1101 | set_variable_references_in_clauses(PlVars, T, NT). | |
1102 | ||
1103 | %% set_variable_references_in_clause(+PlVars, +Clause, -RefClauses). | |
1104 | % We need to set the correct variable references in a new learned clause | |
1105 | % to trigger co-routines etc. | |
1106 | set_variable_references_in_clause(_, [], Out) :- !, Out = []. | |
1107 | set_variable_references_in_clause(PlVars, [_-Pol-_-Name|T], [StackInfo-Pol-Var-Name|NT]) :- | |
1108 | mutdict_get(PlVars, Name, TVar-Name-_-TStackInfo), | |
1109 | !, | |
1110 | Var = TVar, | |
1111 | StackInfo = TStackInfo, | |
1112 | set_variable_references_in_clause(PlVars, T, NT). | |
1113 | set_variable_references_in_clause(_, [_-_-_-Name|_], _) :- | |
1114 | add_error_fail(set_variable_references_in_clause, 'Cannot set references: unknown SAT variable.', [Name]). | |
1115 | ||
1116 | get_from_solver_env(SolverEnv, Key, OutValue) :- | |
1117 | get_from_solver_env_ordered(Key, SolverEnv, Value), | |
1118 | !, | |
1119 | OutValue = Value. | |
1120 | get_from_solver_env(SolverEnv, Key, _) :- | |
1121 | add_error_fail(get_from_solver_env, | |
1122 | 'Wrong key or corrupt solver environment in CDCL(T) SAT solver', | |
1123 | [solver_env:SolverEnv,key:Key]). | |
1124 | ||
1125 | get_from_solver_env_ordered(sat_vars, [sat_vars:SatVars,_,_,_,_,_], SatVars). | |
1126 | get_from_solver_env_ordered(sat_varnames, [_,sat_varnames:SatVarNames,_,_,_,_], SatVarNames). | |
1127 | get_from_solver_env_ordered(sat_bindings, [_,_,sat_bindings:SatBindings,_,_,_], SatBindings). | |
1128 | get_from_solver_env_ordered(t2b_env, [_,_,_,t2b_env:Env,_,_], Env). | |
1129 | get_from_solver_env_ordered(pl_vars, [_,_,_,_,pl_vars:PlVars,_], PlVars). | |
1130 | get_from_solver_env_ordered(binary_clause_vars, [_,_,_,_,_,binary_clause_vars:VarsFromBinaryClauses], VarsFromBinaryClauses). | |
1131 | ||
1132 | bt_asserta(Assertion) :- | |
1133 | asserta(Assertion); (retract(Assertion), !, fail). | |
1134 | ||
1135 | bt_retract(Assertion) :- | |
1136 | ( retract(Assertion) | |
1137 | -> ( true | |
1138 | ; asserta(Assertion), | |
1139 | !, | |
1140 | fail | |
1141 | ) | |
1142 | ; fail | |
1143 | ). | |
1144 | ||
1145 | %% get_unsat_core_from_smt_formula(+FullFormula, +LastVarName, -UnsatCore). | |
1146 | % Assumption: unsat core computation only removes constraints and does not deduce new ones. | |
1147 | % Fails if +FullFormula is satisfiable. | |
1148 | get_unsat_core_from_smt_formula(FullFormula, LastVarName, UnsatCore) :- | |
1149 | debug_format_sat("Compute unsat core for: ", [], FullFormula), | |
1150 | preferences:temporary_set_preference(time_out, 25, Change), | |
1151 | call_cleanup(time_out(unsat_chr_core_list_with_auto_time_limit(FullFormula, 30000, | |
1152 | [auto_time_out_factor(180), % we add 80 % | |
1153 | ignore_if_sol_found, | |
1154 | inspect_quantifiers(false)], GlobalRes, CoreList), 30000, TimeoutResult), | |
1155 | reset_temporary_preference(time_out, Change)), | |
1156 | !, | |
1157 | ( GlobalRes = solution(_) | |
1158 | -> % the present theory conflict only occurs within the current state of ProB's waitflag store; there is at least one choice point | |
1159 | % in the theory solver which needs to be evaluated; we thus do not learn from this "spurious counterexample" but | |
1160 | % trigger chronological backtracking instead of backjumping | |
1161 | debug_format_sat("Spurious counterexample found. Skip backjumping and use chronological backtracking instead.", []), | |
1162 | fail | |
1163 | ; GlobalRes == time_out | |
1164 | -> % ignore core if global result is timeout | |
1165 | TUnsatCore = FullFormula | |
1166 | ; TimeoutResult == time_out | |
1167 | -> % don't waste too much time in unsat core computation | |
1168 | debug_format_sat("Canceled unsat core computation due to exceeding a timeout" ,[]), | |
1169 | TUnsatCore = FullFormula | |
1170 | ; ( CoreList == [] | |
1171 | -> add_error_fail(get_conflict_clause_for_theory_conflict, 'Conflict clause in SMT solving is not a conflict.', [LastVarName]) | |
1172 | ; conjunct_predicates(CoreList, TUnsatCore) | |
1173 | ) | |
1174 | ), | |
1175 | debug_format_sat("Computed unsat core with added WD POs: ", [], TUnsatCore), | |
1176 | ( strip_pos_keep_toplevel_conj(TUnsatCore, UnsatCore) | |
1177 | -> true | |
1178 | ; add_error_fail(strip_pos_keep_toplevel_conj, 'Removing WD POs for CDCL(T) failed.', [unsat_core_with_wd:TUnsatCore]) | |
1179 | ), | |
1180 | debug_format_sat("Computed unsat core: ", [], UnsatCore). | |
1181 | ||
1182 | %% get_conflict_clause_for_theory_conflict(+LastVarName, +LastVarValue, +SolverEnv, -ConflictClause). | |
1183 | % Translate current sat solution, which is a theory conflict, to the theory and compute | |
1184 | % the (minimum) unsat core. Return the negated theory conflict as a conflict clause. | |
1185 | % Note that an SMT formula passed to the theory solver is always a conjunction and | |
1186 | % thus the negated unsat core is a disjunction (clause). | |
1187 | get_conflict_clause_for_theory_conflict(SolverEnv, LastVarName, LastVarValue, SolverEnv, ConflictClause) :- | |
1188 | ( retract(idl_unsat_core(UnsatCore)) | |
1189 | -> true | |
1190 | ; get_from_solver_env(SolverEnv, sat_bindings, SatBindingsNoLast), | |
1191 | get_from_solver_env(SolverEnv, sat_vars, SatVars), | |
1192 | sat_to_predicate_from_solution(SatBindingsNoLast, SatVars, SmtFormulaNoLast), | |
1193 | findall(bind(PendingName,PendingPol), pending_theory_prop(PendingName,PendingPol), PendingTheoryProps), | |
1194 | sat_to_predicate_from_solution([bind(LastVarName,LastVarValue)|PendingTheoryProps], SatVars, FixedConj), | |
1195 | safe_create_texpr(conjunct(FixedConj,SmtFormulaNoLast), pred, [] , FullFormula), | |
1196 | get_unsat_core_from_smt_formula(FullFormula, LastVarName, UnsatCore) | |
1197 | ), !, | |
1198 | find_typed_identifier_uses(UnsatCore, [], UsedIds), | |
1199 | ( list_contains_unfixed_deferred_set_id(UsedIds) | |
1200 | -> asserta(unfixed_deferred_set_error) | |
1201 | ; true | |
1202 | ), | |
1203 | get_conflict_clause_from_unsat_core(UnsatCore, SolverEnv, TConflictClause), | |
1204 | sort(TConflictClause, TTConflictClause), % there can be duplicates due to added top-level WD POs; important to remove | |
1205 | ( TTConflictClause = [_] | |
1206 | -> % currently undiscovered static theory contradiction; SAT variable might not be propagated yet if added WD PO | |
1207 | ConflictClause = TTConflictClause | |
1208 | ; % remove not propagated top-level WD POs; we enforce WD POs in the theory solver but it can | |
1209 | % be the case that a theory conflict occurs before the WD POs are propagated in the SAT solver | |
1210 | remove_not_propagated(TTConflictClause, LastVarName, ConflictClause) | |
1211 | ), | |
1212 | !. | |
1213 | ||
1214 | remove_not_propagated([], _, []). | |
1215 | remove_not_propagated([Pol-Var-Name|T], LastVarName, [Pol-Var-Name|NT]) :- | |
1216 | ( ground(Var) | |
1217 | ; Name == LastVarName | |
1218 | ), | |
1219 | !, | |
1220 | remove_not_propagated(T, LastVarName, NT). | |
1221 | remove_not_propagated([_-_-Name|T], LastVarName, NT) :- | |
1222 | debug_format_sat("Remove not propagated SAT variable ~w from conflict clause.", [Name]), | |
1223 | remove_not_propagated(T, LastVarName, NT). | |
1224 | ||
1225 | %% get_conflict_clause_from_unsat_core(+UnsatCore, +SolverEnv, -ConflictClause). | |
1226 | get_conflict_clause_from_unsat_core(UnsatCore, SolverEnv, ConflictClause) :- | |
1227 | get_from_solver_env(SolverEnv, sat_vars, SatVars), | |
1228 | get_from_solver_env(SolverEnv, t2b_env, T2BEnv), | |
1229 | get_from_solver_env(SolverEnv, pl_vars, PlVars), | |
1230 | predicate_to_sat(only_reuse, [], SatVars, T2BEnv, UnsatCore, _NewEnv, _, UnsatCoreSat, _NewSatVars), | |
1231 | sat_conj_negate_to_clause(UnsatCoreSat, TConflictClause), | |
1232 | set_variable_references_in_clause(PlVars, TConflictClause, ConflictClause), | |
1233 | !. | |
1234 | get_conflict_clause_from_unsat_core(_, _, _) :- | |
1235 | add_error_fail(get_conflict_clause_from_unsat_core, 'Unsat core to conflict clause failed.', []). | |
1236 | ||
1237 | %% get_complete_theory_lemma(+SolverEnv, -TheoryLemmaClause) :- | |
1238 | % Return the complete unsatisfiable SMT formula as a conflict clause. | |
1239 | get_complete_theory_lemma(SolverEnv, TheoryLemmaClause) :- | |
1240 | get_complete_theory_lemma_fixed_binding(SolverEnv, _, _, TheoryLemmaClause). | |
1241 | ||
1242 | %% get_complete_theory_lemma_fixed_binding(+SolverEnv, +SatVarName, +SatVarPol, -TheoryLemmaClause). | |
1243 | % Enforce +SatVarName to have +SatVarPol binding. This is important for theory conflicts since the last | |
1244 | % binding has been undone when backtracking. This is not applied if both inputs are variables, e.g., for SAT conflicts. | |
1245 | get_complete_theory_lemma_fixed_binding(SolverEnv, SatVarName, SatVarPol, TheoryLemmaClause) :- | |
1246 | get_from_solver_env(SolverEnv, pl_vars, PlVars), | |
1247 | get_from_solver_env(SolverEnv, sat_bindings, SatBindings), | |
1248 | get_clause_from_negated_ground_bindings(SatBindings, SatVarName, SatVarPol, TTheoryLemmaClause), | |
1249 | set_variable_references_in_clause(PlVars, TTheoryLemmaClause, TheoryLemmaClause), !. | |
1250 | ||
1251 | %% get_clause_from_negated_ground_bindings(+SatBindings, +FSatVarName, +FSatVarPol, -TheoryLemmaClause) :- | |
1252 | % FSatVarName: name of SAT variable whose binding should be set to +FSatVarPol | |
1253 | get_clause_from_negated_ground_bindings(SatBindings, FSatVarName, FSatVarPol, TheoryLemmaClause) :- | |
1254 | get_clause_from_negated_ground_bindings(SatBindings, FSatVarName, FSatVarPol, [], TheoryLemmaClause). | |
1255 | ||
1256 | get_clause_from_negated_ground_bindings([], _, _, Acc, Acc). | |
1257 | get_clause_from_negated_ground_bindings([bind(SatVarName,_)|T], FSatVarName, FSatVarPol, Acc, TheoryLemmaClause) :- | |
1258 | % theory propagations during grounding are possibly undone in the stack if finding a contradiction during grounding waitflags | |
1259 | % we restore such pending theory propagations here | |
1260 | pending_theory_prop(SatVarName, SatVarPol), | |
1261 | !, | |
1262 | negate_polarity(SatVarPol, NegPol), | |
1263 | get_clause_from_negated_ground_bindings(T, FSatVarName, FSatVarPol, [_-NegPol-_-SatVarName|Acc], TheoryLemmaClause). | |
1264 | get_clause_from_negated_ground_bindings([bind(SatVarName,_)|T], FSatVarName, FSatVarPol, Acc, TheoryLemmaClause) :- | |
1265 | % set fixed polarity | |
1266 | SatVarName == FSatVarName, | |
1267 | !, | |
1268 | negate_polarity(FSatVarPol, NegPol), | |
1269 | get_clause_from_negated_ground_bindings(T, FSatVarName, FSatVarPol, [_-NegPol-_-SatVarName|Acc], TheoryLemmaClause). | |
1270 | get_clause_from_negated_ground_bindings([bind(SatVarName,Pol)|T], FSatVarName, FSatVarPol, Acc, TheoryLemmaClause) :- | |
1271 | ground(Pol), | |
1272 | !, | |
1273 | negate_polarity(Pol, NegPol), | |
1274 | get_clause_from_negated_ground_bindings(T, FSatVarName, FSatVarPol, [_-NegPol-_-SatVarName|Acc], TheoryLemmaClause). | |
1275 | get_clause_from_negated_ground_bindings([_|T], FSatVarName, FSatVarPol, Acc, TheoryLemmaClause) :- | |
1276 | get_clause_from_negated_ground_bindings(T, FSatVarName, FSatVarPol, Acc, TheoryLemmaClause). | |
1277 | ||
1278 | get_clause_from_ground_bindings([], _, _, Acc, Acc). | |
1279 | get_clause_from_ground_bindings([bind(SatVarName,_)|T], FSatVarName, FSatVarPol, Acc, TheoryLemmaClause) :- | |
1280 | % theory propagations during grounding are possibly undone in the stack if finding a contradiction during grounding waitflags | |
1281 | % we restore such pending theory propagations here | |
1282 | pending_theory_prop(SatVarName, SatVarPol), | |
1283 | !, | |
1284 | get_clause_from_ground_bindings(T, FSatVarName, FSatVarPol, [_-SatVarPol-_-SatVarName|Acc], TheoryLemmaClause). | |
1285 | get_clause_from_ground_bindings([bind(SatVarName,Pol)|T], FSatVarName, FSatVarPol, Acc, TheoryLemmaClause) :- | |
1286 | ground(Pol), | |
1287 | !, | |
1288 | get_clause_from_ground_bindings(T, FSatVarName, FSatVarPol, [_-Pol-_-SatVarName|Acc], TheoryLemmaClause). | |
1289 | get_clause_from_ground_bindings([_|T], FSatVarName, FSatVarPol, Acc, TheoryLemmaClause) :- | |
1290 | get_clause_from_ground_bindings(T, FSatVarName, FSatVarPol, Acc, TheoryLemmaClause). | |
1291 | ||
1292 | % Fail if no decision has been made so far, i.e., the decision level is set to -1. | |
1293 | get_last_decision_level(StateMutable, Level) :- | |
1294 | get_full_state(StateMutable, cur_level, TLevel), | |
1295 | TLevel > 0, | |
1296 | !, | |
1297 | Level = TLevel. | |
1298 | ||
1299 | %negate_polarities([], []). | |
1300 | %negate_polarities([StackInfo-Pol-Var-Name|T], [StackInfo-NPol-Var-Name|NT]) :- | |
1301 | % negate_polarity(Pol, NPol), | |
1302 | % negate_polarities(T, NT). | |
1303 | ||
1304 | get_maximum_decision_level([(_,(Level,_),_,_)-_-_-_|T], ConflictLevel) :- | |
1305 | !, | |
1306 | get_maximum_decision_level(T, Level, ConflictLevel). | |
1307 | get_maximum_decision_level([_-_-_-Name|_], _) :- | |
1308 | add_error_fail(get_maximum_decision_level, 'The SAT variable has not been decided yet', [Name]). | |
1309 | ||
1310 | get_maximum_decision_level([], Acc, Acc). | |
1311 | get_maximum_decision_level([(_,(Level,_),_,_)-_-_-_|T], Acc, ConflictLevel) :- | |
1312 | !, | |
1313 | ( Level > Acc | |
1314 | -> NAcc = Level | |
1315 | ; NAcc = Acc | |
1316 | ), | |
1317 | get_maximum_decision_level(T, NAcc, ConflictLevel). | |
1318 | get_maximum_decision_level([_-_-_-Name|_], _, _) :- | |
1319 | add_error_fail(get_maximum_decision_level, 'The SAT variable has not been decided yet', [Name]). | |
1320 | ||
1321 | get_maximum_decision_level_other_than_current([_], _, _, BjLevel) :- | |
1322 | % zero if learning a unit clause | |
1323 | !, | |
1324 | BjLevel = 0. | |
1325 | get_maximum_decision_level_other_than_current(BjClause, BjLevelAcc, CurLevel, BjLevel) :- | |
1326 | get_maximum_decision_level_other_than_current_not_unit(BjClause, BjLevelAcc, CurLevel, BjLevel). | |
1327 | ||
1328 | get_maximum_decision_level_other_than_current_not_unit([], BjLevelAcc, _, BjLevelAcc). | |
1329 | get_maximum_decision_level_other_than_current_not_unit([(_,(Level,_),_,_)-_-_-_|T], BjLevelAcc, CurLevel, BjLevel) :- | |
1330 | ( (Level \== CurLevel, | |
1331 | Level > BjLevelAcc | |
1332 | ) | |
1333 | -> NBjLevelAcc = Level | |
1334 | ; NBjLevelAcc = BjLevelAcc | |
1335 | ), | |
1336 | get_maximum_decision_level_other_than_current_not_unit(T, NBjLevelAcc, CurLevel, BjLevel). | |
1337 | ||
1338 | %% get_antecedent_assignments(+SolverEnv, +ConflictDLevel, +SatVarName, +RPol, +RPropType, +ROriginalClause, -Antecedent). | |
1339 | get_antecedent_assignments(_, _, SatVarName, _, _, ROriginalClause, Antecedent) :- | |
1340 | is_list(ROriginalClause), | |
1341 | !, | |
1342 | select(_-_-_-SatVarName, ROriginalClause, TAntecedent), !, | |
1343 | Antecedent = TAntecedent. | |
1344 | get_antecedent_assignments(SolverEnv, ConflictDLevel, SatVarName, RPol, theory, ROriginalClause, Antecedent) :- | |
1345 | \+ is_list(ROriginalClause), | |
1346 | !, | |
1347 | explain_theory_propagation(SolverEnv, SatVarName, ConflictDLevel, RPol, OriginalClause), | |
1348 | ROriginalClause = OriginalClause, | |
1349 | select(_-_-_-SatVarName, OriginalClause, TAntecedent), !, | |
1350 | Antecedent = TAntecedent. | |
1351 | get_antecedent_assignments(_, _, SatVarName, _, _, _, _) :- | |
1352 | add_error_fail(get_antecedent_assignments, 'No antecedent assignments since variable has not been propagated.', SatVarName). | |
1353 | ||
1354 | %% join_assignments(+A1, +A2, +A2Full, -Joined). | |
1355 | join_assignments([], _, A, A). | |
1356 | join_assignments([StackInfo-Pol-Var-Name|T], A2, A3, Res) :- | |
1357 | ( select(_-_-_-Name, A2, A4) % removes dups assuming that A2 has no dups | |
1358 | -> join_assignments(T, A4, A3, Res) | |
1359 | ; join_assignments(T, A2, [StackInfo-Pol-Var-Name|A3], Res) | |
1360 | ). | |
1361 | ||
1362 | %% resolve(+SolverEnv, +TBjClause, +Resolver, +ROriginalClause, -NTBjClause). | |
1363 | % +Resolver is a SAT variable name to resolve next (i.e., expand its antecedent assignments). | |
1364 | resolve(SolverEnv, TBjClause, ConflictDLevel, Resolver, RPol, RPropType, ROriginalClause, NTBjClause) :- | |
1365 | get_antecedent_assignments(SolverEnv, ConflictDLevel, Resolver, RPol, RPropType, ROriginalClause, Antecedent), | |
1366 | join_assignments(Antecedent, TBjClause, TBjClause, TNTBjClause), % important to not have duplicates | |
1367 | select(_-_-_-Resolver, TNTBjClause, NTBjClause). | |
1368 | ||
1369 | add_used_vars_to_mutdict([], _). | |
1370 | add_used_vars_to_mutdict([_-_-_-SatVarName|T], VarNamesDict) :- | |
1371 | \+ mutdict_get(VarNamesDict, SatVarName, _), | |
1372 | !, | |
1373 | mutdict_put(VarNamesDict, SatVarName, SatVarName), | |
1374 | add_used_vars_to_mutdict(T, VarNamesDict). | |
1375 | add_used_vars_to_mutdict([_|T], VarNamesDict) :- | |
1376 | add_used_vars_to_mutdict(T, VarNamesDict). | |
1377 | ||
1378 | get_variables_used_in_cdcl(ResolvedSoFar, BjClause, UsedVars) :- | |
1379 | add_used_vars_to_mutdict(BjClause, ResolvedSoFar), | |
1380 | mutdict_keys(ResolvedSoFar, UsedVars). | |
1381 | ||
1382 | get_variable_names_in_clause([], []). | |
1383 | get_variable_names_in_clause([_-_-_-SatVarName|T], [SatVarName|NT]) :- | |
1384 | get_variable_names_in_clause(T, NT). | |
1385 | ||
1386 | % sort in reversed stack order | |
1387 | reversed_stack_sort((_,(DLevel1,ACount1),_,_)-_-_-_, (_,(DLevel2,ACount2),_,_)-_-_-_) :- | |
1388 | ground(DLevel1), ground(DLevel2), | |
1389 | ( DLevel1 > DLevel2 | |
1390 | -> true | |
1391 | ; DLevel1 == DLevel2 | |
1392 | -> ACount1 > ACount2 | |
1393 | ; fail | |
1394 | ). | |
1395 | ||
1396 | :- dynamic part_of_first_uip/1. | |
1397 | ||
1398 | % See https://cca.informatik.uni-freiburg.de/papers/SoerenssonBiere-SAT09.pdf | |
1399 | % Generate the 1-UIP clause. Mark all its literals. Remove those implied variables which have all their antecedent literals marked. | |
1400 | minimize_clause(SolverEnv, ConflictDLevel, BjClause, local, MinBjClause) :- | |
1401 | mark_literals(BjClause), | |
1402 | remove_where_all_antecedent_marked(BjClause, SolverEnv, ConflictDLevel, MinBjClause). | |
1403 | % Generate the 1-UIP clause. Mark its literals. Implied variables in 1-UIP clause are candidates for removal. | |
1404 | % Search implication graph. Start from antecedent literals of candidate. Stop at marked literals or decisions. | |
1405 | % If search always ends at marked literals, the candidate can be removed. | |
1406 | minimize_clause(SolverEnv, ConflictDLevel, BjClause, recursive, MinBjClause) :- | |
1407 | mark_literals(BjClause), | |
1408 | remove_recursively_stop_marked(BjClause, SolverEnv, ConflictDLevel, MinBjClause). | |
1409 | ||
1410 | remove_recursively_stop_marked([], _, _, []). | |
1411 | remove_recursively_stop_marked([(PropType,_,_,OriginalClause)-_-Pol-SatVarName|T], SolverEnv, ConflictDLevel, MinBjClause) :- | |
1412 | PropType \== branch, | |
1413 | get_antecedent_assignments(SolverEnv, ConflictDLevel, SatVarName, Pol, PropType, OriginalClause, Antecedent), | |
1414 | samsort(reversed_stack_sort, Antecedent, SAntecedent), % reverse assignment order | |
1415 | recursively_inspect_antecedent(SAntecedent, SolverEnv, ConflictDLevel), | |
1416 | !, | |
1417 | remove_recursively_stop_marked(T, SolverEnv, ConflictDLevel, MinBjClause). | |
1418 | remove_recursively_stop_marked([Lit|T], SolverEnv, ConflictDLevel, [Lit|NT]) :- | |
1419 | remove_recursively_stop_marked(T, SolverEnv, ConflictDLevel, NT). | |
1420 | ||
1421 | recursively_inspect_antecedent([], _, _). | |
1422 | recursively_inspect_antecedent([(PropType,_,_,OriginalClause)-_-Pol-SatVarName|T], SolverEnv, ConflictDLevel) :- | |
1423 | recursive_search_stops_at_marked_or_decision(PropType, OriginalClause, Pol, SatVarName, SolverEnv, ConflictDLevel), | |
1424 | recursively_inspect_antecedent(T, SolverEnv, ConflictDLevel). | |
1425 | ||
1426 | recursive_search_stops_at_marked_or_decision(_, _, _, SatVarName, _, _) :- | |
1427 | part_of_first_uip(SatVarName), | |
1428 | !. | |
1429 | recursive_search_stops_at_marked_or_decision(PropType, OriginalClause, Pol, SatVarName, SolverEnv, ConflictDLevel) :- | |
1430 | PropType \== branch, | |
1431 | get_antecedent_assignments(SolverEnv, ConflictDLevel, SatVarName, Pol, PropType, OriginalClause, Antecedent), | |
1432 | recursively_inspect_antecedent(Antecedent, SolverEnv, ConflictDLevel). | |
1433 | ||
1434 | all_literals_are_marked([]). | |
1435 | all_literals_are_marked([_-_-_-SatVarName|T]) :- | |
1436 | part_of_first_uip(SatVarName), | |
1437 | !, | |
1438 | all_literals_are_marked(T). | |
1439 | ||
1440 | remove_where_all_antecedent_marked([], _, _, []). | |
1441 | remove_where_all_antecedent_marked([(PropType,_,_,OriginalClause)-_-Pol-SatVarName|T], SolverEnv, ConflictDLevel, MinBjClause) :- | |
1442 | PropType == unit, | |
1443 | get_antecedent_assignments(SolverEnv, ConflictDLevel, SatVarName, Pol, PropType, OriginalClause, Antecedent), | |
1444 | all_literals_are_marked(Antecedent), | |
1445 | !, | |
1446 | remove_where_all_antecedent_marked(T, SolverEnv, ConflictDLevel, MinBjClause). | |
1447 | remove_where_all_antecedent_marked([Lit|T], SolverEnv, ConflictDLevel, [Lit|NT]) :- | |
1448 | remove_where_all_antecedent_marked(T, SolverEnv, ConflictDLevel, NT). | |
1449 | ||
1450 | mark_literals(Lits) :- | |
1451 | retractall(part_of_first_uip(_)), | |
1452 | mark_literals_state(Lits). | |
1453 | ||
1454 | mark_literals_state([]). | |
1455 | mark_literals_state([_-_-_-SatVarName|T]) :- | |
1456 | asserta(part_of_first_uip(SatVarName)), | |
1457 | mark_literals_state(T). | |
1458 | ||
1459 | %% get_backjump_clause_conflict_resolution(+SolverEnv, +StateMutable, +ConflictLevel, +ConflictClause, -BjClause, -BjLevel, -BjSatVars, -UsedVars). | |
1460 | % In the conflict graph each node corresponds to a variable assignment. | |
1461 | % The predecessors of node x are the antecedent assignments A^w(x) corresponding | |
1462 | % to the unit clause w (in its original form) that led to the propagation of x (logical implications). | |
1463 | % The directed edges from the nodes in A^w(x) to node x are all labeled with w. | |
1464 | % Nodes that have no predecessor correspond to decision/branching assignments | |
1465 | % (cf. GRASP: A Search Algorithm for Propositional Satisfiability, by Marques-Silva and Sakallah). | |
1466 | % As an improvement, we apply first UIP clause learning (cf. Efficient Conflict Driven Learning in a Boolean Satisfiability Solver, Zhang et al.). | |
1467 | % Compute the conflict graph for a conflicting unit-propagation of a variable and extract a backjump clause. | |
1468 | % -UsedVars are the SAT variables used during conflict analysis that are not part of the final bj clause (can be necessary for branching heuristic). | |
1469 | % -BjSatVars are the SAT variables in the final bj clause. | |
1470 | % Notes: | |
1471 | % - the variable references in the returned clause are not yet set | |
1472 | % - we do not create an actual graph but apply Boolean resolution | |
1473 | get_backjump_clause_conflict_resolution(SolverEnv, StateMutable, ConflictLevel, ConflictClause, BjClause, BjLevel, BjSatVars, UsedVars) :- | |
1474 | get_last_decision_level(StateMutable, _), | |
1475 | new_mutdict(ResolvedSoFar), | |
1476 | get_backjump_clause_and_level(SolverEnv, ConflictLevel, ResolvedSoFar, ConflictClause, BjClause, BjLevel, TUsedVars), | |
1477 | get_variable_names_in_clause(BjClause, BjSatVars), | |
1478 | subtract(TUsedVars, BjSatVars, UsedVars). | |
1479 | ||
1480 | %% get_backjump_clause_and_level(+SolverEnv, +ConflictDLevel, +ResolvedSoFar, +TBjClause, -BjClause, -BjLevel, -UsedVars). | |
1481 | get_backjump_clause_and_level(SolverEnv, ConflictDLevel, ResolvedSoFar, TBjClause, MinBjClause, BjLevel, UsedVars) :- | |
1482 | get_backjump_clause_and_level_sub(ConflictDLevel, 0, _, TBjClause, Resolver-RPol-RPropType-ROriginalClause, ThisLevelCount), | |
1483 | ( ThisLevelCount == 1 | |
1484 | -> % break, first UIP | |
1485 | BjClause = TBjClause, | |
1486 | clause_minimization(ClauseMinType), | |
1487 | ( ClauseMinType \== none | |
1488 | -> ( minimize_clause(SolverEnv, ConflictDLevel, BjClause, ClauseMinType, MinBjClause), ! | |
1489 | ; add_error_fail(minimize_clause, 'Clause minimization failed: ', [BjClause]) | |
1490 | ) | |
1491 | ; MinBjClause = BjClause | |
1492 | ), | |
1493 | get_maximum_decision_level_other_than_current(MinBjClause, 0, ConflictDLevel, BjLevel), | |
1494 | get_variables_used_in_cdcl(ResolvedSoFar, MinBjClause, UsedVars) | |
1495 | ; ground(Resolver), | |
1496 | resolve(SolverEnv, TBjClause, ConflictDLevel, Resolver, RPol, RPropType, ROriginalClause, NToExpand), | |
1497 | mutdict_put(ResolvedSoFar, Resolver, Resolver), | |
1498 | get_backjump_clause_and_level(SolverEnv, ConflictDLevel, ResolvedSoFar, NToExpand, MinBjClause, BjLevel, UsedVars) | |
1499 | ). | |
1500 | ||
1501 | get_backjump_clause_and_level_sub(_, ThisLevelCountAcc, ResolverAcc-_-RPol-RPropType-ROriginalClause, [], ResolverAcc-RPol-RPropType-ROriginalClause, ThisLevelCountAcc). | |
1502 | get_backjump_clause_and_level_sub(ConflictDLevel, ThisLevelCountAcc, ResolverAcc-RACount-RPol-RPropType-ROriginalClause, [(PropType,(Level,ACount),_,OriginalClause)-Pol-_-SatVarName|T], Resolver, ThisLevelCount) :- | |
1503 | ( Level == ConflictDLevel | |
1504 | -> NThisLevelCountAcc is ThisLevelCountAcc + 1 | |
1505 | ; NThisLevelCountAcc = ThisLevelCountAcc | |
1506 | ), | |
1507 | ( ( | |
1508 | Level == ConflictDLevel, | |
1509 | % unit or theory propagation | |
1510 | PropType \== branch, | |
1511 | % use last assigned literal to resolve next | |
1512 | ( var(ResolverAcc) | |
1513 | ; ACount > RACount | |
1514 | ) | |
1515 | ) | |
1516 | -> NResolverAcc = SatVarName-ACount-Pol-PropType-OriginalClause | |
1517 | ; NResolverAcc = ResolverAcc-RACount-RPol-RPropType-ROriginalClause | |
1518 | ), | |
1519 | get_backjump_clause_and_level_sub(ConflictDLevel, NThisLevelCountAcc, NResolverAcc, T, Resolver, ThisLevelCount). | |
1520 | ||
1521 | negate_polarity(pred_true, pred_false). | |
1522 | negate_polarity(pred_false, pred_true). | |
1523 | ||
1524 | retractall_once(Assertion) :- | |
1525 | retractall(cdclt_sat_solver:Assertion), | |
1526 | !. | |
1527 | ||
1528 | asserta_once(Assertion) :- | |
1529 | call(cdclt_sat_solver:Assertion), | |
1530 | !. | |
1531 | asserta_once(Assertion) :- | |
1532 | asserta(cdclt_sat_solver:Assertion). | |
1533 | ||
1534 | b_pred_or_bool_true(X) :- X == truth; X == boolean_true; X == value(pred_true). | |
1535 | b_pred_or_bool_false(X) :- X == falsity; X == boolean_false; X == value(pred_false). | |
1536 | ||
1537 | sat_conj_negate_to_clause(Pred, Clause) :- | |
1538 | conjunction_to_list(Pred, List), | |
1539 | maplist(sat_equality_negate_to_literal, List, Clause). | |
1540 | ||
1541 | sat_equality_negate_to_literal(b(equal(ID,Pol),pred,_), _-NegPol-_-Name) :- | |
1542 | ID = b(identifier(Name),_,_), | |
1543 | Pol = b(Value,boolean,_), | |
1544 | ( b_pred_or_bool_true(Value) | |
1545 | -> NegPol = pred_false | |
1546 | ; NegPol = pred_true | |
1547 | ). | |
1548 | ||
1549 | %%%%% Solver State | |
1550 | create_solver_state(StateMutable) :- | |
1551 | State = [cur_level:0,current_stack_size:0], | |
1552 | create_mutable(solver_state(State), StateMutable). | |
1553 | ||
1554 | %% get_full_state(+StateMutable, +Key, -Datum). | |
1555 | % We assume an order of the SolverState to prevent using member. | |
1556 | get_full_state(StateMutable, Key, Datum) :- | |
1557 | get_mutable(solver_state(SolverState), StateMutable), | |
1558 | get_full_state_ordered(Key, SolverState, Datum), !. | |
1559 | ||
1560 | get_full_state_ordered(cur_level, [cur_level:CurLevel,_], CurLevel). | |
1561 | get_full_state_ordered(current_stack_size, [_,current_stack_size:Size], Size). | |
1562 | ||
1563 | %% delete_from_heuristic(+SatVarName). | |
1564 | delete_from_heuristic(SatVarName) :- | |
1565 | ( fibonacci_heap:elm_exists(SatVarName) | |
1566 | -> fibonacci_heap:delete_elm_bt(SatVarName) | |
1567 | ; % it can be the case that SatVarName has already been removed | |
1568 | % from the mutable due to coroutines etc.; succeed in this case | |
1569 | true | |
1570 | ). | |
1571 | ||
1572 | %% update_full_state(+StateMutable, +Key, +Datum). | |
1573 | % We assume an order of the SolverState to prevent using member. | |
1574 | update_full_state(StateMutable, Key, Datum) :- | |
1575 | get_mutable(solver_state(SolverState), StateMutable), | |
1576 | update_full_state_ordered(Key, Datum, SolverState, NewSolverState), !, | |
1577 | update_mutable(solver_state(NewSolverState), StateMutable). | |
1578 | ||
1579 | update_full_state_ordered(cur_level, NewDatum, [cur_level:_,B], [cur_level:NewDatum,B]). | |
1580 | update_full_state_ordered(current_stack_size, NewDatum, [A,current_stack_size:_], [A,current_stack_size:NewDatum]). | |
1581 | ||
1582 | %% Initialize the dynamic solver state for a specific solver. | |
1583 | init_dynamic_solver_state(SolverName) :- | |
1584 | fibonacci_heap:init, | |
1585 | clean_dynamic_solver_state, | |
1586 | clear_pending_theory_propagations, | |
1587 | asserta(solver_name(SolverName)), | |
1588 | asserta(restarts(0)), | |
1589 | asserta(glue_clauses(0)), | |
1590 | asserta(amount_clause_reductions(0)), | |
1591 | asserta(assignment_count_on_cur_level(0)), | |
1592 | asserta(amount_learned_clauses(0)), | |
1593 | asserta(conflict_stats(total(0), since_restart(0), since_reduction(0))), | |
1594 | asserta(recent_lbds_dl(Diff1-Diff1, 0)), | |
1595 | asserta(recent_stack_sizes_dl(Diff2-Diff2, 0)), | |
1596 | asserta(total_lbd_sum(0)), | |
1597 | init_luby_sequence. | |
1598 | ||
1599 | clean_dynamic_solver_state :- | |
1600 | retractall(assignment_timeout_occurred), | |
1601 | retractall(allow_partial_model), | |
1602 | retractall(unfixed_deferred_set_error), | |
1603 | retractall(assignment_count_on_cur_level(_)), | |
1604 | retractall(pending_theory_prop(_,_)), | |
1605 | retractall(glue_clauses(_)), | |
1606 | retractall(glue_level(_,_,_)), | |
1607 | retractall(solver_name(_)), | |
1608 | retractall(restarts(_)), | |
1609 | retractall(is_restart), | |
1610 | retractall(bt_from_smt_solution), | |
1611 | retractall(recent_lbds_dl(_, _)), | |
1612 | retractall(recent_stack_sizes_dl(_, _)), | |
1613 | retractall(saved_phase(_, _)), | |
1614 | retractall(amount_clause_reductions(_)), | |
1615 | retractall(amount_learned_clauses(_)), | |
1616 | retractall(luby_counter(_)), | |
1617 | retractall(exclude_sat_solution_clause(_)), | |
1618 | retractall(total_lbd_sum(_)), | |
1619 | retractall(conflict_stats(_, _, _)), | |
1620 | retractall(idl_unsat_core(_)), | |
1621 | retractall(backjump_level(_)), | |
1622 | retractall(backjump_clause(_, _, _, _, _, _)). | |
1623 | ||
1624 | %% Remove dynamically stored unsat core found by the IDL solver. | |
1625 | remove_idl_unsat_core :- | |
1626 | retractall_once(idl_unsat_core(_)). | |
1627 | ||
1628 | %% Store an unsat core found by the IDL solver in the SMT solver's dynamic state. | |
1629 | store_idl_unsat_core(Core) :- | |
1630 | assignment_count_on_cur_level(ACount), | |
1631 | ACount > 1, % at least one unit propagation on this level, otherwise just backtrack | |
1632 | retractall_once(idl_unsat_core(_)), | |
1633 | asserta(idl_unsat_core(Core)). | |
1634 | ||
1635 | %% Announce backtracking after a solution has been found in order to backtrack to search for another solution. | |
1636 | %% We have to be able to distinguish between backtracking due to not finding a solution or backtracking | |
1637 | %% triggered by the user to find another solution. | |
1638 | announce_bt_from_smt_solution :- | |
1639 | asserta(bt_from_smt_solution). | |
1640 | %%%%% | |
1641 | ||
1642 | %% b_to_cnf_safe(+In, +State, -Out). | |
1643 | b_to_cnf_safe(In, State, Out) :- | |
1644 | b_to_cnf(In, State, TOut), | |
1645 | !, | |
1646 | Out = TOut. | |
1647 | b_to_cnf_safe(_, _, _) :- | |
1648 | add_internal_error('B to CNF conversion failed ', cdclt), | |
1649 | fail. | |
1650 | ||
1651 | %% b_to_cnf(+In, +State, -Out). | |
1652 | % Accepts predicates with conjunction, disjunction, and equality of SAT variables. No negations. | |
1653 | b_to_cnf(In, State, Out) :- | |
1654 | get_texpr_expr(In, Expr), | |
1655 | b_to_cnf_aux(Expr, State, Res, []), | |
1656 | !, | |
1657 | Res = Out. | |
1658 | b_to_cnf(In, _, _) :- | |
1659 | translate_bexpression(In, PPIn), | |
1660 | !, | |
1661 | add_error_fail(b_to_cnf, 'CNF conversion failed', PPIn). | |
1662 | ||
1663 | b_to_cnf(b(Expr,_,_Info), State) --> | |
1664 | !, | |
1665 | b_to_cnf_aux(Expr, State). | |
1666 | b_to_cnf(In, _, _, _) :- | |
1667 | add_error_fail(b_to_cnf, 'Not properly wrapped:', In). | |
1668 | ||
1669 | b_to_cnf_aux(X, _) --> | |
1670 | {X == truth}, !, | |
1671 | []. | |
1672 | b_to_cnf_aux(X, _) --> | |
1673 | {X == falsity}, !, | |
1674 | [[]]. | |
1675 | b_to_cnf_aux(equal(A,B), State) --> | |
1676 | {get_texpr_expr(B, Expr), | |
1677 | Expr == boolean_true, | |
1678 | get_texpr_expr(A, identifier(Name))}, | |
1679 | !, | |
1680 | {member(bind(Name,Res)-StackInfo, State)}, | |
1681 | [[StackInfo-pred_true-Res-Name]]. | |
1682 | b_to_cnf_aux(equal(A,B), State) --> | |
1683 | {get_texpr_expr(B, Expr), | |
1684 | Expr == boolean_false, | |
1685 | get_texpr_expr(A, identifier(Name)), | |
1686 | member(bind(Name,Res)-StackInfo, State)}, | |
1687 | [[StackInfo-pred_false-Res-Name]]. | |
1688 | b_to_cnf_aux(disjunct(D1,D2), State) --> | |
1689 | b_to_cnf_disj_aux(D1, D2, State). | |
1690 | b_to_cnf_aux(conjunct(A,B), State) --> | |
1691 | b_to_cnf(A, State), | |
1692 | b_to_cnf(B, State). | |
1693 | ||
1694 | b_to_cnf_disj_aux(D1, D2, State) --> | |
1695 | {get_texpr_expr(D1, conjunct(A,B))}, !, | |
1696 | {create_texpr(disjunct(A,D2), pred, [], DJ1), | |
1697 | create_texpr(disjunct(B,D2), pred, [], DJ2)}, | |
1698 | b_to_cnf_aux(conjunct(DJ1,DJ2), State). | |
1699 | b_to_cnf_disj_aux(D1, D2, State) --> | |
1700 | {get_texpr_expr(D2, conjunct(A,B))}, !, | |
1701 | {create_texpr(disjunct(D1,A), pred, [], DJ1), | |
1702 | create_texpr(disjunct(D1,B), pred, [], DJ2)}, | |
1703 | b_to_cnf_aux(conjunct(DJ1,DJ2), State). | |
1704 | b_to_cnf_disj_aux(D1, D2, State, Res, Acc) :- | |
1705 | b_to_cnf(D1, State, Res1), | |
1706 | b_to_cnf(D2, State, Res2), | |
1707 | !, | |
1708 | ( Res1 = [] | |
1709 | -> Res = Acc | |
1710 | ; Res1 = [[]] | |
1711 | -> append(Res2,Acc,Res) | |
1712 | ; Res2 = [] | |
1713 | -> Res = Acc | |
1714 | ; Res2 = [[]] | |
1715 | -> append(Res1,Acc,Res) | |
1716 | ; ( Res1 = [ResD1], | |
1717 | Res2 = [ResD2] | |
1718 | ) | |
1719 | -> Res = [Res12|Acc], | |
1720 | append(ResD1, ResD2, Res12) | |
1721 | ; join_clauses(Res1,Res2,Res,Acc) | |
1722 | -> true | |
1723 | ; add_error_fail(b_to_cnf_disj, 'Cannot join clauses: ', Res1:Res2) | |
1724 | ). | |
1725 | ||
1726 | join_clauses([], _) --> []. | |
1727 | join_clauses([Clause1|T], Clauses2) --> | |
1728 | join_clauses_aux(Clause1,Clauses2), | |
1729 | join_clauses(T,Clauses2). | |
1730 | ||
1731 | join_clauses_aux(_, []) --> []. | |
1732 | join_clauses_aux(Clause1, [Clause2|T]) --> | |
1733 | {append(Clause1, Clause2, NewClause)}, | |
1734 | [NewClause], | |
1735 | join_clauses_aux(Clause1, T). | |
1736 | ||
1737 | ||
1738 | % Used for random restarts. | |
1739 | % First restart is after 32nd conflict, second after additional 32 conflicts, | |
1740 | % third after additional 64 conflicts etc. | |
1741 | init_luby_sequence :- | |
1742 | retractall(luby_counter(_)), | |
1743 | % unit length of 32 | |
1744 | % 1,1,2,1,1,2,4,1,1,2,1,1,2,4,8,.. | |
1745 | assertz(luby_counter(1)), assertz(luby_counter(1)), assertz(luby_counter(2)), assertz(luby_counter(1)), assertz(luby_counter(1)), | |
1746 | assertz(luby_counter(2)), assertz(luby_counter(4)), assertz(luby_counter(1)), assertz(luby_counter(1)), assertz(luby_counter(2)), | |
1747 | assertz(luby_counter(1)), assertz(luby_counter(1)), assertz(luby_counter(2)), assertz(luby_counter(4)), assertz(luby_counter(8)), | |
1748 | assertz(luby_counter(1)), assertz(luby_counter(1)), assertz(luby_counter(2)), assertz(luby_counter(1)), assertz(luby_counter(1)), | |
1749 | assertz(luby_counter(2)), assertz(luby_counter(4)), assertz(luby_counter(8)), assertz(luby_counter(16)), assertz(luby_counter(1)), | |
1750 | assertz(luby_counter(1)), assertz(luby_counter(2)), assertz(luby_counter(1)), assertz(luby_counter(1)), assertz(luby_counter(2)), | |
1751 | assertz(luby_counter(4)), assertz(luby_counter(8)), assertz(luby_counter(16)), assertz(luby_counter(32)), assertz(luby_counter(1)), | |
1752 | assertz(luby_counter(1)), assertz(luby_counter(2)), assertz(luby_counter(1)), assertz(luby_counter(1)), assertz(luby_counter(2)), | |
1753 | assertz(luby_counter(4)), assertz(luby_counter(8)), assertz(luby_counter(16)), assertz(luby_counter(32)), assertz(luby_counter(64)), | |
1754 | assertz(luby_counter(1)), assertz(luby_counter(1)), assertz(luby_counter(2)), assertz(luby_counter(1)), assertz(luby_counter(1)), | |
1755 | assertz(luby_counter(2)), assertz(luby_counter(4)), assertz(luby_counter(8)), assertz(luby_counter(16)), assertz(luby_counter(32)), | |
1756 | assertz(luby_counter(64)), assertz(luby_counter(128)). | |
1757 | ||
1758 | % ---------------- | |
1759 | ||
1760 | %% simplify_cnf(+CNF, -Simplified). | |
1761 | % Boolean resolution. | |
1762 | simplify_cnf([], []). | |
1763 | simplify_cnf([Clause|T], NewCnf) :- | |
1764 | simplify_clause(Clause, _, Simplified, IsTrue), !, | |
1765 | Simplified \== [], % contradiction if a clause is empty | |
1766 | ( IsTrue == true | |
1767 | -> NewCnf = NT % remove true clauses | |
1768 | ; NewCnf = [Simplified|NT] | |
1769 | ), | |
1770 | simplify_cnf(T, NT). | |
1771 | ||
1772 | simplify_clause([], IsTrue, [], IsTrue). | |
1773 | simplify_clause([_-Pol-Var-_|T], IsTrueAcc, NT, IsTrue) :- | |
1774 | ground(Var), | |
1775 | Pol \== Var, | |
1776 | !, | |
1777 | simplify_clause(T, IsTrueAcc, NT, IsTrue). | |
1778 | simplify_clause([StackInfo-Pol-Var-SatVarName|T], IsTrueAcc, [StackInfo-Pol-Var-SatVarName|NT], IsTrue) :- | |
1779 | ( Pol == Var | |
1780 | -> IsTrueAcc = true | |
1781 | ; true | |
1782 | ), | |
1783 | simplify_clause(T, IsTrueAcc, NT, IsTrue). | |
1784 | ||
1785 | clause_order(_-_-_-A3, _-_-_-B3) :- A3 @< B3. | |
1786 | ||
1787 | %% unit_propagate_cnf(+SolverEnv, +StateMutable, +Clauses, -NewClauses). | |
1788 | % A simple unit propagation, useful to run before reification. | |
1789 | % Removes duplicates from each clause. | |
1790 | % Important to identify all unit clauses, b_to_cnf does not check for unique sat variables in clauses. | |
1791 | % An exhaustive unit-propagation prior to the reification is not beneficial | |
1792 | % since simplifying a CNF is slow compared to using watched literals in sat/4. | |
1793 | % Note: It is important to remove duplicates, e.g., using sort/2. Otherwise, a conflict clause with duplicates | |
1794 | % would lead to failure for first UIP CDCL (first UIP not recognized due to duplicate decision level). | |
1795 | unit_propagate_cnf(SolverEnv, StateMutable, Clauses, NewClauses) :- | |
1796 | unit_prop_clause_sort(true, SolverEnv, StateMutable, Clauses, _, _, TNewClauses), !, | |
1797 | simplify_cnf(TNewClauses, NewClauses). | |
1798 | ||
1799 | propagate_unit_clause([StackInfo-Pol-PrologVar-SatVarName], StateMutable, RAcc) :- | |
1800 | ( PrologVar == Pol | |
1801 | -> % duplicate unit clause already propagated | |
1802 | true | |
1803 | ; PrologVar = Pol, | |
1804 | RAcc = true, | |
1805 | debug_format_sat("deterministic unit propagation of ~w with polarity ~w before reification", [SatVarName,Pol]), | |
1806 | get_next_assignment_count_on_level(ACount), | |
1807 | StackInfo = (unit,(0,ACount),Pol,[_-Pol-PrologVar-SatVarName]), | |
1808 | bt_log_sat_stack(StateMutable, SatVarName, Pol), | |
1809 | log_unit_propagation | |
1810 | ). | |
1811 | ||
1812 | %% unit_prop_clause_sort(+Sort, +SolverEnv, +StateMutable, +CNF, +RAcc, -Resolved, -NewClauses). | |
1813 | % Removes duplicates from each clause if +Sort is true. | |
1814 | % Logs if a variable has been unit propagated in -Resolved using +RAcc. | |
1815 | unit_prop_clause_sort(_, _, _, [], RAcc, RAcc, []). | |
1816 | unit_prop_clause_sort(Sort, SolverEnv, StateMutable, [[StackInfo-Pol-PrologVar-SatVarName]|T], RAcc, Resolved, NT) :- | |
1817 | propagate_unit_clause([StackInfo-Pol-PrologVar-SatVarName], StateMutable, RAcc), | |
1818 | !, | |
1819 | unit_prop_clause_sort(Sort, SolverEnv, StateMutable, T, RAcc, Resolved, NT). | |
1820 | unit_prop_clause_sort(Sort, SolverEnv, StateMutable, [Clause|T], RAcc, Resolved, NewClauses) :- | |
1821 | ( Sort = true | |
1822 | -> remove_dups(Clause, TNewClause), | |
1823 | % clause_order ensures that watched literals are initially set to the same variables for stronger propagation | |
1824 | samsort(clause_order, TNewClause, NewClause) | |
1825 | ; NewClause = Clause | |
1826 | ), | |
1827 | ( NewClause = [_-_-_-_] | |
1828 | -> propagate_unit_clause(NewClause, StateMutable, RAcc), | |
1829 | NewClauses = NT | |
1830 | ; NewClauses = [NewClause|NT] | |
1831 | ), !, | |
1832 | unit_prop_clause_sort(Sort, SolverEnv, StateMutable, T, RAcc, Resolved, NT). | |
1833 | ||
1834 | % ---------------- | |
1835 | ||
1836 | portray_cnf(Clauses) :- length(Clauses,Len), format('CNF with ~w clauses:~n',[Len]), | |
1837 | maplist(portray_sat_clause,Clauses). | |
1838 | ||
1839 | portray_sat_clause(Clause) :- write(' '),maplist(portray_literal,Clause),nl. | |
1840 | ||
1841 | portray_literal(pred_false-PrologVar-ID) :- !, format('- ~w(~w) ',[ID,PrologVar]). | |
1842 | portray_literal(pred_true-PrologVar-ID) :- !, format(' ~w(~w) ',[ID,PrologVar]). | |
1843 | portray_literal(Lit) :- format(' *** UNKNOWN: ~w ',[Lit]). | |
1844 | ||
1845 | % ---------------- | |
1846 | ||
1847 | /* | |
1848 | %% static_sat_symmetry_breaking(+Clauses, +SolverEnv, +CurLevelMut, -NewSolverEnv). | |
1849 | % Static SAT symmetry breaking after unit propagation of problem_setup/3 but only once, e.g., not after a restart or bj to level 0 | |
1850 | % Can only be used for pure SAT solving. | |
1851 | static_sat_symmetry_breaking(_, SolverEnv, _, NewSolverEnv) :- | |
1852 | static_sat_symmetry_breaking(false), | |
1853 | !, | |
1854 | NewSolverEnv = SolverEnv. | |
1855 | static_sat_symmetry_breaking(Clauses, SolverEnv, CurLevelMut, NewSolverEnv) :- | |
1856 | \+ symmetry_breaking_pred(_, _), | |
1857 | !, | |
1858 | get_symmetry_breaking_predicates(Clauses, SBPsConjNoRef, NewSatVars), | |
1859 | asserta(symmetry_breaking_pred(SBPsConjNoRef,NewSatVars)), | |
1860 | static_sat_symmetry_breaking(Clauses, SolverEnv, CurLevelMut, NewSolverEnv). | |
1861 | static_sat_symmetry_breaking(_, SolverEnv, CurLevelMut, NewSolverEnv) :- | |
1862 | get_asserted_symmetry_breaking_pred(SolverEnv, SBPsConj, NewSolverEnv), | |
1863 | problem_setup(NewSolverEnv, CurLevelMut, SBPsConj). | |
1864 | ||
1865 | get_asserted_symmetry_breaking_pred(SolverEnv, SBPsConj, NewSolverEnv) :- | |
1866 | symmetry_breaking_pred(SBPsConjNoRef, NewSatVars), | |
1867 | add_symmetry_breaking_eqs_to_solver_env(NewSatVars, SolverEnv, NewSolverEnv), | |
1868 | get_from_solver_env(NewSolverEnv, pl_vars, PlVars), | |
1869 | set_variable_references_in_clauses(PlVars, SBPsConjNoRef, SBPsConj), | |
1870 | findall(Var, (member(Var, NewSatVars), bt_asserta(heuristic_tuple(Var,1))), _). | |
1871 | ||
1872 | %% add_symmetry_breaking_eqs_to_solver_env(+NewSatVars, +SolverEnv, -NewSolverEnv). | |
1873 | % Symmetry breaking might introduce new SAT variables for equalities inbetween cycles of permutations. | |
1874 | % We update the solver environment and create the corresponding SMT formulas for equalities here. | |
1875 | % This is necessary, e.g., if a SAT variable corresponding to an equality introduced | |
1876 | % from symmetry breaking is involved in a conflict. | |
1877 | add_symmetry_breaking_eqs_to_solver_env(NewSatVars, SolverEnv, NewSolverEnv) :- | |
1878 | SolverEnv = [sat_vars:SatVars,sat_varnames:SatVarNames,sat_bindings:SatBindings,t2b_env:Env,pl_vars:PrologSatVarTriple], | |
1879 | add_symmetry_breaking_eqs_to_solver_env(NewSatVars, SatVars, SatVarNames, SatBindings, Env, PrologSatVarTriple, NSatVars, NSatVarNames, NSatBindings, NEnv, NPrologSatVarTriple), | |
1880 | NewSolverEnv = [sat_vars:NSatVars,sat_varnames:NSatVarNames,sat_bindings:NSatBindings,t2b_env:NEnv,pl_vars:NPrologSatVarTriple]. | |
1881 | ||
1882 | add_symmetry_breaking_eqs_to_solver_env([], SatVars, SatVarNames, SatBindings, Env, PrologSatVarTriple, SatVars, SatVarNames, SatBindings, Env, PrologSatVarTriple). | |
1883 | add_symmetry_breaking_eqs_to_solver_env([NewSatVarName-EqClauses|T], SatVars, SatVarNames, SatBindings, Env, PrologSatVarTriple, NSatVars, NSatVarNames, NSatBindings, NEnv, NPrologSatVarTriple) :- | |
1884 | maplist(clause_to_smt_disjunction(SatVars), EqClauses, EqSmtClauses), | |
1885 | conjunct_predicates(EqSmtClauses, EqSmt1), % all true | |
1886 | maplist(negate_smt_formula, EqSmtClauses, NegEqSmtClauses), | |
1887 | conjunct_predicates(NegEqSmtClauses, EqSmt2), % or all false | |
1888 | EqSmt = b(disjunct(EqSmt1,EqSmt2),pred,[]), | |
1889 | SatVars1 = [b(identifier(NewSatVarName),boolean,[smt_formula(EqSmt),eq_symmetry_break])|SatVars], | |
1890 | SatVarNames1 = [NewSatVarName|SatVarNames], | |
1891 | SatBindings1 = [bind(NewSatVarName,Var)|SatBindings], | |
1892 | PrologSatVarTriple1 = [Var-NewSatVarName-EqSmt|PrologSatVarTriple], | |
1893 | Env1 = [(EqSmt,b(identifier(NewSatVarName),boolean,[]))|Env], | |
1894 | add_symmetry_breaking_eqs_to_solver_env(T, SatVars1, SatVarNames1, SatBindings1, Env1, PrologSatVarTriple1, NSatVars, NSatVarNames, NSatBindings, NEnv, NPrologSatVarTriple). | |
1895 | ||
1896 | %clause_to_smt_disjunction(_, [], b(truth,pred,[])). | |
1897 | clause_to_smt_disjunction(SatVars, [Pol-_-SatVarName|T], SmtDisj) :- | |
1898 | get_smt_formula_from_vars_for_sat_pol(SatVars, SatVarName, Pol, SmtFormula), | |
1899 | clause_to_smt_disjunction(SatVars, T, SmtFormula, SmtDisj). | |
1900 | ||
1901 | clause_to_smt_disjunction(_, [], Acc, Acc). | |
1902 | clause_to_smt_disjunction(SatVars, [Pol-_-SatVarName|T], Acc, SmtDisj) :- | |
1903 | get_smt_formula_from_vars_for_sat_pol(SatVars, SatVarName, Pol, SmtFormula), | |
1904 | NAcc = b(disjunct(SmtFormula,Acc),pred,[]), | |
1905 | clause_to_smt_disjunction(SatVars, T, NAcc, SmtDisj). | |
1906 | */ | |
1907 | ||
1908 | /* | |
1909 | % Remove half of the clauses every "frequency_constant + constant_factor * x" conflicts, | |
1910 | % where x is the amount of clause reductions so far. We keep clauses with a small LBD forever. | |
1911 | possibly_discard_learned_clauses :- | |
1912 | conflict_stats(_, _, since_reduction(SRed)), | |
1913 | cdclt_settings:discard_learned_clauses_frequency_constant(Frequency), | |
1914 | SRed >= Frequency, % first check to improve performance | |
1915 | amount_clause_reductions(Reductions), | |
1916 | cdclt_settings:discard_learned_clauses_constant_factor(Factor), | |
1917 | Threshold is Frequency + Factor * Reductions, | |
1918 | SRed == Threshold, | |
1919 | !, | |
1920 | log_set_of_learned_clauses_reduction, | |
1921 | debug_format_sat("~nDiscard half of learned clauses..", []), | |
1922 | cdclt_settings:discard_clause_greater_lbd(LbdLimit), | |
1923 | amount_learned_clauses(ALC), | |
1924 | Half is ALC // 2, | |
1925 | NReductions is Reductions + 1, | |
1926 | retract(amount_clause_reductions(_)), | |
1927 | asserta(amount_clause_reductions(NReductions)), | |
1928 | discard_half_of_learned_clauses_greater_lbd(0, Half, LbdLimit, Removed), | |
1929 | log_forgotten_clauses(Removed), | |
1930 | retract(amount_learned_clauses(Old)), | |
1931 | New is Old - Removed, | |
1932 | asserta(amount_learned_clauses(New)), | |
1933 | retract(conflict_stats(total(Total), since_restart(SRRed), _)), | |
1934 | asserta(conflict_stats(total(Total), since_restart(SRRed), since_reduction(0))), !. | |
1935 | possibly_discard_learned_clauses. | |
1936 | % Remove half of the clauses learned so far. | |
1937 | % We keep clauses with an LBD smaller than cdclt_settings:discard_clause_greater_lbd/1 | |
1938 | % forever. Thus it is not guaranteed that exactly half of the clauses are deleted if | |
1939 | % a lot of high quality clauses have been learned. | |
1940 | discard_half_of_learned_clauses_greater_lbd(C, Half, LbdLimit, Removed) :- | |
1941 | C =< Half, | |
1942 | retract(backjump_clause(BjLevel, BjClause, LbdScore, BjSatVars, UsedVars, AC)), | |
1943 | !, | |
1944 | ( LbdScore > LbdLimit | |
1945 | -> C1 is C + 1, | |
1946 | discard_half_of_learned_clauses_greater_lbd(C1, Half, LbdLimit, Removed) | |
1947 | ; discard_half_of_learned_clauses_greater_lbd(C, Half, LbdLimit, Removed), | |
1948 | asserta(backjump_clause(BjLevel, BjClause, LbdScore, BjSatVars, UsedVars, AC)) | |
1949 | ). | |
1950 | discard_half_of_learned_clauses_greater_lbd(C, _, _, C). | |
1951 | */ |