ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_condition.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// Globally blocked clause elimination (which we call here 'conditioning')
12// is described first in the PhD thesis of Benjamin Kiesl from 2019. An
13// extended version, which in particular describes the algorithm implemented
14// below is in our invited ATVA'19 paper [KieslHeuleBiere-ATVA'19]. This
15// accordingly needs witnesses consisting potentially of more than one
16// literal. It is the first technique implemented in CaDiCaL with this
17// feature (PR clause elimination thus should work in principle too).
18
19// Basically globally blocked clauses are like set blocked clauses, except
20// that the witness cube (of literals to be flipped during reconstruction)
21// can contain variables which are not in the blocked clause. This
22// can simulate some interesting global optimizations like 'headlines' from
23// the FAN algorithm for ATPG. The technique was actually motivated to
24// simulate this optimization. It turns out that globally blocked clauses
25// can be seen as 'conditional autarkies', where in essence the condition
26// cube is the negation of the globally blocked redundant clause (it
27// needs to contain one autarky literal though) and the autarky part
28// represents the witness.
29
30/*------------------------------------------------------------------------*/
31
32// Elimination of globally blocked clauses is first tried in regular
33// intervals in terms of the number of conflicts. Then the main heuristics
34// is to trigger 'condition' if the decision level is above the current
35// moving average of the back jump level.
36
37// TODO We might need to consider less frequent conditioning.
38
40
41 if (!opts.condition)
42 return false;
43 if (!preprocessing && !opts.inprocessing)
44 return false;
45 if (preprocessing)
46 CADICAL_assert (lim.preprocessing);
47
48 // Triggered in regular 'opts.conditionint' conflict intervals.
49 //
50 if (lim.condition > stats.conflicts)
51 return false;
52
53 if (!level)
54 return false; // One decision necessary.
55
56 if (level <= averages.current.jump)
57 return false; // Main heuristic.
58
59 if (!stats.current.irredundant)
60 return false;
61 double remain = active ();
62 if (!remain)
63 return false;
64 double ratio = stats.current.irredundant / remain;
65 return ratio <= opts.conditionmaxrat;
66}
67
68/*------------------------------------------------------------------------*/
69
70// We start with the current assignment and then temporarily unassign
71// literals. They are reassigned afterwards. The global state of the CDCL
72// solver should not change though. Thus we copied from 'search_unassign'
73// in 'backtrack.cpp' what is needed to unassign literals and then from
74// 'search_assign' in 'propagate.cpp' what is needed for reassigning
75// literals, but restricted the copied code to only updating the actual
76// assignment (in 'vals') and not changing anything else.
77
78// We use temporarily unassigning for two purposes. First, if a conditional
79// literal does not occur negated in a candidate clause it is unassigned.
80// Second, as a minor optimization, we first unassign all root-level
81// assigned (fixed) literals, to avoid checking the decision level of
82// literals during the procedure.
83
85 LOG ("condition unassign %d", lit);
86 CADICAL_assert (val (lit) > 0);
87 set_val (lit, 0);
88}
89
91 LOG ("condition assign %d", lit);
93 set_val (lit, 1);
94}
95
96/*------------------------------------------------------------------------*/
97
98// The current partition into conditional part and autarky part during
99// refinement is represented through a conditional bit in 'marks'.
100
101inline bool Internal::is_conditional_literal (int lit) const {
102 return val (lit) > 0 && getbit (lit, 0);
103}
104
105inline bool Internal::is_autarky_literal (int lit) const {
106 return val (lit) > 0 && !getbit (lit, 0);
107}
108
110 LOG ("marking %d as conditional literal", lit);
111 CADICAL_assert (val (lit) > 0);
112 setbit (lit, 0);
115}
116
118 LOG ("unmarking %d as conditional literal", lit);
120 unsetbit (lit, 0);
121}
122
123/*------------------------------------------------------------------------*/
124
125// We also need to know the literals which are in the current clause. These
126// are just marked (also in 'marks' but with the (signed) upper two bits).
127// We need a signed mark here, since we have to distinguish positive and
128// negative occurrences of literals in the candidate clause.
129
130inline bool Internal::is_in_candidate_clause (int lit) const {
131 return marked67 (lit) > 0;
132}
133
135 LOG ("marking %d as literal of the candidate clause", lit);
136 mark67 (lit);
139}
140
142 LOG ("unmarking %d as literal of the candidate clause", lit);
144 unmark67 (lit);
145}
146
147/*------------------------------------------------------------------------*/
148
150 bool operator() (Clause *a, Clause *b) {
151 return !a->conditioned && b->conditioned;
152 }
153};
154
155// This is the function for eliminating globally blocked clauses. It is
156// triggered during CDCL search according to 'conditioning' above and uses
157// the current assignment as basis to find globally blocked clauses.
158
159long Internal::condition_round (long delta) {
160
161 long limit;
162#ifndef CADICAL_QUIET
163 long props = 0;
164#endif
165 if (LONG_MAX - delta < stats.condprops)
166 limit = LONG_MAX;
167 else
168 limit = stats.condprops + delta;
169
170 size_t initial_trail_level = trail.size ();
171 int initial_level = level;
172
173 LOG ("initial trail level %zd", initial_trail_level);
174
176
177#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
178 int additionally_assigned = 0;
179#endif
180
181 for (auto idx : vars) {
182 const signed char tmp = val (idx);
183 Var &v = var (idx);
184 if (tmp) {
185 if (v.level) {
186 const int lit = tmp < 0 ? -idx : idx;
187 if (!active (idx)) {
188 LOG ("temporarily unassigning inactive literal %d", lit);
190 }
191 if (frozen (idx)) {
192 LOG ("temporarily unassigning frozen literal %d", lit);
194 }
195 }
196 } else if (frozen (idx)) {
197 LOG ("keeping frozen literal %d unassigned", idx);
198 } else if (!active (idx)) {
199 LOG ("keeping inactive literal %d unassigned", idx);
200 } else { // if (preprocessing) {
201 if (initial_level == level) {
202 level++;
203 LOG ("new condition decision level");
204 }
205 const int lit = decide_phase (idx, true);
207 v.level = level;
208 trail.push_back (lit);
209#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
210 additionally_assigned++;
211#endif
212 }
213 }
214 LOG ("assigned %d additional literals", additionally_assigned);
215
216 // We compute statistics about the size of the assignments.
217 //
218 // The initial assignment consists of the non-root-level assigned literals
219 // split into a conditional and an autarky part. The conditional part
220 // consists of literals assigned true and occurring negated in a clause
221 // (touch the clause), which does not contain another literal assigned to
222 // true. This initial partition is the same for all refinements used in
223 // checking whether a candidate clause is globally blocked.
224 //
225 // For each candidate clause some of the conditional literals have to be
226 // unassigned, and the autarky is shrunken by turning some of the autarky
227 // literals into conditional literals (which might get unassigned in a
228 // later refinement though).
229 //
230 // The fix-point of this procedure produces a final assignment, which
231 // consists of the remaining assigned literals, again split into a
232 // conditional and an autarky part.
233 //
234 struct {
235 size_t assigned, conditional, autarky;
236 } initial, remain;
237
238 initial.assigned = 0;
239 for (auto idx : vars) {
240 const signed char tmp = val (idx);
241 if (!tmp)
242 continue;
243 if (!var (idx).level)
244 continue;
245 LOG ("initial assignment %ds", tmp < 0 ? -idx : idx);
246 initial.assigned++;
247 }
248
249 PHASE ("condition", stats.conditionings, "initial assignment of size %zd",
250 initial.assigned);
251
252 // For each candidate clause we refine the assignment (monotonically),
253 // by unassigning some conditional literals and turning some autarky
254 // literals into conditionals.
255 //
256 // As the conditional part is usually smaller than the autarky part our
257 // implementation only explicitly maintains the initial conditional part,
258 // with conditional bit set to true through 'mark_as_conditional_literal'.
259 // The autarky part consists of all literals assigned true which do not
260 // have their conditional bit set to true. Since in both cases the
261 // literal has to be assigned true, we only need a single bit for both the
262 // literal as well as its negation (it does not have to be 'signed').
263 //
264 vector<int> conditional;
265
266 vector<Clause *> candidates; // Gather candidate clauses.
267#ifndef CADICAL_QUIET
268 size_t watched = 0; // Number of watched clauses.
269#endif
270
271 initial.autarky = initial.assigned; // Initially all are in autarky
272 initial.conditional = 0; // and none in conditional part.
273
274 // Upper bound on the number of watched clauses. In principle one could
275 // use 'SIZE_MAX' but this is not available by default (yet).
276 //
277 const size_t size_max = clauses.size () + 1;
278
279 // Initialize additional occurrence lists.
280 //
281 init_occs ();
282
283 // Number of previously conditioned and unconditioned candidates.
284 //
285 size_t conditioned = 0, unconditioned = 0;
286
287 // Now go over all (non-garbage) irredundant clauses and check whether
288 // they are candidates, have to be watched, or whether they force the
289 // negation of some of their literals to be conditional initially.
290 //
291 for (const auto &c : clauses) {
292 if (c->garbage)
293 continue; // Can already be ignored.
294 if (c->redundant)
295 continue; // Ignore redundant clauses too.
296
297 // First determine the following numbers for the candidate clause
298 // (restricted to non-root-level assignments).
299 //
300 int positive = 0; // Number true literals.
301 int negative = 0; // Number false literals.
302 int watch = 0; // True Literal to watch.
303 //
304 size_t minsize = size_max; // Number of occurrences of 'watch'.
305 //
306 // But also ignore root-level satisfied but not yet garbage clauses.
307 //
308 bool satisfied = false; // Root level satisfied.
309 //
310 for (const_literal_iterator l = c->begin ();
311 !satisfied && l != c->end (); l++) {
312 const int lit = *l;
313 const signed char tmp = val (lit);
314 if (tmp && !var (lit).level)
315 satisfied = (tmp > 0);
316 else if (tmp < 0)
317 negative++;
318 else if (tmp > 0) {
319 const size_t size = occs (lit).size ();
320 if (size < minsize)
321 watch = lit, minsize = size;
322 positive++;
323 }
324 }
325 if (satisfied) { // Ignore root-level satisfied clauses.
326 mark_garbage (c); // But mark them as garbage already now.
327 continue; // ... with next clause 'c'.
328 }
329
330 // Candidates are clauses with at least a positive literal in it.
331 //
332 if (positive > 0) {
333 LOG (c, "found %d positive literals in candidate", positive);
334 candidates.push_back (c);
335 if (c->conditioned)
336 conditioned++;
337 else
338 unconditioned++;
339 }
340
341 // Only one positive literal in each clauses with also at least one
342 // negative literal has to be watched in occurrence lists. These
343 // watched clauses will be checked to contain only negative literals as
344 // soon such a positive literal is unassigned. If this is the case
345 // these false literals have to be unassigned and potentially new
346 // conditional literals have to be determined.
347 //
348 // Note that only conditional literals are unassigned. However it does
349 // not matter that we might also watch autarky literals, because either
350 // such an autarky literal remains a witness that the clause is
351 // satisfied as long it remains an autarky literal. Otherwise at one
352 // point it becomes conditional and is unassigned, but then a
353 // replacement watch will be searched.
354 //
355 if (negative > 0 && positive > 0) {
356 LOG (c, "found %d negative literals in candidate", negative);
358 CADICAL_assert (val (watch) > 0);
359 Occs &os = occs (watch);
360 CADICAL_assert (os.size () == minsize);
361 os.push_back (c);
362#ifndef CADICAL_QUIET
363 watched++;
364#endif
365 LOG (c, "watching %d with %zd occurrences in", watch, minsize);
366 }
367
368 // The initial global conditional part for the current assignment is
369 // extracted from clauses with only negative literals. It is the same
370 // for all considered candidate clauses. These negative literals make up
371 // the global conditional part, are marked here.
372 //
373 if (negative > 0 && !positive) {
374
375 size_t new_conditionals = 0;
376
377 for (const_literal_iterator l = c->begin (); l != c->end (); l++) {
378 const int lit = *l;
379 signed char tmp = val (lit);
380 if (!tmp)
381 continue;
382 CADICAL_assert (tmp < 0);
383 if (!var (lit).level)
384 continue; // Not unassigned yet!
386 continue;
388 conditional.push_back (-lit);
389 new_conditionals++;
390 }
391 if (new_conditionals > 0)
392 LOG (c, "marked %zu negations of literals as conditional in",
393 new_conditionals);
394
395 initial.conditional += new_conditionals;
396 CADICAL_assert (initial.autarky >= new_conditionals);
397 initial.autarky -= new_conditionals;
398 }
399
400 } // End of loop over all clauses to collect candidates etc.
401
402 PHASE ("condition", stats.conditionings, "found %zd candidate clauses",
403 candidates.size ());
404 PHASE ("condition", stats.conditionings,
405 "watching %zu literals and clauses", watched);
406 PHASE ("condition", stats.conditionings,
407 "initially %zd conditional literals %.0f%%", initial.conditional,
408 percent (initial.conditional, initial.assigned));
409 PHASE ("condition", stats.conditionings,
410 "initially %zd autarky literals %.0f%%", initial.autarky,
411 percent (initial.autarky, initial.assigned));
412#ifdef LOGGING
413 for (size_t i = 0; i < conditional.size (); i++) {
414 LOG ("initial conditional %d", conditional[i]);
415 CADICAL_assert (is_conditional_literal (conditional[i]));
416 }
417 for (size_t i = 0; i < trail.size (); i++)
418 if (is_autarky_literal (trail[i]))
419 LOG ("initial autarky %d", trail[i]);
420#endif
421 CADICAL_assert (initial.conditional == conditional.size ());
422 CADICAL_assert (initial.assigned == initial.conditional + initial.autarky);
423
424 stats.condassinit += initial.assigned;
425 stats.condcondinit += initial.conditional;
426 stats.condautinit += initial.autarky;
427 stats.condassvars += active ();
428
429 // To speed-up and particularly simplify the code we unassign all
430 // root-level variables temporarily, actually all inactive assigned
431 // variables. This allows us to avoid tests on whether an assigned
432 // literal is actually root-level assigned and thus should be ignored (not
433 // considered to be assigned). For this to work we have to ignore root
434 // level satisfied clauses as done above. These are neither candidates
435 // nor have to be watched. Remaining originally root-level assigned
436 // literals in clauses are only set to false.
437 //
438 for (const auto &lit : trail)
439 if (fixed (lit))
441
442 // Stack to save temporarily unassigned (conditional) literals.
443 //
444 vector<int> unassigned;
445
446 // Make sure to focus on clauses not tried before by marking clauses which
447 // have been checked before using the 'conditioned' bit of clauses. If all
448 // candidates have their bit set, we have to reset it. Since the
449 // assignment might be completely different then last time and thus also
450 // the set of candidates this method does not really exactly lead to a
451 // round robin scheme of scheduling clauses.
452 //
453 // TODO consider computing conditioned and unconditioned over all clauses.
454 //
455 CADICAL_assert (conditioned + unconditioned == candidates.size ());
456 if (conditioned && unconditioned) {
457 stable_sort (candidates.begin (), candidates.end (),
459 PHASE ("condition", stats.conditionings,
460 "focusing on %zd candidates %.0f%% not tried last time",
461 unconditioned, percent (unconditioned, candidates.size ()));
462 } else if (conditioned && !unconditioned) {
463 for (auto const &c : candidates) {
464 CADICAL_assert (c->conditioned);
465 c->conditioned = false; // Reset 'conditioned' bit.
466 }
467 PHASE ("condition", stats.conditionings,
468 "all %zd candidates tried before", conditioned);
469 } else {
470 CADICAL_assert (!conditioned);
471 PHASE ("condition", stats.conditionings, "all %zd candidates are fresh",
472 unconditioned);
473 }
474
475 // TODO prune assignments further!
476 // And thus might result in less watched clauses.
477 // So watching should be done here and not earlier.
478 // Also, see below, we might need to consider the negation of unassigned
479 // literals in candidate clauses as being watched.
480
481 // Now try to block all candidate clauses.
482 //
483 long blocked = 0; // Number of Successfully blocked clauses.
484 //
485#ifndef CADICAL_QUIET
486 size_t untried = candidates.size ();
487#endif
488 for (const auto &c : candidates) {
489
490 if (initial.autarky <= 0)
491 break;
492
493 if (c->reason)
494 continue;
495
496 bool terminated_or_limit_hit = true;
498 LOG ("asynchronous termination detected");
499 else if (stats.condprops >= limit)
500 LOG ("condition propagation limit %ld hit", limit);
501 else
502 terminated_or_limit_hit = false;
503
504 if (terminated_or_limit_hit) {
505 PHASE ("condition", stats.conditionings,
506 "%zd candidates %.0f%% not tried after %ld propagations",
507 untried, percent (untried, candidates.size ()), props);
508 break;
509 }
510#ifndef CADICAL_QUIET
511 untried--;
512#endif
513 CADICAL_assert (!c->garbage);
514 CADICAL_assert (!c->redundant);
515
516 LOG (c, "candidate");
517 c->conditioned = 1; // Next time later.
518
519 // We watch an autarky literal in the clause, and can stop trying to
520 // globally block the clause as soon it turns into a conditional
521 // literal and we can not find another one. If the fix-point assignment
522 // is reached and we still have an autarky literal left the watched one
523 // is reported as witness for this clause being globally blocked.
524 //
525 int watched_autarky_literal = 0;
526
527 // First mark all true literals in the candidate clause and find an
528 // autarky literal which witnesses that this clause has still a chance
529 // to be globally blocked.
530 //
531 for (const_literal_iterator l = c->begin (); l != c->end (); l++) {
532 const int lit = *l;
534 if (watched_autarky_literal)
535 continue;
536 if (!is_autarky_literal (lit))
537 continue;
538 watched_autarky_literal = lit;
539
540 // TODO assign non-assigned literals to false?
541 // Which might need to trigger watching additional clauses.
542 }
543
544 if (!watched_autarky_literal) {
545 LOG ("no initial autarky literal found");
546 for (const_literal_iterator l = c->begin (); l != c->end (); l++)
548 continue;
549 }
550
551 stats.condcands++; // Only now ...
552
553 LOG ("watching first autarky literal %d", watched_autarky_literal);
554
555 // Save assignment sizes for statistics, logging and checking.
556 //
557 remain = initial;
558
559 // Position of next conditional and unassigned literal to process in the
560 // 'conditional' and the 'unassigned' stack.
561 //
562 struct {
563 size_t conditional, unassigned;
564 } next = {0, 0};
565
566 CADICAL_assert (unassigned.empty ());
567 CADICAL_assert (conditional.size () == initial.conditional);
568
569 while (watched_autarky_literal && stats.condprops < limit &&
570 next.conditional < conditional.size ()) {
571
572 CADICAL_assert (next.unassigned == unassigned.size ());
573
574 const int conditional_lit = conditional[next.conditional++];
575 LOG ("processing next conditional %d", conditional_lit);
576 CADICAL_assert (is_conditional_literal (conditional_lit));
577
578 if (is_in_candidate_clause (-conditional_lit)) {
579 LOG ("conditional %d negated in candidate clause", conditional_lit);
580 continue;
581 }
582
583 LOG ("conditional %d does not occur negated in candidate clause",
584 conditional_lit);
585
586 condition_unassign (conditional_lit);
587 CADICAL_assert (!is_conditional_literal (conditional_lit));
588 unassigned.push_back (conditional_lit);
589
590 CADICAL_assert (remain.assigned > 0);
591 CADICAL_assert (remain.conditional > 0);
592 remain.conditional--;
593 remain.assigned--;
594
595 while (watched_autarky_literal && stats.condprops < limit &&
596 next.unassigned < unassigned.size ()) {
597 const int unassigned_lit = unassigned[next.unassigned++];
598 LOG ("processing next unassigned %d", unassigned_lit);
599 CADICAL_assert (!val (unassigned_lit));
600#ifndef CADICAL_QUIET
601 props++;
602#endif
603 stats.condprops++;
604
605 Occs &os = occs (unassigned_lit);
606 if (os.empty ())
607 continue;
608
609 // Traverse all watched clauses of 'unassigned_lit' and find
610 // replacement watches or if none is found turn the negation of all
611 // false autarky literals in that clause into conditional literals.
612 // If one of those autarky literals is the watched autarky literal
613 // in the candidate clause, that one has to be updated too.
614 //
615 // We expect that this loop is a hot-spot for the procedure and thus
616 // are more careful about accessing end points for iterating.
617 //
618 auto i = os.begin (), j = i;
619 for (; watched_autarky_literal && j != os.end (); j++) {
620 Clause *d = *i++ = *j;
621
622 int replacement = 0; // New watched literal in 'd'.
623 int negative = 0; // Negative autarky literals in 'd'.
624
625 for (const_literal_iterator l = d->begin (); l != d->end ();
626 l++) {
627 const int lit = *l;
628 const signed char tmp = val (lit);
629 if (tmp > 0)
630 replacement = lit;
631 if (tmp < 0 && is_autarky_literal (-lit))
632 negative++;
633 }
634
635 if (replacement) {
636 LOG ("found replacement %d for unassigned %d", replacement,
637 unassigned_lit);
638 LOG (d, "unwatching %d in", unassigned_lit);
639 i--; // Drop watch!
640 LOG (d, "watching %d in", replacement);
641
642 CADICAL_assert (replacement != unassigned_lit);
643 occs (replacement).push_back (d);
644
645 continue; // ... with next watched clause 'd'.
646 }
647
648 LOG ("no replacement found for unassigned %d", unassigned_lit);
649
650 // Keep watching 'd' by 'unassigned_lit' if no replacement found.
651
652 if (!negative) {
653 LOG (d, "no negative autarky literals left in");
654 continue; // ... with next watched clause 'd'.
655 }
656
657 LOG (d, "found %d negative autarky literals in", negative);
658
659 for (const_literal_iterator l = d->begin ();
660 watched_autarky_literal && l != d->end (); l++) {
661 const int lit = *l;
662 if (!is_autarky_literal (-lit))
663 continue;
665 conditional.push_back (-lit);
666
667 remain.conditional++;
668 CADICAL_assert (remain.autarky > 0);
669 remain.autarky--;
670
671 if (-lit != watched_autarky_literal)
672 continue;
673
674 LOG ("need to replace autarky literal %d in candidate", -lit);
675 replacement = 0;
676
677 // TODO save starting point because we only move it forward?
678
679 for (const_literal_iterator k = c->begin ();
680 !replacement && k != c->end (); k++) {
681 const int other = *k;
682 if (is_autarky_literal (other))
683 replacement = other;
684 }
685 watched_autarky_literal = replacement;
686
687 if (replacement) {
688 LOG (c, "watching autarky %d instead %d in candidate",
689 replacement, watched_autarky_literal);
690 watched_autarky_literal = replacement;
691 } else {
692 LOG ("failed to find an autarky replacement");
693 watched_autarky_literal = 0; // Breaks out of 4 loops!!!!!
694 }
695 } // End of loop of turning autarky literals into conditionals.
696 } // End of loop of all watched clauses of an unassigned literal.
697 //
698 // We might abort the occurrence traversal early but already
699 // removed some watches, thus have to just copy the rest.
700 //
701 if (i < j) {
702 while (j != os.end ())
703 *i++ = *j++;
704 LOG ("flushed %zd occurrences of %d", os.end () - i,
705 unassigned_lit);
706 os.resize (i - os.begin ());
707 }
708 } // End of loop which goes over all unprocessed unassigned literals.
709 } // End of loop which goes over all unprocessed conditional literals.
710
711 // We are still processing the candidate 'c' and now have reached a
712 // final fix-point assignment partitioned into a conditional and an
713 // autarky part, or during unassigned literals figured that there is no
714 // positive autarky literal left in 'c'.
715
716 LOG ("remaining assignment of size %zd", remain.assigned);
717 LOG ("remaining conditional part of size %zd", remain.conditional);
718 LOG ("remaining autarky part of size %zd", remain.autarky);
719 //
720 CADICAL_assert (remain.assigned - remain.conditional == remain.autarky);
721 //
722#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
723 //
724 // This is a sanity check, that the size of our implicit representation
725 // of the autarky part matches our 'remain' counts. We need the same
726 // code for determining autarky literals as in the loop below which adds
727 // autarky literals to the extension stack.
728 //
729 struct {
730 size_t assigned, conditional, autarky;
731 } check;
732 check.assigned = check.conditional = check.autarky = 0;
733 for (size_t i = 0; i < trail.size (); i++) {
734 const int lit = trail[i];
735 if (val (lit)) {
736 check.assigned++;
738 LOG ("remaining conditional %d", lit);
740 check.conditional++;
741 } else {
743 LOG ("remaining autarky %d", lit);
744 check.autarky++;
745 }
746 } else {
749 }
750 }
751 CADICAL_assert (remain.assigned == check.assigned);
752 CADICAL_assert (remain.conditional == check.conditional);
753 CADICAL_assert (remain.autarky == check.autarky);
754#endif
755
756 // Success if an autarky literal is left in the clause and
757 // we did not abort the loop too early because the propagation
758 // limit was hit.
759 //
760 if (watched_autarky_literal && stats.condprops < limit) {
761 CADICAL_assert (is_autarky_literal (watched_autarky_literal));
762 CADICAL_assert (is_in_candidate_clause (watched_autarky_literal));
763
764 blocked++;
765 stats.conditioned++;
766 LOG (c, "positive autarky literal %d globally blocks",
767 watched_autarky_literal);
768
769 LOG ("remaining %zd assigned literals %.0f%%", remain.assigned,
770 percent (remain.assigned, initial.assigned));
771 LOG ("remaining %zd conditional literals %.0f%%", remain.conditional,
772 percent (remain.conditional, remain.assigned));
773 LOG ("remaining %zd autarky literals %.0f%%", remain.autarky,
774 percent (remain.autarky, remain.assigned));
775
776 // A satisfying assignment of a formula after removing a globally
777 // blocked clause might not satisfy that clause. As for variable
778 // elimination and classical blocked clauses, we thus maintain an
779 // extension stack for reconstructing an assignment which both
780 // satisfies the remaining formula as well as the clause.
781 //
782 // For globally blocked clauses we simply have to flip all literals in
783 // the autarky part and thus save the autarky on the extension stack
784 // in addition to the removed clause. In the classical situation (in
785 // bounded variable elimination etc.) we simply save one literal on
786 // the extension stack.
787 //
788 // TODO find a way to shrink the autarky part or some other way to
789 // avoid pushing too many literals on the extension stack.
790 //
791 external->push_zero_on_extension_stack ();
792 for (const auto &lit : trail)
794 external->push_witness_literal_on_extension_stack (lit);
795 if (proof)
796 proof->weaken_minus (c);
797 external->push_clause_on_extension_stack (c);
798
799 mark_garbage (c);
800
801 stats.condassrem += remain.assigned;
802 stats.condcondrem += remain.conditional;
803 stats.condautrem += remain.autarky;
804 stats.condassirem += initial.assigned;
805 }
806
807 // In this last part specific to one candidate clause, we have to get
808 // back to the initial assignment and reset conditionals. First we
809 // assign all the unassigned literals (if necessary).
810 //
811 if (!unassigned.empty ()) {
812 LOG ("reassigning %zd literals", unassigned.size ());
813 while (!unassigned.empty ()) {
814 const int lit = unassigned.back ();
815 unassigned.pop_back ();
817 }
818 }
819
820 // Then we remove from the conditional stack autarky literals which
821 // became conditional and also reset their 'conditional' bit.
822 //
823 if (initial.conditional < conditional.size ()) {
824 LOG ("flushing %zd autarky literals from conditional stack",
825 conditional.size () - initial.conditional);
826 while (initial.conditional < conditional.size ()) {
827 const int lit = conditional.back ();
828 conditional.pop_back ();
830 }
831 }
832
833 // Finally unmark all literals in the candidate clause.
834 //
835 for (const_literal_iterator l = c->begin (); l != c->end (); l++)
837
838 } // End of loop over all candidate clauses.
839
840 PHASE ("condition", stats.conditionings,
841 "globally blocked %ld clauses %.0f%%", blocked,
842 percent (blocked, candidates.size ()));
843
844 // Unmark initial conditional variables.
845 //
846 for (const auto &lit : conditional)
848
849 erase_vector (unassigned);
850 erase_vector (conditional);
851 erase_vector (candidates);
852
853 // Unassign additionally assigned literals.
854 //
855#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
856 int additionally_unassigned = 0;
857#endif
858 while (trail.size () > initial_trail_level) {
859 int lit = trail.back ();
860 trail.pop_back ();
862#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
863 additionally_unassigned++;
864#endif
865 }
866 LOG ("unassigned %d additionally assigned literals",
867 additionally_unassigned);
868 CADICAL_assert (additionally_unassigned == additionally_assigned);
869
870 if (level > initial_level) {
871 LOG ("reset condition decision level");
872 level = initial_level;
873 }
874
875 reset_occs ();
877
878 // Reassign previously assigned variables again.
879 //
880 LOG ("reassigning previously assigned variables");
881 for (size_t i = 0; i < initial_trail_level; i++) {
882 const int lit = trail[i];
883 const signed char tmp = val (lit);
884 CADICAL_assert (tmp >= 0);
885 if (!tmp)
887 }
888
889#ifndef CADICAL_NDEBUG
890 for (const auto &lit : trail)
892#endif
893
895
896 return blocked;
897}
898
899void Internal::condition (bool update_limits) {
900
901 if (unsat)
902 return;
903 if (!stats.current.irredundant)
904 return;
905
907 stats.conditionings++;
908
909 // Propagation limit to avoid too much work in 'condition'. We mark
910 // tried candidate clauses after giving up, such that next time we run
911 // 'condition' we can try them.
912 //
913 long limit = stats.propagations.search;
914 limit *= opts.conditioneffort;
915 limit /= 1000;
916 if (limit < opts.conditionmineff)
917 limit = opts.conditionmineff;
918 if (limit > opts.conditionmaxeff)
919 limit = opts.conditionmaxeff;
920 CADICAL_assert (stats.current.irredundant);
921 limit *= 2.0 * active () / (double) stats.current.irredundant;
922 limit = max (limit, 2l * active ());
923
924 PHASE ("condition", stats.conditionings,
925 "started after %" PRIu64 " conflicts limited by %ld propagations",
926 stats.conflicts, limit);
927
928 long blocked = condition_round (limit);
929
931 report ('g', !blocked);
932
933 if (!update_limits)
934 return;
935
936 long delta = opts.conditionint * (stats.conditionings + 1);
937 lim.condition = stats.conflicts + delta;
938
939 PHASE ("condition", stats.conditionings,
940 "next limit at %" PRIu64 " after %ld conflicts", lim.condition,
941 delta);
942}
943
944} // namespace CaDiCaL
945
#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
vector< Clause * > Occs
Definition occs.hpp:18
const int * const_literal_iterator
Definition clause.hpp:18
void erase_vector(std::vector< T > &v)
Definition util.hpp:90
double percent(double a, double b)
Definition util.hpp:21
#define START_SIMPLIFIER(S, M)
Definition profile.hpp:172
#define STOP_SIMPLIFIER(S, M)
Definition profile.hpp:197
int lit
Definition satVec.h:130
literal_iterator begin()
Definition clause.hpp:131
literal_iterator end()
Definition clause.hpp:132
void unsetbit(int lit, int bit)
Definition internal.hpp:546
External * external
Definition internal.hpp:312
void condition_assign(int lit)
void mark67(int lit)
Definition internal.hpp:504
long condition_round(long unassigned_literal_propagation_limit)
Var & var(int lit)
Definition internal.hpp:452
void unmark_in_candidate_clause(int lit)
void mark_garbage(Clause *)
void setbit(int lit, int bit)
Definition internal.hpp:540
void report(char type, int verbose_level=0)
bool is_conditional_literal(int lit) const
vector< int > trail
Definition internal.hpp:259
int fixed(int lit)
void unmark67(int lit)
Definition internal.hpp:517
bool terminated_asynchronously(int factor=1)
bool frozen(int lit)
void condition(bool update_limits=true)
void mark_as_conditional_literal(int lit)
int decide_phase(int idx, bool target)
signed char val(int lit) const
bool limit(const char *name, int)
signed char marked(int lit) const
Definition internal.hpp:478
void set_val(int lit, signed char val)
bool active(int lit)
Definition internal.hpp:360
bool is_autarky_literal(int lit) const
signed char marked67(int lit) const
Definition internal.hpp:498
vector< Clause * > clauses
Definition internal.hpp:283
const Range vars
Definition internal.hpp:324
Occs & occs(int lit)
Definition internal.hpp:465
int active() const
Definition internal.hpp:362
void condition_unassign(int lit)
void mark_in_candidate_clause(int lit)
bool is_in_candidate_clause(int lit) const
void unmark_as_conditional_literal(int lit)
bool getbit(int lit, int bit) const
Definition internal.hpp:536
int level
Definition var.hpp:19
bool operator()(Clause *a, Clause *b)
unsigned size
Definition vector.h:35
Definition watch.h:41