ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_probe.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "internal.hpp"
4
6
7namespace CaDiCaL {
8
9/*------------------------------------------------------------------------*/
10
11// Failed literal probing uses its own propagation and assignment
12// functions. It further provides on-the-fly generation of hyper binary
13// resolvents but only probes on roots of the binary implication graph. The
14// search for failed literals is limited, but untried roots are kept until
15// the next time 'probe' is called. Left over probes from the last attempt
16// and new probes are tried until the limit is hit or all are tried.
17
18/*------------------------------------------------------------------------*/
19
21 if (!opts.inprobing)
22 return false;
23 if (!preprocessing && !opts.inprocessing)
24 return false;
25 if (preprocessing)
26 CADICAL_assert (lim.preprocessing);
27 if (stats.inprobingphases && last.inprobe.reductions == stats.reductions)
28 return false;
29 return lim.inprobe <= stats.conflicts;
30}
31
32/*------------------------------------------------------------------------*/
33
35 const int idx = vidx (lit);
36 int res = parents[idx];
37 if (lit < 0)
38 res = -res;
39 return res;
40}
41
42inline void Internal::set_parent_reason_literal (int lit, int reason) {
43 const int idx = vidx (lit);
44 if (lit < 0)
45 reason = -reason;
46 parents[idx] = reason;
47}
48
49/*-----------------------------------------------------------------------*/
50
51// for opts.probehbr=false we need to do a lot of extra work to remember the
52// correct lrat_chains... This solution is also memory intensive I think
53// all corresponding functions are guarded to only work with the right
54// options so they can be called without checking for options
55//
56// call locally after failed_literal or backtracking
57//
59 if (!lrat || opts.probehbr)
60 return;
61 for (auto &field : probehbr_chains) {
62 for (auto &chain : field) {
63 chain.clear ();
64 }
65 }
66}
67
68// call globally before a probe round (or a lookahead round)
69//
71 if (!lrat || opts.probehbr)
72 return;
73 const size_t size = 2 * (1 + (size_t) max_var);
74 probehbr_chains.resize (size);
75 for (size_t i = 0; i < size; i++) {
76 probehbr_chains[i].resize (size);
77 // commented because not needed... should be empty already
78 /*
79 for (size_t j = 0; j < size; j++) {
80 vector<int64_t> empty;
81 probehbr_chains[i][j] = empty;
82 }
83 */
84 }
85}
86
87// sets lrat_chain to the stored chain in probehbr_chains.
88// this leads to conflict with unit reason uip
89//
90void Internal::get_probehbr_lrat (int lit, int uip) {
91 if (!lrat || opts.probehbr)
92 return;
94 CADICAL_assert (lrat_chain.empty ());
95 CADICAL_assert (val (uip) < 0);
97 int64_t id = unit_id (-uip);
98 lrat_chain.push_back (id);
99}
100
101// sets the corresponding probehbr_chain to what is currently stored in
102// lrat_chain. also clears lrat_chain.
103//
104void Internal::set_probehbr_lrat (int lit, int uip) {
105 if (!lrat || opts.probehbr)
106 return;
108 CADICAL_assert (lrat_chain.size ());
109 CADICAL_assert (probehbr_chains[vlit (lit)][vlit (uip)].empty ());
111 lrat_chain.clear ();
112}
113
114// compute lrat_chain for the part of the tree from lit to dom
115// use mini_chain because it needs to be reversed
116//
117void Internal::probe_dominator_lrat (int dom, Clause *reason) {
118 if (!lrat || !dom)
119 return;
120 LOG (reason, "probe dominator LRAT for %d from", dom);
121 for (const auto lit : *reason) {
122 if (val (lit) >= 0)
123 continue;
124 const auto other = -lit;
125 if (other == dom)
126 continue;
127 Flags &f = flags (other);
128 if (f.seen)
129 continue;
130 f.seen = true;
131 analyzed.push_back (other);
132 Var u = var (other);
133 if (u.level) {
134 if (!u.reason) {
135 LOG ("this may be a problem %d", other);
136 continue;
137 }
139 continue;
140 }
141 int64_t id = unit_id (other);
142 lrat_chain.push_back (id);
143 }
144 lrat_chain.push_back (reason->id);
145}
146
147/*------------------------------------------------------------------------*/
148
149// On-the-fly (dynamic) hyper binary resolution on decision level one can
150// make use of the fact that the implication graph is actually a tree.
151
152// Compute a dominator of two literals in the binary implication tree.
153
154int Internal::probe_dominator (int a, int b) {
156 int l = a, k = b;
157 Var *u = &var (l), *v = &var (k);
158 CADICAL_assert (val (l) > 0), CADICAL_assert (val (k) > 0);
159 CADICAL_assert (u->level == 1), CADICAL_assert (v->level == 1);
160 while (l != k) {
161 if (u->trail > v->trail)
162 swap (l, k), swap (u, v);
164 return l;
165 int parent = get_parent_reason_literal (k);
166 CADICAL_assert (parent), CADICAL_assert (val (parent) > 0);
167 v = &var (k = parent);
168 CADICAL_assert (v->level == 1);
169 }
170 LOG ("dominator %d of %d and %d", l, a, b);
171 CADICAL_assert (val (l) > 0);
172 return l;
173}
174
175// The idea of dynamic on-the-fly hyper-binary resolution came up in the
176// PrecoSAT solver, where it originally was used on all decision levels.
177
178// It turned out, that most of the hyper-binary resolvents were generated
179// during probing on decision level one anyhow. Thus this version is
180// specialized to decision level one, where actually all long (non-binary)
181// forcing clauses can be resolved to become binary. So if we find a clause
182// which would force a new assignment at decision level one during probing
183// we resolve it (the 'reason' argument) to obtain a hyper binary resolvent.
184// It consists of the still unassigned literal (the new unit) and the
185// negation of the unique closest dominator of the negation of all (false)
186// literals in the clause (which has to exist on decision level one).
187
188// There are two special cases which should be mentioned:
189//
190// (A) The reason is already a binary clause in a certain sense, since all
191// its unwatched literals are root level fixed to false. In this
192// situation it would be better to shrink the clause immediately instead
193// of adding a new clause consisting only of the watched literals.
194// However, this would happen during the next garbage collection anyhow.
195//
196// (B) The resolvent subsumes the original reason clause. This is
197// equivalent to the property that the negated dominator is contained in
198// the original reason. Again one could in principle shrink the clause.
199//
200// Note that (A) is actually subsumed by (B). The possible optimization to
201// shrink the clause on-the-fly is difficult (need to update 'blit' and
202// 'binary' of the other watch at least) and also not really that important.
203// For (B) we simply add the new binary resolvent and mark the old subsumed
204// clause as garbage instead. And since in the situation of (A) the
205// shrinking will be performed at the next garbage collection anyhow, we
206// do not change clauses in (A).
207
208// The hyper binary resolvent clause is redundant unless it subsumes the
209// original reason and that one is irredundant.
210
211// If the option 'opts.probehbr' is 'false', we actually do not add the new
212// hyper binary resolvent, but simply pretend we would have added it and
213// still return the dominator as new reason / parent for the new unit.
214
215// Finally note that adding clauses changes the watches of the propagated
216// literal and thus we can not use standard iterators during probing but
217// need to fall back to indices. One watch for the hyper binary resolvent
218// clause is added at the end of the currently propagated watches, but its
219// watch is a binary watch and will be skipped during propagating long
220// clauses anyhow.
221
224 CADICAL_assert (level == 1);
225 CADICAL_assert (reason->size > 2);
226 const const_literal_iterator end = reason->end ();
227 const int *lits = reason->literals;
229#ifndef CADICAL_NDEBUG
230 // First literal unassigned, all others false.
231 CADICAL_assert (!val (lits[0]));
232 for (k = lits + 1; k != end; k++)
233 CADICAL_assert (val (*k) < 0);
234 CADICAL_assert (var (lits[1]).level == 1);
235#endif
236 LOG (reason, "hyper binary resolving");
237 stats.hbrs++;
238 stats.hbrsizes += reason->size;
239 const int lit = lits[1];
240 int dom = -lit, non_root_level_literals = 0;
241 for (k = lits + 2; k != end; k++) {
242 const int other = -*k;
243 CADICAL_assert (val (other) > 0);
244 if (!var (other).level)
245 continue;
246 dom = probe_dominator (dom, other);
247 non_root_level_literals++;
248 }
249 probe_reason = reason;
250 if (non_root_level_literals && opts.probehbr) { // !(A)
251 bool contained = false;
252 for (k = lits + 1; !contained && k != end; k++)
253 contained = (*k == -dom);
254 const bool red = !contained || reason->redundant;
255 if (red)
256 stats.hbreds++;
257 LOG ("new %s hyper binary resolvent %d %d",
258 (red ? "redundant" : "irredundant"), -dom, lits[0]);
259 CADICAL_assert (clause.empty ());
260 clause.push_back (-dom);
261 clause.push_back (lits[0]);
262 probe_dominator_lrat (dom, reason);
263 if (lrat)
266 probe_reason = c;
267 if (red)
268 c->hyper = true;
269 clause.clear ();
270 lrat_chain.clear ();
271 if (contained) {
272 stats.hbrsubs++;
273 LOG (reason, "subsumed original");
274 mark_garbage (reason);
275 }
276 } else if (non_root_level_literals && lrat) {
277 // still calculate LRAT and remember for later
278 CADICAL_assert (!opts.probehbr);
279 probe_dominator_lrat (dom, reason);
281 set_probehbr_lrat (dom, lits[0]);
282 }
283 return dom;
284}
285
286/*------------------------------------------------------------------------*/
287
288// The following functions 'probe_assign' and 'probe_propagate' are used for
289// propagating during failed literal probing in simplification mode, as
290// replacement of the generic propagation routine 'propagate' and
291// 'search_assign'.
292
293// The code is mostly copied from 'propagate.cpp' and specialized. We only
294// comment on the differences. More explanations are in 'propagate.cpp'.
295
296inline void Internal::probe_assign (int lit, int parent) {
298 int idx = vidx (lit);
299 CADICAL_assert (!val (idx));
300 CADICAL_assert (!flags (idx).eliminated () || !parent);
301 CADICAL_assert (!parent || val (parent) > 0);
302 Var &v = var (idx);
303 v.level = level;
304 v.trail = (int) trail.size ();
306 num_assigned++;
307 v.reason = level ? probe_reason : 0;
308 probe_reason = 0;
310 if (!level)
312 else
313 CADICAL_assert (level == 1);
314 const signed char tmp = sign (lit);
315 set_val (idx, tmp);
316 CADICAL_assert (val (lit) > 0);
317 CADICAL_assert (val (-lit) < 0);
318 trail.push_back (lit);
319
320 // Do not save the current phase during inprocessing but remember the
321 // number of units on the trail of the last time this literal was
322 // assigned. This allows us to avoid some redundant failed literal
323 // probing attempts. Search for 'propfixed' in 'probe.cpp' for details.
324 //
325 if (level)
326 propfixed (lit) = stats.all.fixed;
327
328 if (parent)
329 LOG ("probe assign %d parent %d", lit, parent);
330 else if (level)
331 LOG ("probe assign %d probe", lit);
332 else
333 LOG ("probe assign %d negated failed literal UIP", lit);
334}
335
339 CADICAL_assert (propagated == trail.size ());
340 level++;
341 control.push_back (Level (lit, trail.size ()));
342 probe_assign (lit, 0);
343}
344
351
352/*------------------------------------------------------------------------*/
353
354// same as in propagate but inlined here
355//
357 if (!lrat)
358 return;
359 if (level)
360 return; // not decision level 0
361 LOG ("building chain for units");
362 CADICAL_assert (lrat_chain.empty ());
364 for (auto &reason_lit : *probe_reason) {
365 if (lit == reason_lit)
366 continue;
367 CADICAL_assert (val (reason_lit));
368 if (!val (reason_lit))
369 continue;
370 const int signed_reason_lit = val (reason_lit) * reason_lit;
371 int64_t id = unit_id (signed_reason_lit);
372 lrat_chain.push_back (id);
373 }
374 lrat_chain.push_back (probe_reason->id);
375}
376
377/*------------------------------------------------------------------------*/
378
379// This is essentially the same as 'propagate' except that we prioritize and
380// always propagate binary clauses first (see our CPAIOR'13 paper on tree
381// based look ahead), then immediately stop at a conflict and of course use
382// 'probe_assign' instead of 'search_assign'. The binary propagation part
383// is factored out too. If a new unit on decision level one is found we
384// perform hyper binary resolution and thus actually build an implication
385// tree instead of a DAG. Statistics counters are also different.
386
389 int64_t &ticks = stats.ticks.probe;
390 while (propagated2 != trail.size ()) {
391 const int lit = -trail[propagated2++];
392 LOG ("probe propagating %d over binary clauses", -lit);
393 Watches &ws = watches (lit);
394 ticks += 1 + cache_lines (ws.size (), sizeof (const_watch_iterator *));
395 for (const auto &w : ws) {
396 if (!w.binary ())
397 continue;
398 const signed char b = val (w.blit);
399 if (b > 0)
400 continue;
401 ticks++;
402 if (b < 0)
403 conflict = w.clause; // but continue
404 else {
405 CADICAL_assert (lrat_chain.empty ());
407 probe_reason = w.clause;
408 probe_lrat_for_units (w.blit);
409 probe_assign (w.blit, -lit);
410 lrat_chain.clear ();
411 }
412 }
413 }
414}
415
420 int64_t before = propagated2 = propagated;
421 int64_t &ticks = stats.ticks.probe;
422 while (!conflict) {
423 if (propagated2 != trail.size ())
425 else if (propagated != trail.size ()) {
426 const int lit = -trail[propagated++];
427 LOG ("probe propagating %d over large clauses", -lit);
428 Watches &ws = watches (lit);
429 ticks += 1 + cache_lines (ws.size (),
430 sizeof (sizeof (const_watch_iterator *)));
431 size_t i = 0, j = 0;
432 while (i != ws.size ()) {
433 const Watch w = ws[j++] = ws[i++];
434 if (w.binary ())
435 continue;
436 const signed char b = val (w.blit);
437 if (b > 0)
438 continue;
439 ticks++;
440 if (w.clause->garbage)
441 continue;
442 const literal_iterator lits = w.clause->begin ();
443 const int other = lits[0] ^ lits[1] ^ lit;
444 // lits[0] = other, lits[1] = lit;
445 const signed char u = val (other);
446 if (u > 0)
447 ws[j - 1].blit = other;
448 else {
449 const int size = w.clause->size;
450 const const_literal_iterator end = lits + size;
451 const literal_iterator middle = lits + w.clause->pos;
452 literal_iterator k = middle;
453 int r = 0;
454 signed char v = -1;
455 while (k != end && (v = val (r = *k)) < 0)
456 k++;
457 if (v < 0) {
458 k = lits + 2;
459 CADICAL_assert (w.clause->pos <= size);
460 while (k != middle && (v = val (r = *k)) < 0)
461 k++;
462 }
463 w.clause->pos = k - lits;
464 CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ());
465 if (v > 0)
466 ws[j - 1].blit = r;
467 else if (!v) {
468 ticks++;
469 LOG (w.clause, "unwatch %d in", r);
470 *k = lit;
471 lits[0] = other;
472 lits[1] = r;
473 watch_literal (r, lit, w.clause);
474 j--;
475 } else if (!u) {
476 ticks++;
477 if (level == 1) {
478 lits[0] = other, lits[1] = lit;
479 CADICAL_assert (lrat_chain.empty ());
481 int dom = hyper_binary_resolve (w.clause);
482 probe_assign (other, dom);
483 } else {
484 ticks++;
485 CADICAL_assert (lrat_chain.empty ());
488 probe_lrat_for_units (other);
489 probe_assign_unit (other);
490 lrat_chain.clear ();
491 }
493 } else
494 conflict = w.clause;
495 }
496 }
497 if (j != i) {
498 while (i != ws.size ())
499 ws[j++] = ws[i++];
500 ws.resize (j);
501 }
502 } else
503 break;
504 }
505 int64_t delta = propagated2 - before;
506 stats.propagations.probe += delta;
507 if (conflict)
508 LOG (conflict, "conflict");
509 STOP (propagate);
510 return !conflict;
511}
512
513/*------------------------------------------------------------------------*/
514
515// This a specialized instance of 'analyze'.
516
518
519 LOG ("analyzing failed literal probe %d", failed);
520 stats.failed++;
521 stats.probefailed++;
522
525 CADICAL_assert (level == 1);
526 CADICAL_assert (analyzed.empty ());
527 CADICAL_assert (lrat_chain.empty ());
528
529 START (analyze);
530
531 LOG (conflict, "analyzing failed literal conflict");
532
533 int uip = 0;
534 for (const auto &lit : *conflict) {
535 const int other = -lit;
536 if (!var (other).level) {
537 CADICAL_assert (val (other) > 0);
538 continue;
539 }
540 uip = uip ? probe_dominator (uip, other) : other;
541 }
543 if (lrat)
545
546 LOG ("found probing UIP %d", uip);
547 CADICAL_assert (uip);
548
549 vector<int> work;
550
551 int parent = uip;
552 while (parent != failed) {
553 const int next = get_parent_reason_literal (parent);
554 parent = next;
555 CADICAL_assert (parent);
556 work.push_back (parent);
557 }
558
559 backtrack ();
560 conflict = 0;
561
562 CADICAL_assert (!val (uip));
563 probe_assign_unit (-uip);
564 lrat_chain.clear ();
565
566 if (!probe_propagate ())
568
569 size_t j = 0;
570 while (!unsat && j < work.size ()) {
571 // CADICAL_assert (!opts.probehbr); CADICAL_assertion fails ...
572 const int parent = work[j++];
573 const signed char tmp = val (parent);
574 if (tmp > 0) {
575 CADICAL_assert (!opts.probehbr); // ... CADICAL_assertion should hold here
576 get_probehbr_lrat (parent, uip);
577 LOG ("clashing failed parent %d", parent);
579 } else if (tmp == 0) {
580 CADICAL_assert (!opts.probehbr); // ... and here
581 LOG ("found unassigned failed parent %d", parent);
582 get_probehbr_lrat (parent, uip); // this is computed during
583 probe_assign_unit (-parent); // propagation and can include
584 lrat_chain.clear (); // multiple chains where only one
585 if (!probe_propagate ())
586 learn_empty_clause (); // is needed!
587 }
588 uip = parent;
589 }
590 work.clear ();
591 erase_vector (work);
592
593 STOP (analyze);
594
595 CADICAL_assert (unsat || val (failed) < 0);
596}
597
598/*------------------------------------------------------------------------*/
599
600bool Internal::is_binary_clause (Clause *c, int &a, int &b) {
602 if (c->garbage)
603 return false;
604 int first = 0, second = 0;
605 for (const auto &lit : *c) {
606 const signed char tmp = val (lit);
607 if (tmp > 0)
608 return false;
609 if (tmp < 0)
610 continue;
611 if (second)
612 return false;
613 if (first)
614 second = lit;
615 else
616 first = lit;
617 }
618 if (!second)
619 return false;
620 a = first, b = second;
621 return true;
622}
623
624// We probe on literals first, which occur more often negated and thus we
625// sort the 'probes' stack in such a way that literals which occur negated
626// less frequently come first. Probes are taken from the back of the stack.
627
631 typedef size_t Type;
632 Type operator() (int a) const { return internal->noccs (-a); }
633};
634
635// Fill the 'probes' schedule.
636
638
639 CADICAL_assert (probes.empty ());
640
641 int64_t &ticks = stats.ticks.probe;
642
643 // First determine all the literals which occur in binary clauses. It is
644 // way faster to go over the clauses once, instead of walking the watch
645 // lists for each literal.
646 //
647 init_noccs ();
648 ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *));
649 for (const auto &c : clauses) {
650 int a, b;
651 ticks++;
652 if (!is_binary_clause (c, a, b))
653 continue;
654 noccs (a)++;
655 noccs (b)++;
656 }
657
658 for (auto idx : vars) {
659
660 // Then focus on roots of the binary implication graph, which are
661 // literals occurring negatively in a binary clause, but not positively.
662 // If neither 'idx' nor '-idx' is a root it makes less sense to probe
663 // this variable.
664
665 // This argument requires that equivalent literal substitution through
666 // 'decompose' is performed, because otherwise there might be 'cyclic
667 // roots' which are not tried, i.e., -1 2 0, 1 -2 0, 1 2 3 0, 1 2 -3 0.
668
669 ticks += 2;
670
671 const bool have_pos_bin_occs = noccs (idx) > 0;
672 const bool have_neg_bin_occs = noccs (-idx) > 0;
673
674 if (have_pos_bin_occs == have_neg_bin_occs)
675 continue;
676
677 int probe = have_neg_bin_occs ? idx : -idx;
678
679 // See the discussion where 'propfixed' is used below.
680 //
681 if (propfixed (probe) >= stats.all.fixed)
682 continue;
683
684 LOG ("scheduling probe %d negated occs %" PRId64 "", probe,
685 noccs (-probe));
686 probes.push_back (probe);
687 }
688
689 rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this));
690
691 reset_noccs ();
693
694 PHASE ("probe-round", stats.probingrounds,
695 "scheduled %zd literals %.0f%%", probes.size (),
696 percent (probes.size (), 2u * max_var));
697}
698
699// Follow the ideas in 'generate_probes' but flush non root probes and
700// reorder remaining probes.
701
703
704 CADICAL_assert (!probes.empty ());
705 int64_t &ticks = stats.ticks.probe;
706
707 init_noccs ();
708 ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *));
709 for (const auto &c : clauses) {
710 int a, b;
711 ticks++;
712 if (!is_binary_clause (c, a, b))
713 continue;
714 noccs (a)++;
715 noccs (b)++;
716 }
717
718 const auto eop = probes.end ();
719 auto j = probes.begin ();
720 for (auto i = j; i != eop; i++) {
721 int lit = *i;
722 if (!active (lit))
723 continue;
724 ticks += 2;
725 const bool have_pos_bin_occs = noccs (lit) > 0;
726 const bool have_neg_bin_occs = noccs (-lit) > 0;
727 if (have_pos_bin_occs == have_neg_bin_occs)
728 continue;
729 if (have_pos_bin_occs)
730 lit = -lit;
732 if (propfixed (lit) >= stats.all.fixed)
733 continue;
734 LOG ("keeping probe %d negated occs %" PRId64 "", lit, noccs (-lit));
735 *j++ = lit;
736 }
737 size_t remain = j - probes.begin ();
738#ifndef CADICAL_QUIET
739 size_t flushed = probes.size () - remain;
740#endif
741 probes.resize (remain);
742
743 rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this));
744
745 reset_noccs ();
747
748 PHASE ("probe-round", stats.probingrounds,
749 "flushed %zd literals %.0f%% remaining %zd", flushed,
750 percent (flushed, remain + flushed), remain);
751}
752
754
755 int generated = 0;
756
757 for (;;) {
758
759 if (probes.empty ()) {
760 if (generated++)
761 return 0;
763 }
764
765 while (!probes.empty ()) {
766
767 int probe = probes.back ();
768 probes.pop_back ();
769
770 // Eliminated or assigned.
771 //
772 if (!active (probe))
773 continue;
774
775 // There is now new unit since the last time we propagated this probe,
776 // thus we propagated it before without obtaining a conflict and
777 // nothing changed since then. Thus there is no need to propagate it
778 // again. This observation was independently made by Partik Simons
779 // et.al. in the context of implementing 'smodels' (see for instance
780 // Alg. 4 in his JAIR article from 2002) and it has also been
781 // contributed to the thesis work of Yacine Boufkhad.
782 //
783 if (propfixed (probe) >= stats.all.fixed)
784 continue;
785
786 return probe;
787 }
788 }
789}
790
792
793 if (!opts.probe)
794 return false;
795 if (unsat)
796 return false;
798 return false;
799
801
803 stats.probingrounds++;
804
805 // Probing is limited in terms of non-probing propagations
806 // 'stats.propagations'. We allow a certain percentage 'opts.probeeffort'
807 // (say %5) of probing propagations in each probing with a lower bound of
808 // 'opts.probmineff'.
809 //
810
811 PHASE ("probe-round", stats.probingrounds,
812 "probing limit of %" PRId64 " propagations ", limit);
813
814 int old_failed = stats.failed;
815#ifndef CADICAL_QUIET
816 int64_t old_probed = stats.probed;
817#endif
818 int64_t old_hbrs = stats.hbrs;
819
820 if (!probes.empty ())
821 flush_probes ();
822
823 // We reset 'propfixed' since there was at least another conflict thus
824 // a new learned clause, which might produce new propagations (and hyper
825 // binary resolvents). During 'generate_probes' we keep the old value.
826 //
827 for (auto idx : vars)
828 propfixed (idx) = propfixed (-idx) = -1;
829
830 CADICAL_assert (unsat || propagated == trail.size ());
831 propagated = propagated2 = trail.size ();
832
833 int probe;
835 while (!unsat && !terminated_asynchronously () &&
836 stats.ticks.probe < limit && (probe = next_probe ())) {
837 stats.probed++;
838 LOG ("probing %d", probe);
840 if (probe_propagate ())
841 backtrack ();
842 else
845 }
846
847 if (unsat)
848 LOG ("probing derived empty clause");
849 else if (propagated < trail.size ()) {
850 LOG ("probing produced %zd units",
851 (size_t) (trail.size () - propagated));
852 if (!propagate ()) {
853 LOG ("propagating units after probing results in empty clause");
855 } else
856 sort_watches ();
857 }
858
859 int failed = stats.failed - old_failed;
860#ifndef CADICAL_QUIET
861 int64_t probed = stats.probed - old_probed;
862#endif
863 int64_t hbrs = stats.hbrs - old_hbrs;
864
865 PHASE ("probe-round", stats.probingrounds,
866 "probed %" PRId64 " and found %d failed literals", probed, failed);
867
868 if (hbrs)
869 PHASE ("probe-round", stats.probingrounds,
870 "found %" PRId64 " hyper binary resolvents", hbrs);
871
873
874 report ('p', !opts.reportall && !(unsat + failed + hbrs));
875
876 return !unsat && failed;
877}
878
879/*------------------------------------------------------------------------*/
880
881// This schedules a number of inprocessing techniques.
882// These range from very cheap and beneficial (decompose) to
883// more expensive and sometimes less beneficial. We want to limit
884// expensive techniques to some fraction of total time or search time.
885// this is done using 'ticks'.
886// Generally, there are options for each of the techniques to set the
887// efficiency, i.e., the fraction of ticks they are allowed as budget.
888// Whenever e.g. vivify is called, the budget is calculated from the
889// search ticks that have passed since the last vivify round and this
890// efficiency.
891// We want to be able to run inprocessing frequently, without it dominating
892// runtimes. This entire inprocessing scheme is scheduled after a certain
893// amount of conflicts were found, the gap between two inprocessing rounds
894// increasing by a constant number each time. In effect, the number of
895// inprocessing rounds is allways the square root of the number of conflicts
896// with some constant factor.
897// This factor can also be with the option 'inprobeint'
898// Some of the techniques are not run always, for different reasons.
899// 'factor' or BVA depends on certain structures of the irredundant clauses
900// and as such will only be run when new irredundant clauses are derived or
901// it was not able to finish with the entire search space.
902// 'sweeping' is especially usefull on certain classes of formulas, and uses
903// a increasing or decreasing delay that depends on how usefull it was.
904// In cases where it is less usefull, we obviously want to reset the budged,
905// even if the routine was delayed.
906// Additionally 'vivify', 'sweep' and 'factor' can also have a big initial
907// overhead in setting up the datastructures. This has to be accounted for
908// with the 'ticks', however, since inprocessing is done frequently, this
909// overhead is too expensive to pay. So instead, we accumulate the budget
910// of 'ticks' and delay the technique until it passes a certain threshhold,
911// which depends on the the cost of initialization. Note that in the case of
912// sweeping, we have two different delays, one which resets the budged, and
913// one which passes it to the next round. In this case the former takes
914// precendent, until we would run sweeping once, at which point the focus
915// switches to the latter delay until the budget is big enough, such that
916// sweeping can be run. Then we switch back to the other delay.
917
918void CaDiCaL::Internal::inprobe (bool update_limits) {
919
920 if (unsat)
921 return;
922 if (level)
923 backtrack ();
924 if (!propagate ()) {
926 return;
927 }
928
929 stats.inprobingphases++;
930 if (external_prop) {
932 private_steps = true;
933 }
934 const int before = active ();
935 const int before_extended = stats.variables_extension;
936
937 // schedule of inprobing techniques.
938 //
939 {
941 decompose ();
942 if (ternary ())
943 decompose (); // If we derived a binary clause
944 if (probe ())
945 decompose ();
946
947 if (extract_gates ())
948 decompose ();
949 if (sweep ()) // full occurrence list
950 decompose (); // ... and (ELS) afterwards.
951 (void) vivify (); // resets watches
952 transred (); // builds big.
953 factor (); // resets watches, partial occurrence list
954 }
955
956 if (external_prop) {
958 private_steps = false;
959 }
960
961 if (!update_limits)
962 return;
963
964 const int after = active ();
965 const int after_extended = stats.variables_extension;
966 const int diff_extended = after_extended - before_extended;
967 CADICAL_assert (diff_extended >= 0);
968 const int removed = before - after + diff_extended;
969 CADICAL_assert (removed >= 0);
970
971 if (removed) {
972 stats.inprobesuccess++;
973 PHASE ("probe-phase", stats.inprobingphases,
974 "successfully removed %d active variables %.0f%%", removed,
975 percent (removed, before));
976 } else
977 PHASE ("probe-phase", stats.inprobingphases,
978 "could not remove any active variable");
979
980 const int64_t delta =
981 25 * opts.inprobeint * log10 (stats.inprobingphases + 9);
982 lim.inprobe = stats.conflicts + delta;
983
984 PHASE ("probe-phase", stats.inprobingphases,
985 "new limit at %" PRId64 " conflicts after %" PRId64 " conflicts",
986 lim.inprobe, delta);
987
988 last.inprobe.reductions = stats.reductions;
989}
990
991} // namespace CaDiCaL
992
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
#define SET_EFFORT_LIMIT(LIMIT, NAME, THRESHHOLD)
Definition limit.hpp:131
#define PHASE(...)
Definition message.hpp:52
int sign(int lit)
Definition util.hpp:22
void shrink_vector(std::vector< T > &v)
Definition util.hpp:101
Watches::const_iterator const_watch_iterator
Definition watch.hpp:48
int * literal_iterator
Definition clause.hpp:17
const char * flags()
bool contained(int64_t c, int64_t l, int64_t u)
Definition util.hpp:49
const int * const_literal_iterator
Definition clause.hpp:18
vector< Watch > Watches
Definition watch.hpp:45
void erase_vector(std::vector< T > &v)
Definition util.hpp:90
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_SIMPLIFIER(S, M)
Definition profile.hpp:172
#define STOP_SIMPLIFIER(S, M)
Definition profile.hpp:197
#define START(P)
Definition profile.hpp:150
int lit
Definition satVec.h:130
literal_iterator begin()
Definition clause.hpp:131
literal_iterator end()
Definition clause.hpp:132
int & propfixed(int lit)
Definition internal.hpp:456
void mark_duplicated_binary_clauses_as_garbage()
void watch_literal(int lit, int blit, Clause *c)
Definition internal.hpp:623
int64_t cache_lines(size_t bytes)
Definition internal.hpp:722
void inprobe(bool update_limits=true)
vector< int > analyzed
Definition internal.hpp:267
Var & var(int lit)
Definition internal.hpp:452
void mark_garbage(Clause *)
vector< int64_t > lrat_chain
Definition internal.hpp:210
int vidx(int lit) const
Definition internal.hpp:395
bool is_binary_clause(Clause *c, int &, int &)
void report(char type, int verbose_level=0)
Flags & flags(int lit)
Definition internal.hpp:454
vector< int > trail
Definition internal.hpp:259
bool terminated_asynchronously(int factor=1)
const Sange lits
Definition internal.hpp:325
void probe_assign_unit(int lit)
signed char val(int lit) const
bool limit(const char *name, int)
int64_t unit_id(int lit) const
Definition internal.hpp:434
void set_val(int lit, signed char val)
void set_parent_reason_literal(int lit, int reason)
void failed_literal(int lit)
void probe_assign(int lit, int parent)
bool active(int lit)
Definition internal.hpp:360
void backtrack(int target_level=0)
int64_t & noccs(int lit)
Definition internal.hpp:466
unsigned vlit(int lit) const
Definition internal.hpp:408
void probe_assign_decision(int lit)
vector< Clause * > clauses
Definition internal.hpp:283
vector< vector< vector< int64_t > > > probehbr_chains
Definition internal.hpp:216
Clause * new_hyper_binary_resolved_clause(bool red, int glue)
const Range vars
Definition internal.hpp:324
int probe_dominator(int a, int b)
void require_mode(Mode m) const
Definition internal.hpp:173
void get_probehbr_lrat(int lit, int uip)
int get_parent_reason_literal(int lit)
vector< Level > control
Definition internal.hpp:282
vector< int > parents
Definition internal.hpp:232
void probe_lrat_for_units(int lit)
void learn_unit_clause(int lit)
void probe_dominator_lrat(int dom, Clause *reason)
Clause * probe_reason
Definition internal.hpp:252
vector< int > probes
Definition internal.hpp:281
void set_probehbr_lrat(int lit, int uip)
int hyper_binary_resolve(Clause *)
vector< int > clause
Definition internal.hpp:260
int level
Definition var.hpp:19
int trail
Definition var.hpp:20
Clause * reason
Definition var.hpp:21
bool binary() const
Definition watch.hpp:42
Clause * clause
Definition watch.hpp:35
unsigned size
Definition vector.h:35
vector watches
Definition watch.h:49