ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_analyze.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// Code for conflict analysis, i.e., to generate the first UIP clause. The
12// main function is 'analyze' below. It further uses 'minimize' to minimize
13// the first UIP clause, which is in 'minimize.cpp'. An important side
14// effect of conflict analysis is to update the decision queue by bumping
15// variables. Similarly analyzed clauses are bumped to mark them as active.
16
17/*------------------------------------------------------------------------*/
18
22 LOG ("learned empty clause");
23 external->check_learned_empty_clause ();
24 int64_t id = ++clause_id;
25 if (proof) {
26 proof->add_derived_empty_clause (id, lrat_chain);
27 }
28 unsat = true;
29 conflict_id = id;
30 marked_failed = true;
31 conclusion.push_back (id);
32 lrat_chain.clear ();
33}
34
37 LOG ("learned unit clause %d, stored at position %d", lit, vlit (lit));
38 external->check_learned_unit_clause (lit);
39 int64_t id = ++clause_id;
40 if (lrat || frat) {
41 const unsigned uidx = vlit (lit);
42 unit_clauses (uidx) = id;
43 }
44 if (proof) {
45 proof->add_derived_unit_clause (id, lit, lrat_chain);
46 }
48}
49
50/*------------------------------------------------------------------------*/
51
52// Move bumped variables to the front of the (VMTF) decision queue. The
53// 'bumped' time stamp is updated accordingly. It is used to determine
54// whether the 'queue.assigned' pointer has to be moved in 'unassign'.
55
57 CADICAL_assert (opts.bump);
58 const int idx = vidx (lit);
59 if (!links[idx].next)
60 return;
61 queue.dequeue (links, idx);
62 queue.enqueue (links, idx);
63 CADICAL_assert (stats.bumped != INT64_MAX);
64 btab[idx] = ++stats.bumped;
65 LOG ("moved to front variable %d and bumped to %" PRId64 "", idx,
66 btab[idx]);
67 if (!vals[idx])
69}
70
71/*------------------------------------------------------------------------*/
72
73// It would be better to use 'isinf' but there are some historical issues
74// with this function. On some platforms it is a macro and even for C++ it
75// changed the scope (in pre 5.0 gcc) from '::isinf' to 'std::isinf'. I do
76// not want to worry about these strange incompatibilities and thus use the
77// same trick as in older solvers (since the MiniSAT team invented EVSIDS)
78// and simply put a hard limit here. It is less elegant but easy to port.
79
80static inline bool evsids_limit_hit (double score) {
81 CADICAL_assert (sizeof (score) == 8); // assume IEEE 754 64-bit double
82 return score > 1e150; // MAX_DOUBLE is around 1.8e308
83}
84
85/*------------------------------------------------------------------------*/
86
87// Classical exponential VSIDS as pioneered by MiniSAT.
88
90 stats.rescored++;
91 double divider = score_inc;
92 for (auto idx : vars) {
93 const double tmp = stab[idx];
94 if (tmp > divider)
95 divider = tmp;
96 }
97 PHASE ("rescore", stats.rescored, "rescoring %d variable scores by 1/%g",
98 max_var, divider);
99 CADICAL_assert (divider > 0);
100 double factor = 1.0 / divider;
101 for (auto idx : vars)
102 stab[idx] *= factor;
103 score_inc *= factor;
104 PHASE ("rescore", stats.rescored,
105 "new score increment %g after %" PRId64 " conflicts", score_inc,
106 stats.conflicts);
107}
108
110 CADICAL_assert (opts.bump);
111 int idx = vidx (lit);
112 double old_score = score (idx);
113 CADICAL_assert (!evsids_limit_hit (old_score));
114 double new_score = old_score + score_inc;
115 if (evsids_limit_hit (new_score)) {
116 LOG ("bumping %g score of %d hits EVSIDS score limit", old_score, idx);
118 old_score = score (idx);
119 CADICAL_assert (!evsids_limit_hit (old_score));
120 new_score = old_score + score_inc;
121 }
122 CADICAL_assert (!evsids_limit_hit (new_score));
123 LOG ("new %g score of %d", new_score, idx);
124 score (idx) = new_score;
125 if (scores.contains (idx))
126 scores.update (idx);
127}
128
129// Important variables recently used in conflict analysis are 'bumped',
130
132 if (use_scores ())
134 else
135 bump_queue (lit);
136}
137
138// After every conflict the variable score increment is increased by a
139// factor (if we are currently using scores).
140
143 CADICAL_assert (!evsids_limit_hit (score_inc));
144 double f = 1e3 / opts.scorefactor;
145 double new_score_inc = score_inc * f;
146 if (evsids_limit_hit (new_score_inc)) {
147 LOG ("bumping %g increment by %g hits EVSIDS score limit", score_inc,
148 f);
150 new_score_inc = score_inc * f;
151 }
152 CADICAL_assert (!evsids_limit_hit (new_score_inc));
153 LOG ("bumped score increment from %g to %g with factor %g", score_inc,
154 new_score_inc, f);
155 score_inc = new_score_inc;
156}
157
158/*------------------------------------------------------------------------*/
159
163 typedef uint64_t Type;
164 Type operator() (const int &a) const { return internal->bumped (a); }
165};
166
170 bool operator() (const int &a, const int &b) const {
171 const auto s = analyze_bumped_rank (internal) (a);
172 const auto t = analyze_bumped_rank (internal) (b);
173 return s < t;
174 }
175};
176
177/*------------------------------------------------------------------------*/
178
180
181 CADICAL_assert (opts.bump);
182
183 START (bump);
184
185 if (!use_scores ()) {
186
187 // Variables are bumped in the order they are in the current decision
188 // queue. This maintains relative order between bumped variables in
189 // the queue and seems to work best. We also experimented with
190 // focusing on variables of the last decision level, but results were
191 // mixed.
192
193 MSORT (opts.radixsortlim, analyzed.begin (), analyzed.end (),
195 }
196
197 for (const auto &lit : analyzed)
199
200 if (use_scores ())
202
203 STOP (bump);
204}
205
206/*------------------------------------------------------------------------*/
207
208// We use the glue time stamp table 'gtab' for fast glue computation.
209
211 int res = 0;
212 const int64_t stamp = ++stats.recomputed;
213 for (const auto &lit : *c) {
214 int level = var (lit).level;
215 CADICAL_assert (gtab[level] <= stamp);
216 if (gtab[level] == stamp)
217 continue;
218 gtab[level] = stamp;
219 res++;
220 }
221 return res;
222}
223
224// Clauses resolved since the last reduction are marked as 'used', their
225// glue is recomputed and they are promoted if the glue shrinks. Note that
226// promotion from 'tier3' to 'tier2' will set 'used' to '2'.
227
229 LOG (c, "bumping");
230 c->used = max_used;
231 if (c->hyper)
232 return;
233 if (!c->redundant)
234 return;
235 int new_glue = recompute_glue (c);
236 if (new_glue < c->glue)
237 promote_clause (c, new_glue);
238
239 const size_t glue =
240 std::min ((size_t) c->glue, stats.used[stable].size () - 1);
241 ++stats.used[stable][glue];
242 ++stats.bump_used[stable];
243}
244
246/*------------------------------------------------------------------------*/
247
248// During conflict analysis literals not seen yet either become part of the
249// first unique implication point (UIP) clause (if on lower decision level),
250// are dropped (if fixed), or are resolved away (if on the current decision
251// level and different from the first UIP). At the same time we update the
252// number of seen literals on a decision level. This helps conflict clause
253// minimization. The number of seen levels is the glucose level (also
254// called 'glue', or 'LBD').
255
256inline void Internal::analyze_literal (int lit, int &open,
257 int &resolvent_size,
258 int &antecedent_size) {
260 Var &v = var (lit);
261 Flags &f = flags (lit);
262
263 if (!v.level) {
264 if (f.seen || !lrat)
265 return;
266 f.seen = true;
267 unit_analyzed.push_back (lit);
268 CADICAL_assert (val (lit) < 0);
269 int64_t id = unit_id (-lit);
270 unit_chain.push_back (id);
271 return;
272 }
273 ++antecedent_size;
274 if (f.seen)
275 return;
276
277 // before marking as seen, get reason and check for missed unit
278
279 CADICAL_assert (val (lit) < 0);
281 if (v.reason == external_reason) {
282 CADICAL_assert (!opts.exteagerreasons);
284 if (!v.reason) { // actually a unit
285 --antecedent_size;
286 LOG ("%d unit after explanation", -lit);
287 if (f.seen || !lrat)
288 return;
289 f.seen = true;
290 unit_analyzed.push_back (lit);
291 CADICAL_assert (val (lit) < 0);
292 const unsigned uidx = vlit (-lit);
293 int64_t id = unit_clauses (uidx);
294 CADICAL_assert (id);
295 unit_chain.push_back (id);
296 return;
297 }
298 }
299
300 f.seen = true;
301 analyzed.push_back (lit);
302
304 if (v.level < level)
305 clause.push_back (lit);
306 Level &l = control[v.level];
307 if (!l.seen.count++) {
308 LOG ("found new level %d contributing to conflict", v.level);
309 levels.push_back (v.level);
310 }
311 if (v.trail < l.seen.trail)
312 l.seen.trail = v.trail;
313 ++resolvent_size;
314 LOG ("analyzed literal %d assigned at level %d", lit, v.level);
315 if (v.level == level)
316 open++;
317}
318
319inline void Internal::analyze_reason (int lit, Clause *reason, int &open,
320 int &resolvent_size,
321 int &antecedent_size) {
322 CADICAL_assert (reason);
324 bump_clause (reason);
325 if (lrat)
326 lrat_chain.push_back (reason->id);
327 for (const auto &other : *reason)
328 if (other != lit)
329 analyze_literal (other, open, resolvent_size, antecedent_size);
330}
331
332/*------------------------------------------------------------------------*/
333
334// This is an idea which was implicit in MapleCOMSPS 2016 for 'limit = 1'.
335// See also the paragraph on 'bumping reason side literals' in their SAT'16
336// paper [LiangGaneshPoupartCzarnecki-SAT'16]. Reason side bumping was
337// performed exactly when 'LRB' based decision heuristics was used, which in
338// the original version was enabled after 10000 conflicts until a time limit
339// of 2500 seconds was reached (half of the competition time limit). The
340// Maple / Glucose / MiniSAT evolution winning the SAT race in 2019 made
341// the schedule of reason side bumping deterministic, i.e., avoiding a time
342// limit, by switching between 'LRB' and 'VSIDS' in an interval of initially
343// 30 million propagations, which then is increased geometrically by 10%.
344
347 CADICAL_assert (val (lit) < 0);
348 Flags &f = flags (lit);
349 if (f.seen)
350 return false;
351 const Var &v = var (lit);
352 if (!v.level)
353 return false;
354 f.seen = true;
355 analyzed.push_back (lit);
356 LOG ("bumping also reason literal %d assigned at level %d", lit, v.level);
357 return true;
358}
359
360// We experimented with deeper reason bumping without much success though.
361
362inline void Internal::bump_also_reason_literals (int lit, int depth_limit,
363 size_t analyzed_limit) {
365 CADICAL_assert (depth_limit > 0);
366 const Var &v = var (lit);
368 if (!v.level)
369 return;
370 Clause *reason = v.reason;
371 if (!reason || reason == external_reason)
372 return;
373 stats.ticks.search[stable]++;
374 for (const auto &other : *reason) {
375 if (other == lit)
376 continue;
377 if (!bump_also_reason_literal (other))
378 continue;
379 if (depth_limit < 2)
380 continue;
381 bump_also_reason_literals (-other, depth_limit - 1, analyzed_limit);
382 if (analyzed.size () > analyzed_limit)
383 break;
384 }
385}
386
388 CADICAL_assert (opts.bump);
389 if (!opts.bumpreason)
390 return;
391 if (averages.current.decisions > opts.bumpreasonrate) {
392 LOG ("decisions per conflict rate %g > limit %d",
393 (double) averages.current.decisions, opts.bumpreasonrate);
394 return;
395 }
396 if (delay[stable].bumpreasons.limit) {
397 LOG ("delaying reason bumping %" PRId64 " more times",
398 delay[stable].bumpreasons.limit);
399 delay[stable].bumpreasons.limit--;
400 return;
401 }
402 CADICAL_assert (opts.bumpreasondepth > 0);
403 const int depth_limit = opts.bumpreasondepth + stable;
404 size_t saved_analyzed = analyzed.size ();
405 size_t analyzed_limit = saved_analyzed * opts.bumpreasonlimit;
406 for (const auto &lit : clause)
407 if (analyzed.size () <= analyzed_limit)
408 bump_also_reason_literals (-lit, depth_limit, analyzed_limit);
409 else
410 break;
411 if (analyzed.size () > analyzed_limit) {
412 LOG ("not bumping reason side literals as limit exhausted");
413 for (size_t i = saved_analyzed; i != analyzed.size (); i++) {
414 const int lit = analyzed[i];
415 Flags &f = flags (lit);
417 f.seen = false;
418 }
419 delay[stable].bumpreasons.interval++;
420 analyzed.resize (saved_analyzed);
421 } else {
422 LOG ("bumping reasons up to depth %d", opts.bumpreasondepth);
423 delay[stable].bumpreasons.interval /= 2;
424 }
425 LOG ("delay internal %" PRId64, delay[stable].bumpreasons.interval);
426 delay[stable].bumpreasons.limit = delay[stable].bumpreasons.interval;
427}
428
429/*------------------------------------------------------------------------*/
430
432 LOG ("clearing %zd unit analyzed literals", unit_analyzed.size ());
433 for (const auto &lit : unit_analyzed) {
434 Flags &f = flags (lit);
437 f.seen = false;
438 CADICAL_assert (!f.keep);
441 }
442 unit_analyzed.clear ();
443}
444
446 LOG ("clearing %zd analyzed literals", analyzed.size ());
447 for (const auto &lit : analyzed) {
448 Flags &f = flags (lit);
450 f.seen = false;
451 CADICAL_assert (!f.keep);
454 }
455 analyzed.clear ();
456#if 0 // to expensive, even for debugging mode
457 if (unit_analyzed.size ())
458 return;
459 for (auto idx : vars) {
460 Flags &f = flags (idx);
461 CADICAL_assert (!f.seen);
462 }
463#endif
464}
465
467 LOG ("clearing %zd analyzed levels", levels.size ());
468 for (const auto &l : levels)
469 if (l < (int) control.size ())
470 control[l].reset ();
471 levels.clear ();
472}
473
474/*------------------------------------------------------------------------*/
475
476// Smaller level and trail. Comparing literals on their level is necessary
477// for chronological backtracking, since trail order might in this case not
478// respect level order.
479
483 typedef uint64_t Type;
485 Var &v = internal->var (a);
486 uint64_t res = v.level;
487 res <<= 32;
488 res |= v.trail;
489 return ~res;
490 }
491};
492
496 bool operator() (const int &a, const int &b) const {
499 }
500};
501
502/*------------------------------------------------------------------------*/
503
504// Generate new driving clause and compute jump level.
505
506Clause *Internal::new_driving_clause (const int glue, int &jump) {
507
508 const size_t size = clause.size ();
509 Clause *res;
510
511 if (!size) {
512
513 jump = 0;
514 res = 0;
515
516 } else if (size == 1) {
517
518 iterating = true;
519 jump = 0;
520 res = 0;
521
522 } else {
523
524 CADICAL_assert (clause.size () > 1);
525
526 // We have to get the last assigned literals into the watch position.
527 // Sorting all literals with respect to reverse assignment order is
528 // overkill but seems to get slightly faster run-time. For 'minimize'
529 // we sort the literals too heuristically along the trail order (so in
530 // the opposite order) with the hope to hit the recursion limit less
531 // frequently. Thus sorting effort is doubled here.
532 //
533 MSORT (opts.radixsortlim, clause.begin (), clause.end (),
535
536 jump = var (clause[1]).level;
537 res = new_learned_redundant_clause (glue);
538 res->used = 1 + (glue <= opts.reducetier2glue);
539 }
540
541 LOG ("jump level %d", jump);
542
543 return res;
544}
545
546/*------------------------------------------------------------------------*/
547
548// determine the OTFS level for OTFS. Unlike the find_conflict_level, we do
549// not have to fix the clause
550
551inline int Internal::otfs_find_backtrack_level (int &forced) {
552 CADICAL_assert (opts.otfs);
553 int res = 0;
554
555 for (const auto &lit : *conflict) {
556 const int tmp = var (lit).level;
557 if (tmp == level) {
558 forced = lit;
559 } else if (tmp > res) {
560 res = tmp;
561 LOG ("bt level is now %d due to %d", res, lit);
562 }
563 }
564 return res;
565}
566
567/*------------------------------------------------------------------------*/
568
569// If chronological backtracking is enabled we need to find the actual
570// conflict level and then potentially can also reuse the conflict clause
571// as driving clause instead of deriving a redundant new driving clause
572// (forcing 'forced') if the number 'count' of literals in conflict assigned
573// at the conflict level is exactly one.
574
575inline int Internal::find_conflict_level (int &forced) {
576
578 CADICAL_assert (opts.chrono || opts.otfs || external_prop);
579
580 int res = 0, count = 0;
581
582 forced = 0;
583
584 for (const auto &lit : *conflict) {
585 const int tmp = var (lit).level;
586 if (tmp > res) {
587 res = tmp;
588 forced = lit;
589 count = 1;
590 } else if (tmp == res) {
591 count++;
592 if (res == level && count > 1)
593 break;
594 }
595 }
596
597 LOG ("%d literals on actual conflict level %d", count, res);
598
599 const int size = conflict->size;
600 int *lits = conflict->literals;
601
602 // Move the two highest level literals to the front.
603 //
604 for (int i = 0; i < 2; i++) {
605
606 const int lit = lits[i];
607
608 int highest_position = i;
609 int highest_literal = lit;
610 int highest_level = var (highest_literal).level;
611
612 for (int j = i + 1; j < size; j++) {
613 const int other = lits[j];
614 const int tmp = var (other).level;
615 if (highest_level >= tmp)
616 continue;
617 highest_literal = other;
618 highest_position = j;
619 highest_level = tmp;
620 if (highest_level == res)
621 break;
622 }
623
624 // No unwatched higher assignment level literal.
625 //
626 if (highest_position == i)
627 continue;
628
629 if (highest_position > 1) {
630 LOG (conflict, "unwatch %d in", lit);
632 }
633
634 lits[highest_position] = lit;
635 lits[i] = highest_literal;
636
637 if (highest_position > 1)
638 watch_literal (highest_literal, lits[!i], conflict);
639 }
640
641 // Only if the number of highest level literals in the conflict is one
642 // then we can reuse the conflict clause as driving clause for 'forced'.
643 //
644 if (count != 1)
645 forced = 0;
646
647 return res;
648}
649
650/*------------------------------------------------------------------------*/
651
653
654 int res;
655
656 CADICAL_assert (level > jump);
657
658 if (!opts.chrono) {
659 res = jump;
660 LOG ("chronological backtracking disabled using jump level %d", res);
661 } else if (opts.chronoalways) {
662 stats.chrono++;
663 res = level - 1;
664 LOG ("forced chronological backtracking to level %d", res);
665 } else if (jump >= level - 1) {
666 res = jump;
667 LOG ("jump level identical to chronological backtrack level %d", res);
668 } else if ((size_t) jump < assumptions.size ()) {
669 res = jump;
670 LOG ("using jump level %d since it is lower than assumption level %zd",
671 res, assumptions.size ());
672 } else if (level - jump > opts.chronolevelim) {
673 stats.chrono++;
674 res = level - 1;
675 LOG ("back-jumping over %d > %d levels prohibited"
676 "thus backtracking chronologically to level %d",
677 level - jump, opts.chronolevelim, res);
678 } else if (opts.chronoreusetrail) {
679 int best_idx = 0, best_pos = 0;
680
681 if (use_scores ()) {
682 for (size_t i = control[jump + 1].trail; i < trail.size (); i++) {
683 const int idx = abs (trail[i]);
684 if (best_idx && !score_smaller (this) (best_idx, idx))
685 continue;
686 best_idx = idx;
687 best_pos = i;
688 }
689 LOG ("best variable score %g", score (best_idx));
690 } else {
691 for (size_t i = control[jump + 1].trail; i < trail.size (); i++) {
692 const int idx = abs (trail[i]);
693 if (best_idx && bumped (best_idx) >= bumped (idx))
694 continue;
695 best_idx = idx;
696 best_pos = i;
697 }
698 LOG ("best variable bumped %" PRId64 "", bumped (best_idx));
699 }
700 CADICAL_assert (best_idx);
701 LOG ("best variable %d at trail position %d", best_idx, best_pos);
702
703 // Now find the frame and decision level in the control stack of that
704 // best variable index. Note that, as in 'reuse_trail', the frame
705 // 'control[i]' for decision level 'i' contains the trail before that
706 // decision level, i.e., the decision 'control[i].decision' sits at
707 // 'control[i].trail' in the trail and we thus have to check the level
708 // of the control frame one higher than at the result level.
709 //
710 res = jump;
711 while (res < level - 1 && control[res + 1].trail <= best_pos)
712 res++;
713
714 if (res == jump)
715 LOG ("default non-chronological back-jumping to level %d", res);
716 else {
717 stats.chrono++;
718 LOG ("chronological backtracking to level %d to reuse trail", res);
719 }
720
721 } else {
722 res = jump;
723 LOG ("non-chronological back-jumping to level %d", res);
724 }
725
726 return res;
727}
728
729/*------------------------------------------------------------------------*/
730
732 CADICAL_assert (opts.eagersubsume);
733 LOG (c, "trying eager subsumption with");
734 mark (c);
735 int64_t lim = stats.eagertried + opts.eagersubsumelim;
736 const auto begin = clauses.begin ();
737 auto it = clauses.end ();
738#ifdef LOGGING
739 int64_t before = stats.eagersub;
740#endif
741 while (it != begin && stats.eagertried++ <= lim) {
742 Clause *d = *--it;
743 if (c == d)
744 continue;
745 if (d->garbage)
746 continue;
747 if (!d->redundant)
748 continue;
749 int needed = c->size;
750 for (auto &lit : *d) {
751 if (marked (lit) <= 0)
752 continue;
753 if (!--needed)
754 break;
755 }
756 if (needed)
757 continue;
758 LOG (d, "eager subsumed");
759 stats.eagersub++;
760 stats.subsumed++;
761 mark_garbage (d);
762 }
763 unmark (c);
764#ifdef LOGGING
765 uint64_t subsumed = stats.eagersub - before;
766 if (subsumed)
767 LOG ("eagerly subsumed %" PRIu64 " clauses", subsumed);
768#endif
769}
770
771/*------------------------------------------------------------------------*/
772
774 CADICAL_assert (new_conflict);
775 CADICAL_assert (new_conflict->size > 2);
776 LOG (new_conflict, "applying OTFS on lit %d", uip);
777 auto sorted = std::vector<int> ();
778 sorted.reserve (new_conflict->size);
779 CADICAL_assert (sorted.empty ());
780 ++stats.otfs.strengthened;
781
782 int *lits = new_conflict->literals;
783
784 CADICAL_assert (lits[0] == uip || lits[1] == uip);
785 const int other_init = lits[0] ^ lits[1] ^ uip;
786
787 CADICAL_assert (mini_chain.empty ());
788
789 const int old_size = new_conflict->size;
790 int new_size = 0;
791 for (int i = 0; i < old_size; ++i) {
792 const int other = lits[i];
793 sorted.push_back (other);
794 if (var (other).level)
795 lits[new_size++] = other;
796 }
797
798 LOG (new_conflict, "removing all units in");
799
800 CADICAL_assert (lits[0] == uip || lits[1] == uip);
801 const int other = lits[0] ^ lits[1] ^ uip;
802 lits[0] = other;
803 lits[1] = lits[--new_size];
804 LOG (new_conflict, "putting uip at pos 1");
805
806 if (other_init != other)
807 remove_watch (watches (other_init), new_conflict);
808 remove_watch (watches (uip), new_conflict);
809
810 CADICAL_assert (!lrat || lrat_chain.back () == new_conflict->id);
811 if (lrat) {
812 CADICAL_assert (!lrat_chain.empty ());
813 for (const auto &id : unit_chain) {
814 mini_chain.push_back (id);
815 }
816 const auto end = lrat_chain.rend ();
817 const auto begin = lrat_chain.rbegin ();
818 for (auto i = begin; i != end; i++) {
819 const auto id = *i;
820 mini_chain.push_back (id);
821 }
822 lrat_chain.clear ();
824 unit_chain.clear ();
825 }
826 CADICAL_assert (unit_analyzed.empty ());
827 // sort the clause
828 {
829 int highest_pos = 0;
830 int highest_level = 0;
831 for (int i = 1; i < new_size; i++) {
832 const unsigned other = lits[i];
833 CADICAL_assert (val (other) < 0);
834 const int level = var (other).level;
836 LOG ("checking %d", other);
837 if (level <= highest_level)
838 continue;
839 highest_pos = i;
840 highest_level = level;
841 }
842 LOG ("highest lit is %d", lits[highest_pos]);
843 if (highest_pos != 1)
844 swap (lits[1], lits[highest_pos]);
845 LOG ("removing %d literals", new_conflict->size - new_size);
846
847 if (new_size == 1) {
848 LOG (new_conflict, "new size = 1, so interrupting");
849 CADICAL_assert (!opts.exteagerreasons);
850 return 0;
851 } else {
852 otfs_strengthen_clause (new_conflict, uip, new_size, sorted);
853 CADICAL_assert (new_size == new_conflict->size);
854 }
855 }
856
857 if (other_init != other)
858 watch_literal (other, lits[1], new_conflict);
859 else {
860 update_watch_size (watches (other), lits[1], new_conflict);
861 }
862 watch_literal (lits[1], other, new_conflict);
863
864 LOG (new_conflict, "strengthened clause by OTFS");
865 sorted.clear ();
866
867 return new_conflict;
868}
869
870/*------------------------------------------------------------------------*/
871inline void Internal::otfs_subsume_clause (Clause *subsuming,
872 Clause *subsumed) {
873 stats.subsumed++;
874 CADICAL_assert (subsuming->size <= subsumed->size);
875 LOG (subsumed, "subsumed");
876 if (subsumed->redundant)
877 stats.subred++;
878 else
879 stats.subirr++;
880 if (subsumed->redundant || !subsuming->redundant) {
881 mark_garbage (subsumed);
882 return;
883 }
884 LOG ("turning redundant subsuming clause into irredundant clause");
885 subsuming->redundant = false;
886 if (proof)
887 proof->strengthen (subsuming->id);
888 mark_garbage (subsumed);
889 stats.current.irredundant++;
890 stats.added.irredundant++;
891 stats.irrlits += subsuming->size;
892 CADICAL_assert (stats.current.redundant > 0);
893 stats.current.redundant--;
894 CADICAL_assert (stats.added.redundant > 0);
895 stats.added.redundant--;
896 // ... and keep 'stats.added.total'.
897}
898
899/*------------------------------------------------------------------------*/
900
901// Candidate clause 'c' is strengthened by removing 'lit' and units.
902//
903void Internal::otfs_strengthen_clause (Clause *c, int lit, int new_size,
904 const std::vector<int> &old) {
905 stats.strengthened++;
906 CADICAL_assert (c->size > 2);
907 (void) shrink_clause (c, new_size);
908 if (proof) {
909 proof->otfs_strengthen_clause (c, old, mini_chain);
910 }
911 if (!c->redundant) {
913 }
914 mini_chain.clear ();
915 c->used = true;
916 LOG (c, "strengthened");
917 external->check_shrunken_clause (c);
918}
919
920/*------------------------------------------------------------------------*/
921
922// If the average number of decisions per conflict (analysis actually so not
923// taking OTFS conflicts into account) is high we do not bump reasons. This
924// is the function which updates the exponential moving decision rate
925// average.
926
928 int64_t current = stats.decisions;
929 int64_t decisions = current - saved_decisions;
930 UPDATE_AVERAGE (averages.current.decisions, decisions);
931 saved_decisions = current;
932}
933
934/*------------------------------------------------------------------------*/
935
936// This is the main conflict analysis routine. It assumes that a conflict
937// was found. Then we derive the 1st UIP clause, optionally minimize it,
938// add it as learned clause, and then uses the clause for conflict directed
939// back-jumping and flipping the 1st UIP literal. In combination with
940// chronological backtracking (see discussion above) the algorithm becomes
941// slightly more involved.
942
944
945 START (analyze);
946
948 CADICAL_assert (lrat_chain.empty ());
949 CADICAL_assert (unit_chain.empty ());
950 CADICAL_assert (unit_analyzed.empty ());
951 CADICAL_assert (clause.empty ());
952
953 // First update moving averages of trail height at conflict.
954 //
955 UPDATE_AVERAGE (averages.current.trail.fast, num_assigned);
956 UPDATE_AVERAGE (averages.current.trail.slow, num_assigned);
958
959 /*----------------------------------------------------------------------*/
960
961 if (external_prop && !external_prop_is_lazy && opts.exteagerreasons) {
963 }
964
965 if (opts.chrono || external_prop) {
966
967 int forced;
968
969 const int conflict_level = find_conflict_level (forced);
970
971 // In principle we can perform conflict analysis as in non-chronological
972 // backtracking except if there is only one literal with the maximum
973 // assignment level in the clause. Then standard conflict analysis is
974 // unnecessary and we can use the conflict as a driving clause. In the
975 // pseudo code of the SAT'18 paper on chronological backtracking this
976 // corresponds to the situation handled in line 4-6 in Alg. 1, except
977 // that the pseudo code in the paper only backtracks while we eagerly
978 // assign the single literal on the highest decision level.
979
980 if (forced) {
981
982 CADICAL_assert (forced);
983 CADICAL_assert (conflict_level > 0);
984 LOG ("single highest level literal %d", forced);
985
986 // The pseudo code in the SAT'18 paper actually backtracks to the
987 // 'second highest decision' level, while their code backtracks
988 // to 'conflict_level-1', which is more in the spirit of chronological
989 // backtracking anyhow and thus we also do the latter.
990 //
991 backtrack (conflict_level - 1);
992
993 // if we are on decision level 0 search assign will learn unit
994 // so we need a valid chain here (of course if we are not on decision
995 // level 0 this will not result in a valid chain).
996 // we can just use build_chain_for_units in propagate
997 //
998 build_chain_for_units (forced, conflict, 0);
999
1000 LOG ("forcing %d", forced);
1002
1003 conflict = 0;
1004 STOP (analyze);
1005 return;
1006 }
1007
1008 // Backtracking to the conflict level is in the pseudo code in the
1009 // SAT'18 chronological backtracking paper, but not in their actual
1010 // implementation. In principle we do not need to backtrack here.
1011 // However, as a side effect of backtracking to the conflict level we
1012 // set 'level' to the conflict level which then allows us to reuse the
1013 // old 'analyze' code as is. The alternative (which we also tried but
1014 // then abandoned) is to use 'conflict_level' instead of 'level' in the
1015 // analysis, which however requires to pass it to the 'analyze_reason'
1016 // and 'analyze_literal' functions.
1017 //
1018 backtrack (conflict_level);
1019 }
1020
1021 // Actual conflict on root level, thus formula unsatisfiable.
1022 //
1023 if (!level) {
1025 if (external->learner)
1026 external->export_learned_empty_clause ();
1027 STOP (analyze);
1028 return;
1029 }
1030
1031 /*----------------------------------------------------------------------*/
1032
1033 // First derive the 1st UIP clause by going over literals assigned on the
1034 // current decision level. Literals in the conflict are marked as 'seen'
1035 // as well as all literals in reason clauses of already 'seen' literals on
1036 // the current decision level. Thus the outer loop starts with the
1037 // conflict clause as 'reason' and then uses the 'reason' of the next
1038 // seen literal on the trail assigned on the current decision level.
1039 // During this process maintain the number 'open' of seen literals on the
1040 // current decision level with not yet processed 'reason'. As soon 'open'
1041 // drops to one, we have found the first unique implication point. This
1042 // is sound because the topological order in which literals are processed
1043 // follows the assignment order and a more complex algorithm to find
1044 // articulation points is not necessary.
1045 //
1046 Clause *reason = conflict;
1047 LOG (reason, "analyzing conflict");
1048
1049 CADICAL_assert (clause.empty ());
1050 CADICAL_assert (lrat_chain.empty ());
1051
1052 const auto &t = &trail;
1053 int i = t->size (); // Start at end-of-trail.
1054 int open = 0; // Seen but not processed on this level.
1055 int uip = 0; // The first UIP literal.
1056 int resolvent_size = 0; // without the uip
1057 int antecedent_size = 1; // with the uip and without unit literals
1058 int conflict_size = 0; // without the uip and without unit literals
1059 int resolved = 0; // number of resolution (0 = clause in CNF)
1060 const bool otfs = opts.otfs;
1061
1062 for (;;) {
1063 antecedent_size = 1; // for uip
1064 analyze_reason (uip, reason, open, resolvent_size, antecedent_size);
1065 if (resolved == 0)
1066 conflict_size = antecedent_size - 1;
1067 CADICAL_assert (resolvent_size == open + (int) clause.size ());
1068
1069 if (otfs && resolved > 0 && antecedent_size > 2 &&
1070 resolvent_size < antecedent_size) {
1071 CADICAL_assert (reason != conflict);
1072 LOG (analyzed, "found candidate for OTFS conflict");
1073 LOG (clause, "found candidate for OTFS conflict");
1074 LOG (reason, "found candidate (size %d) for OTFS resolvent",
1075 antecedent_size);
1076 const int other = reason->literals[0] ^ reason->literals[1] ^ uip;
1077 CADICAL_assert (other != uip);
1078 reason = on_the_fly_strengthen (reason, uip);
1079 if (opts.bump)
1080 bump_variables ();
1081
1082 CADICAL_assert (conflict_size);
1083 if (!reason) {
1084 uip = -other;
1085 CADICAL_assert (open == 1);
1086 LOG ("clause is actually unit %d, stopping", -uip);
1087 reverse (begin (mini_chain), end (mini_chain));
1088 for (auto id : mini_chain)
1089 lrat_chain.push_back (id);
1090 mini_chain.clear ();
1092 CADICAL_assert (!opts.exteagerreasons);
1093 clause.clear ();
1094 break;
1095 }
1096 CADICAL_assert (conflict_size >= 2);
1097
1098 if (resolved == 1 && resolvent_size < conflict_size) {
1099 // here both clauses are part of the CNF, so one subsumes the other
1100 otfs_subsume_clause (reason, conflict);
1101 LOG (reason, "changing conflict to");
1102 --conflict_size;
1103 CADICAL_assert (conflict_size == reason->size);
1104 ++stats.otfs.subsumed;
1105 ++stats.subsumed;
1106 }
1107
1108 LOG (reason, "changing conflict to");
1109 conflict = reason;
1110 if (open == 1) {
1111 int forced = 0;
1112 const int conflict_level = otfs_find_backtrack_level (forced);
1113 int new_level = determine_actual_backtrack_level (conflict_level);
1114 UPDATE_AVERAGE (averages.current.level, new_level);
1115 backtrack (new_level);
1116
1117 LOG ("forcing %d", forced);
1119
1120 // Clean up.
1121 //
1122 conflict = 0;
1125 clause.clear ();
1126 STOP (analyze);
1127 return;
1128 }
1129
1130 stats.conflicts++;
1131
1134 clause.clear ();
1135 resolvent_size = 0;
1136 antecedent_size = 1;
1137 resolved = 0;
1138 open = 0;
1139 analyze_reason (0, reason, open, resolvent_size, antecedent_size);
1140 conflict_size = antecedent_size - 1;
1141 CADICAL_assert (open > 1);
1142 }
1143
1144 ++resolved;
1145
1146 uip = 0;
1147 while (!uip) {
1148 CADICAL_assert (i > 0);
1149 const int lit = (*t)[--i];
1150 if (!flags (lit).seen)
1151 continue;
1152 if (var (lit).level == level)
1153 uip = lit;
1154 }
1155 if (!--open)
1156 break;
1157 reason = var (uip).reason;
1158 if (reason == external_reason) {
1159 CADICAL_assert (!opts.exteagerreasons);
1160 reason = learn_external_reason_clause (-uip, 0, true);
1161 var (uip).reason = reason;
1162 }
1163 CADICAL_assert (reason != external_reason);
1164 LOG (reason, "analyzing %d reason", uip);
1165 CADICAL_assert (resolvent_size);
1166 --resolvent_size;
1167 }
1168 LOG ("first UIP %d", uip);
1169 clause.push_back (-uip);
1170
1171 // Update glue and learned (1st UIP literals) statistics.
1172 //
1173 int size = (int) clause.size ();
1174 const int glue = (int) levels.size () - 1;
1175 LOG (clause, "1st UIP size %d and glue %d clause", size, glue);
1176 UPDATE_AVERAGE (averages.current.glue.fast, glue);
1177 UPDATE_AVERAGE (averages.current.glue.slow, glue);
1178 stats.learned.literals += size;
1179 stats.learned.clauses++;
1180 CADICAL_assert (glue < size);
1181
1182 // up to this point lrat_chain contains the proof for current clause in
1183 // reversed order. in minimize and shrink the clause is changed and
1184 // therefore lrat_chain has to be extended. Unfortunately we cannot create
1185 // the chain directly during minimization (or shrinking) but afterwards we
1186 // can calculate it pretty easily and even better the same algorithm works
1187 // for both shrinking and minimization.
1188
1189 // Minimize the 1st UIP clause as pioneered by Niklas Soerensson in
1190 // MiniSAT and described in our joint SAT'09 paper.
1191 //
1192 if (size > 1) {
1193 if (opts.shrink)
1195 else if (opts.minimize)
1196 minimize_clause ();
1197
1198 size = (int) clause.size ();
1199
1200 // Update decision heuristics.
1201 //
1202 if (opts.bump) {
1204 bump_variables ();
1205 }
1206
1207 if (external->learner)
1208 external->export_learned_large_clause (clause);
1209 } else if (external->learner)
1210 external->export_learned_unit_clause (-uip);
1211
1212 // Update actual size statistics.
1213 //
1214 stats.units += (size == 1);
1215 stats.binaries += (size == 2);
1216 UPDATE_AVERAGE (averages.current.size, size);
1217
1218 // reverse lrat_chain. We could probably work with reversed iterators
1219 // (views) to be more efficient but we would have to distinguish in proof
1220 //
1221 if (lrat) {
1222 LOG (unit_chain, "unit chain: ");
1223 for (auto id : unit_chain)
1224 lrat_chain.push_back (id);
1225 unit_chain.clear ();
1226 reverse (lrat_chain.begin (), lrat_chain.end ());
1227 }
1228
1229 // Determine back-jump level, learn driving clause, backtrack and assign
1230 // flipped 1st UIP literal.
1231 //
1232 int jump;
1233 Clause *driving_clause = new_driving_clause (glue, jump);
1234 UPDATE_AVERAGE (averages.current.jump, jump);
1235
1236 int new_level = determine_actual_backtrack_level (jump);
1237 UPDATE_AVERAGE (averages.current.level, new_level);
1238 backtrack (new_level);
1239
1240 // It should hold that (!level <=> size == 1)
1241 // and (!uip <=> size == 0)
1242 // this means either we have already learned a clause => size >= 2
1243 // in this case we will not learn empty clause or unit here
1244 // or we haven't actually learned a clause in new_driving_clause
1245 // then lrat_chain is still valid and we will learn a unit or empty clause
1246 //
1247 if (uip) {
1248 search_assign_driving (-uip, driving_clause);
1249 } else
1251
1252 if (stable)
1253 reluctant.tick (); // Reluctant has its own 'conflict' counter.
1254
1255 // Clean up.
1256 //
1260 clause.clear ();
1261 conflict = 0;
1262
1263 lrat_chain.clear ();
1264 STOP (analyze);
1265
1266 if (driving_clause && opts.eagersubsume)
1268
1269 if (lim.recompute_tier <= stats.conflicts)
1270 recompute_tier ();
1271}
1272
1273// We wait reporting a learned unit until propagation of that unit is
1274// completed. Otherwise the 'i' report gives the number of remaining
1275// variables before propagating the unit (and hides the actual remaining
1276// variables after propagating it).
1277
1279 iterating = false;
1280 report ('i');
1281}
1282
1283} // namespace CaDiCaL
1284
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
#define UPDATE_AVERAGE(A, Y)
Definition ema.hpp:56
#define PHASE(...)
Definition message.hpp:52
void remove_watch(Watches &ws, Clause *clause)
Definition watch.hpp:50
const char * flags()
void update_watch_size(Watches &ws, int blit, Clause *conflict)
Definition watch.hpp:63
#define STOP(P)
Definition profile.hpp:158
#define START(P)
Definition profile.hpp:150
#define MSORT(LIMIT, FIRST, LAST, RANK, LESS)
Definition radix.hpp:173
int lit
Definition satVec.h:130
unsigned used
Definition clause.hpp:59
bool removable
Definition flags.hpp:17
void update_queue_unassigned(int idx)
Definition internal.hpp:652
void watch_literal(int lit, int blit, Clause *c)
Definition internal.hpp:623
External * external
Definition internal.hpp:312
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
vector< int64_t > gtab
Definition internal.hpp:235
void bump_clause(Clause *)
int vidx(int lit) const
Definition internal.hpp:395
void bump_also_reason_literals(int lit, int depth_limit, size_t size_limit)
void report(char type, int verbose_level=0)
bool bump_also_reason_literal(int lit)
Clause * new_learned_redundant_clause(int glue)
void unmark(int lit)
Definition internal.hpp:490
Flags & flags(int lit)
Definition internal.hpp:454
vector< int > trail
Definition internal.hpp:259
const unsigned max_used
Definition internal.hpp:314
const Sange lits
Definition internal.hpp:325
void mark_removed(int lit)
void promote_clause(Clause *, int new_glue)
Clause * on_the_fly_strengthen(Clause *conflict, int lit)
int64_t saved_decisions
Definition internal.hpp:205
void otfs_strengthen_clause(Clause *, int, int, const std::vector< int > &)
Clause * learn_external_reason_clause(int lit, int falsified_elit=0, bool no_backtrack=false)
vector< int64_t > conclusion
Definition internal.hpp:207
void eagerly_subsume_recently_learned_clauses(Clause *)
signed char val(int lit) const
signed char marked(int lit) const
Definition internal.hpp:478
int64_t unit_id(int lit) const
Definition internal.hpp:434
vector< int64_t > unit_chain
Definition internal.hpp:213
bool use_scores() const
Definition internal.hpp:471
void otfs_subsume_clause(Clause *subsuming, Clause *subsumed)
void bump_variable(int lit)
vector< int > assumptions
Definition internal.hpp:261
void backtrack(int target_level=0)
int recompute_glue(Clause *)
int find_conflict_level(int &forced)
unsigned vlit(int lit) const
Definition internal.hpp:408
void bump_clause2(Clause *)
vector< int > unit_analyzed
Definition internal.hpp:268
Reluctant reluctant
Definition internal.hpp:198
vector< Clause * > clauses
Definition internal.hpp:283
signed char * vals
Definition internal.hpp:221
vector< int64_t > btab
Definition internal.hpp:234
const Range vars
Definition internal.hpp:324
double & score(int lit)
Definition internal.hpp:457
void bump_queue(int idx)
void analyze_literal(int lit, int &open, int &resolvent_size, int &antecedent_size)
Clause * new_driving_clause(const int glue, int &jump)
Clause * external_reason
Definition internal.hpp:245
int otfs_find_backtrack_level(int &forced)
vector< Level > control
Definition internal.hpp:282
int64_t & unit_clauses(int uidx)
Definition internal.hpp:443
vector< double > stab
Definition internal.hpp:230
void bump_variable_score(int lit)
size_t shrink_clause(Clause *, int new_size)
ScoreSchedule scores
Definition internal.hpp:229
void learn_unit_clause(int lit)
int64_t & bumped(int lit)
Definition internal.hpp:455
vector< int64_t > mini_chain
Definition internal.hpp:211
Watches & watches(int lit)
Definition internal.hpp:467
void analyze_reason(int lit, Clause *, int &open, int &resolvent_size, int &antecedent_size)
void search_assign_driving(int lit, Clause *reason)
int determine_actual_backtrack_level(int jump)
void build_chain_for_units(int lit, Clause *reason, bool forced)
vector< int > levels
Definition internal.hpp:266
vector< int > clause
Definition internal.hpp:260
struct CaDiCaL::Level::@023147271015376226021074167111310127126167046351 seen
int level
Definition var.hpp:19
int trail
Definition var.hpp:20
Clause * reason
Definition var.hpp:21
Type operator()(const int &a) const
bool operator()(const int &a, const int &b) const
bool operator()(const int &a, const int &b) const
signed char mark
Definition value.h:8