ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_lookahead.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "internal.hpp"
4
6
7namespace CaDiCaL {
8
9struct literal_occ {
10 int lit;
11 int count;
12 bool operator< (const literal_occ &locc) const {
13 return (count > locc.count) || (count == locc.count && lit < locc.lit);
14 }
16 ++count;
17 return *this;
18 }
19};
20
22 std::vector<literal_occ> loccs ((std::size_t) max_var + 1);
23 for (std::size_t lit = 0; lit < loccs.size (); ++lit) {
24 loccs[lit].lit = lit;
25 }
26 for (const auto &c : clauses)
27 if (!c->redundant)
28 for (const auto &lit : *c)
29 if (active (lit))
30 ++loccs[std::abs (lit)];
31 std::sort (begin (loccs), end (loccs));
32 std::vector<int> locc_map;
33 locc_map.reserve (max_var);
34 for (const auto &locc : loccs)
35 locc_map.push_back (locc.lit);
36 return locc_map;
37}
38
39int Internal::lookahead_locc (const std::vector<int> &loccs) {
40 for (auto lit : loccs)
41 if (active (abs (lit)) && !assumed (lit) && !assumed (-lit) &&
42 !val (lit))
43 return lit;
44 return 0;
45}
46
47// This calculates the literal that appears the most often reusing the
48// available datastructures and iterating over the clause set. This is too
49// slow to be called iteratively. A faster (but inexact) version is
50// lookahead_populate_loc and lookahead_loc.
52 init_noccs ();
53 for (const auto &c : clauses)
54 if (!c->redundant)
55 for (const auto &lit : *c)
56 if (active (lit))
57 noccs (lit)++;
58 int64_t max_noccs = 0;
59 int res = 0;
60
61 if (unsat)
62 return INT_MIN;
63
64 propagate ();
65 for (int idx = 1; idx <= max_var; idx++) {
66 if (!active (idx) || assumed (idx) || assumed (-idx) || val (idx))
67 continue;
68 for (int sign = -1; sign <= 1; sign += 2) {
69 const int lit = sign * idx;
70 if (!active (lit))
71 continue;
72 int64_t tmp = noccs (lit);
73 if (tmp <= max_noccs)
74 continue;
75 max_noccs = tmp;
76 res = lit;
77 }
78 }
79 MSG ("maximum occurrence %" PRId64 " of literal %d", max_noccs, res);
80 reset_noccs ();
81 return res;
82}
83
84// We probe on literals first, which occur more often negated and thus we
85// sort the 'probes' stack in such a way that literals which occur negated
86// less frequently come first. Probes are taken from the back of the stack.
87
91 typedef size_t Type;
92 Type operator() (int a) const { return internal->noccs (-a); }
93};
94
95// Follow the ideas in 'generate_probes' but flush non root probes and
96// reorder remaining probes.
97
99
100 CADICAL_assert (!probes.empty ());
101
102 init_noccs ();
103 for (const auto &c : clauses) {
104 int a, b;
105 if (!is_binary_clause (c, a, b))
106 continue;
107 noccs (a)++;
108 noccs (b)++;
109 }
110
111 const auto eop = probes.end ();
112 auto j = probes.begin ();
113 for (auto i = j; i != eop; i++) {
114 int lit = *i;
115 if (!active (lit))
116 continue;
117 const bool have_pos_bin_occs = noccs (lit) > 0;
118 const bool have_neg_bin_occs = noccs (-lit) > 0;
119 if (have_pos_bin_occs == have_neg_bin_occs)
120 continue;
121 if (have_pos_bin_occs)
122 lit = -lit;
124 if (propfixed (lit) >= stats.all.fixed)
125 continue;
126 MSG ("keeping probe %d negated occs %" PRId64 "", lit, noccs (-lit));
127 *j++ = lit;
128 }
129 size_t remain = j - probes.begin ();
130#ifndef CADICAL_QUIET
131 size_t flushed = probes.size () - remain;
132#endif
133 probes.resize (remain);
134
135 rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this));
136
137 reset_noccs ();
139
140 PHASE ("probe-round", stats.probingrounds,
141 "flushed %zd literals %.0f%% remaining %zd", flushed,
142 percent (flushed, remain + flushed), remain);
143}
144
146
147 CADICAL_assert (probes.empty ());
148
149 // First determine all the literals which occur in binary clauses. It is
150 // way faster to go over the clauses once, instead of walking the watch
151 // lists for each literal.
152 //
153 init_noccs ();
154 for (const auto &c : clauses) {
155 int a, b;
156 if (!is_binary_clause (c, a, b))
157 continue;
158 noccs (a)++;
159 noccs (b)++;
160 }
161
162 for (int idx = 1; idx <= max_var; idx++) {
163
164 // Then focus on roots of the binary implication graph, which are
165 // literals occurring negatively in a binary clause, but not positively.
166 // If neither 'idx' nor '-idx' is a root it makes less sense to probe
167 // this variable.
168
169 // This argument requires that equivalent literal substitution through
170 // 'decompose' is performed, because otherwise there might be 'cyclic
171 // roots' which are not tried, i.e., -1 2 0, 1 -2 0, 1 2 3 0, 1 2 -3 0.
172
173 const bool have_pos_bin_occs = noccs (idx) > 0;
174 const bool have_neg_bin_occs = noccs (-idx) > 0;
175
176 // if (have_pos_bin_occs == have_neg_bin_occs) continue;
177
178 if (have_pos_bin_occs) {
179 int probe = -idx;
180
181 // See the discussion where 'propfixed' is used below.
182 //
183 if (propfixed (probe) >= stats.all.fixed)
184 continue;
185
186 MSG ("scheduling probe %d negated occs %" PRId64 "", probe,
187 noccs (-probe));
188 probes.push_back (probe);
189 }
190
191 if (have_neg_bin_occs) {
192 int probe = idx;
193
194 // See the discussion where 'propfixed' is used below.
195 //
196 if (propfixed (probe) >= stats.all.fixed)
197 continue;
198
199 MSG ("scheduling probe %d negated occs %" PRId64 "", probe,
200 noccs (-probe));
201 probes.push_back (probe);
202 }
203 }
204
205 rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this));
206
207 reset_noccs ();
209
210 PHASE ("probe-round", stats.probingrounds,
211 "scheduled %zd literals %.0f%%", probes.size (),
212 percent (probes.size (), 2 * max_var));
213}
214
216
217 int generated = 0;
218
219 for (;;) {
220
221 if (probes.empty ()) {
222 if (generated++)
223 return 0;
225 }
226
227 while (!probes.empty ()) {
228
229 int probe = probes.back ();
230 probes.pop_back ();
231
232 // Eliminated or assigned.
233 //
234 if (!active (probe) || assumed (probe) || assumed (-probe))
235 continue;
236
237 // There is now new unit since the last time we propagated this probe,
238 // thus we propagated it before without obtaining a conflict and
239 // nothing changed since then. Thus there is no need to propagate it
240 // again. This observation was independently made by Partik Simons
241 // et.al. in the context of implementing 'smodels' (see for instance
242 // Alg. 4 in his JAIR article from 2002) and it has also been
243 // contributed to the thesis work of Yacine Boufkhad.
244 //
245 if (propfixed (probe) >= stats.all.fixed)
246 continue;
247
248 return probe;
249 }
250 }
251}
252
253bool non_tautological_cube (std::vector<int> cube) {
254 std::sort (begin (cube), end (cube), clause_lit_less_than ());
255
256 for (size_t i = 0, j = 1; j < cube.size (); ++i, ++j)
257 if (cube[i] == cube[j])
258 return false;
259 else if (cube[i] == -cube[j])
260 return false;
261 else if (cube[i] == 0)
262 return false;
263
264 return true;
265}
266
268
269 if (external->terminator && external->terminator->terminate ()) {
270 MSG ("connected terminator forces termination");
271 return true;
272 }
273
274 if (termination_forced) {
275 MSG ("termination forced");
276 return true;
277 }
278 return false;
279}
280
281// We run probing on all literals with some differences:
282//
283// * no limit on the number of propagations. We rely on terminating to
284// stop()
285// * we run only one round
286//
287// The run can be expensive, so we actually first run the cheaper
288// occurrence version and only then run lookahead.
289//
291
292 if (!active ())
293 return 0;
294
295 MSG ("lookahead-probe-round %" PRId64
296 " without propagations limit and %zu assumptions",
297 stats.probingrounds, assumptions.size ());
298
299 termination_forced = false;
300
301#ifndef CADICAL_QUIET
302 int old_failed = stats.failed;
303 int64_t old_probed = stats.probed;
304#endif
305 int64_t old_hbrs = stats.hbrs;
306
307 if (unsat)
308 return INT_MIN;
309 if (level)
310 backtrack ();
311 if (!propagate ()) {
312 MSG ("empty clause before probing");
314 return INT_MIN;
315 }
316
317 if (terminating_asked ())
318 return most_occurring_literal ();
319
320 decompose ();
321
322 if (ternary ()) // If we derived a binary clause
323 decompose (); // then start another round of ELS.
324
325 // Remove duplicated binary clauses and perform in essence hyper unary
326 // resolution, i.e., derive the unit '2' from '1 2' and '-1 2'.
327 //
329
330 lim.conflicts = -1;
331
332 if (!probes.empty ())
334
335 // We reset 'propfixed' since there was at least another conflict thus
336 // a new learned clause, which might produce new propagations (and hyper
337 // binary resolvents). During 'generate_probes' we keep the old value.
338 //
339 for (int idx = 1; idx <= max_var; idx++)
340 propfixed (idx) = propfixed (-idx) = -1;
341
342 CADICAL_assert (unsat || propagated == trail.size ());
343 propagated = propagated2 = trail.size ();
344
345 int probe;
346 int res = most_occurring_literal ();
347 int max_hbrs = -1;
348
349 set_mode (PROBE);
350
351 MSG ("unsat = %d, terminating_asked () = %d ", unsat,
354 while (!unsat && !terminating_asked () &&
356 stats.probed++;
357 int hbrs;
358
360 if (probe_propagate ())
361 hbrs = trail.size (), backtrack ();
362 else
363 hbrs = 0, failed_literal (probe);
365 if (max_hbrs < hbrs ||
366 (max_hbrs == hbrs &&
367 internal->bumped (probe) > internal->bumped (res))) {
368 res = probe;
369 max_hbrs = hbrs;
370 }
371 }
372
374
375 if (unsat) {
376 MSG ("probing derived empty clause");
377 res = INT_MIN;
378 } else if (propagated < trail.size ()) {
379 MSG ("probing produced %zd units",
380 (size_t) (trail.size () - propagated));
381 if (!propagate ()) {
382 MSG ("propagating units after probing results in empty clause");
384 res = INT_MIN;
385 } else
386 sort_watches ();
387 }
388
389#ifndef CADICAL_QUIET
390 int failed = stats.failed - old_failed;
391 int64_t probed = stats.probed - old_probed;
392#endif
393 int64_t hbrs = stats.hbrs - old_hbrs;
394
395 MSG ("lookahead-probe-round %" PRId64 " probed %" PRId64
396 " and found %d failed literals",
397 stats.probingrounds, probed, failed);
398
399 if (hbrs)
400 PHASE ("lookahead-probe-round", stats.probingrounds,
401 "found %" PRId64 " hyper binary resolvents", hbrs);
402
403 MSG ("lookahead literal %d with %d\n", res, max_hbrs);
404
405 return res;
406}
407
408CubesWithStatus Internal::generate_cubes (int depth, int min_depth) {
409 if (!active () || depth == 0) {
410 CubesWithStatus cubes;
411 cubes.status = 0;
412 cubes.cubes.push_back (std::vector<int> ());
413 return cubes;
414 }
415
416 lookingahead = true;
418 MSG ("Generating cubes of depth %i", depth);
419
420 // presimplify required due to assumptions
421
422 termination_forced = false;
423 int res = already_solved ();
424 if (res == 0)
425 res = restore_clauses ();
426 if (unsat)
427 res = 10;
428 if (res != 0)
429 res = solve (true);
430 if (res != 0) {
431 MSG ("Solved during preprocessing");
432 CubesWithStatus cubes;
433 cubes.status = res;
434 lookingahead = false;
435 STOP (lookahead);
436 return cubes;
437 }
438
439 reset_limits ();
440 MSG ("generate cubes with %zu assumptions\n", assumptions.size ());
441
442 CADICAL_assert (ntab.empty ());
443 std::vector<int> current_assumptions{assumptions};
444 std::vector<std::vector<int>> cubes{{assumptions}};
445 auto loccs{lookahead_populate_locc ()};
446 LOG ("loccs populated\n");
447 CADICAL_assert (ntab.empty ());
448
449 for (int i = 0; i < depth; ++i) {
450 LOG ("Probing at depth %i, currently %zu have been generated", i,
451 cubes.size ());
452 std::vector<std::vector<int>> cubes2{std::move (cubes)};
453 cubes.clear ();
454
455 for (size_t j = 0; j < cubes2.size (); ++j) {
456 CADICAL_assert (ntab.empty ());
459 for (auto lit : cubes2[j])
460 assume (lit);
462 propagate ();
463 // preprocess_round(0); //uncomment maybe
464
465 if (unsat) {
466 LOG ("current cube is unsat; skipping");
467 unsat = false;
468 continue;
469 }
470
471 int res = terminating_asked () ? lookahead_locc (loccs)
473 if (unsat) {
474 LOG ("current cube is unsat; skipping");
475 unsat = false;
476 continue;
477 }
478
479 if (res == 0) {
480 LOG ("no lit to split %i", res);
481 cubes.push_back (cubes2[j]);
482 continue;
483 }
484
485 CADICAL_assert (res != 0);
486 LOG ("splitting on lit %i", res);
487 std::vector<int> cube1{cubes2[j]};
488 cube1.push_back (res);
489 std::vector<int> cube2{std::move (cubes2[j])};
490 cube2.push_back (-res);
491 cubes.push_back (cube1);
492 cubes.push_back (cube2);
493 }
494
495 if (terminating_asked () && i >= min_depth)
496 break;
497 }
498
499 CADICAL_assert (std::for_each (
500 std::begin (cubes), std::end (cubes),
501 [] (std::vector<int> cube) { return non_tautological_cube (cube); }));
503
504 for (auto lit : current_assumptions)
505 assume (lit);
506
507 STOP (lookahead);
508 lookingahead = false;
509
510 if (unsat) {
511 LOG ("Solved during preprocessing");
512 CubesWithStatus cubes;
513 cubes.status = 20;
514 return cubes;
515 }
516
517 CubesWithStatus rcubes;
518 rcubes.status = 0;
519 rcubes.cubes = cubes;
520
521 return rcubes;
522}
523
524} // namespace CaDiCaL
525
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
#define PHASE(...)
Definition message.hpp:52
#define MSG(...)
Definition message.hpp:49
int sign(int lit)
Definition util.hpp:22
bool non_tautological_cube(std::vector< int > cube)
void shrink_vector(std::vector< T > &v)
Definition util.hpp:101
double percent(double a, double b)
Definition util.hpp:21
void rsort(I first, I last, Rank rank)
Definition radix.hpp:45
#define STOP(P)
Definition profile.hpp:158
#define START(P)
Definition profile.hpp:150
int lit
Definition satVec.h:130
std::vector< std::vector< int > > cubes
Definition internal.hpp:131
int & propfixed(int lit)
Definition internal.hpp:456
void mark_duplicated_binary_clauses_as_garbage()
External * external
Definition internal.hpp:312
bool is_binary_clause(Clause *c, int &, int &)
vector< int > trail
Definition internal.hpp:259
CubesWithStatus generate_cubes(int, int)
signed char val(int lit) const
vector< int64_t > ntab
Definition internal.hpp:239
std::vector< int > lookahead_populate_locc()
void failed_literal(int lit)
vector< int > assumptions
Definition internal.hpp:261
void reset_mode(Mode m)
Definition internal.hpp:169
bool active(int lit)
Definition internal.hpp:360
void backtrack(int target_level=0)
bool assumed(int lit)
int64_t & noccs(int lit)
Definition internal.hpp:466
void set_mode(Mode m)
Definition internal.hpp:165
void probe_assign_decision(int lit)
vector< Clause * > clauses
Definition internal.hpp:283
int solve(bool preprocess_only=false)
int lookahead_locc(const std::vector< int > &)
Internal * internal
Definition internal.hpp:311
vector< int > probes
Definition internal.hpp:281
volatile bool termination_forced
Definition internal.hpp:320
bool operator<(const literal_occ &locc) const
Definition exor.h:123