ruby-minisat 1.14.2 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -21
- data/Gemfile +4 -0
- data/LICENSE +3 -2
- data/README.md +42 -0
- data/Rakefile +1 -48
- data/examples/shikaku.rb +2 -2
- data/ext/minisat/extconf.rb +19 -4
- data/ext/minisat/minisat-wrap.cpp +11 -5
- data/ext/minisat/minisat.c +17 -3
- data/ext/minisat/minisat.h +1 -1
- data/minisat/minisat-2.2.0.tar.gz +0 -0
- data/minisat/{MiniSat_v1.14 → minisat}/LICENSE +2 -1
- data/minisat/minisat/README +24 -0
- data/minisat/minisat/core/Dimacs.h +89 -0
- data/minisat/minisat/core/Main.cc +192 -0
- data/minisat/minisat/core/Solver.cc +923 -0
- data/minisat/minisat/core/Solver.h +373 -0
- data/minisat/minisat/core/SolverTypes.h +407 -0
- data/minisat/minisat/mtl/Alg.h +84 -0
- data/minisat/minisat/mtl/Alloc.h +131 -0
- data/minisat/minisat/mtl/Heap.h +148 -0
- data/minisat/minisat/mtl/IntTypes.h +42 -0
- data/minisat/minisat/mtl/Map.h +193 -0
- data/minisat/minisat/mtl/Queue.h +69 -0
- data/minisat/{MiniSat_v1.14 → minisat/mtl}/Sort.h +14 -47
- data/minisat/minisat/mtl/Vec.h +130 -0
- data/minisat/minisat/mtl/XAlloc.h +45 -0
- data/minisat/minisat/mtl/config.mk +6 -0
- data/minisat/minisat/mtl/template.mk +107 -0
- data/minisat/minisat/simp/Main.cc +211 -0
- data/minisat/minisat/simp/SimpSolver.cc +717 -0
- data/minisat/minisat/simp/SimpSolver.h +197 -0
- data/minisat/minisat/utils/Options.cc +91 -0
- data/minisat/minisat/utils/Options.h +386 -0
- data/minisat/minisat/utils/ParseUtils.h +122 -0
- data/minisat/minisat/utils/System.cc +95 -0
- data/minisat/minisat/utils/System.h +60 -0
- data/ruby-minisat.gemspec +21 -0
- metadata +94 -75
- data/README.rdoc +0 -56
- data/minisat/MiniSat_v1.14.2006-Aug-29.src.zip +0 -0
- data/minisat/MiniSat_v1.14/Global.h +0 -274
- data/minisat/MiniSat_v1.14/Heap.h +0 -100
- data/minisat/MiniSat_v1.14/Main.C +0 -244
- data/minisat/MiniSat_v1.14/Makefile +0 -88
- data/minisat/MiniSat_v1.14/README +0 -30
- data/minisat/MiniSat_v1.14/Solver.C +0 -781
- data/minisat/MiniSat_v1.14/Solver.h +0 -206
- data/minisat/MiniSat_v1.14/Solver.o +0 -0
- data/minisat/MiniSat_v1.14/SolverTypes.h +0 -130
- data/minisat/MiniSat_v1.14/TODO +0 -73
- data/minisat/MiniSat_v1.14/VarOrder.h +0 -96
@@ -0,0 +1,923 @@
|
|
1
|
+
/***************************************************************************************[Solver.cc]
|
2
|
+
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
3
|
+
Copyright (c) 2007-2010, Niklas Sorensson
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction,
|
7
|
+
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
8
|
+
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
9
|
+
furnished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
12
|
+
substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
15
|
+
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
16
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
17
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
18
|
+
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
**************************************************************************************************/
|
20
|
+
|
21
|
+
#include <math.h>
|
22
|
+
|
23
|
+
#include "mtl/Sort.h"
|
24
|
+
#include "core/Solver.h"
|
25
|
+
|
26
|
+
using namespace Minisat;
|
27
|
+
|
28
|
+
//=================================================================================================
|
29
|
+
// Options:
|
30
|
+
|
31
|
+
|
32
|
+
static const char* _cat = "CORE";
|
33
|
+
|
34
|
+
static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false));
|
35
|
+
static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false));
|
36
|
+
static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true));
|
37
|
+
static DoubleOption opt_random_seed (_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false));
|
38
|
+
static IntOption opt_ccmin_mode (_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2));
|
39
|
+
static IntOption opt_phase_saving (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
|
40
|
+
static BoolOption opt_rnd_init_act (_cat, "rnd-init", "Randomize the initial activity", false);
|
41
|
+
static BoolOption opt_luby_restart (_cat, "luby", "Use the Luby restart sequence", true);
|
42
|
+
static IntOption opt_restart_first (_cat, "rfirst", "The base restart interval", 100, IntRange(1, INT32_MAX));
|
43
|
+
static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 2, DoubleRange(1, false, HUGE_VAL, false));
|
44
|
+
static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false));
|
45
|
+
|
46
|
+
|
47
|
+
//=================================================================================================
|
48
|
+
// Constructor/Destructor:
|
49
|
+
|
50
|
+
|
51
|
+
Solver::Solver() :
|
52
|
+
|
53
|
+
// Parameters (user settable):
|
54
|
+
//
|
55
|
+
verbosity (0)
|
56
|
+
, var_decay (opt_var_decay)
|
57
|
+
, clause_decay (opt_clause_decay)
|
58
|
+
, random_var_freq (opt_random_var_freq)
|
59
|
+
, random_seed (opt_random_seed)
|
60
|
+
, luby_restart (opt_luby_restart)
|
61
|
+
, ccmin_mode (opt_ccmin_mode)
|
62
|
+
, phase_saving (opt_phase_saving)
|
63
|
+
, rnd_pol (false)
|
64
|
+
, rnd_init_act (opt_rnd_init_act)
|
65
|
+
, garbage_frac (opt_garbage_frac)
|
66
|
+
, restart_first (opt_restart_first)
|
67
|
+
, restart_inc (opt_restart_inc)
|
68
|
+
|
69
|
+
// Parameters (the rest):
|
70
|
+
//
|
71
|
+
, learntsize_factor((double)1/(double)3), learntsize_inc(1.1)
|
72
|
+
|
73
|
+
// Parameters (experimental):
|
74
|
+
//
|
75
|
+
, learntsize_adjust_start_confl (100)
|
76
|
+
, learntsize_adjust_inc (1.5)
|
77
|
+
|
78
|
+
// Statistics: (formerly in 'SolverStats')
|
79
|
+
//
|
80
|
+
, solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
|
81
|
+
, dec_vars(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
|
82
|
+
|
83
|
+
, ok (true)
|
84
|
+
, cla_inc (1)
|
85
|
+
, var_inc (1)
|
86
|
+
, watches (WatcherDeleted(ca))
|
87
|
+
, qhead (0)
|
88
|
+
, simpDB_assigns (-1)
|
89
|
+
, simpDB_props (0)
|
90
|
+
, order_heap (VarOrderLt(activity))
|
91
|
+
, progress_estimate (0)
|
92
|
+
, remove_satisfied (true)
|
93
|
+
|
94
|
+
// Resource constraints:
|
95
|
+
//
|
96
|
+
, conflict_budget (-1)
|
97
|
+
, propagation_budget (-1)
|
98
|
+
, asynch_interrupt (false)
|
99
|
+
{}
|
100
|
+
|
101
|
+
|
102
|
+
Solver::~Solver()
|
103
|
+
{
|
104
|
+
}
|
105
|
+
|
106
|
+
|
107
|
+
//=================================================================================================
|
108
|
+
// Minor methods:
|
109
|
+
|
110
|
+
|
111
|
+
// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be
|
112
|
+
// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result).
|
113
|
+
//
|
114
|
+
Var Solver::newVar(bool sign, bool dvar)
|
115
|
+
{
|
116
|
+
int v = nVars();
|
117
|
+
watches .init(mkLit(v, false));
|
118
|
+
watches .init(mkLit(v, true ));
|
119
|
+
assigns .push(l_Undef);
|
120
|
+
vardata .push(mkVarData(CRef_Undef, 0));
|
121
|
+
//activity .push(0);
|
122
|
+
activity .push(rnd_init_act ? drand(random_seed) * 0.00001 : 0);
|
123
|
+
seen .push(0);
|
124
|
+
polarity .push(sign);
|
125
|
+
decision .push();
|
126
|
+
trail .capacity(v+1);
|
127
|
+
setDecisionVar(v, dvar);
|
128
|
+
return v;
|
129
|
+
}
|
130
|
+
|
131
|
+
|
132
|
+
bool Solver::addClause_(vec<Lit>& ps)
|
133
|
+
{
|
134
|
+
assert(decisionLevel() == 0);
|
135
|
+
if (!ok) return false;
|
136
|
+
|
137
|
+
// Check if clause is satisfied and remove false/duplicate literals:
|
138
|
+
sort(ps);
|
139
|
+
Lit p; int i, j;
|
140
|
+
for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
|
141
|
+
if (value(ps[i]) == l_True || ps[i] == ~p)
|
142
|
+
return true;
|
143
|
+
else if (value(ps[i]) != l_False && ps[i] != p)
|
144
|
+
ps[j++] = p = ps[i];
|
145
|
+
ps.shrink(i - j);
|
146
|
+
|
147
|
+
if (ps.size() == 0)
|
148
|
+
return ok = false;
|
149
|
+
else if (ps.size() == 1){
|
150
|
+
uncheckedEnqueue(ps[0]);
|
151
|
+
return ok = (propagate() == CRef_Undef);
|
152
|
+
}else{
|
153
|
+
CRef cr = ca.alloc(ps, false);
|
154
|
+
clauses.push(cr);
|
155
|
+
attachClause(cr);
|
156
|
+
}
|
157
|
+
|
158
|
+
return true;
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
void Solver::attachClause(CRef cr) {
|
163
|
+
const Clause& c = ca[cr];
|
164
|
+
assert(c.size() > 1);
|
165
|
+
watches[~c[0]].push(Watcher(cr, c[1]));
|
166
|
+
watches[~c[1]].push(Watcher(cr, c[0]));
|
167
|
+
if (c.learnt()) learnts_literals += c.size();
|
168
|
+
else clauses_literals += c.size(); }
|
169
|
+
|
170
|
+
|
171
|
+
void Solver::detachClause(CRef cr, bool strict) {
|
172
|
+
const Clause& c = ca[cr];
|
173
|
+
assert(c.size() > 1);
|
174
|
+
|
175
|
+
if (strict){
|
176
|
+
remove(watches[~c[0]], Watcher(cr, c[1]));
|
177
|
+
remove(watches[~c[1]], Watcher(cr, c[0]));
|
178
|
+
}else{
|
179
|
+
// Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause)
|
180
|
+
watches.smudge(~c[0]);
|
181
|
+
watches.smudge(~c[1]);
|
182
|
+
}
|
183
|
+
|
184
|
+
if (c.learnt()) learnts_literals -= c.size();
|
185
|
+
else clauses_literals -= c.size(); }
|
186
|
+
|
187
|
+
|
188
|
+
void Solver::removeClause(CRef cr) {
|
189
|
+
Clause& c = ca[cr];
|
190
|
+
detachClause(cr);
|
191
|
+
// Don't leave pointers to free'd memory!
|
192
|
+
if (locked(c)) vardata[var(c[0])].reason = CRef_Undef;
|
193
|
+
c.mark(1);
|
194
|
+
ca.free(cr);
|
195
|
+
}
|
196
|
+
|
197
|
+
|
198
|
+
bool Solver::satisfied(const Clause& c) const {
|
199
|
+
for (int i = 0; i < c.size(); i++)
|
200
|
+
if (value(c[i]) == l_True)
|
201
|
+
return true;
|
202
|
+
return false; }
|
203
|
+
|
204
|
+
|
205
|
+
// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
|
206
|
+
//
|
207
|
+
void Solver::cancelUntil(int level) {
|
208
|
+
if (decisionLevel() > level){
|
209
|
+
for (int c = trail.size()-1; c >= trail_lim[level]; c--){
|
210
|
+
Var x = var(trail[c]);
|
211
|
+
assigns [x] = l_Undef;
|
212
|
+
if (phase_saving > 1 || (phase_saving == 1) && c > trail_lim.last())
|
213
|
+
polarity[x] = sign(trail[c]);
|
214
|
+
insertVarOrder(x); }
|
215
|
+
qhead = trail_lim[level];
|
216
|
+
trail.shrink(trail.size() - trail_lim[level]);
|
217
|
+
trail_lim.shrink(trail_lim.size() - level);
|
218
|
+
} }
|
219
|
+
|
220
|
+
|
221
|
+
//=================================================================================================
|
222
|
+
// Major methods:
|
223
|
+
|
224
|
+
|
225
|
+
Lit Solver::pickBranchLit()
|
226
|
+
{
|
227
|
+
Var next = var_Undef;
|
228
|
+
|
229
|
+
// Random decision:
|
230
|
+
if (drand(random_seed) < random_var_freq && !order_heap.empty()){
|
231
|
+
next = order_heap[irand(random_seed,order_heap.size())];
|
232
|
+
if (value(next) == l_Undef && decision[next])
|
233
|
+
rnd_decisions++; }
|
234
|
+
|
235
|
+
// Activity based decision:
|
236
|
+
while (next == var_Undef || value(next) != l_Undef || !decision[next])
|
237
|
+
if (order_heap.empty()){
|
238
|
+
next = var_Undef;
|
239
|
+
break;
|
240
|
+
}else
|
241
|
+
next = order_heap.removeMin();
|
242
|
+
|
243
|
+
return next == var_Undef ? lit_Undef : mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : polarity[next]);
|
244
|
+
}
|
245
|
+
|
246
|
+
|
247
|
+
/*_________________________________________________________________________________________________
|
248
|
+
|
|
249
|
+
| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void]
|
250
|
+
|
|
251
|
+
| Description:
|
252
|
+
| Analyze conflict and produce a reason clause.
|
253
|
+
|
|
254
|
+
| Pre-conditions:
|
255
|
+
| * 'out_learnt' is assumed to be cleared.
|
256
|
+
| * Current decision level must be greater than root level.
|
257
|
+
|
|
258
|
+
| Post-conditions:
|
259
|
+
| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
|
260
|
+
| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the
|
261
|
+
| rest of literals. There may be others from the same level though.
|
262
|
+
|
|
263
|
+
|________________________________________________________________________________________________@*/
|
264
|
+
void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
|
265
|
+
{
|
266
|
+
int pathC = 0;
|
267
|
+
Lit p = lit_Undef;
|
268
|
+
|
269
|
+
// Generate conflict clause:
|
270
|
+
//
|
271
|
+
out_learnt.push(); // (leave room for the asserting literal)
|
272
|
+
int index = trail.size() - 1;
|
273
|
+
|
274
|
+
do{
|
275
|
+
assert(confl != CRef_Undef); // (otherwise should be UIP)
|
276
|
+
Clause& c = ca[confl];
|
277
|
+
|
278
|
+
if (c.learnt())
|
279
|
+
claBumpActivity(c);
|
280
|
+
|
281
|
+
for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){
|
282
|
+
Lit q = c[j];
|
283
|
+
|
284
|
+
if (!seen[var(q)] && level(var(q)) > 0){
|
285
|
+
varBumpActivity(var(q));
|
286
|
+
seen[var(q)] = 1;
|
287
|
+
if (level(var(q)) >= decisionLevel())
|
288
|
+
pathC++;
|
289
|
+
else
|
290
|
+
out_learnt.push(q);
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
// Select next clause to look at:
|
295
|
+
while (!seen[var(trail[index--])]);
|
296
|
+
p = trail[index+1];
|
297
|
+
confl = reason(var(p));
|
298
|
+
seen[var(p)] = 0;
|
299
|
+
pathC--;
|
300
|
+
|
301
|
+
}while (pathC > 0);
|
302
|
+
out_learnt[0] = ~p;
|
303
|
+
|
304
|
+
// Simplify conflict clause:
|
305
|
+
//
|
306
|
+
int i, j;
|
307
|
+
out_learnt.copyTo(analyze_toclear);
|
308
|
+
if (ccmin_mode == 2){
|
309
|
+
uint32_t abstract_level = 0;
|
310
|
+
for (i = 1; i < out_learnt.size(); i++)
|
311
|
+
abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict)
|
312
|
+
|
313
|
+
for (i = j = 1; i < out_learnt.size(); i++)
|
314
|
+
if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level))
|
315
|
+
out_learnt[j++] = out_learnt[i];
|
316
|
+
|
317
|
+
}else if (ccmin_mode == 1){
|
318
|
+
for (i = j = 1; i < out_learnt.size(); i++){
|
319
|
+
Var x = var(out_learnt[i]);
|
320
|
+
|
321
|
+
if (reason(x) == CRef_Undef)
|
322
|
+
out_learnt[j++] = out_learnt[i];
|
323
|
+
else{
|
324
|
+
Clause& c = ca[reason(var(out_learnt[i]))];
|
325
|
+
for (int k = 1; k < c.size(); k++)
|
326
|
+
if (!seen[var(c[k])] && level(var(c[k])) > 0){
|
327
|
+
out_learnt[j++] = out_learnt[i];
|
328
|
+
break; }
|
329
|
+
}
|
330
|
+
}
|
331
|
+
}else
|
332
|
+
i = j = out_learnt.size();
|
333
|
+
|
334
|
+
max_literals += out_learnt.size();
|
335
|
+
out_learnt.shrink(i - j);
|
336
|
+
tot_literals += out_learnt.size();
|
337
|
+
|
338
|
+
// Find correct backtrack level:
|
339
|
+
//
|
340
|
+
if (out_learnt.size() == 1)
|
341
|
+
out_btlevel = 0;
|
342
|
+
else{
|
343
|
+
int max_i = 1;
|
344
|
+
// Find the first literal assigned at the next-highest level:
|
345
|
+
for (int i = 2; i < out_learnt.size(); i++)
|
346
|
+
if (level(var(out_learnt[i])) > level(var(out_learnt[max_i])))
|
347
|
+
max_i = i;
|
348
|
+
// Swap-in this literal at index 1:
|
349
|
+
Lit p = out_learnt[max_i];
|
350
|
+
out_learnt[max_i] = out_learnt[1];
|
351
|
+
out_learnt[1] = p;
|
352
|
+
out_btlevel = level(var(p));
|
353
|
+
}
|
354
|
+
|
355
|
+
for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared)
|
356
|
+
}
|
357
|
+
|
358
|
+
|
359
|
+
// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is
|
360
|
+
// visiting literals at levels that cannot be removed later.
|
361
|
+
bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
|
362
|
+
{
|
363
|
+
analyze_stack.clear(); analyze_stack.push(p);
|
364
|
+
int top = analyze_toclear.size();
|
365
|
+
while (analyze_stack.size() > 0){
|
366
|
+
assert(reason(var(analyze_stack.last())) != CRef_Undef);
|
367
|
+
Clause& c = ca[reason(var(analyze_stack.last()))]; analyze_stack.pop();
|
368
|
+
|
369
|
+
for (int i = 1; i < c.size(); i++){
|
370
|
+
Lit p = c[i];
|
371
|
+
if (!seen[var(p)] && level(var(p)) > 0){
|
372
|
+
if (reason(var(p)) != CRef_Undef && (abstractLevel(var(p)) & abstract_levels) != 0){
|
373
|
+
seen[var(p)] = 1;
|
374
|
+
analyze_stack.push(p);
|
375
|
+
analyze_toclear.push(p);
|
376
|
+
}else{
|
377
|
+
for (int j = top; j < analyze_toclear.size(); j++)
|
378
|
+
seen[var(analyze_toclear[j])] = 0;
|
379
|
+
analyze_toclear.shrink(analyze_toclear.size() - top);
|
380
|
+
return false;
|
381
|
+
}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
return true;
|
387
|
+
}
|
388
|
+
|
389
|
+
|
390
|
+
/*_________________________________________________________________________________________________
|
391
|
+
|
|
392
|
+
| analyzeFinal : (p : Lit) -> [void]
|
393
|
+
|
|
394
|
+
| Description:
|
395
|
+
| Specialized analysis procedure to express the final conflict in terms of assumptions.
|
396
|
+
| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and
|
397
|
+
| stores the result in 'out_conflict'.
|
398
|
+
|________________________________________________________________________________________________@*/
|
399
|
+
void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
|
400
|
+
{
|
401
|
+
out_conflict.clear();
|
402
|
+
out_conflict.push(p);
|
403
|
+
|
404
|
+
if (decisionLevel() == 0)
|
405
|
+
return;
|
406
|
+
|
407
|
+
seen[var(p)] = 1;
|
408
|
+
|
409
|
+
for (int i = trail.size()-1; i >= trail_lim[0]; i--){
|
410
|
+
Var x = var(trail[i]);
|
411
|
+
if (seen[x]){
|
412
|
+
if (reason(x) == CRef_Undef){
|
413
|
+
assert(level(x) > 0);
|
414
|
+
out_conflict.push(~trail[i]);
|
415
|
+
}else{
|
416
|
+
Clause& c = ca[reason(x)];
|
417
|
+
for (int j = 1; j < c.size(); j++)
|
418
|
+
if (level(var(c[j])) > 0)
|
419
|
+
seen[var(c[j])] = 1;
|
420
|
+
}
|
421
|
+
seen[x] = 0;
|
422
|
+
}
|
423
|
+
}
|
424
|
+
|
425
|
+
seen[var(p)] = 0;
|
426
|
+
}
|
427
|
+
|
428
|
+
|
429
|
+
void Solver::uncheckedEnqueue(Lit p, CRef from)
|
430
|
+
{
|
431
|
+
assert(value(p) == l_Undef);
|
432
|
+
assigns[var(p)] = lbool(!sign(p));
|
433
|
+
vardata[var(p)] = mkVarData(from, decisionLevel());
|
434
|
+
trail.push_(p);
|
435
|
+
}
|
436
|
+
|
437
|
+
|
438
|
+
/*_________________________________________________________________________________________________
|
439
|
+
|
|
440
|
+
| propagate : [void] -> [Clause*]
|
441
|
+
|
|
442
|
+
| Description:
|
443
|
+
| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
|
444
|
+
| otherwise CRef_Undef.
|
445
|
+
|
|
446
|
+
| Post-conditions:
|
447
|
+
| * the propagation queue is empty, even if there was a conflict.
|
448
|
+
|________________________________________________________________________________________________@*/
|
449
|
+
CRef Solver::propagate()
|
450
|
+
{
|
451
|
+
CRef confl = CRef_Undef;
|
452
|
+
int num_props = 0;
|
453
|
+
watches.cleanAll();
|
454
|
+
|
455
|
+
while (qhead < trail.size()){
|
456
|
+
Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
|
457
|
+
vec<Watcher>& ws = watches[p];
|
458
|
+
Watcher *i, *j, *end;
|
459
|
+
num_props++;
|
460
|
+
|
461
|
+
for (i = j = (Watcher*)ws, end = i + ws.size(); i != end;){
|
462
|
+
// Try to avoid inspecting the clause:
|
463
|
+
Lit blocker = i->blocker;
|
464
|
+
if (value(blocker) == l_True){
|
465
|
+
*j++ = *i++; continue; }
|
466
|
+
|
467
|
+
// Make sure the false literal is data[1]:
|
468
|
+
CRef cr = i->cref;
|
469
|
+
Clause& c = ca[cr];
|
470
|
+
Lit false_lit = ~p;
|
471
|
+
if (c[0] == false_lit)
|
472
|
+
c[0] = c[1], c[1] = false_lit;
|
473
|
+
assert(c[1] == false_lit);
|
474
|
+
i++;
|
475
|
+
|
476
|
+
// If 0th watch is true, then clause is already satisfied.
|
477
|
+
Lit first = c[0];
|
478
|
+
Watcher w = Watcher(cr, first);
|
479
|
+
if (first != blocker && value(first) == l_True){
|
480
|
+
*j++ = w; continue; }
|
481
|
+
|
482
|
+
// Look for new watch:
|
483
|
+
for (int k = 2; k < c.size(); k++)
|
484
|
+
if (value(c[k]) != l_False){
|
485
|
+
c[1] = c[k]; c[k] = false_lit;
|
486
|
+
watches[~c[1]].push(w);
|
487
|
+
goto NextClause; }
|
488
|
+
|
489
|
+
// Did not find watch -- clause is unit under assignment:
|
490
|
+
*j++ = w;
|
491
|
+
if (value(first) == l_False){
|
492
|
+
confl = cr;
|
493
|
+
qhead = trail.size();
|
494
|
+
// Copy the remaining watches:
|
495
|
+
while (i < end)
|
496
|
+
*j++ = *i++;
|
497
|
+
}else
|
498
|
+
uncheckedEnqueue(first, cr);
|
499
|
+
|
500
|
+
NextClause:;
|
501
|
+
}
|
502
|
+
ws.shrink(i - j);
|
503
|
+
}
|
504
|
+
propagations += num_props;
|
505
|
+
simpDB_props -= num_props;
|
506
|
+
|
507
|
+
return confl;
|
508
|
+
}
|
509
|
+
|
510
|
+
|
511
|
+
/*_________________________________________________________________________________________________
|
512
|
+
|
|
513
|
+
| reduceDB : () -> [void]
|
514
|
+
|
|
515
|
+
| Description:
|
516
|
+
| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
|
517
|
+
| clauses are clauses that are reason to some assignment. Binary clauses are never removed.
|
518
|
+
|________________________________________________________________________________________________@*/
|
519
|
+
struct reduceDB_lt {
|
520
|
+
ClauseAllocator& ca;
|
521
|
+
reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {}
|
522
|
+
bool operator () (CRef x, CRef y) {
|
523
|
+
return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); }
|
524
|
+
};
|
525
|
+
void Solver::reduceDB()
|
526
|
+
{
|
527
|
+
int i, j;
|
528
|
+
double extra_lim = cla_inc / learnts.size(); // Remove any clause below this activity
|
529
|
+
|
530
|
+
sort(learnts, reduceDB_lt(ca));
|
531
|
+
// Don't delete binary or locked clauses. From the rest, delete clauses from the first half
|
532
|
+
// and clauses with activity smaller than 'extra_lim':
|
533
|
+
for (i = j = 0; i < learnts.size(); i++){
|
534
|
+
Clause& c = ca[learnts[i]];
|
535
|
+
if (c.size() > 2 && !locked(c) && (i < learnts.size() / 2 || c.activity() < extra_lim))
|
536
|
+
removeClause(learnts[i]);
|
537
|
+
else
|
538
|
+
learnts[j++] = learnts[i];
|
539
|
+
}
|
540
|
+
learnts.shrink(i - j);
|
541
|
+
checkGarbage();
|
542
|
+
}
|
543
|
+
|
544
|
+
|
545
|
+
void Solver::removeSatisfied(vec<CRef>& cs)
|
546
|
+
{
|
547
|
+
int i, j;
|
548
|
+
for (i = j = 0; i < cs.size(); i++){
|
549
|
+
Clause& c = ca[cs[i]];
|
550
|
+
if (satisfied(c))
|
551
|
+
removeClause(cs[i]);
|
552
|
+
else
|
553
|
+
cs[j++] = cs[i];
|
554
|
+
}
|
555
|
+
cs.shrink(i - j);
|
556
|
+
}
|
557
|
+
|
558
|
+
|
559
|
+
void Solver::rebuildOrderHeap()
|
560
|
+
{
|
561
|
+
vec<Var> vs;
|
562
|
+
for (Var v = 0; v < nVars(); v++)
|
563
|
+
if (decision[v] && value(v) == l_Undef)
|
564
|
+
vs.push(v);
|
565
|
+
order_heap.build(vs);
|
566
|
+
}
|
567
|
+
|
568
|
+
|
569
|
+
/*_________________________________________________________________________________________________
|
570
|
+
|
|
571
|
+
| simplify : [void] -> [bool]
|
572
|
+
|
|
573
|
+
| Description:
|
574
|
+
| Simplify the clause database according to the current top-level assigment. Currently, the only
|
575
|
+
| thing done here is the removal of satisfied clauses, but more things can be put here.
|
576
|
+
|________________________________________________________________________________________________@*/
|
577
|
+
bool Solver::simplify()
|
578
|
+
{
|
579
|
+
assert(decisionLevel() == 0);
|
580
|
+
|
581
|
+
if (!ok || propagate() != CRef_Undef)
|
582
|
+
return ok = false;
|
583
|
+
|
584
|
+
if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
|
585
|
+
return true;
|
586
|
+
|
587
|
+
// Remove satisfied clauses:
|
588
|
+
removeSatisfied(learnts);
|
589
|
+
if (remove_satisfied) // Can be turned off.
|
590
|
+
removeSatisfied(clauses);
|
591
|
+
checkGarbage();
|
592
|
+
rebuildOrderHeap();
|
593
|
+
|
594
|
+
simpDB_assigns = nAssigns();
|
595
|
+
simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now)
|
596
|
+
|
597
|
+
return true;
|
598
|
+
}
|
599
|
+
|
600
|
+
|
601
|
+
/*_________________________________________________________________________________________________
|
602
|
+
|
|
603
|
+
| search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool]
|
604
|
+
|
|
605
|
+
| Description:
|
606
|
+
| Search for a model the specified number of conflicts.
|
607
|
+
| NOTE! Use negative value for 'nof_conflicts' indicate infinity.
|
608
|
+
|
|
609
|
+
| Output:
|
610
|
+
| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If
|
611
|
+
| all variables are decision variables, this means that the clause set is satisfiable. 'l_False'
|
612
|
+
| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
|
613
|
+
|________________________________________________________________________________________________@*/
|
614
|
+
lbool Solver::search(int nof_conflicts)
|
615
|
+
{
|
616
|
+
assert(ok);
|
617
|
+
int backtrack_level;
|
618
|
+
int conflictC = 0;
|
619
|
+
vec<Lit> learnt_clause;
|
620
|
+
starts++;
|
621
|
+
|
622
|
+
for (;;){
|
623
|
+
CRef confl = propagate();
|
624
|
+
if (confl != CRef_Undef){
|
625
|
+
// CONFLICT
|
626
|
+
conflicts++; conflictC++;
|
627
|
+
if (decisionLevel() == 0) return l_False;
|
628
|
+
|
629
|
+
learnt_clause.clear();
|
630
|
+
analyze(confl, learnt_clause, backtrack_level);
|
631
|
+
cancelUntil(backtrack_level);
|
632
|
+
|
633
|
+
if (learnt_clause.size() == 1){
|
634
|
+
uncheckedEnqueue(learnt_clause[0]);
|
635
|
+
}else{
|
636
|
+
CRef cr = ca.alloc(learnt_clause, true);
|
637
|
+
learnts.push(cr);
|
638
|
+
attachClause(cr);
|
639
|
+
claBumpActivity(ca[cr]);
|
640
|
+
uncheckedEnqueue(learnt_clause[0], cr);
|
641
|
+
}
|
642
|
+
|
643
|
+
varDecayActivity();
|
644
|
+
claDecayActivity();
|
645
|
+
|
646
|
+
if (--learntsize_adjust_cnt == 0){
|
647
|
+
learntsize_adjust_confl *= learntsize_adjust_inc;
|
648
|
+
learntsize_adjust_cnt = (int)learntsize_adjust_confl;
|
649
|
+
max_learnts *= learntsize_inc;
|
650
|
+
|
651
|
+
if (verbosity >= 1)
|
652
|
+
printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n",
|
653
|
+
(int)conflicts,
|
654
|
+
(int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals,
|
655
|
+
(int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100);
|
656
|
+
}
|
657
|
+
|
658
|
+
}else{
|
659
|
+
// NO CONFLICT
|
660
|
+
if (nof_conflicts >= 0 && conflictC >= nof_conflicts || !withinBudget()){
|
661
|
+
// Reached bound on number of conflicts:
|
662
|
+
progress_estimate = progressEstimate();
|
663
|
+
cancelUntil(0);
|
664
|
+
return l_Undef; }
|
665
|
+
|
666
|
+
// Simplify the set of problem clauses:
|
667
|
+
if (decisionLevel() == 0 && !simplify())
|
668
|
+
return l_False;
|
669
|
+
|
670
|
+
if (learnts.size()-nAssigns() >= max_learnts)
|
671
|
+
// Reduce the set of learnt clauses:
|
672
|
+
reduceDB();
|
673
|
+
|
674
|
+
Lit next = lit_Undef;
|
675
|
+
while (decisionLevel() < assumptions.size()){
|
676
|
+
// Perform user provided assumption:
|
677
|
+
Lit p = assumptions[decisionLevel()];
|
678
|
+
if (value(p) == l_True){
|
679
|
+
// Dummy decision level:
|
680
|
+
newDecisionLevel();
|
681
|
+
}else if (value(p) == l_False){
|
682
|
+
analyzeFinal(~p, conflict);
|
683
|
+
return l_False;
|
684
|
+
}else{
|
685
|
+
next = p;
|
686
|
+
break;
|
687
|
+
}
|
688
|
+
}
|
689
|
+
|
690
|
+
if (next == lit_Undef){
|
691
|
+
// New variable decision:
|
692
|
+
decisions++;
|
693
|
+
next = pickBranchLit();
|
694
|
+
|
695
|
+
if (next == lit_Undef)
|
696
|
+
// Model found:
|
697
|
+
return l_True;
|
698
|
+
}
|
699
|
+
|
700
|
+
// Increase decision level and enqueue 'next'
|
701
|
+
newDecisionLevel();
|
702
|
+
uncheckedEnqueue(next);
|
703
|
+
}
|
704
|
+
}
|
705
|
+
}
|
706
|
+
|
707
|
+
|
708
|
+
double Solver::progressEstimate() const
|
709
|
+
{
|
710
|
+
double progress = 0;
|
711
|
+
double F = 1.0 / nVars();
|
712
|
+
|
713
|
+
for (int i = 0; i <= decisionLevel(); i++){
|
714
|
+
int beg = i == 0 ? 0 : trail_lim[i - 1];
|
715
|
+
int end = i == decisionLevel() ? trail.size() : trail_lim[i];
|
716
|
+
progress += pow(F, i) * (end - beg);
|
717
|
+
}
|
718
|
+
|
719
|
+
return progress / nVars();
|
720
|
+
}
|
721
|
+
|
722
|
+
/*
|
723
|
+
Finite subsequences of the Luby-sequence:
|
724
|
+
|
725
|
+
0: 1
|
726
|
+
1: 1 1 2
|
727
|
+
2: 1 1 2 1 1 2 4
|
728
|
+
3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8
|
729
|
+
...
|
730
|
+
|
731
|
+
|
732
|
+
*/
|
733
|
+
|
734
|
+
static double luby(double y, int x){
|
735
|
+
|
736
|
+
// Find the finite subsequence that contains index 'x', and the
|
737
|
+
// size of that subsequence:
|
738
|
+
int size, seq;
|
739
|
+
for (size = 1, seq = 0; size < x+1; seq++, size = 2*size+1);
|
740
|
+
|
741
|
+
while (size-1 != x){
|
742
|
+
size = (size-1)>>1;
|
743
|
+
seq--;
|
744
|
+
x = x % size;
|
745
|
+
}
|
746
|
+
|
747
|
+
return pow(y, seq);
|
748
|
+
}
|
749
|
+
|
750
|
+
// NOTE: assumptions passed in member-variable 'assumptions'.
|
751
|
+
lbool Solver::solve_()
|
752
|
+
{
|
753
|
+
model.clear();
|
754
|
+
conflict.clear();
|
755
|
+
if (!ok) return l_False;
|
756
|
+
|
757
|
+
solves++;
|
758
|
+
|
759
|
+
max_learnts = nClauses() * learntsize_factor;
|
760
|
+
learntsize_adjust_confl = learntsize_adjust_start_confl;
|
761
|
+
learntsize_adjust_cnt = (int)learntsize_adjust_confl;
|
762
|
+
lbool status = l_Undef;
|
763
|
+
|
764
|
+
if (verbosity >= 1){
|
765
|
+
printf("============================[ Search Statistics ]==============================\n");
|
766
|
+
printf("| Conflicts | ORIGINAL | LEARNT | Progress |\n");
|
767
|
+
printf("| | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n");
|
768
|
+
printf("===============================================================================\n");
|
769
|
+
}
|
770
|
+
|
771
|
+
// Search:
|
772
|
+
int curr_restarts = 0;
|
773
|
+
while (status == l_Undef){
|
774
|
+
double rest_base = luby_restart ? luby(restart_inc, curr_restarts) : pow(restart_inc, curr_restarts);
|
775
|
+
status = search(rest_base * restart_first);
|
776
|
+
if (!withinBudget()) break;
|
777
|
+
curr_restarts++;
|
778
|
+
}
|
779
|
+
|
780
|
+
if (verbosity >= 1)
|
781
|
+
printf("===============================================================================\n");
|
782
|
+
|
783
|
+
|
784
|
+
if (status == l_True){
|
785
|
+
// Extend & copy model:
|
786
|
+
model.growTo(nVars());
|
787
|
+
for (int i = 0; i < nVars(); i++) model[i] = value(i);
|
788
|
+
}else if (status == l_False && conflict.size() == 0)
|
789
|
+
ok = false;
|
790
|
+
|
791
|
+
cancelUntil(0);
|
792
|
+
return status;
|
793
|
+
}
|
794
|
+
|
795
|
+
//=================================================================================================
|
796
|
+
// Writing CNF to DIMACS:
|
797
|
+
//
|
798
|
+
// FIXME: this needs to be rewritten completely.
|
799
|
+
|
800
|
+
static Var mapVar(Var x, vec<Var>& map, Var& max)
|
801
|
+
{
|
802
|
+
if (map.size() <= x || map[x] == -1){
|
803
|
+
map.growTo(x+1, -1);
|
804
|
+
map[x] = max++;
|
805
|
+
}
|
806
|
+
return map[x];
|
807
|
+
}
|
808
|
+
|
809
|
+
|
810
|
+
void Solver::toDimacs(FILE* f, Clause& c, vec<Var>& map, Var& max)
|
811
|
+
{
|
812
|
+
if (satisfied(c)) return;
|
813
|
+
|
814
|
+
for (int i = 0; i < c.size(); i++)
|
815
|
+
if (value(c[i]) != l_False)
|
816
|
+
fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max)+1);
|
817
|
+
fprintf(f, "0\n");
|
818
|
+
}
|
819
|
+
|
820
|
+
|
821
|
+
void Solver::toDimacs(const char *file, const vec<Lit>& assumps)
|
822
|
+
{
|
823
|
+
FILE* f = fopen(file, "wr");
|
824
|
+
if (f == NULL)
|
825
|
+
fprintf(stderr, "could not open file %s\n", file), exit(1);
|
826
|
+
toDimacs(f, assumps);
|
827
|
+
fclose(f);
|
828
|
+
}
|
829
|
+
|
830
|
+
|
831
|
+
void Solver::toDimacs(FILE* f, const vec<Lit>& assumps)
|
832
|
+
{
|
833
|
+
// Handle case when solver is in contradictory state:
|
834
|
+
if (!ok){
|
835
|
+
fprintf(f, "p cnf 1 2\n1 0\n-1 0\n");
|
836
|
+
return; }
|
837
|
+
|
838
|
+
vec<Var> map; Var max = 0;
|
839
|
+
|
840
|
+
// Cannot use removeClauses here because it is not safe
|
841
|
+
// to deallocate them at this point. Could be improved.
|
842
|
+
int cnt = 0;
|
843
|
+
for (int i = 0; i < clauses.size(); i++)
|
844
|
+
if (!satisfied(ca[clauses[i]]))
|
845
|
+
cnt++;
|
846
|
+
|
847
|
+
for (int i = 0; i < clauses.size(); i++)
|
848
|
+
if (!satisfied(ca[clauses[i]])){
|
849
|
+
Clause& c = ca[clauses[i]];
|
850
|
+
for (int j = 0; j < c.size(); j++)
|
851
|
+
if (value(c[j]) != l_False)
|
852
|
+
mapVar(var(c[j]), map, max);
|
853
|
+
}
|
854
|
+
|
855
|
+
// Assumptions are added as unit clauses:
|
856
|
+
cnt += assumptions.size();
|
857
|
+
|
858
|
+
fprintf(f, "p cnf %d %d\n", max, cnt);
|
859
|
+
|
860
|
+
for (int i = 0; i < assumptions.size(); i++){
|
861
|
+
assert(value(assumptions[i]) != l_False);
|
862
|
+
fprintf(f, "%s%d 0\n", sign(assumptions[i]) ? "-" : "", mapVar(var(assumptions[i]), map, max)+1);
|
863
|
+
}
|
864
|
+
|
865
|
+
for (int i = 0; i < clauses.size(); i++)
|
866
|
+
toDimacs(f, ca[clauses[i]], map, max);
|
867
|
+
|
868
|
+
if (verbosity > 0)
|
869
|
+
printf("Wrote %d clauses with %d variables.\n", cnt, max);
|
870
|
+
}
|
871
|
+
|
872
|
+
|
873
|
+
//=================================================================================================
|
874
|
+
// Garbage Collection methods:
|
875
|
+
|
876
|
+
void Solver::relocAll(ClauseAllocator& to)
|
877
|
+
{
|
878
|
+
// All watchers:
|
879
|
+
//
|
880
|
+
// for (int i = 0; i < watches.size(); i++)
|
881
|
+
watches.cleanAll();
|
882
|
+
for (int v = 0; v < nVars(); v++)
|
883
|
+
for (int s = 0; s < 2; s++){
|
884
|
+
Lit p = mkLit(v, s);
|
885
|
+
// printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1);
|
886
|
+
vec<Watcher>& ws = watches[p];
|
887
|
+
for (int j = 0; j < ws.size(); j++)
|
888
|
+
ca.reloc(ws[j].cref, to);
|
889
|
+
}
|
890
|
+
|
891
|
+
// All reasons:
|
892
|
+
//
|
893
|
+
for (int i = 0; i < trail.size(); i++){
|
894
|
+
Var v = var(trail[i]);
|
895
|
+
|
896
|
+
if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)])))
|
897
|
+
ca.reloc(vardata[v].reason, to);
|
898
|
+
}
|
899
|
+
|
900
|
+
// All learnt:
|
901
|
+
//
|
902
|
+
for (int i = 0; i < learnts.size(); i++)
|
903
|
+
ca.reloc(learnts[i], to);
|
904
|
+
|
905
|
+
// All original:
|
906
|
+
//
|
907
|
+
for (int i = 0; i < clauses.size(); i++)
|
908
|
+
ca.reloc(clauses[i], to);
|
909
|
+
}
|
910
|
+
|
911
|
+
|
912
|
+
void Solver::garbageCollect()
|
913
|
+
{
|
914
|
+
// Initialize the next region to a size corresponding to the estimated utilization degree. This
|
915
|
+
// is not precise but should avoid some unnecessary reallocations for the new region:
|
916
|
+
ClauseAllocator to(ca.size() - ca.wasted());
|
917
|
+
|
918
|
+
relocAll(to);
|
919
|
+
if (verbosity >= 2)
|
920
|
+
printf("| Garbage collection: %12d bytes => %12d bytes |\n",
|
921
|
+
ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
|
922
|
+
to.moveTo(ca);
|
923
|
+
}
|