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