ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_congruence.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "congruence.hpp"
4#include "internal.hpp"
5#include <algorithm>
6#include <cstdint>
7#include <iterator>
8#include <utility>
9#include <vector>
10
12
13namespace CaDiCaL {
14
16 : internal (i), table (128, Hash (nonces))
17#ifdef LOGGING
18 ,
19 fresh_id (internal->clause_id)
20#endif
21{
22}
23
25 return lazy_propagated_idx[internal->vidx (lit)];
26}
27
29 int8_t f = g->degenerated_ite;
30 const int lhs = g->lhs;
31 const int cond = g->rhs [0];
32 const int then_lit = g->rhs[1];
33 const int else_lit = g->rhs[2];
34
35 if (lhs == cond) {
38 }
39 if (lhs == -cond) {
42 }
43 if (lhs == then_lit) {
46 }
47 if (lhs == else_lit) {
50 }
51 g->degenerated_ite = f;
52 CADICAL_assert (lhs != -then_lit);
53 CADICAL_assert (lhs != -else_lit);
54 CADICAL_assert (cond != then_lit);
55 CADICAL_assert (cond != else_lit);
56 CADICAL_assert (cond != -then_lit);
57 CADICAL_assert (cond != -else_lit);
58}
59
60void check_correct_ite_flags (const Gate *const g) {
61#ifndef CADICAL_NDEBUG
62 const int8_t f = g->degenerated_ite;
63 const int lhs = g->lhs;
64 const int cond = g->rhs [0];
65 const int then_lit = g->rhs[1];
66 const int else_lit = g->rhs[2];
67 CADICAL_assert (g->pos_lhs_ids.size () == 4);
68 if (g->pos_lhs_ids[0].clause == nullptr)
70 if (g->pos_lhs_ids[1].clause == nullptr)
72 if (g->pos_lhs_ids[2].clause == nullptr)
74 if (g->pos_lhs_ids[3].clause == nullptr)
76 if (lhs == cond) {
79 }
80 if (lhs == -cond) {
83 }
84 if (lhs == then_lit) {
87 }
88 if (lhs == else_lit) {
91 }
92 CADICAL_assert (lhs != -then_lit);
93 CADICAL_assert (lhs != -else_lit);
94 CADICAL_assert (cond != then_lit);
95 CADICAL_assert (cond != else_lit);
96 CADICAL_assert (cond != -then_lit);
97 CADICAL_assert (cond != -else_lit);
98#else
99 (void)g;
100#endif
101}
102
103/*------------------------------------------------------------------------*/
104
105static size_t hash_lits (std::array<int, 16> &nonces,
106 const vector<int> &lits) {
107 size_t hash = 0;
108 const auto end_nonces = end (nonces);
109 const auto begin_nonces = begin (nonces);
110 auto n = begin_nonces;
111 for (auto lit : lits) {
112 hash += lit;
113 hash *= *n++;
114 hash = (hash << 4) | (hash >> 60);
115 if (n == end_nonces)
116 n = begin_nonces;
117 }
118 hash ^= hash >> 32;
119 return hash;
120}
121
122size_t Hash::operator() (const Gate *const g) const {
123 CADICAL_assert (hash_lits (nonces, g->rhs) == g->hash);
124 return g->hash;
125}
126
127bool gate_contains (Gate *g, int lit) {
128 return find (begin (g->rhs), end (g->rhs), lit) != end (g->rhs);
129}
130/*------------------------------------------------------------------------*/
132 typedef uint64_t Type;
133 uint64_t operator() (const CompactBinary &a) {
134 return ((uint64_t) a.lit1 << 32) + a.lit2;
135 };
136};
137
139 bool operator() (const CompactBinary &a, const CompactBinary &b) {
140 return compact_binary_rank () (a) < compact_binary_rank () (b);
141 };
142};
143
144bool Closure::find_binary (int lit, int other) const {
145 const auto offsize =
146 offsetsize[internal->vlit (lit)]; // in C++17: [offset, size] =
147 const auto offset = offsize.first;
148 const auto size = offsize.second;
149 const auto begin = std::begin (binaries) + offset;
150 const auto end = std::begin (binaries) + size;
151 CADICAL_assert (end <= std::end (binaries));
152 const CompactBinary target = CompactBinary (nullptr, 0, lit, other);
153 auto it = std::lower_bound (begin, end, target, compact_binary_order ());
154 // search_binary only returns a bool
155 bool found = (it != end && it->lit1 == lit && it->lit2 == other);
156 if (found) {
157 LOG ("found binary [%zd] %d %d", it->id, lit, other);
158 if (internal->lrat)
159 lrat_chain.push_back (it->id);
160 }
161 return found;
162}
163
165 if (!internal->opts.congruencebinaries)
166 return;
167 START (extractbinaries);
168 offsetsize.resize (internal->max_var * 2 + 3, make_pair (0, 0));
169
170 // in kissat this is done during watch clearing. TODO: consider doing this
171 // too.
172 for (Clause *c : internal->clauses) {
173 if (c->garbage)
174 continue;
175 if (c->redundant && c->size != 2)
176 continue;
177 if (c->size > 2)
178 continue;
179 CADICAL_assert (c->size == 2);
180 const int lit = c->literals[0];
181 const int other = c->literals[1];
182 const bool already_sorted =
183 internal->vlit (lit) < internal->vlit (other);
184 binaries.push_back (CompactBinary (c, c->id,
185 already_sorted ? lit : other,
186 already_sorted ? other : lit));
187 }
188
189 MSORT (internal->opts.radixsortlim, begin (binaries), end (binaries),
191
192 {
193 const size_t size = binaries.size ();
194 size_t i = 0;
195 while (i < size) {
196 CompactBinary bin = binaries[i];
197 const int lit = bin.lit1;
198 size_t j = i;
199 while (j < size && binaries[j].lit1 == lit) {
200 ++j;
201 }
202 CADICAL_assert (j >= i);
203 CADICAL_assert (j <= size);
204 offsetsize[internal->vlit (lit)] = make_pair (i, j);
205 i = j;
206 }
207 }
208
209 size_t extracted = 0, already_present = 0, duplicated = 0;
210
211 const size_t size = internal->clauses.size ();
212 for (size_t i = 0; i < size; ++i) {
213 Clause *d = internal->clauses[i]; // binary clauses are appended, so
214 // reallocation possible
215 if (d->garbage)
216 continue;
217 if (d->redundant)
218 continue;
219 if (d->size != 3)
220 continue;
221 const int *lits = d->literals;
222 const int a = lits[0];
223 const int b = lits[1];
224 const int c = lits[2]; // obfuscating d->literals[2] which triggers an error in pedandic mode
225 if (internal->val (a))
226 continue;
227 if (internal->val (b))
228 continue;
229 if (internal->val (c))
230 continue;
231 int l = 0, k = 0;
232 if (find_binary (-a, b) || find_binary (-a, c)) {
233 l = b, k = c;
234 } else if (find_binary (-b, a) || find_binary (-b, c)) {
235 l = a, k = c;
236 } else if (find_binary (-c, a) || find_binary (-c, b)) {
237 l = a, k = b;
238 } else
239 continue;
240 LOG (d, "strengthening");
241 if (!find_binary (l, k)) {
242 if (internal->lrat)
243 lrat_chain.push_back (d->id);
244 add_binary_clause (l, k);
245 ++extracted;
246 } else {
247 ++already_present;
248 if (internal->lrat)
249 lrat_chain.clear ();
250 }
251 }
252 lrat_chain.clear ();
253
254 offsetsize.clear ();
255
256 // kissat has code to remove duplicates, which we have already removed
257 // before starting congruence
258 MSORT (internal->opts.radixsortlim, begin (binaries), end (binaries),
260 const size_t new_size = binaries.size ();
261 {
262 size_t i = 0;
263 for (size_t j = 1; j < new_size; ++j) {
264 CADICAL_assert (i < j);
265 if (binaries[i].lit1 == binaries[j].lit1 &&
266 binaries[i].lit2 == binaries[j].lit2) {
267 // subsuming later clause
269 binaries[j].clause); // the local one is specialized
270 ++duplicated;
271 } else {
272 binaries[++i] = binaries[j];
273 }
274 }
275 CADICAL_assert (i <= new_size);
276 binaries.resize (i);
277 }
278 binaries.clear ();
279 STOP (extractbinaries);
280 LOG ("extracted %zu binaries (plus %zu already present and %zu "
281 "duplicates)",
282 extracted, already_present, duplicated);
283}
284
285/*------------------------------------------------------------------------*/
286// marking structure for congruence closure, by reference
287signed char &Closure::marked (int lit) {
288 CADICAL_assert (internal->vlit (lit) < marks.size ());
289 return marks[internal->vlit (lit)];
290}
291
293 for (auto lit : internal->analyzed) {
295 marked (lit) = 0;
296 }
297 internal->analyzed.clear ();
298}
299
301 CADICAL_assert (marked (lit) & 1);
302 LOG (c, "mu1 %d -> %zd", lit, c->id);
303 mu1_ids[internal->vlit (lit)] = LitClausePair (lit, c);
304}
305
307 CADICAL_assert (marked (lit) & 2);
308 if (!internal->lrat)
309 return;
310 LOG (c, "mu2 %d -> %zd", lit, c->id);
311 mu2_ids[internal->vlit (lit)] = LitClausePair (lit, c);
312}
313
315 CADICAL_assert (marked (lit) & 4);
316 if (!internal->lrat)
317 return;
318 LOG (c, "mu4 %d -> %zd", lit, c->id);
319 mu4_ids[internal->vlit (lit)] = LitClausePair (lit, c);
320}
321
323 return mu1_ids[internal->vlit (lit)];
324}
325
327 return mu2_ids[internal->vlit (lit)];
328}
329
331 return mu4_ids[internal->vlit (lit)];
332}
333
337
338 typedef uint64_t Type;
339
340 Type operator() (const int &a) const { return internal->vlit (a); }
341};
344 int lhs;
346 sort_literals_by_var_rank_except (Internal *i, int my_lhs, int except2)
347 : internal (i), lhs (my_lhs), except (except2) {}
349 : internal (i), lhs (my_lhs), except (0) {}
350 typedef uint64_t Type;
351 Type operator() (const int &a) const {
352 Type res = 0;
353 if (abs (a) == abs (except))
354 res = 1 - (a > 0);
355 else if (abs (a) == abs (lhs))
356 res = 3 - (a > 0);
357 else
358 res = internal->vlit (a) + 2; // probably +2 enough
359 return ~res;
360 }
361};
362
365 int lhs;
367 sort_literals_by_var_smaller_except (Internal *i, int my_lhs, int except2)
368 : internal (i), lhs (my_lhs), except (except2) {}
370 : internal (i), lhs (my_lhs), except (0) {}
371 bool operator() (const int &a, const int &b) const {
374 if (abs (a) == abs (except) && abs (b) != abs (except))
375 return false;
376 if (abs (a) != abs (except) && abs (b) == abs (except))
377 return true;
378 if (abs (a) == abs (lhs) && abs (b) != abs (lhs))
379 return false;
380 if (abs (a) != abs (lhs) && abs (b) == abs (lhs))
381 return true;
384 }
385};
394
396 int except2) {
397 MSORT (internal->opts.radixsortlim, begin (rhs), end (rhs),
400}
406/*------------------------------------------------------------------------*/
408 CADICAL_assert (internal->vlit (lit) < representant.size ());
409 return representant[internal->vlit (lit)];
410}
412 CADICAL_assert (internal->vlit (lit) < representant.size ());
413 return representant[internal->vlit (lit)];
414}
415
417 CADICAL_assert (internal->vlit (lit) < eager_representant.size ());
418 return eager_representant[internal->vlit (lit)];
419}
420
422 CADICAL_assert (internal->vlit (lit) < eager_representant.size ());
423 return eager_representant[internal->vlit (lit)];
424}
425
427 int res = lit;
428 int nxt = lit;
429 do {
430 res = nxt;
431 nxt = representative (nxt);
432 if (nxt != res) {
433 LOG ("%d has reason %" PRIu64, res, representative_id (res));
434 lrat_chain.push_back (representative_id (res));
435 }
436 } while (nxt != res || marked (nxt) || marked (-nxt));
437
438 return nxt;
439}
441 int res = lit;
442 int nxt = lit;
443 do {
444 res = nxt;
445 nxt = representative (nxt);
446 } while (nxt != res);
447
448 return res;
449}
450
451int Closure::find_representative_and_compress (int lit, bool update_eager) {
452 LOG ("finding representative of %d", lit);
453 int res = lit;
454 int nxt = lit;
455 int path_length = 0;
456 do {
457 res = nxt;
458 nxt = representative (nxt);
459 ++path_length;
460 LOG ("updating %d -> %d", res, nxt);
461 } while (nxt != res);
462
463 if (path_length > 2) {
464 LOG ("learning new rewriting from %d to %d (current path length: %d)",
465 lit, res, path_length);
466 if (update_eager)
468 if (internal->lrat) {
470 Clause *equiv = add_tmp_binary_clause (-lit, res);
471
472 if (equiv) {
473 representative_id (lit) = equiv->id;
474 if (update_eager)
475 eager_representative_id (lit) = equiv->id;
476 }
477 }
478 if (internal->lrat)
479 lrat_chain.clear ();
480 } else if (path_length == 2) {
481 if (update_eager) {
482 LOG ("updating information %d -> %d in eager", lit, res);
484 if (internal->lrat)
487 }
488 }
489
490 if (lit != res) {
491 representative (lit) = res;
492 }
493 LOG ("representative of %d is %d", lit, res);
494 return res;
495}
496
498 if (!internal->lrat)
499 return;
500 CADICAL_assert (internal->val (lit) > 0);
501 LRAT_ID id = internal->unit_id (lit);
502 lrat_chain.push_back (id);
503}
504
506 int res = lit;
507 int nxt = lit;
508 do {
509 res = nxt;
510 nxt = eager_representative (nxt);
511 } while (nxt != res);
512
513 return res;
514}
515
517 if (!internal->lrat)
518 return find_representative (lit);
519 int res = lit;
520 int nxt = lit;
521 int path_length = 0;
522 do {
523 res = nxt;
524 nxt = eager_representative (nxt);
525 ++path_length;
526 } while (nxt != res);
527
528 // CADICAL_assert (res == find_representative (lit));
529 // we have to do path compression to support LRAT proofs
530 if (path_length > 2) {
531 LOG ("learning new rewriting from %d to %d (current path length: %d)",
532 lit, res, path_length);
533 std::vector<LRAT_ID> tmp_lrat_chain;
534 if (internal->lrat) {
535 tmp_lrat_chain = std::move (lrat_chain);
536 lrat_chain.clear ();
538 }
540 Clause *equiv = add_tmp_binary_clause (-lit, res);
541 equiv->hyper = true;
542
543 if (internal->lrat && equiv) {
544 eager_representative_id (lit) = equiv->id;
545 }
546 if (internal->lrat) {
547 lrat_chain = std::move (tmp_lrat_chain);
548 }
549 } else if (path_length == 2) {
550 LOG ("duplicated information %d -> %d to eager with clause %" PRIu64,
554 }
555 CADICAL_assert (internal->clause.empty ());
556 return res;
557}
558
563
571
573 CADICAL_assert (internal->lrat);
574 LOG ("production of LRAT chain for %d with representative %" PRIu64, lit,
576 CADICAL_assert (internal->lrat);
577 CADICAL_assert (lrat_chain.empty ());
578 int res = lit;
579 int nxt = lit;
580 CADICAL_assert (nxt != representative (nxt));
581 do {
582 res = nxt;
583 nxt = representative (nxt);
584 if (nxt != res) {
585 LOG ("%d has reason %" PRIu64, res, representative_id (res));
586 lrat_chain.push_back (representative_id (res));
587 }
588 } while (nxt != res);
589}
590
592 CADICAL_assert (internal->lrat);
593 LOG ("production of LRAT chain for %d with representative %" PRIu64, lit,
595 CADICAL_assert (internal->lrat);
596 CADICAL_assert (lrat_chain.empty ());
597 int res = lit;
598 int nxt = lit;
600 do {
601 res = nxt;
602 nxt = eager_representative (nxt);
603 if (nxt != res) {
604 LOG ("%d has reason %" PRIu64, res, eager_representative_id (res));
605 lrat_chain.push_back (eager_representative_id (res));
606 }
607 } while (nxt != res);
608}
609
611 if (!internal->lrat)
612 return 0;
613 int res = lit;
614#ifndef CADICAL_NDEBUG
615 int nxt = representative (res);
616 CADICAL_assert (nxt == representative (res));
617#endif
618 LOG ("checking for existing LRAT chain for %d with clause %" PRIu64, lit,
621 return representative_id (res);
622}
623
625 if (!internal->lrat)
626 return 0;
627 int res = lit;
628#ifndef CADICAL_NDEBUG
629 int nxt = eager_representative (res);
631#endif
632 LOG ("checking for existing LRAT chain for %d with clause %" PRIu64, lit,
635 return eager_representative_id (res);
636}
637
646
652 CADICAL_assert (internal->vlit (lit) < representant_id.size ());
653 return representant_id[internal->vlit (lit)];
654}
655
657 LOG (g, "marking as garbage");
659 g->garbage = true;
660 garbage.push_back (g);
661}
662
663bool Closure::remove_gate (GatesTable::iterator git) {
664 CADICAL_assert (git != end (table));
665 CADICAL_assert (!internal->unsat);
666 (*git)->indexed = false;
667 LOG ((*git), "removing from hash table");
668 table.erase (git);
669 return true;
670}
671
673 if (!g->indexed)
674 return false;
675 CADICAL_assert (!internal->unsat);
676 CADICAL_assert (table.find (g) != end (table));
677 table.erase (table.find (g));
678 g->indexed = false;
679 LOG (g, "removing from hash table");
680 return true;
681}
682
685 CADICAL_assert (!internal->unsat);
686 CADICAL_assert (g->arity () > 1);
687 CADICAL_assert (g->hash == hash_lits (nonces, g->rhs));
688 LOG (g, "adding to hash table");
689 table.insert (g);
690 g->indexed = true;
691}
692
694 std::vector<LitClausePair> &litIds, int except_lhs, bool remove_units) {
696 for (auto &litId : litIds) {
697 CADICAL_assert (litId.clause);
698 litId.clause = produce_rewritten_clause_lrat (litId.clause, except_lhs,
699 remove_units);
700 litId.current_lit = find_eager_representative (litId.current_lit);
701 }
702 litIds.erase (
703 std::remove_if (begin (litIds), end (litIds),
704 [] (const LitClausePair &p) { return !p.clause; }),
705 end (litIds));
706}
707
709 std::vector<LitClausePair> &litIds, int except_lhs,
710 size_t &old_position1, size_t &old_position2, bool remove_units) {
711 CADICAL_assert (internal->lrat_chain.empty ());
712 CADICAL_assert (old_position1 != old_position2);
713 size_t j = 0;
714 for (size_t i = 0; i < litIds.size (); ++i) {
715 CADICAL_assert (j <= i);
716 litIds[j].clause = produce_rewritten_clause_lrat (
717 litIds[i].clause, except_lhs, remove_units);
718 litIds[j].current_lit =
719 find_eager_representative (litIds[i].current_lit);
720 if (i == old_position1) {
721 if (litIds[j].clause)
722 old_position1 = j;
723 else
724 old_position1 = -1;
725 }
726 if (i == old_position2) {
727 if (litIds[j].clause)
728 old_position2 = j;
729 else
730 old_position2 = -1;
731 }
732 if (litIds[j].clause)
733 ++j;
734 }
735 litIds.resize (j);
736}
737
739 CADICAL_assert (internal->clause.empty ());
740 CADICAL_assert (internal->lrat_chain.empty ());
741 CADICAL_assert (clause.empty ());
742 CADICAL_assert (lrat_chain.empty ());
743 bool changed = false;
744 bool tautology = false;
745 for (auto lit : *c) {
746 LOG ("checking if %d is required", lit);
747 if (internal->marked2 (lit)) {
748 continue;
749 }
750 if (internal->marked2 (-lit)) {
751 tautology = true;
752 break;
753 }
754 if (lit == except || lit == -except) {
755 internal->mark2 (lit);
756 clause.push_back (lit);
757 continue;
758 }
759 if (internal->val (lit) < 0) {
760#if 1
761 LOG ("found unit %d, removing it", -lit);
762 LRAT_ID id = internal->unit_id (-lit);
763 lrat_chain.push_back (id);
764 changed = true;
765 continue;
766#else
767 LOG ("found unit %d, but ignoring it", -lit);
768#endif
769 }
770 if (internal->val (lit) > 0) {
771 LOG ("found positive unit, so clause is subsumed by unit");
772 tautology = true;
773 }
775 const bool marked = internal->marked2 (other);
776 const bool neg_marked = internal->marked2 (-other);
777 if (!marked)
778 internal->mark2 (other);
779 if (neg_marked) {
780 tautology = true;
781 LOG ("tautology due to %d -> %d", lit, other);
782 } else if (lit == other && marked) {
783 changed = true;
784 LOG ("%d -> %d already in", lit, other);
785 } else if (lit != other) {
786 if (!marked)
787 clause.push_back (other);
788 changed = true;
790 } else if (!marked)
791 clause.push_back (lit);
792 }
793
794 for (auto lit : *c) {
795 internal->unmark (lit);
796 }
797
798 for (auto lit : clause) {
799 internal->unmark (lit);
800 }
801
802 lrat_chain.push_back (c->id);
803 if (tautology) {
804 LOG ("generated clause is a tautology");
805 lrat_chain.clear ();
806 clause.clear ();
807 } else if (changed && clause.size () == 1) {
808 LOG (lrat_chain, "LRAT chain");
809 } else {
810 LOG (c, "oops this should not happen");
811 CADICAL_assert (false);
812 }
813}
814
816 CADICAL_assert (internal->lrat);
817 CADICAL_assert (!clause.empty ());
818 CADICAL_assert (!lrat_chain.empty ());
819 bool clear = false;
820
821 LOG (clause, "learn new tmp clause");
822 CADICAL_assert (clause.size () >= 2);
823 internal->external->check_learned_clause ();
824
825 CADICAL_assert (internal->clause.size () <= (size_t) INT_MAX);
826 const int size = (int) clause.size ();
827 CADICAL_assert (size >= 2);
828
829 size_t bytes = Clause::bytes (size);
830 Clause *c = (Clause *) new char[bytes];
831 DeferDeleteArray<char> clause_delete ((char *) c);
832
833 c->id = ++internal->clause_id;
834
835 c->conditioned = false;
836 c->covered = false;
837 c->enqueued = false;
838 c->frozen = false;
839 c->garbage = false;
840 c->gate = false;
841 c->hyper = false;
842 c->instantiated = false;
843 c->moved = false;
844 c->reason = false;
845 c->redundant = false;
846 c->transred = false;
847 c->subsume = false;
848 c->swept = false;
849 c->flushed = false;
850 c->vivified = false;
851 c->vivify = false;
852 c->used = 0;
853
854 c->glue = size;
855 c->size = size;
856 c->pos = 2;
857
858 for (int i = 0; i < size; i++)
859 c->literals[i] = clause[i];
860
861 // Just checking that we did not mess up our sophisticated memory layout.
862 // This might be compiler dependent though. Crucial for correctness.
863 //
864 CADICAL_assert (c->bytes () == bytes);
865
866 clause_delete.release ();
867 LOG (c, "new pointer %p", (void *) c);
868
869 if (clear)
870 clause.clear ();
871
872 if (internal->proof) {
873 internal->proof->add_derived_clause (c, lrat_chain);
874 }
875 extra_clauses.push_back (c);
876 CADICAL_assert (internal->lrat_chain.empty ());
877 return c;
878}
879
881 CADICAL_assert (internal->clause.empty () || clause.empty ());
882 bool clear = false;
883 if (internal->clause.empty ()) {
884 swap (internal->clause, clause);
885 clear = true;
886 }
887
888 Clause *c = internal->new_clause (false);
889
890 if (clear)
891 internal->clause.clear ();
892
893 if (internal->proof) {
894 internal->proof->add_derived_clause (c, lrat_chain);
895 }
896
897 return c;
898}
899
900// TODO we here duplicate the arguments of push_id_and_rewriting_lrat but we
901// probably do not need that.
903 std::vector<LitClausePair> &litIds, int except_lhs, bool remove_units) {
905 for (auto &litId : litIds) {
906 if (!litId.clause)
907 continue;
908 litId.clause = produce_rewritten_clause_lrat (litId.clause, except_lhs,
909 remove_units);
910 litId.current_lit = find_eager_representative (litId.current_lit);
911 }
912}
913
915 bool remove_units, bool fail_on_unit) {
916 CADICAL_assert (internal->clause.empty ());
917 CADICAL_assert (internal->lrat_chain.empty ());
918 auto tmp_lrat (std::move (lrat_chain));
919 lrat_chain.clear ();
920 LOG (c, "rewriting clause for LRAT proof, except for rewriting %d",
921 except_lhs);
922 CADICAL_assert (internal->clause.empty ());
923 CADICAL_assert (lrat_chain.empty ());
924 bool changed = false;
925 bool tautology = false;
926 for (auto lit : *c) {
927 LOG ("checking if %d is required", lit);
928 if (internal->marked2 (lit)) {
929 continue;
930 }
931 if (internal->marked2 (-lit)) {
932 tautology = true;
933 break;
934 }
935 if (lit == except_lhs || lit == -except_lhs) {
936 internal->mark2 (lit);
937 clause.push_back (lit);
938 continue;
939 }
940 if (internal->val (lit) < 0) {
941 if (remove_units || lazy_propagated (lit)) {
942 LOG ("found unit %d, removing it", -lit);
943 LRAT_ID id = internal->unit_id (-lit);
944 lrat_chain.push_back (id);
945 changed = true;
946 continue;
947 } else
948 LOG ("found unit %d, but ignoring it", -lit);
949 }
950 if (internal->val (lit) > 0) {
951 LOG ("found positive unit %d, so clause is subsumed by unit", lit);
952 if (remove_units || lazy_propagated (lit))
953 tautology = true;
954 }
956 const bool marked = internal->marked2 (other);
957 const bool neg_marked = internal->marked2 (-other);
958 if (!marked)
959 internal->mark2 (other);
960 if (neg_marked) {
961 tautology = true;
962 LOG ("tautology due to %d -> %d", lit, other);
963 } else if (lit == other && marked) {
964 changed = true;
965 LOG ("%d -> %d already in", lit, other);
966 } else if (lit != other) {
967 if (!marked)
968 clause.push_back (other);
969 changed = true;
971 } else if (!marked)
972 clause.push_back (lit);
973 }
974
975 for (auto lit : *c) {
976 internal->unmark (lit);
977 }
978
979 for (auto lit : clause) {
980 internal->unmark (lit);
981 }
982
983 lrat_chain.push_back (c->id);
984 Clause *d;
985 CADICAL_assert (internal->clause.empty ());
986 if (tautology) {
987 LOG ("generated clause is a tautology");
988 d = nullptr;
989 lrat_chain.clear ();
990 } else if (changed && clause.size () == 1) {
991 LOG (lrat_chain, "LRAT chain");
992 if (fail_on_unit) {
993 d = nullptr;
994 CADICAL_assert (false && "rewriting produced a unit clause");
995 } else {
996 d = c;
997 }
998 } else if (changed) {
999 LOG (lrat_chain, "LRAT Chain");
1000 d = new_tmp_clause (clause);
1001 LOG (d, "rewritten clause to");
1002 } else {
1003 LOG (c, "clause is unchanged, so giving up");
1004 lrat_chain.clear ();
1005 d = c;
1006 }
1007 clause.clear ();
1008 lrat_chain = std::move (tmp_lrat);
1009 CADICAL_assert (internal->clause.empty ());
1010 return d;
1011}
1012
1013void Closure::push_id_on_chain (std::vector<LRAT_ID> &chain,
1014 Rewrite rewrite, int lit) {
1015 LOG ("adding reason %zd for rewriting %d marked",
1016 lit == rewrite.src ? rewrite.id1 : rewrite.id2, lit);
1017 chain.push_back (lit == rewrite.src ? rewrite.id1 : rewrite.id2);
1018}
1019
1021 std::vector<LRAT_ID> &chain,
1022 bool insert_id_after,
1023 Rewrite rewrite2,
1024 int except_lhs,
1025 int except_lhs2) {
1026 LOG (c,
1027 "computing normalized LRAT chain for clause to produce unit, "
1028 "rewriting except for %d (%" PRIu64 ", %" PRIu64 ") and %d (%" PRIu64
1029 ", %" PRIu64 ") and skipping %d and %d",
1030 rewrite1.src, rewrite1.id1, rewrite1.id2, rewrite2.src, rewrite2.id1,
1031 rewrite2.id2, except_lhs, except_lhs2);
1032 CADICAL_assert (c);
1033 std::vector<LRAT_ID> units, rewriting;
1034 for (auto other : *c) {
1035 // unclear how to achieve this in the simplify context where other ==
1036 // g->lhs might be set CADICAL_assert (internal->val (other) <= 0 || other ==
1037 // except);
1038 if (other == except_lhs || other == -except_lhs) {
1039 // do nothing;
1040 } else if (other == except_lhs2 || other == -except_lhs2) {
1041 // do nothing;
1042 } else if (internal->val (other) < 0) {
1043 LOG ("found unit %d", -other);
1044 LRAT_ID id = internal->unit_id (-other);
1045 units.push_back (id);
1046 } else if (other == rewrite1.src && rewrite1.id1) {
1047 push_id_on_chain (rewriting, rewrite1, other);
1048 } else if (other == -rewrite1.src && rewrite1.id2) {
1049 push_id_on_chain (rewriting, rewrite1, other);
1050 } else if (other == rewrite2.src && rewrite2.id1) {
1051 push_id_on_chain (rewriting, rewrite2, other);
1052 } else if (other == -rewrite2.src && rewrite2.id2) {
1053 push_id_on_chain (rewriting, rewrite2, other);
1054 } else if (other != find_eager_representative_and_compress (other)) {
1055#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
1056 const int rewritten_other = eager_representative (other);
1057 CADICAL_assert (other != rewritten_other);
1058 LOG ("reason for representative of %d %d is %" PRIu64 "", other,
1059 rewritten_other, find_eager_representative_lrat (other));
1060#endif
1061 rewriting.push_back (find_eager_representative_lrat (other));
1062 } else {
1063 LOG ("no rewriting needed for %d", other);
1064 }
1065 }
1066 for (auto id : units)
1067 chain.push_back (id);
1068
1069 if (!insert_id_after)
1070 chain.push_back (c->id);
1071 for (auto id : rewriting)
1072 chain.push_back (id);
1073
1074 if (insert_id_after)
1075 chain.push_back (c->id);
1076}
1077
1078// Note: it is important that the Rewrite takes over the normal rewriting,
1079// because we can force rewriting that way that have not been done eagerly
1080// yet.
1082 std::vector<LRAT_ID> &chain,
1083 bool insert_id_after,
1084 Rewrite rewrite2,
1085 int except_lhs,
1086 int except_lhs2) {
1087 LOG (c,
1088 "computing normalized LRAT chain for clause, rewriting except for "
1089 "%d (%" PRIu64 ", %" PRIu64 ") and %d (%" PRIu64 ", %" PRIu64
1090 ") and skipping %d and %d",
1091 rewrite1.src, rewrite1.id1, rewrite1.id2, rewrite2.src, rewrite2.id1,
1092 rewrite2.id2, except_lhs, except_lhs2);
1093 CADICAL_assert (c);
1094 if (!insert_id_after)
1095 chain.push_back (c->id);
1096 for (auto other : *c) {
1097 // unclear how to achieve this in the simplify context where other ==
1098 // g->lhs might be set CADICAL_assert (internal->val (other) <= 0 || other ==
1099 // except);
1100 if (other == except_lhs) {
1101 // do nothing;
1102 } else if (other == except_lhs2) {
1103 // do nothing;
1104 } else if (internal->val (other) < 0) {
1105 LOG ("found unit %d", -other);
1106 LRAT_ID id = internal->unit_id (-other);
1107 CADICAL_assert (id);
1108 chain.push_back (id);
1109 } else if (other == rewrite1.src && rewrite1.id1) {
1110 push_id_on_chain (chain, rewrite1, other);
1111 } else if (other == -rewrite1.src && rewrite1.id2) {
1112 push_id_on_chain (chain, rewrite1, other);
1113 } else if (other == rewrite2.src && rewrite2.id1) {
1114 push_id_on_chain (chain, rewrite2, other);
1115 } else if (other == -rewrite2.src && rewrite2.id2) {
1116 push_id_on_chain (chain, rewrite2, other);
1117 } else {
1118 CADICAL_assert (other == find_eager_representative (other));
1119 LOG ("no rewriting needed for %d", other);
1120 }
1121 }
1122 if (insert_id_after)
1123 chain.push_back (c->id);
1124}
1125
1126// Note: it is important that the Rewrite takes over the normal rewriting,
1127// because we can force rewriting that way that have not been done eagerly
1128// yet.
1129void Closure::push_id_on_chain (std::vector<LRAT_ID> &chain, Clause *c) {
1130 CADICAL_assert (c);
1131 chain.push_back (c->id);
1132 LOG (lrat_chain, "chain");
1133}
1134
1135void Closure::push_id_on_chain (std::vector<LRAT_ID> &chain,
1136 const std::vector<LitClausePair> &reasons) {
1137 for (auto litId : reasons) {
1138 LOG (litId.clause, "found lrat in gate %d from %zd", litId.current_lit,
1139 litId.clause->id);
1140 push_id_on_chain (chain, litId.clause);
1141 }
1142 LOG (lrat_chain, "chain from %zd reasons", reasons.size ());
1143}
1144
1146 LRAT_ID id1, LRAT_ID id2,
1147 int dst) {
1148 if (!internal->lrat)
1149 return;
1150 LOG ("calculating LRAT chain learn_congruence_unit_when_lhs_set");
1151 CADICAL_assert (!g->pos_lhs_ids.empty ());
1152 CADICAL_assert (internal->analyzed.empty ());
1153 CADICAL_assert (internal->val (g->lhs) < 0);
1154 switch (g->tag) {
1156 LOG (lrat_chain, "lrat");
1157 LOG (lrat_chain, "lrat");
1158 for (auto litId : g->neg_lhs_ids)
1160 litId.clause, Rewrite (src, dst, id1, id2), lrat_chain);
1161 LOG (lrat_chain, "lrat");
1162 break;
1163 default:
1164 CADICAL_assert (false);
1165 }
1166}
1167
1168// Something very important here: as we are producing a unit, we cannot
1169// simplify or rewrite the clauses as this will produce units.
1171 Gate *g, int src, int dst, int clashing, int falsified, int unit) {
1172 if (!internal->lrat)
1173 return;
1174 CADICAL_assert (!g->pos_lhs_ids.empty ());
1175 CADICAL_assert (internal->analyzed.empty ());
1176 CADICAL_assert (lrat_chain.empty ());
1177 std::vector<LRAT_ID> proof_chain;
1178 switch (g->tag) {
1180 if (clashing) {
1181 LOG ("clashing %d where -lhs=%d", clashing, -g->lhs);
1182 // Example: -2 = 1&3 and 3=2
1183 // The proof consists in taking the binary clause of the clashing
1184 // literal
1185 if (clashing == -g->lhs) {
1186 for (auto litId : g->pos_lhs_ids) {
1187 LOG (litId.clause,
1188 "found lrat in gate %d from %zd (looking for %d)",
1189 litId.current_lit, litId.clause->id, falsified);
1190 if (litId.current_lit == clashing) {
1192 litId.clause, Rewrite (), proof_chain, true, Rewrite (),
1193 g->degenerated_and_neg || g->degenerated_and_pos ? 0 : -g->lhs);
1194 }
1195 }
1196 } else {
1197 // Example: 3 = (-1&2) and 2=1
1198 // The proof consists in taking the binary clause with the rewrites
1199 // Example where the rewrite must be before:
1200 // 2: 3v2
1201 // 9: -2v1
1202 // 6: 3v1
1203 // The chain cannot start by 9
1205 LOG ("%d %d %d", src, dst, g->lhs);
1206 if (src == g->lhs || dst == g->lhs) {
1207 LOG ("degenerated AND gate with dst=lhs");
1208 for (const auto &litId : g->pos_lhs_ids) {
1209 LOG (litId.clause, "definition clause %d ->",
1210 litId.current_lit);
1211 if (litId.current_lit == clashing) {
1212 push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (),
1213 proof_chain, true,
1214 Rewrite (), 0);
1215 LOG (proof_chain, "produced lrat chain so far");
1216 }
1217 }
1218 CADICAL_assert (!proof_chain.empty ());
1219 } else {
1220 LOG ("degenerated AND gate with conflict without LHS");
1221 for (const auto &litId : g->pos_lhs_ids) {
1222 LOG (litId.clause, "definition clause %d ->",
1223 litId.current_lit);
1224 push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (),
1225 proof_chain, false,
1226 Rewrite (), -g->lhs);
1227 LOG (proof_chain, "produced lrat chain so far");
1228 }
1229 }
1230 } else {
1231 LOG ("normal AND gate");
1232 for (const auto &litId : g->pos_lhs_ids) {
1233 push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (),
1234 proof_chain, false, Rewrite (),
1235 g->degenerated_and_neg || g->degenerated_and_pos ? 0 : -g->lhs);
1236 LOG (proof_chain, "produced lrat chain so far");
1237 }
1238 }
1239 }
1240 LOG (proof_chain, "produced lrat chain");
1241 } else if (falsified) {
1242 LOG ("falsifies %d", falsified);
1243 // Example is 3=(1&2) with 2=false or 3=(1&4) with 4=2 and 2=false
1244 // (can happen when the unit was derived in the middle of the
1245 // rewriting)
1246 for (auto litId : g->pos_lhs_ids) {
1247 LOG (litId.clause,
1248 "found lrat in gate %d from %zd (looking for %d)",
1249 litId.current_lit, litId.clause->id, falsified);
1250 if (litId.current_lit == falsified ||
1251 (litId.current_lit == src && dst == falsified)) {
1252 push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (),
1253 proof_chain, true, Rewrite (),
1254 -dst, -g->lhs);
1255 }
1256 }
1257 } else {
1258 CADICAL_assert (unit);
1259 // Example is 1 = 2&3 where 2 and 3 are false
1260 for (auto litId : g->neg_lhs_ids) {
1261 push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (),
1262 proof_chain);
1263 }
1264 LOG (proof_chain, "produced lrat chain");
1265 break;
1266 }
1267 lrat_chain = std::move (proof_chain);
1268 break;
1269 default:
1270 CADICAL_assert (false);
1271 }
1272 (void) unit;
1273}
1274
1276 if (internal->unsat)
1277 return false;
1278 LOG ("fully propagating");
1279 CADICAL_assert (internal->watching ());
1281 bool no_conflict = internal->propagate ();
1282
1283 if (no_conflict)
1284 return true;
1285 internal->learn_empty_clause ();
1286 if (internal->lrat)
1287 lrat_chain.clear ();
1288
1289 return false;
1290}
1291bool Closure::learn_congruence_unit (int lit, bool delay_propagation, bool force_propagation) {
1292 if (internal->unsat)
1293 return false;
1294 const signed char val_lit = internal->val (lit);
1295 if (val_lit > 0) {
1296 LOG ("already set lit %d", lit);
1297 if (internal->lrat)
1298 lrat_chain.clear ();
1299 if (force_propagation)
1300 return fully_propagate();
1301 return true;
1302 }
1303 LOG ("adding unit %s", LOGLIT (lit));
1304 ++internal->stats.congruence.units;
1305 CADICAL_assert (!internal->lrat || !lrat_chain.empty ());
1306 if (val_lit < 0) {
1307 if (internal->lrat) {
1308 CADICAL_assert (internal->lrat_chain.empty ());
1309 LRAT_ID id = internal->unit_id (-lit);
1310 internal->lrat_chain.push_back (id);
1311 for (auto id : lrat_chain)
1312 internal->lrat_chain.push_back (id);
1313 lrat_chain.clear ();
1314 }
1315 internal->learn_empty_clause ();
1316 return false;
1317 }
1318
1319 LOG (lrat_chain, "assigning due to LRAT chain");
1320 swap (lrat_chain, internal->lrat_chain);
1321 internal->assign_unit (lit);
1322 CADICAL_assert (lrat_chain.empty ());
1323 CADICAL_assert (internal->lrat_chain.empty ());
1324 if (delay_propagation)
1325 return false;
1326 else return fully_propagate ();
1327}
1328
1329// for merging the literals there are many cases
1330// TODO: LRAT does not work if the LHS is not in normal form and if the
1331// representative is also in the gate.
1333 Gate *g, Gate *h, int lit, int other,
1334 const std::vector<LRAT_ID> &extra_reasons_lit,
1335 const std::vector<LRAT_ID> &extra_reasons_ulit) {
1336 CADICAL_assert (!internal->unsat);
1337 CADICAL_assert (g->lhs == lit);
1338 CADICAL_assert (g == h || h->lhs == other);
1339 (void) g, (void) h;
1340 LOG ("merging literals %s and %s", LOGLIT(lit), LOGLIT(other));
1341 // TODO: this should not update_eager but still calculate the LRAT chain
1342 // below!
1343 const int repr_lit = find_representative_and_compress (lit, false);
1344 const int repr_other = find_representative_and_compress (other, false);
1346 find_representative_and_compress (-other, false);
1347 LOG ("merging literals %d [=%d] and %d [=%d]", lit, repr_lit, other,
1348 repr_other);
1349
1350 if (repr_lit == repr_other) {
1351 LOG ("already merged %d and %d", lit, other);
1352 if (internal->lrat)
1353 lrat_chain.clear ();
1354 return false;
1355 }
1356
1357 const int val_lit = internal->val (lit);
1358 const int val_other = internal->val (other);
1359 if (val_lit) {
1360 if (val_lit == val_other) {
1361 LOG ("not merging lits %d and %d assigned to same value", lit, other);
1362 if (internal->lrat)
1363 lrat_chain.clear ();
1364 return false;
1365 }
1366 }
1367
1368 // For LRAT we need to distinguish more cases for a more regular
1369 // reconstruction.
1370 //
1371 // 1. if lit = -other, then we learn lit and -lit to derive false
1372 //
1373 // 2. otherwise, we learn the new clauses lit = -other (which are two real
1374 // clauses).
1375 //
1376 // 2a. if repr_lit = -repr_other, we learn the units repr_lit and
1377 // -repr_lit to derive false
1378 //
1379 // 2b. otherwise, we learn the equivalences repr_lit = -repr_other
1380 // (which are two real clauses)
1381 //
1382 // Without LRAT this is easier, as we directly learn the conclusion
1383 // (either false or the equivalence). The steps can also not be merged
1384 // because repr_lit can appear in the gate and hence in the resolution
1385 // chain.
1386 int smaller_repr = repr_lit;
1387 int larger_repr = repr_other;
1388 int smaller = lit;
1389 int larger = other;
1390 const std::vector<LRAT_ID> *smaller_chain = &extra_reasons_ulit;
1391 const std::vector<LRAT_ID> *larger_chain = &extra_reasons_lit;
1392
1393 if (abs (smaller_repr) > abs (larger_repr)) {
1394 swap (smaller_repr, larger_repr);
1395 swap (smaller, larger);
1396 swap (smaller_chain, larger_chain);
1397 }
1398
1399 CADICAL_assert (find_representative (smaller_repr) == smaller_repr);
1400 CADICAL_assert (find_representative (larger_repr) == larger_repr);
1401 if (lit == -other) {
1402 CADICAL_assert (chain.empty ());
1403 LOG ("merging clashing %d and %d", lit, other);
1404 if (internal->proof) {
1405 if (internal->lrat) {
1406 for (auto id : *smaller_chain)
1407 lrat_chain.push_back (id);
1408 }
1409 unsimplified.push_back (smaller);
1411
1412 if (internal->lrat) {
1413 internal->lrat_chain.push_back (id);
1414 for (auto id : *larger_chain)
1415 internal->lrat_chain.push_back (id);
1416 LOG (internal->lrat_chain, "lrat chain");
1417 }
1418 }
1419 internal->learn_empty_clause ();
1421 return false;
1422 }
1423
1424 LOG ("merging %d and %d first and then the equivalences of %d and %d "
1425 "with LRAT",
1426 lit, other, repr_lit, repr_other);
1427 Clause *eq1_tmp = nullptr;
1428 if (internal->lrat) {
1429 lrat_chain = *smaller_chain;
1430 eq1_tmp = add_tmp_binary_clause (-larger, smaller);
1431 }
1432 CADICAL_assert (!internal->lrat || eq1_tmp);
1433
1434 Clause *eq2_tmp = nullptr;
1435 if (internal->lrat) {
1436 lrat_chain = *larger_chain;
1437 LOG (lrat_chain, "lrat chain");
1438
1439 eq2_tmp = add_tmp_binary_clause (larger, -smaller);
1440 // the order in the clause is important for the
1441 // repr_lit == -repr_other to get the right chain
1442 }
1443 CADICAL_assert (!internal->lrat || eq2_tmp);
1444 if (internal->lrat)
1445 lrat_chain.clear ();
1446
1447 if (repr_lit == -repr_other) {
1448 // now derive empty clause
1449 Rewrite rew1, rew2;
1450 if (internal->lrat) {
1451 // no need to calculate push_id_and_rewriting_lrat here because all
1452 // the job is done by the arguments already
1453 rew1 = Rewrite (lit == repr_lit ? 0 : lit, repr_lit,
1454 lit == repr_lit ? 0 : representative_id (lit),
1455 lit == repr_lit ? 0 : representative_id (-lit));
1456 rew2 = Rewrite (other == repr_other ? 0 : other, repr_other,
1457 other == repr_other ? 0 : representative_id (other),
1458 other == repr_other ? 0 : representative_id (-other));
1459 push_id_and_rewriting_lrat_unit (eq1_tmp, rew1, lrat_chain, true,
1460 rew2);
1461 swap (lrat_chain, internal->lrat_chain);
1462 }
1463 internal->assign_unit (-larger_repr);
1464 if (internal->lrat) {
1465 internal->lrat_chain.clear ();
1466
1467 if (larger != larger_repr)
1468 push_lrat_unit (-larger_repr);
1470 eq2_tmp, rew1, lrat_chain, true, rew2,
1471 larger != larger_repr ? larger_repr : 0);
1472 LOG (lrat_chain, "lrat chain");
1473 swap (lrat_chain, internal->lrat_chain);
1474 }
1475 internal->learn_empty_clause ();
1476 if (internal->lrat)
1477 internal->lrat_chain.clear ();
1478 return false;
1479 }
1480
1481 if (val_lit) {
1482 if (val_lit == val_other) {
1483 LOG ("not merging lits %d and %d assigned to same value", lit, other);
1484 if (internal->lrat)
1485 lrat_chain.clear ();
1486 return false;
1487 }
1488 if (val_lit == -val_other) {
1489 LOG ("merging lits %d and %d assigned to inconsistent value", lit,
1490 other);
1491 CADICAL_assert (lrat_chain.empty ());
1492 if (internal->lrat) {
1493 Clause *c = val_lit ? eq2_tmp : eq1_tmp;
1494 int pos = val_lit ? other : lit;
1495 int neg = val_lit ? -lit : -other;
1497 push_lrat_unit (neg);
1499 }
1500 internal->learn_empty_clause ();
1501 if (internal->lrat)
1502 lrat_chain.clear ();
1503 return false;
1504 }
1505
1506 CADICAL_assert (!val_other);
1507 LOG ("merging assigned %d and unassigned %d", lit, other);
1508 CADICAL_assert (lrat_chain.empty ());
1509 const int unit = (val_lit < 0) ? -other : other;
1510 if (internal->lrat) {
1511 Clause *c;
1512 if (lit == smaller) {
1513 if (val_lit < 0)
1514 c = eq1_tmp;
1515 else
1516 c = eq2_tmp;
1517 } else {
1518 if (val_lit < 0)
1519 c = eq2_tmp;
1520 else
1521 c = eq1_tmp;
1522 }
1524 Rewrite (), unit);
1525 }
1526 learn_congruence_unit (unit);
1527 if (internal->lrat)
1528 lrat_chain.clear ();
1529 return false;
1530 }
1531
1532 if (!val_lit && val_other) {
1533 LOG ("merging assigned %d and unassigned %d", lit, other);
1534 CADICAL_assert (lrat_chain.empty ());
1535 const int unit = (val_other < 0) ? -lit : lit;
1536 if (internal->lrat) {
1537 Clause *c;
1538 if (lit == smaller) {
1539 if (val_lit < 0)
1540 c = eq1_tmp;
1541 else
1542 c = eq2_tmp;
1543 } else {
1544 if (val_lit < 0)
1545 c = eq2_tmp;
1546 else
1547 c = eq1_tmp;
1548 }
1550 Rewrite (), lit, unit);
1551 }
1552 learn_congruence_unit (unit);
1553 if (internal->lrat)
1554 lrat_chain.clear ();
1555 return false;
1556 }
1557
1558 Clause *eq1_repr, *eq2_repr;
1559 if (smaller_repr != smaller || larger != larger_repr) {
1560 if (internal->lrat) {
1561 lrat_chain.clear ();
1562 Rewrite rew1 = Rewrite (
1563 smaller_repr != smaller ? smaller : 0,
1564 smaller_repr != smaller ? smaller_repr : 0,
1565 smaller_repr != smaller ? representative_id (smaller) : 0,
1566 smaller_repr != smaller ? representative_id (-smaller) : 0);
1567 Rewrite rew2 =
1568 Rewrite (larger_repr != larger ? larger : 0,
1569 larger_repr != larger ? larger_repr : 0,
1570 larger_repr != larger ? representative_id (larger) : 0,
1571 larger_repr != larger ? representative_id (-larger) : 0);
1572 push_id_and_rewriting_lrat_full (eq1_tmp, rew1, lrat_chain, true,
1573 rew2);
1574 }
1575 eq1_repr = learn_binary_tmp_or_full_clause (-larger_repr, smaller_repr);
1576 } else {
1577 if (internal->lrat)
1578 eq1_repr = maybe_promote_tmp_binary_clause (eq1_tmp);
1579 else
1580 eq1_repr = maybe_add_binary_clause (-larger_repr, smaller_repr);
1581 }
1582
1583 if (internal->lrat) {
1584 lrat_chain.clear ();
1585 }
1586
1587 if (smaller_repr != smaller || larger != larger_repr) {
1588
1589 if (internal->lrat) {
1590 lrat_chain.clear ();
1591 // eq2 = larger, -smaller
1592 Rewrite rew1 = Rewrite (
1593 smaller_repr != smaller ? smaller : 0,
1594 smaller_repr != smaller ? smaller_repr : 0,
1595 smaller_repr != smaller ? representative_id (smaller) : 0,
1596 smaller_repr != smaller ? representative_id (-smaller) : 0);
1597 Rewrite rew2 =
1598 Rewrite (larger_repr != larger ? larger : 0,
1599 larger_repr != larger ? larger_repr : 0,
1600 larger_repr != larger ? representative_id (larger) : 0,
1601 larger_repr != larger ? representative_id (-larger) : 0);
1602 push_id_and_rewriting_lrat_full (eq2_tmp, rew1, lrat_chain, true,
1603 rew2);
1604 }
1605
1606 eq2_repr = learn_binary_tmp_or_full_clause (larger_repr, -smaller_repr);
1607
1608 } else {
1609 if (internal->lrat)
1610 eq2_repr = maybe_promote_tmp_binary_clause (eq2_tmp);
1611 else
1612 eq2_repr = maybe_add_binary_clause (larger_repr, -smaller_repr);
1613 }
1614 lrat_chain.clear ();
1615
1616 if (internal->lrat) {
1617 representative_id (larger_repr) = eq1_repr->id;
1618 CADICAL_assert (std::find (begin (*eq1_repr), end (*eq1_repr), -larger_repr) !=
1619 end (*eq1_repr));
1620 representative_id (-larger_repr) = eq2_repr->id;
1621 CADICAL_assert (std::find (begin (*eq2_repr), end (*eq2_repr), larger_repr) !=
1622 end (*eq2_repr));
1623 }
1624 LOG ("updating %d -> %d", larger_repr, smaller_repr);
1625 representative (larger_repr) = smaller_repr;
1626 representative (-larger_repr) = -smaller_repr;
1627 schedule_literal (larger_repr);
1628 ++internal->stats.congruence.congruent;
1629 CADICAL_assert (lrat_chain.empty ());
1630 return true;
1631}
1632
1633// Variant when there are no gates
1634// TODO: this is exactly the same as the other function without the gates.
1635// Kill the arguments!
1637 int lit, int other, const std::vector<LRAT_ID> &extra_reasons_lit,
1638 const std::vector<LRAT_ID> &extra_reasons_ulit) {
1639 CADICAL_assert (!internal->unsat);
1640 LOG ("merging literals %s and %s", LOGLIT (lit), LOGLIT (other));
1641 // TODO: this should not update_eager but still calculate the LRAT chain
1642 // below!
1643 const int repr_lit = find_representative_and_compress (lit, false);
1644 const int repr_other = find_representative_and_compress (other, false);
1646 find_representative_and_compress (-other, false);
1647 LOG ("merging literals %s [=%d] and %s [=%d]", LOGLIT (lit), repr_lit,
1648 LOGLIT (other), repr_other);
1649 LOG (lrat_chain, "lrat chain beginning of merge");
1650
1651 if (repr_lit == repr_other) {
1652 LOG ("already merged %s and %s", LOGLIT (lit), LOGLIT (other));
1653 if (internal->lrat)
1654 lrat_chain.clear ();
1655 return false;
1656 }
1657
1658 const int val_lit = internal->val (lit);
1659 const int val_other = internal->val (other);
1660
1661 // For LRAT we need to distinguish more cases for a more regular
1662 // reconstruction.
1663 //
1664 // 1. if lit = -other, then we learn lit and -lit to derive false
1665 //
1666 // 2. otherwise, we learn the new clauses lit = -other (which are two real
1667 // clauses).
1668 //
1669 // 2a. if repr_lit = -repr_other, we learn the units repr_lit and
1670 // -repr_lit to derive false
1671 //
1672 // 2b. otherwise, we learn the equivalences repr_lit = -repr_other
1673 // (which are two real clauses)
1674 //
1675 // Without LRAT this is easier, as we directly learn the conclusion
1676 // (either false or the equivalence). The steps can also not be merged
1677 // because repr_lit can appear in the gate and hence in the resolution
1678 // chain.
1679 int smaller_repr = repr_lit;
1680 int larger_repr = repr_other;
1681 int val_smaller = val_lit;
1682 int val_larger = val_other;
1683 int smaller = lit;
1684 int larger = other;
1685 const std::vector<LRAT_ID> *smaller_chain = &extra_reasons_ulit;
1686 const std::vector<LRAT_ID> *larger_chain = &extra_reasons_lit;
1687
1688 if (abs (smaller_repr) > abs (larger_repr)) {
1689 swap (smaller_repr, larger_repr);
1690 swap (smaller, larger);
1691 swap (smaller_chain, larger_chain);
1692 swap (val_smaller, val_larger);
1693 }
1694
1695 CADICAL_assert (find_representative (smaller_repr) == smaller_repr);
1696 CADICAL_assert (find_representative (larger_repr) == larger_repr);
1697 if (lit == -other) {
1698 LOG ("merging clashing %d and %d", lit, other);
1699 if (!val_smaller) {
1700 if (internal->lrat)
1701 internal->lrat_chain = *smaller_chain;
1702 internal->assign_unit (smaller);
1703 if (internal->lrat)
1704 internal->lrat_chain.clear ();
1705
1707 if (internal->lrat) {
1708 CADICAL_assert (internal->lrat_chain.empty ());
1709 swap (internal->lrat_chain, lrat_chain);
1710 for (auto id : *larger_chain)
1711 internal->lrat_chain.push_back (id);
1712 LOG (internal->lrat_chain, "lrat chain");
1713 }
1714 internal->learn_empty_clause ();
1715 return false;
1716 } else {
1717 if (internal->lrat)
1718 internal->lrat_chain =
1719 (val_smaller < 0 ? *smaller_chain : *larger_chain);
1720 if (internal->lrat)
1721 internal->lrat_chain.push_back (
1722 internal->unit_id (val_smaller > 0 ? smaller : -smaller));
1723 internal->learn_empty_clause ();
1724 return false;
1725 }
1726 }
1727
1728 if (val_lit && val_lit == val_other) {
1729 LOG ("not merging lits %d and %d assigned to same value", lit, other);
1730 return false;
1731 }
1732
1733 if (val_lit && val_lit == -val_other) {
1734 if (internal->lrat) {
1735 internal->lrat_chain.push_back (
1736 internal->unit_id (val_smaller < 0 ? -smaller : smaller));
1737 internal->lrat_chain.push_back (
1738 internal->unit_id (val_larger < 0 ? -larger : larger));
1739 for (auto id : (val_smaller < 0 ? *smaller_chain : *larger_chain)) {
1740 internal->lrat_chain.push_back(id);
1741 }
1742 }
1743 internal->learn_empty_clause ();
1744 return false;
1745 }
1746
1747 LOG ("merging %d and %d first and then the equivalences of %d and %d "
1748 "with LRAT",
1749 lit, other, repr_lit, repr_other);
1750 Clause *eq1_tmp = nullptr;
1751 if (internal->lrat) {
1752 lrat_chain = *smaller_chain;
1753 eq1_tmp = add_tmp_binary_clause (-larger, smaller);
1754 CADICAL_assert (eq1_tmp);
1755 }
1756 CADICAL_assert (!internal->lrat || eq1_tmp);
1757
1758 Clause *eq2_tmp = nullptr;
1759 if (internal->lrat) {
1760 lrat_chain = *larger_chain;
1761 LOG (lrat_chain, "lrat chain");
1762 // the order in the clause is important for the
1763 // repr_lit == -repr_other to get the right chain
1764 eq2_tmp = add_tmp_binary_clause (larger, -smaller);
1765 CADICAL_assert (eq2_tmp);
1766 }
1767
1768 CADICAL_assert (!internal->lrat || eq2_tmp);
1769 if (internal->lrat)
1770 lrat_chain.clear ();
1771
1772 if (repr_lit == -repr_other) {
1773 // now derive empty clause
1774 Rewrite rew1, rew2;
1775 if (internal->lrat) {
1776 // no need to calculate push_id_and_rewriting_lrat here because all
1777 // the job is done by the arguments already
1778 rew1 = Rewrite (lit == repr_lit ? 0 : lit, repr_lit,
1779 lit == repr_lit ? 0 : representative_id (lit),
1780 lit == repr_lit ? 0 : representative_id (-lit));
1781 rew2 = Rewrite (other == repr_other ? 0 : other, repr_other,
1782 other == repr_other ? 0 : representative_id (other),
1783 other == repr_other ? 0 : representative_id (-other));
1784 push_id_and_rewriting_lrat_unit (eq1_tmp, rew1, lrat_chain, true,
1785 rew2);
1786 swap (lrat_chain, internal->lrat_chain);
1787 }
1788 CADICAL_assert (val_larger == internal->val (larger_repr));
1789 if (!val_larger) {
1790 // not assigned, first assign one
1791 internal->assign_unit (-larger_repr);
1792 if (internal->lrat) {
1793 internal->lrat_chain.clear ();
1794
1795 if (larger != larger_repr)
1796 push_lrat_unit (-larger_repr);
1797 // no need to calculate push_id_and_rewriting_lrat here because all
1798 // the job is done by the arguments already
1800 eq2_tmp, rew1, lrat_chain, true, rew2,
1801 larger != larger_repr ? larger_repr : 0);
1802 LOG (lrat_chain, "lrat chain");
1803 swap (lrat_chain, internal->lrat_chain);
1804 }
1805 } else {
1806 // otherwise, no need to
1807 if (internal->lrat)
1808 lrat_chain.push_back (internal->unit_id (larger_repr));
1809 }
1810 internal->learn_empty_clause ();
1811 if (internal->lrat)
1812 internal->lrat_chain.clear ();
1813 return false;
1814 }
1815
1816 if (val_lit) {
1817 if (val_lit == val_other) {
1818 LOG ("not merging lits %d and %d assigned to same value", lit, other);
1819 if (internal->lrat)
1820 lrat_chain.clear ();
1821 return false;
1822 }
1823 if (val_lit == -val_other) {
1824 LOG ("merging lits %d and %d assigned to inconsistent value", lit,
1825 other);
1826 CADICAL_assert (lrat_chain.empty ());
1827 if (internal->lrat) {
1828 Clause *c = val_lit ? eq2_tmp : eq1_tmp;
1829 int pos = val_lit ? other : lit;
1830 int neg = val_lit ? -lit : -other;
1832 push_lrat_unit (neg);
1834 }
1835 internal->learn_empty_clause ();
1836 if (internal->lrat)
1837 lrat_chain.clear ();
1838 return false;
1839 }
1840
1841 CADICAL_assert (!val_other);
1842 LOG ("merging assigned %d and unassigned %d", lit, other);
1843 CADICAL_assert (lrat_chain.empty ());
1844 const int unit = (val_lit < 0) ? -other : other;
1845 if (internal->lrat) {
1846 Clause *c;
1847 if (lit == smaller) {
1848 if (val_lit < 0)
1849 c = eq1_tmp;
1850 else
1851 c = eq2_tmp;
1852 } else {
1853 if (val_lit < 0)
1854 c = eq2_tmp;
1855 else
1856 c = eq1_tmp;
1857 }
1859 Rewrite (), unit);
1860 }
1861 learn_congruence_unit (unit);
1862 if (internal->lrat)
1863 lrat_chain.clear ();
1864 return false;
1865 }
1866
1867 if (!val_lit && val_other) {
1868 LOG ("merging assigned %d and unassigned %d", lit, other);
1869 CADICAL_assert (lrat_chain.empty ());
1870 const int unit = (val_other < 0) ? -lit : lit;
1871 if (internal->lrat) {
1872 Clause *c;
1873 if (lit == smaller) {
1874 CADICAL_assert (other == larger);
1875 if (val_other > 0)
1876 c = eq1_tmp;
1877 else
1878 c = eq2_tmp;
1879 } else {
1880 if (val_other > 0)
1881 c = eq2_tmp;
1882 else
1883 c = eq1_tmp;
1884 }
1886 Rewrite (), lit, unit);
1887 }
1888 learn_congruence_unit (unit);
1889 if (internal->lrat)
1890 lrat_chain.clear ();
1891 return false;
1892 }
1893
1894 Clause *eq1_repr, *eq2_repr;
1895 if (smaller_repr != smaller || larger != larger_repr) {
1896 if (internal->lrat) {
1897 lrat_chain.clear ();
1898 Rewrite rew1 = Rewrite (
1899 smaller_repr != smaller ? smaller : 0,
1900 smaller_repr != smaller ? smaller_repr : 0,
1901 smaller_repr != smaller ? representative_id (smaller) : 0,
1902 smaller_repr != smaller ? representative_id (-smaller) : 0);
1903 Rewrite rew2 =
1904 Rewrite (larger_repr != larger ? larger : 0,
1905 larger_repr != larger ? larger_repr : 0,
1906 larger_repr != larger ? representative_id (larger) : 0,
1907 larger_repr != larger ? representative_id (-larger) : 0);
1908 push_id_and_rewriting_lrat_full (eq1_tmp, rew1, lrat_chain, true,
1909 rew2);
1910 }
1911 eq1_repr = learn_binary_tmp_or_full_clause (-larger_repr, smaller_repr);
1912 } else {
1913 if (internal->lrat)
1914 eq1_repr = maybe_promote_tmp_binary_clause (eq1_tmp);
1915 else
1916 eq1_repr = maybe_add_binary_clause (-larger_repr, smaller_repr);
1917 }
1918
1919 if (internal->lrat) {
1920 lrat_chain.clear ();
1921 }
1922
1923 if (smaller_repr != smaller || larger != larger_repr) {
1924
1925 if (internal->lrat) {
1926 lrat_chain.clear ();
1927 // eq2 = larger, -smaller
1928 Rewrite rew1 = Rewrite (
1929 smaller_repr != smaller ? smaller : 0,
1930 smaller_repr != smaller ? smaller_repr : 0,
1931 smaller_repr != smaller ? representative_id (smaller) : 0,
1932 smaller_repr != smaller ? representative_id (-smaller) : 0);
1933 Rewrite rew2 =
1934 Rewrite (larger_repr != larger ? larger : 0,
1935 larger_repr != larger ? larger_repr : 0,
1936 larger_repr != larger ? representative_id (larger) : 0,
1937 larger_repr != larger ? representative_id (-larger) : 0);
1938 push_id_and_rewriting_lrat_full (eq2_tmp, rew1, lrat_chain, true,
1939 rew2);
1940 }
1941 eq2_repr = learn_binary_tmp_or_full_clause (larger_repr, -smaller_repr);
1942 } else {
1943 if (internal->lrat)
1944 eq2_repr = maybe_promote_tmp_binary_clause (eq2_tmp);
1945 else
1946 eq2_repr = maybe_add_binary_clause (larger_repr, -smaller_repr);
1947 }
1948 lrat_chain.clear ();
1949
1950 if (internal->lrat) {
1951 representative_id (larger_repr) = eq1_repr->id;
1952 CADICAL_assert (std::find (begin (*eq1_repr), end (*eq1_repr), -larger_repr) !=
1953 end (*eq1_repr));
1954 representative_id (-larger_repr) = eq2_repr->id;
1955 check_not_tmp_binary_clause (eq1_repr);
1956 check_not_tmp_binary_clause (eq2_repr);
1957 CADICAL_assert (std::find (begin (*eq2_repr), end (*eq2_repr), larger_repr) !=
1958 end (*eq2_repr));
1959 }
1960 LOG ("updating %d -> %d", larger_repr, smaller_repr);
1961 representative (larger_repr) = smaller_repr;
1962 representative (-larger_repr) = -smaller_repr;
1963 schedule_literal (larger_repr);
1964 ++internal->stats.congruence.congruent;
1965 CADICAL_assert (lrat_chain.empty ());
1966 return true;
1967}
1968
1970 if (internal->lrat)
1972 if (!c)
1973 return;
1974 if (!c->redundant)
1975 return;
1976 LOG (c, "turning redundant subsuming clause into irredundant clause");
1977 c->redundant = false;
1978 if (internal->proof)
1979 internal->proof->strengthen (c->id);
1980 internal->stats.current.irredundant++;
1981 internal->stats.added.irredundant++;
1982 internal->stats.irrlits += c->size;
1983 CADICAL_assert (internal->stats.current.redundant > 0);
1984 internal->stats.current.redundant--;
1985 CADICAL_assert (internal->stats.added.redundant > 0);
1986 internal->stats.added.redundant--;
1987 // ... and keep 'stats.added.total'.
1988}
1989
1990// This function is rather tricky for LRAT. If you have 2 = 1 and 3=4 you
1991// cannot add 2=3. You really to connect the representatives directly
1992// therefore you actually need to learn the clauses 2->3->4 and -2->1 and
1993// vice-versa
1995 Clause *c2) {
1996 CADICAL_assert (!internal->unsat);
1997 LRAT_ID id1 = c1 ? c1->id : 0;
1998 LRAT_ID id2 = c2 ? c2->id : 0;
1999 if (internal->lrat) {
2000 CADICAL_assert (c1);
2001 CADICAL_assert (c2);
2002 CADICAL_assert (c1->size == 2);
2003 CADICAL_assert (c2->size == 2);
2004 CADICAL_assert (c1->literals[0] == lit || c1->literals[1] == lit);
2005 CADICAL_assert (c2->literals[0] == other || c2->literals[1] == other);
2006 CADICAL_assert (c1->literals[0] == -other || c1->literals[1] == -other);
2007 CADICAL_assert (c2->literals[0] == -lit || c2->literals[1] == -lit);
2010 }
2011 int repr_lit = find_representative (lit);
2012 int repr_other = find_representative (other);
2015 LOG ("merging literals %d [=%d] and %d [=%d] lrat", lit, repr_lit, other,
2016 repr_other);
2017
2018 if (repr_lit == repr_other) {
2019 LOG ("already merged %d and %d", lit, other);
2020 return false;
2021 }
2022 const int val_lit = internal->val (lit);
2023 const int val_other = internal->val (other);
2024
2025 if (val_lit) {
2026 if (val_lit == val_other) {
2027 LOG ("not merging lits %d and %d assigned to same value", lit, other);
2028 return false;
2029 }
2030 if (val_lit == -val_other) {
2031 if (internal->lrat)
2032 lrat_chain.push_back (internal->unit_id (lit)),
2033 lrat_chain.push_back (internal->unit_id (other));
2034 LOG ("merging lits %d and %d assigned to inconsistent value", lit,
2035 other);
2036 internal->learn_empty_clause ();
2037 return false;
2038 }
2039
2040 CADICAL_assert (!val_other);
2041 LOG ("merging assigned %d and unassigned %d", lit, other);
2042 const int unit = (val_lit < 0) ? -other : other;
2043 if (internal->lrat)
2044 lrat_chain.push_back (internal->unit_id (unit));
2045 if (val_lit < 0)
2046 lrat_chain.push_back (c2->id);
2047 else
2048 lrat_chain.push_back (c1->id);
2049 learn_congruence_unit (unit);
2050 return false;
2051 }
2052
2053 if (!val_lit && val_other) {
2054 LOG ("merging assigned %d and unassigned %d", other, lit);
2055 const int unit = (val_other < 0) ? -lit : lit;
2056 if (internal->lrat)
2057 lrat_chain.push_back (
2058 internal->unit_id (val_other < 0 ? -other : other));
2059 if (val_lit < 0)
2060 lrat_chain.push_back (c1->id);
2061 else
2062 lrat_chain.push_back (c2->id);
2063 learn_congruence_unit (unit);
2064 return false;
2065 }
2066
2067 int smaller_repr = repr_lit;
2068 int larger_repr = repr_other;
2069 int smaller = lit;
2070 int larger = other;
2071
2072 if (abs (smaller_repr) > abs (larger_repr)) {
2073 swap (smaller_repr, larger_repr);
2074 swap (smaller, larger);
2075 }
2076
2077 CADICAL_assert (find_representative (smaller_repr) == smaller_repr);
2078 CADICAL_assert (find_representative (larger_repr) == larger_repr);
2079
2080 if (repr_lit == -repr_other) {
2081 LOG ("merging clashing %d [=%d] and %d[=%d], smaller: %d", lit,
2082 repr_lit, other, repr_other, smaller);
2083 if (internal->lrat) {
2084 Rewrite rew1 =
2085 Rewrite (lit, lit == repr_lit ? 0 : repr_lit,
2086 lit == repr_lit ? 0 : find_representative_lrat (lit),
2087 lit == repr_lit ? 0 : find_representative_lrat (-lit));
2088 Rewrite rew2 = Rewrite (
2089 other, other == repr_other ? 0 : repr_other,
2090 other == repr_other ? 0 : find_representative_lrat (other),
2091 other == repr_other ? 0 : find_representative_lrat (-other));
2092 push_id_and_rewriting_lrat_unit (c1, rew1, lrat_chain, true, rew2);
2093 LOG (lrat_chain, "lrat chain");
2094 swap (internal->lrat_chain, lrat_chain);
2095 }
2096 internal->assign_unit (repr_lit);
2097 if (internal->lrat) {
2098 lrat_chain.clear ();
2099 LRAT_ID id = internal->unit_id (repr_lit);
2100 CADICAL_assert (id);
2101 lrat_chain.push_back (id);
2102 if (lit != repr_lit) {
2103 const LRAT_ID repr_id2 = find_representative_lrat (-lit);
2104 lrat_chain.push_back (repr_id2);
2105 }
2106 lrat_chain.push_back (id2);
2107 if (other != repr_other) {
2108 const LRAT_ID repr_larger_id2 = find_representative_lrat (other);
2109 lrat_chain.push_back (repr_larger_id2);
2110 }
2111 LOG (lrat_chain, "lrat chain");
2112 swap (internal->lrat_chain, lrat_chain);
2113 }
2114 internal->learn_empty_clause ();
2115 return false;
2116 }
2117
2118 LOG ("merging %d [=%d] and %d [=%d]", lit, repr_lit, other, repr_other);
2119 promote_clause (c1), promote_clause (c2);
2120 bool learn_clause = (lit != repr_lit) || (other != repr_other);
2121 if (learn_clause) {
2122 if (internal->lrat) {
2123 if (lit != repr_lit) {
2124 LOG ("adding chain for lit %d -> %d", lit, repr_lit);
2126 }
2127 if (other != repr_other) {
2128 LOG ("adding chain for lit %d -> %d", -other, -repr_other);
2129 lrat_chain.push_back (find_representative_lrat (-other));
2130 }
2131 lrat_chain.push_back (id1);
2132 }
2133 Clause *eq1 = learn_binary_tmp_or_full_clause (repr_lit, -repr_other);
2134
2135 if (internal->lrat) {
2136 lrat_chain.clear ();
2137 if (lit != repr_lit)
2139 if (other != repr_other)
2140 lrat_chain.push_back (find_representative_lrat (other));
2141 lrat_chain.push_back (id2);
2142 }
2143 Clause *eq2 = learn_binary_tmp_or_full_clause (-repr_lit, repr_other);
2144 if (internal->lrat) {
2145 lrat_chain.clear ();
2146 if (smaller_repr == repr_lit) {
2147 CADICAL_assert (larger_repr == repr_other);
2148 representative_id (-larger_repr) = eq2->id;
2149 CADICAL_assert (std::find (eq2->begin (), eq2->end (), larger_repr) !=
2150 eq2->end ());
2151 representative_id (larger_repr) = eq1->id;
2152 CADICAL_assert (std::find (eq1->begin (), eq1->end (), -larger_repr) !=
2153 eq1->end ());
2154 } else {
2155 CADICAL_assert (larger_repr == repr_lit);
2156 representative_id (-larger_repr) = eq1->id;
2157 CADICAL_assert (std::find (eq1->begin (), eq1->end (), larger_repr) !=
2158 eq1->end ());
2159 representative_id (larger_repr) = eq2->id;
2160 CADICAL_assert (std::find (eq2->begin (), eq2->end (), -larger_repr) !=
2161 eq2->end ());
2162 }
2163 }
2164
2165 } else if (internal->lrat) {
2166 LOG ("not learning new clause, using already existing one");
2167 if (smaller_repr == repr_lit) {
2168 LOG ("setting ids of %d: %" PRIu64 "; %d: %" PRIu64 " (case 1)",
2169 larger, id1, -larger, id2);
2170 representative_id (-larger_repr) = id2;
2171 representative_id (larger_repr) = id1;
2172 } else {
2173 LOG ("setting ids of %d: %" PRIu64 "; %d: %" PRIu64 " (case 2)",
2174 larger, id2, -larger, id1);
2175 representative_id (-larger_repr) = id1;
2176 representative_id (larger_repr) = id2;
2177 }
2178 }
2179
2180 LOG ("updating %d -> %d", larger_repr, smaller_repr);
2181 representative (larger_repr) = smaller_repr;
2182 representative (-larger_repr) = -smaller_repr;
2183 schedule_literal (larger_repr);
2184 ++internal->stats.congruence.congruent;
2185 return true;
2186}
2187
2188/*------------------------------------------------------------------------*/
2189GOccs &Closure::goccs (int lit) { return gtab[internal->vlit (lit)]; }
2190
2192 LOG (g, "connect %d to", lit);
2193 // incorrect for ITE
2194 // CADICAL_assert (std::find(begin (goccs (lit)), end (goccs (lit)), g) ==
2195 // std::end (goccs (lit)));
2196 goccs (lit).push_back (g);
2197}
2198
2199uint64_t &Closure::largecount (int lit) {
2200 CADICAL_assert (internal->vlit (lit) < glargecounts.size ());
2201 return glargecounts[internal->vlit (lit)];
2202}
2203
2204/*------------------------------------------------------------------------*/
2205// Initialization
2206
2208 representant.resize (2 * internal->max_var + 3);
2209 eager_representant.resize (2 * internal->max_var + 3);
2210 if (internal->lrat) {
2211 eager_representant_id.resize (2 * internal->max_var + 3);
2212 representant_id.resize (2 * internal->max_var + 3);
2213 lazy_propagated_idx.resize (internal->max_var + 1, false);
2214 for (auto lit : internal->trail)
2215 lazy_propagated (lit) = true;
2216 }
2217 marks.resize (2 * internal->max_var + 3);
2218 mu1_ids.resize (2 * internal->max_var + 3);
2219 if (internal->lrat) {
2220 mu2_ids.resize (2 * internal->max_var + 3);
2221 mu4_ids.resize (2 * internal->max_var + 3);
2222 }
2223#ifndef CADICAL_NDEBUG
2224 for (auto &it : mu1_ids)
2225 it.current_lit = 0, it.clause = nullptr;
2226 for (auto &it : mu2_ids)
2227 it.current_lit = 0, it.clause = nullptr;
2228 for (auto &it : mu4_ids)
2229 it.current_lit = 0, it.clause = nullptr;
2230#endif
2231 scheduled.resize (internal->max_var + 1);
2232 gtab.resize (2 * internal->max_var + 3);
2233 for (auto v : internal->vars) {
2234 representative (v) = v;
2235 representative (-v) = -v;
2236 eager_representative (v) = v;
2237 eager_representative (-v) = -v;
2238 }
2239 units = internal->propagated;
2240 Random rand (internal->stats.congruence.rounds);
2241 for (auto &n : nonces) {
2242 n = 1 | rand.next ();
2243 }
2244#ifdef LOGGING
2245 fresh_id = internal->clause_id;
2246#endif
2247 internal->init_noccs ();
2248 internal->init_occs ();
2249}
2250
2252 LOG ("[gate-extraction]");
2253 for (Clause *c : internal->clauses) {
2254 if (c->garbage)
2255 continue;
2256 if (c->redundant && c->size != 2)
2257 continue;
2258 if (c->size > 2)
2259 continue;
2260 CADICAL_assert (c->size == 2);
2261 const int lit = c->literals[0];
2262 const int other = c->literals[1];
2263 internal->noccs (lit)++;
2264 internal->noccs (other)++;
2265 internal->watch_clause (c);
2266 }
2267}
2268
2269/*------------------------------------------------------------------------*/
2271 CADICAL_assert (internal->clause.empty ());
2273 if (internal->lrat)
2274 return;
2275 LOG (g, "checking implied");
2276 const int lhs = g->lhs;
2277 const int not_lhs = -lhs;
2278 for (auto other : g->rhs)
2279 check_binary_implied (not_lhs, other);
2280 internal->clause = g->rhs;
2281 check_implied ();
2282 internal->clause.clear ();
2283}
2284
2286 if (!internal->proof) {
2287 CADICAL_assert (chain.empty ());
2288 return;
2289 }
2290 if (chain.empty ())
2291 return;
2292 LOG ("starting deletion of proof chain");
2293 auto &clause = internal->clause;
2294 CADICAL_assert (clause.empty ());
2295 uint32_t id1 = UINT32_MAX, id2 = UINT32_MAX;
2296 LRAT_ID id = 0;
2297
2298 LOG (chain, "chain:");
2299 for (auto lit : chain) {
2300 LOG ("reading %d from chain", lit);
2301 if (id1 == UINT32_MAX) {
2302 id1 = lit;
2303 id = (LRAT_ID) id1;
2304 continue;
2305 }
2306 if (id2 == UINT32_MAX) {
2307 id2 = lit;
2308 id = ((LRAT_ID) id1 << 32) + id2;
2309 continue;
2310 }
2311 if (lit) { // parsing the id first
2312 LOG ("found %d as literal in chain", lit);
2313 clause.push_back (lit);
2314 } else {
2315 CADICAL_assert (id);
2316 internal->proof->delete_clause (id, false, clause);
2317 clause.clear ();
2318 id = 0, id1 = UINT32_MAX, id2 = UINT32_MAX;
2319 }
2320 }
2321 CADICAL_assert (clause.empty ());
2322 chain.clear ();
2323 LOG ("finished deletion of proof chain");
2324}
2325
2326/*------------------------------------------------------------------------*/
2327// Simplification
2330 if (g->garbage)
2331 return true;
2332 const int lhs = g->lhs;
2333 if (internal->val (lhs) > 0) {
2334 mark_garbage (g);
2335 return true;
2336 }
2337
2338 CADICAL_assert (g->arity () > 1);
2339 return false;
2340}
2341
2344 if (g->garbage)
2345 return true;
2346 CADICAL_assert (g->arity () > 1);
2347 return false;
2348}
2349
2350void Closure::shrink_and_gate (Gate *g, int falsifies, int clashing) {
2351 if (falsifies) {
2352 g->rhs.resize (1);
2353 g->rhs[0] = falsifies;
2354 g->hash = hash_lits (nonces, g->rhs);
2355 } else if (clashing) {
2356 LOG (g, "gate before clashing on %d", clashing);
2357 g->rhs.resize (2);
2358 g->rhs[0] = clashing;
2359 g->rhs[1] = -clashing;
2360 g->hash = hash_lits (nonces, g->rhs);
2361 LOG (g, "gate after clashing on %d", clashing);
2362 }
2363 g->shrunken = true;
2364}
2365
2367 Gate *g, int src, LRAT_ID id1, LRAT_ID id2, int dst,
2368 std::vector<LRAT_ID> &extra_reasons_lit,
2369 std::vector<LRAT_ID> &extra_reasons_ulit) {
2370 LOG ("generate chain for gate boiling down to unit");
2371 if (g->neg_lhs_ids.size () != 1) {
2372
2374 // can happen for 4 = AND 3 4 (degenerated with only the clause -4 3)
2375 // with a rewriting 4 -> 1 (unchanged clause)
2376 // and later 1 -> 3 (unchanged clause)
2377 // but you do not know anymore from the gate that it is degenerated
2378 CADICAL_assert (g->pos_lhs_ids.size () == 1);
2380 extra_reasons_ulit, true, Rewrite ());
2381 return;
2382 }
2383 CADICAL_assert (g->lhs == g->rhs[0] || (g->lhs == src && g->rhs[0] == dst));
2384 CADICAL_assert (g->pos_lhs_ids.size () <= 1); // either degenerated or empty A = A
2385 return;
2386 }
2387 CADICAL_assert (g->neg_lhs_ids.size () == 1);
2388 CADICAL_assert (!g->pos_lhs_ids.empty ());
2389
2390 const int repr_lit = find_representative (g->lhs);
2391 const int repr_other = find_representative (g->rhs[0]);
2392 if (repr_lit == repr_other) {
2393 LOG ("skipping already merged");
2394 return;
2395 }
2396
2398 extra_reasons_ulit, true, Rewrite (),
2399 g->lhs, -dst);
2400 LOG (extra_reasons_ulit, "lrat chain for negative side");
2401
2402 lrat_chain.clear ();
2403
2404 CADICAL_assert (!g->pos_lhs_ids.empty ());
2405 for (auto litId : g->pos_lhs_ids)
2407 litId.clause, Rewrite (src, dst, id1, id2), extra_reasons_lit, true,
2408 Rewrite (), -g->lhs, dst);
2409 LOG (extra_reasons_lit, "lrat chain for positive side");
2410}
2411
2413 Gate *g, Gate *h, std::vector<LRAT_ID> &extra_reasons_lit,
2414 std::vector<LRAT_ID> &extra_reasons_ulit, bool remove_units) {
2415 CADICAL_assert (g != h);
2416 LOG (g, "merging");
2417 LOG (h, "with");
2418 // If the LHS are identical, do not even attempt to build the LRAT chain
2420 return;
2421 // set to same value, don't do anything
2422 if (internal->val (g->lhs) && internal->val (g->lhs) == internal->val (h->lhs))
2423 return;
2424 const bool g_tautology = gate_contains (g, g->lhs);
2425 const bool h_tautology = gate_contains (h, h->lhs);
2426 if (g_tautology && h_tautology) {
2427 LOG ("both gates are a tautology");
2428 // special case: actually we have an equivalence due to binary clauses
2429 // and all gate clauses (except one binary) are actually tautologies
2430 for (auto &litId : g->pos_lhs_ids) {
2431 if (litId.current_lit == h->lhs) {
2432 CADICAL_assert (extra_reasons_lit.empty ());
2433 LOG (litId.clause, "binary clause to push into the reason");
2434 litId.clause = produce_rewritten_clause_lrat (litId.clause, g->lhs,
2435 remove_units);
2436 CADICAL_assert (litId.clause);
2437 extra_reasons_lit.push_back (litId.clause->id);
2438 }
2439 }
2440 CADICAL_assert (!extra_reasons_lit.empty ());
2441 CADICAL_assert (extra_reasons_lit.size () == 1);
2442
2443 for (auto &litId : h->pos_lhs_ids) {
2444 if (litId.current_lit == g->lhs) {
2445 CADICAL_assert (extra_reasons_ulit.empty ());
2446 CADICAL_assert (litId.clause);
2447 LOG (litId.clause, "binary clause to push into the reason");
2448 litId.clause = produce_rewritten_clause_lrat (litId.clause, h->lhs,
2449 remove_units);
2450 CADICAL_assert (litId.clause);
2451 extra_reasons_ulit.push_back (litId.clause->id);
2452 }
2453 }
2454 CADICAL_assert (!extra_reasons_ulit.empty ());
2455 CADICAL_assert (extra_reasons_ulit.size () == 1);
2456 return;
2457 }
2458 if (g_tautology || h_tautology) {
2459 // special case: actually we have an equivalence due to binary clauses
2460 // and some of the clauses from the gate are actually tautologies
2461 CADICAL_assert (g_tautology != h_tautology);
2462 Gate *tauto = (g_tautology ? g : h);
2463 Gate *other = (g_tautology ? h : g);
2464 LOG (tauto, "one gate is a tautology");
2465 CADICAL_assert (tauto != other);
2466 CADICAL_assert (tauto == h || tauto == g);
2467
2468 auto &extra_reasons_tauto =
2469 (!g_tautology ? extra_reasons_lit : extra_reasons_ulit);
2470 auto &extra_reasons_other =
2471 (!g_tautology ? extra_reasons_ulit : extra_reasons_lit);
2472
2473 // one direction: the binary clause already exists
2474 for (auto &litId : other->pos_lhs_ids) {
2475 if (litId.current_lit == tauto->lhs) {
2476 CADICAL_assert (litId.clause);
2477 CADICAL_assert (extra_reasons_tauto.empty ());
2478 LOG (litId.clause, "binary clause to push into the reason");
2479 litId.clause = produce_rewritten_clause_lrat (
2480 litId.clause, other->lhs, remove_units);
2481 CADICAL_assert (litId.clause);
2482 extra_reasons_tauto.push_back (litId.clause->id);
2483 }
2484 }
2485 CADICAL_assert (!extra_reasons_tauto.empty ());
2486
2487 // other direction, we have to resolve
2488 LOG (tauto, "now the other direction");
2489 for (auto &litId : tauto->pos_lhs_ids) {
2490 CADICAL_assert (litId.clause);
2491 LOG (litId.clause,
2492 "binary clause from %d to push into the reason [avoiding %d]",
2493 litId.current_lit, tauto->lhs);
2494 if (litId.current_lit != tauto->lhs) {
2495 LOG (litId.clause, "binary clause to push into the reason");
2496 CADICAL_assert (litId.clause);
2497 litId.clause = produce_rewritten_clause_lrat (
2498 litId.clause, tauto->lhs, remove_units);
2499 if (!litId.clause) // degenerated but does not know yet
2500 continue;
2501 CADICAL_assert (litId.clause);
2502 extra_reasons_other.push_back (litId.clause->id);
2503 }
2504 tauto->pos_lhs_ids.erase (std::remove_if (begin (tauto->pos_lhs_ids),
2505 end (tauto->pos_lhs_ids),
2506 [] (const LitClausePair &p) {
2507 return !p.clause;
2508 }),
2509 end (tauto->pos_lhs_ids));
2510 }
2511 CADICAL_assert (!extra_reasons_other.empty ());
2513 remove_units);
2514 push_id_on_chain (extra_reasons_other, other->neg_lhs_ids);
2515 CADICAL_assert (!extra_reasons_tauto.empty ());
2516 CADICAL_assert (!extra_reasons_other.empty ());
2517 return;
2518 }
2519 // default: resolve all clauses
2520 // first rewrite
2521 // TODO: do we really need dest as second exclusion?
2523 remove_units);
2524 CADICAL_assert (internal->clause.empty ());
2526 remove_units);
2527 CADICAL_assert (internal->clause.empty ());
2529 remove_units);
2530 CADICAL_assert (internal->clause.empty ());
2532 remove_units);
2533 CADICAL_assert (internal->clause.empty ());
2534
2535 push_id_on_chain (extra_reasons_ulit, h->pos_lhs_ids);
2536 push_id_on_chain (extra_reasons_ulit, g->neg_lhs_ids[0].clause);
2537 lrat_chain.clear ();
2538 LOG (extra_reasons_ulit, "lrat chain for negative side");
2539
2540 push_id_on_chain (extra_reasons_lit, g->pos_lhs_ids);
2541 push_id_on_chain (extra_reasons_lit, h->neg_lhs_ids);
2542
2543 lrat_chain.clear ();
2544 LOG (extra_reasons_lit, "lrat chain for positive side");
2545 CADICAL_assert (!extra_reasons_lit.empty ());
2546 CADICAL_assert (!extra_reasons_ulit.empty ());
2547}
2548
2549void Closure::update_and_gate (Gate *g, GatesTable::iterator it, int src,
2550 int dst, LRAT_ID id1, LRAT_ID id2,
2551 int falsifies, int clashing) {
2552 LOG (g, "update and gate of arity %ld", g->arity ());
2553 CADICAL_assert (lrat_chain.empty ());
2554 bool garbage = true;
2555 if (falsifies || clashing) {
2556 if (internal->lrat)
2557 learn_congruence_unit_falsifies_lrat_chain (g, src, dst, clashing,
2558 falsifies, 0);
2559 int unit = -g->lhs;
2560 if (unit == src)
2561 unit = dst;
2562 else if (unit == -src)
2563 unit = -dst;
2564 learn_congruence_unit (unit);
2565 if (internal->lrat)
2566 lrat_chain.clear ();
2567 } else if (g->arity () == 1) {
2568 const signed char v = internal->val (g->lhs);
2569 if (v > 0) {
2570 if (internal->lrat)
2572 g->lhs);
2573 learn_congruence_unit (g->rhs[0]);
2574 if (internal->lrat)
2575 lrat_chain.clear ();
2576 } else if (v < 0) {
2577 if (internal->lrat)
2578 learn_congruence_unit_when_lhs_set (g, src, id1, id2, dst);
2579 learn_congruence_unit (-g->rhs[0]);
2580 if (internal->lrat)
2581 lrat_chain.clear ();
2582 } else {
2583 std::vector<LRAT_ID> extra_reasons_lit;
2584 std::vector<LRAT_ID> extra_reasons_ulit;
2585 if (internal->lrat)
2586 update_and_gate_unit_build_lrat_chain (g, src, id1, id2, g->rhs[0],
2587 extra_reasons_lit,
2588 extra_reasons_ulit);
2589 if (merge_literals_lrat (g, g, g->lhs, g->rhs[0], extra_reasons_lit,
2590 extra_reasons_ulit)) {
2591 ++internal->stats.congruence.unaries;
2592 ++internal->stats.congruence.unary_and;
2593 }
2594 }
2595 } else {
2596 CADICAL_assert (g->arity () > 1);
2598 Gate *h = find_and_lits (g->rhs, g);
2599 CADICAL_assert (g != h);
2600 if (h) {
2602 std::vector<LRAT_ID> extra_reasons_lit2;
2603 std::vector<LRAT_ID> extra_reasons_ulit2;
2604 if (internal->lrat)
2605 update_and_gate_build_lrat_chain (g, h, extra_reasons_lit2,
2606 extra_reasons_ulit2);
2607 if (merge_literals_lrat (g, h, g->lhs, h->lhs, extra_reasons_lit2,
2608 extra_reasons_ulit2))
2609 ++internal->stats.congruence.ands;
2610 } else {
2611 if (g->indexed) {
2612 LOG (g, "removing from table");
2613 (void) table.erase (it);
2614 }
2615 g->hash = hash_lits (nonces, g->rhs);
2616 LOG (g, "inserting gate into table");
2617 CADICAL_assert (table.count (g) == 0);
2618 table.insert (g);
2619 g->indexed = true;
2620 garbage = false;
2621 if (internal->lrat)
2622 lrat_chain.clear ();
2623 }
2624 }
2625
2626 if (garbage && !internal->unsat)
2627 mark_garbage (g);
2628}
2629
2630void Closure::update_xor_gate (Gate *g, GatesTable::iterator git) {
2632 CADICAL_assert (!internal->unsat && chain.empty ());
2633 LOG (g, "updating");
2634 bool garbage = true;
2635 // TODO Florian LRAT for learn_congruence_unit
2636 CADICAL_assert (g->arity () == 0 || internal->clause.empty ());
2637 CADICAL_assert (clause.empty ());
2638 if (g->arity () == 0) {
2639 if (internal->clause.size ()) {
2640 CADICAL_assert (!internal->proof || (internal->clause.size () == 1 &&
2641 internal->clause.back () == -g->lhs));
2642 CADICAL_assert (!internal->lrat || lrat_chain.size ());
2643 internal->clause.clear ();
2644
2645 } else if (internal->lrat) {
2647 CADICAL_assert (clause.size () && clause.back () == -g->lhs);
2648 clause.clear ();
2649 }
2650
2651 if (internal->lrat && internal->val (-g->lhs) < 0) {
2652 internal->lrat_chain.push_back (internal->unit_id (g->lhs));
2653 for (auto id : lrat_chain)
2654 internal->lrat_chain.push_back (id);
2655 lrat_chain.clear ();
2656 internal->learn_empty_clause();
2657 } else
2659
2660 CADICAL_assert (clause.empty ());
2661 } else if (g->arity () == 1) {
2662 std::vector<LRAT_ID> reasons_implication, reasons_back;
2663 if (internal->lrat) {
2666 g->pos_lhs_ids = first;
2667 CADICAL_assert (g->pos_lhs_ids.size () == 2);
2668 reasons_implication.push_back (g->pos_lhs_ids[0].clause->id);
2669 reasons_back.push_back (g->pos_lhs_ids[1].clause->id);
2670 }
2671 const signed char v = internal->val (g->lhs);
2672 if (v > 0) {
2673 if (internal->lrat) {
2674 push_lrat_unit (g->lhs);
2675 lrat_chain.push_back (g->pos_lhs_ids[0].clause->id);
2676 }
2677 learn_congruence_unit (g->rhs[0]);
2678 } else if (v < 0) {
2679 if (internal->lrat) {
2680 push_lrat_unit (-g->lhs);
2681 lrat_chain.push_back (g->pos_lhs_ids[1].clause->id);
2682 }
2683 learn_congruence_unit (-g->rhs[0]);
2684 } else if (merge_literals_lrat (
2685 g->lhs, g->rhs[0], reasons_implication,
2686 reasons_back)) { // TODO Florian merge with LRAT
2687 ++internal->stats.congruence.unaries;
2688 ++internal->stats.congruence.unary_and;
2689 }
2690 CADICAL_assert (clause.empty ());
2691 } else {
2692 Gate *h = find_xor_gate (g);
2693 if (h) {
2695 std::vector<LRAT_ID> reasons_implication, reasons_back;
2697 reasons_implication, reasons_back);
2698 if (merge_literals_lrat (g->lhs, h->lhs, reasons_implication,
2699 reasons_back))
2700 ++internal->stats.congruence.xors;
2702 } else {
2703 if (g->indexed) {
2704 remove_gate (git);
2705 }
2706 g->hash = hash_lits (nonces, g->rhs);
2707 LOG (g, "reinserting in table");
2708 table.insert (g);
2709 g->indexed = true;
2710 CADICAL_assert (table.find (g) != end (table));
2711 garbage = false;
2712 }
2713 CADICAL_assert (clause.empty ());
2714 }
2715 if (garbage && !internal->unsat)
2716 mark_garbage (g);
2717 CADICAL_assert (clause.empty ());
2718}
2719
2721 if (skip_and_gate (g))
2722 return;
2723 GatesTable::iterator git = (g->indexed ? table.find (g) : end (table));
2724 CADICAL_assert (!g->indexed || git != end (table));
2725 LOG (g, "simplifying");
2726 int falsifies = 0;
2727 std::vector<int>::iterator it = begin (g->rhs);
2728 bool ulhs_in_rhs = false;
2729 for (auto lit : g->rhs) {
2730 const signed char v = internal->val (lit);
2731 if (v > 0) {
2732 continue;
2733 }
2734 if (v < 0) {
2735 falsifies = lit;
2736 continue;
2737 }
2738 if (lit == -g->lhs)
2739 ulhs_in_rhs = true;
2740 *it++ = lit;
2741 if (lit == g->lhs)
2742 g->degenerated_and_pos = true;
2743 if (lit == -g->lhs)
2744 g->degenerated_and_neg = true;
2745 }
2746
2747 if (internal->lrat) { // updating reasons
2748 size_t i = 0, size = g->pos_lhs_ids.size ();
2749 for (size_t j = 0; j < size; ++j) {
2750 LOG ("looking at %d [%ld %ld]", g->pos_lhs_ids[j].current_lit, i, j);
2751 g->pos_lhs_ids[i] = g->pos_lhs_ids[j];
2752 if (!g->degenerated_and_pos &&
2753 internal->val (g->pos_lhs_ids[i].current_lit) &&
2754 g->pos_lhs_ids[i].current_lit != falsifies)
2755 continue;
2756 LOG ("keeping %d [%ld %ld]", g->pos_lhs_ids[i].current_lit, i, j);
2757 ++i;
2758 }
2759 LOG ("resizing to %ld", i);
2760 g->pos_lhs_ids.resize (i);
2761 }
2762
2763 CADICAL_assert (it <= end (g->rhs)); // can be equal when ITE are converted to
2764 // ands leading to
2765 CADICAL_assert (it >= begin (g->rhs));
2766 LOG (g, "shrunken");
2767
2768 g->shrunken = true;
2769 g->rhs.resize (it - std::begin (g->rhs));
2770 g->hash = hash_lits (nonces, g->rhs);
2771
2772 LOG (g, "shrunken");
2773 shrink_and_gate (g, falsifies);
2774 std::vector<LRAT_ID> reasons_lrat_src, reasons_lrat_usrc;
2775
2776 update_and_gate (g, git, 0, 0, 0, 0, falsifies, 0);
2777 ++internal->stats.congruence.simplified_ands;
2778 ++internal->stats.congruence.simplified;
2779
2780 if (ulhs_in_rhs) { // missing in Kissat, TODO: port back
2781 CADICAL_assert (gate_contains (g, -g->lhs));
2782 if (internal->lrat) {
2783 for (auto litId : g->pos_lhs_ids) {
2784 if (litId.current_lit == g->lhs) {
2785 compute_rewritten_clause_lrat_simple (litId.clause, 0);
2786 break;
2787 }
2788 }
2789 }
2791 }
2792}
2793
2795 switch (g->tag) {
2798 break;
2801 break;
2804 break;
2805 default:
2806 CADICAL_assert (false);
2807 break;
2808 }
2809 CADICAL_assert (lrat_chain.empty ());
2810 return !internal->unsat;
2811}
2812
2814 const auto &occs = goccs (lit);
2815 for (Gate *g : occs) {
2816 CADICAL_assert (lrat_chain.empty ());
2817 CADICAL_assert (clause.empty ());
2818 if (!simplify_gate (g))
2819 return false;
2820 }
2821 return true;
2822}
2823/*------------------------------------------------------------------------*/
2824// AND gates
2825
2827 CADICAL_assert (is_sorted (begin (rhs), end (rhs),
2829 return find_gate_lits (rhs, Gate_Type::And_Gate, except);
2830}
2831
2832// search for the gate in the hash-table. We cannot use find, as we might
2833// be changing a gate, so there might be 2 gates with the same LHS (the one
2834// we are changing and the other we are looking for)
2836 Gate *except) {
2837 Gate *g = new Gate;
2838 g->tag = typ;
2839 g->rhs = rhs;
2840 g->hash = hash_lits (nonces, g->rhs);
2841 g->lhs = 0;
2842 g->garbage = false;
2843#ifdef LOGGING
2844 g->id = 0;
2845#endif
2846 const auto &its = table.equal_range (g);
2847 Gate *h = nullptr;
2848 for (auto it = its.first; it != its.second; ++it) {
2849 LOG ((*it), "checking gate in the table");
2850 if (*it == except)
2851 continue;
2852 CADICAL_assert ((*it)->lhs != g->lhs);
2853 if ((*it)->tag != g->tag)
2854 continue;
2855 if ((*it)->rhs != g->rhs)
2856 continue;
2857 h = *it;
2858 break;
2859 }
2860
2861 if (h) {
2862 LOG (g, "searching");
2863 LOG (h, "already existing");
2864 delete g;
2865 return h;
2866 }
2867
2868 else {
2869 LOG (g->rhs, "gate not found in table");
2870 delete g;
2871 return nullptr;
2872 }
2873}
2874
2875Gate *Closure::new_and_gate (Clause *base_clause, int lhs) {
2876 rhs.clear ();
2877 auto &lits = this->lits;
2878
2879 for (auto lit : lits) {
2880 if (lhs != lit) {
2881 CADICAL_assert (lhs != -lit);
2882 rhs.push_back (-lit);
2883 }
2884 }
2885
2886 CADICAL_assert (rhs.size () + 1 == lits.size ());
2887 sort_literals_by_var (this->rhs);
2888
2889 Gate *h = find_and_lits (this->rhs);
2890 Gate *g = new Gate;
2891 g->lhs = lhs;
2893 if (internal->lrat) {
2894 g->neg_lhs_ids.push_back (LitClausePair (lhs, base_clause));
2895 for (auto i : lrat_chain_and_gate)
2896 g->pos_lhs_ids.push_back (i);
2897#ifdef LOGGING
2898 std::vector<LRAT_ID> result;
2899 transform (begin (g->pos_lhs_ids), end (g->pos_lhs_ids),
2900 back_inserter (result),
2901 [] (const LitClausePair &x) { return x.clause->id; });
2902 LOG (result, "lrat chain positive (%d):", lhs);
2903 result.clear ();
2904 transform (begin (g->neg_lhs_ids), end (g->neg_lhs_ids),
2905 back_inserter (result),
2906 [] (const LitClausePair &x) { return x.clause->id; });
2907 LOG (result, "lrat chain negative (%d):", lhs);
2908#endif
2909 }
2910
2911 if (internal->lrat)
2912 lrat_chain_and_gate.clear ();
2913
2914 if (h) {
2915 std::vector<LRAT_ID> reasons_lrat_src, reasons_lrat_usrc;
2916 if (internal->lrat)
2917 merge_and_gate_lrat_produce_lrat (g, h, reasons_lrat_src,
2918 reasons_lrat_usrc);
2919 if (merge_literals_lrat (g, h, lhs, h->lhs, reasons_lrat_src,
2920 reasons_lrat_usrc)) {
2921 LOG ("found merged literals");
2922 ++internal->stats.congruence.ands;
2923 }
2924 return nullptr;
2925 } else {
2926 g->rhs = {rhs};
2927 CADICAL_assert (!internal->lrat ||
2928 g->pos_lhs_ids.size () ==
2929 g->arity ()); // otherwise we need intermediate clauses
2930 g->garbage = false;
2931 g->indexed = true;
2932 g->shrunken = false;
2933 g->hash = hash_lits (nonces, g->rhs);
2934
2935 table.insert (g);
2936 ++internal->stats.congruence.gates;
2937#ifdef LOGGING
2938 g->id = fresh_id++;
2939#endif
2940 LOG (g, "creating new");
2941 for (auto lit : g->rhs) {
2942 connect_goccs (g, lit);
2943 }
2944 }
2945 return g;
2946}
2947
2948Gate *Closure::find_first_and_gate (Clause *base_clause, int lhs) {
2949 CADICAL_assert (internal->analyzed.empty ());
2950 const int not_lhs = -lhs;
2951 LOG ("trying to find AND gate with first LHS %d", (lhs));
2952 LOG ("negated LHS %d occurs in %zd binary clauses", (not_lhs),
2953 internal->occs (not_lhs).size ());
2954 unsigned matched = 0;
2955
2956 const size_t arity = lits.size () - 1;
2957
2958 for (auto w : internal->watches (not_lhs)) {
2959 LOG (w.clause, "checking clause for candidates");
2960 CADICAL_assert (w.binary ());
2961 CADICAL_assert (w.clause->size == 2);
2962 CADICAL_assert (w.clause->literals[0] == -lhs || w.clause->literals[1] == -lhs);
2963 const int other = w.blit;
2964 signed char &mark = marked (other);
2965 if (mark) {
2966 LOG ("marking %d mu2", other);
2967 ++matched;
2968 CADICAL_assert (~(mark & 2));
2969 mark |= 2;
2970 internal->analyzed.push_back (other);
2971 set_mu2_reason (other, w.clause);
2972 if (internal->lrat)
2973 lrat_chain_and_gate.push_back (LitClausePair (other, w.clause));
2974 }
2975 }
2976
2977 LOG ("found %zd initial LHS candidates", internal->analyzed.size ());
2978 if (matched < arity) {
2979 if (internal->lrat)
2980 lrat_chain_and_gate.clear ();
2981 return nullptr;
2982 }
2983
2984 Gate *g = new_and_gate (base_clause, lhs);
2985
2986 if (internal->lrat) {
2987 lrat_chain_and_gate.clear ();
2988 }
2989 return g;
2990}
2991
2993 Clause *eq1;
2994 if (internal->lrat) {
2995 eq1 = add_tmp_binary_clause (a, b);
2997 } else
2998 eq1 = maybe_add_binary_clause (a, b);
2999 return eq1;
3000}
3001
3003 CADICAL_assert (internal->clause.empty ());
3004 CADICAL_assert (internal->lrat_chain.empty ());
3005 CADICAL_assert (!internal->lrat);
3006 CADICAL_assert (lrat_chain.empty ());
3007 LOG ("learning binary clause %d %d", a, b);
3008 if (internal->unsat)
3009 return nullptr;
3010 if (a == -b)
3011 return nullptr;
3012 if (!internal->lrat) {
3013 const signed char a_value = internal->val (a);
3014 if (a_value > 0)
3015 return nullptr;
3016 const signed char b_value = internal->val (b);
3017 if (b_value > 0)
3018 return nullptr;
3019 int unit = 0;
3020 if (a == b)
3021 unit = a;
3022 else if (a_value < 0 && !b_value) {
3023 unit = b;
3024 } else if (!a_value && b_value < 0)
3025 unit = a;
3026 if (unit) {
3027 LOG ("clause reduced to unit %d", unit);
3028 learn_congruence_unit (unit);
3029 return nullptr;
3030 }
3031 CADICAL_assert (!a_value), CADICAL_assert (!b_value);
3032 }
3033 return add_binary_clause (a, b);
3034}
3035
3037 CADICAL_assert (internal->clause.empty ());
3038 internal->clause.push_back (a);
3039 internal->clause.push_back (b);
3040 if (internal->lrat) {
3041 CADICAL_assert (lrat_chain.size () >= 1);
3042 CADICAL_assert (internal->lrat_chain.empty ());
3043 swap (internal->lrat_chain, lrat_chain);
3044 }
3045 LOG (internal->lrat_chain, "chain");
3046 Clause *res = internal->new_hyper_ternary_resolved_clause_and_watch (
3047 false, full_watching);
3048 const bool already_sorted = internal->vlit (a) < internal->vlit (b);
3049 binaries.push_back (CompactBinary (res, res->id, already_sorted ? a : b,
3050 already_sorted ? b : a));
3051 if (!full_watching)
3052 new_unwatched_binary_clauses.push_back (res);
3053 LOG (res, "learning clause");
3054 internal->clause.clear ();
3055 if (internal->lrat) {
3056 internal->lrat_chain.clear ();
3057 }
3058 CADICAL_assert (internal->clause.empty ());
3059 CADICAL_assert (internal->lrat_chain.empty ());
3060 return res;
3061}
3062
3064#ifndef CADICAL_NDEBUG
3065 CADICAL_assert (internal->lrat);
3066 CADICAL_assert (internal->lrat_chain.empty ());
3067 CADICAL_assert (c->size == 2);
3068 if (internal->val (c->literals[0]) || internal->val (c->literals[1]))
3069 return;
3070 CADICAL_assert (std::find (begin (extra_clauses), end (extra_clauses), c) ==
3071 end (extra_clauses));
3072#else
3073 (void) c;
3074#endif
3075};
3076
3078 CADICAL_assert (internal->lrat);
3079 CADICAL_assert (internal->lrat_chain.empty ());
3080 CADICAL_assert (c->size == 2);
3081 LOG (c, "promoting tmp");
3082#ifndef CADICAL_NDEBUG
3083 CADICAL_assert (std::find (begin (extra_clauses), end (extra_clauses), c) !=
3084 end (extra_clauses));
3085#endif
3086 if (internal->val (c->literals[0]) || internal->val (c->literals[1]))
3087 return c;
3088 lrat_chain.push_back (c->id);
3089 Clause *res = add_binary_clause (c->literals[0], c->literals[1]);
3090 LOG (res, "promoted to");
3091 return res;
3092};
3093
3095 CADICAL_assert (internal->clause.empty ());
3096 CADICAL_assert (internal->lrat_chain.empty ());
3097 CADICAL_assert (internal->lrat);
3098 LOG ("learning tmp binary clause %d %d", a, b);
3099 if (internal->unsat)
3100 return nullptr;
3101 if (a == -b)
3102 return nullptr;
3103 CADICAL_assert (internal->clause.empty ());
3104 internal->clause.push_back (a);
3105 internal->clause.push_back (b);
3106 if (internal->lrat) {
3107 CADICAL_assert (lrat_chain.size () >= 1);
3108 CADICAL_assert (internal->lrat_chain.empty ());
3109 }
3110 LOG (lrat_chain, "chain");
3111 Clause *res = new_tmp_clause (internal->clause);
3112 internal->clause.clear ();
3113 if (internal->lrat) {
3114 lrat_chain.clear ();
3115 }
3116 CADICAL_assert (internal->clause.empty ());
3117 CADICAL_assert (internal->lrat_chain.empty ());
3118 LOG (res, "promoted to");
3119 return res;
3120}
3121
3123 const int not_lhs = -lhs;
3124
3125 if (marked (not_lhs) < 2) {
3126 LOG ("skipping no-candidate LHS %d (%d)", lhs, marked (not_lhs));
3127 return nullptr;
3128 }
3129
3130 LOG ("trying to find AND gate with remaining LHS %d", (lhs));
3131 LOG ("negated LHS %d occurs times in %zd binary clauses", (not_lhs),
3132 internal->noccs (-lhs));
3133
3134 const size_t arity = lits.size () - 1;
3135 size_t matched = 0;
3136 CADICAL_assert (1 < arity);
3137
3138 for (auto w : internal->watches (not_lhs)) {
3139 CADICAL_assert (w.binary ());
3140#ifdef LOGGING
3141 Clause *c = w.clause;
3142 LOG (c, "checking");
3143 CADICAL_assert (c->size == 2);
3144 CADICAL_assert (c->literals[0] == not_lhs || c->literals[1] == not_lhs);
3145#endif
3146 const int other = w.blit;
3147 signed char &mark = marked (other);
3148 if (!mark)
3149 continue;
3150 ++matched;
3151 if (!(mark & 2)) {
3152 lrat_chain_and_gate.push_back (LitClausePair (other, w.clause));
3153 LOG ("pushing %d -> %zd", other, w.clause->id);
3154 continue;
3155 }
3156 LOG ("marking %d mu4", other);
3157 CADICAL_assert (!(mark & 4));
3158 mark |= 4;
3159 lrat_chain_and_gate.push_back (LitClausePair (other, w.clause));
3160 if (internal->lrat)
3161 set_mu4_reason (other, w.clause);
3162 }
3163
3164 {
3165 auto q = begin (internal->analyzed);
3166 CADICAL_assert (!internal->analyzed.empty ());
3167 CADICAL_assert (marked (not_lhs) == 3);
3168 for (auto lit : internal->analyzed) {
3169 signed char &mark = marked (lit);
3170 if (lit == not_lhs) {
3171 mark = 1;
3172 continue;
3173 }
3174
3175 CADICAL_assert ((mark & 3) == 3);
3176 if (mark & 4) {
3177 mark = 3;
3178 *q = lit;
3179 ++q;
3180 LOG ("keeping LHS candidate %d", -lit);
3181 } else {
3182 LOG ("dropping LHS candidate %d", -lit);
3183 mark = 1;
3184 }
3185 }
3186 CADICAL_assert (q != end (internal->analyzed));
3187 CADICAL_assert (marked (not_lhs) == 1);
3188 internal->analyzed.resize (q - begin (internal->analyzed));
3189 LOG ("after filtering %zu LHS candidate remain",
3190 internal->analyzed.size ());
3191 }
3192
3193 if (matched < arity) {
3194 if (internal->lrat)
3195 lrat_chain_and_gate.clear ();
3196 return nullptr;
3197 }
3198
3199 if (!internal->lrat)
3200 lrat_chain_and_gate.clear ();
3201 return new_and_gate (base_clause, lhs);
3202}
3203
3207 typedef uint64_t Type;
3209 uint64_t res = internal->noccs (-a);
3210 res <<= 32;
3211 res |= a;
3212 return res;
3213 }
3214};
3215
3224
3226 CADICAL_assert (!c->garbage);
3227 CADICAL_assert (lrat_chain.empty ());
3228 LOG (c, "extracting and gates with clause");
3229 unsigned size = 0;
3230 const unsigned arity_limit =
3231 min (internal->opts.congruenceandarity, MAX_ARITY);
3232 const unsigned size_limit = arity_limit + 1;
3233 size_t max_negbincount = 0;
3234 lits.clear ();
3235
3236 for (int lit : *c) {
3237 signed char v = internal->val (lit);
3238 if (v < 0) {
3239 // push_lrat_unit (-lit);
3240 continue;
3241 }
3242 if (v > 0) {
3243 CADICAL_assert (!internal->level);
3244 LOG (c, "found satisfied clause");
3245 internal->mark_garbage (c);
3246 if (internal->lrat)
3247 lrat_chain.clear ();
3248 return;
3249 }
3250 if (++size > size_limit) {
3251 LOG (c, "clause is actually too large, thus skipping");
3252 if (internal->lrat)
3253 lrat_chain.clear ();
3254 return;
3255 }
3256 const size_t count = internal->noccs (-lit);
3257 if (!count) {
3258 LOG (c,
3259 "%d negated does not occur in any binary clause, thus skipping",
3260 lit);
3261 if (internal->lrat)
3262 lrat_chain.clear ();
3263 return;
3264 }
3265
3266 if (count > max_negbincount)
3267 max_negbincount = count;
3268 lits.push_back (lit);
3269 }
3270
3271 if (size < 3) {
3272 LOG (c, "is actually too small, thus skipping");
3273 if (internal->lrat)
3274 lrat_chain.clear ();
3275 CADICAL_assert (lrat_chain.empty ());
3276 return;
3277 }
3278
3279 const size_t arity = size - 1;
3280 if (max_negbincount < arity) {
3281 LOG (c,
3282 "all literals have less than %lu negated occurrences"
3283 "thus skipping",
3284 arity);
3285 if (internal->lrat)
3286 lrat_chain.clear ();
3287 return;
3288 }
3289
3290 internal->analyzed.clear ();
3291 size_t reduced = 0;
3292 const size_t clause_size = lits.size ();
3293 for (size_t i = 0; i < clause_size; ++i) {
3294 const int lit = lits[i];
3295 const unsigned count = internal->noccs (-lit);
3296 marked (-lit) = 1;
3297 set_mu1_reason (-lit, c);
3298 if (count < arity) {
3299 if (reduced < i) {
3300 lits[i] = lits[reduced];
3301 lits[reduced++] = lit;
3302 } else if (reduced == i)
3303 ++reduced;
3304 }
3305 }
3306 const size_t reduced_size = clause_size - reduced;
3307 CADICAL_assert (reduced_size);
3308 LOG (c, "trying as base arity %lu AND gate", arity);
3309 CADICAL_assert (begin (lits) + reduced_size <= end (lits));
3310 MSORT (internal->opts.radixsortlim, begin (lits),
3311 begin (lits) + reduced_size,
3314 bool first = true;
3315 unsigned extracted = 0;
3316
3317 for (size_t i = 0; i < clause_size; ++i) {
3318 CADICAL_assert (lrat_chain.empty ());
3319 if (internal->unsat)
3320 break;
3321 if (c->garbage)
3322 break;
3323 const int lhs = lits[i];
3324 LOG ("trying LHS candidate literal %d with %ld negated occurrences",
3325 (lhs), internal->noccs (-lhs));
3326
3327 if (first) {
3328 first = false;
3329 CADICAL_assert (internal->analyzed.empty ());
3330 if (find_first_and_gate (c, lhs) != nullptr) {
3331 CADICAL_assert (lrat_chain.empty ());
3332 ++extracted;
3333 }
3334 } else if (internal->analyzed.empty ()) {
3335 LOG ("early abort AND gate search");
3336 break;
3337 } else if (find_remaining_and_gate (c, lhs)) {
3338 CADICAL_assert (lrat_chain.empty ());
3339 ++extracted;
3340 }
3341 }
3342
3343 unmark_all ();
3344 LOG (lits, "finish unmarking");
3345 for (auto lit : lits) {
3346 marked (-lit) = 0;
3347 }
3348 lrat_chain_and_gate.clear ();
3349 if (extracted)
3350 LOG (c, "extracted %u with arity %lu AND base", extracted, arity);
3351}
3352
3354 internal->clear_noccs ();
3355 internal->clear_watches ();
3356}
3357
3360 if (!internal->opts.congruenceand)
3361 return;
3362 START (extractands);
3363 marks.resize (internal->max_var * 2 + 3);
3365
3366 const size_t size = internal->clauses.size ();
3367 for (size_t i = 0; i < size && !internal->terminated_asynchronously ();
3368 ++i) { // we can learn new binary clauses, but no for loop
3369 CADICAL_assert (lrat_chain.empty ());
3370 Clause *c = internal->clauses[i];
3371 if (c->garbage)
3372 continue;
3373 if (c->size == 2)
3374 continue;
3375 if (c->hyper)
3376 continue;
3377 if (c->redundant)
3378 continue;
3380 CADICAL_assert (lrat_chain.empty ());
3381 }
3382
3384 STOP (extractands);
3385}
3386
3387/*------------------------------------------------------------------------*/
3388// XOR gates
3389
3391 CADICAL_assert (internal->vlit (lit) < gnew_largecounts.size ());
3392 return gnew_largecounts[internal->vlit (lit)];
3393}
3394
3395uint64_t &Closure::largecounts (int lit) {
3396 CADICAL_assert (internal->vlit (lit) < glargecounts.size ());
3397 return glargecounts[internal->vlit (lit)];
3398}
3399
3400bool parity_lits (const vector<int> &lits) {
3401 unsigned res = 0;
3402 for (auto lit : lits)
3403 res ^= (lit < 0);
3404 return res;
3405}
3406
3407void inc_lits (vector<int> &lits) {
3408 bool carry = true;
3409 for (size_t i = 0; i < lits.size () && carry; ++i) {
3410 int lit = lits[i];
3411 carry = (lit < 0);
3412 lits[i] = -lit;
3413 }
3414}
3415
3416void Closure::check_ternary (int a, int b, int c) {
3417 CADICAL_assert (internal->clause.empty ());
3418 if (internal->lrat)
3419 return;
3420 auto &clause = internal->clause;
3421 CADICAL_assert (clause.empty ());
3422 clause.push_back (a);
3423 clause.push_back (b);
3424 clause.push_back (c);
3425 internal->external->check_learned_clause ();
3426 if (internal->proof) {
3427 const LRAT_ID id = internal->clause_id++;
3428 internal->proof->add_derived_clause (id, false, clause, {});
3429 internal->proof->delete_clause (id, false, clause);
3430 }
3431
3432 clause.clear ();
3433}
3434
3436 CADICAL_assert (internal->clause.empty ());
3437 if (internal->lrat)
3438 return;
3439 auto &clause = internal->clause;
3440 CADICAL_assert (clause.empty ());
3441 clause.push_back (a);
3442 clause.push_back (b);
3443 check_implied ();
3444 clause.clear ();
3445}
3446
3448 if (internal->lrat)
3449 return;
3450 internal->external->check_learned_clause ();
3451}
3452
3454 CADICAL_assert (internal->clause.empty ());
3455 CADICAL_assert (clause.empty ());
3456 if (!internal->proof)
3457 return;
3458 LOG (g, "starting XOR shrinking proof chain");
3460 vector<LitClausePair> newclauses;
3461 if (internal->lrat) {
3463 pivot);
3464 gate_sort_lrat_reasons (first, pivot, g->lhs);
3465 }
3466
3467 auto &clause = internal->clause;
3468
3469 const int lhs = g->lhs;
3470 clause.push_back (-lhs);
3471 for (auto lit : g->rhs)
3472 clause.push_back (lit);
3473
3474 const bool parity = (lhs > 0);
3476 const size_t size = clause.size ();
3477 const unsigned end = 1u << (size - 1);
3478 CADICAL_assert (!internal->lrat || first.size () == 2 * end);
3479#ifdef LOGGING
3480 for (auto pair : first) {
3481 LOG (pair.clause, "key %d", pair.current_lit);
3482 }
3483#endif
3484 // TODO Florian adjust indices of first depending on order...
3485 //
3486 for (unsigned i = 0; i != end; ++i) {
3487 while (i && parity != parity_lits (clause))
3488 inc_lits (clause);
3489 LOG (clause, "xor shrinking clause");
3490 if (!internal->lrat) {
3491 clause.push_back (pivot);
3493 clause.pop_back ();
3494 clause.push_back (-pivot);
3496 clause.pop_back ();
3497 }
3498 if (internal->lrat) {
3499 CADICAL_assert (lrat_chain.empty ());
3500 lrat_chain.push_back (first[2 * i].clause->id);
3501 lrat_chain.push_back (first[2 * i + 1].clause->id);
3502 }
3503 if (clause.size () > 1) {
3504 if (internal->lrat) {
3506 newclauses.push_back (LitClausePair (0, c));
3507 lrat_chain.clear ();
3508 } else {
3510 }
3511 }
3512 if (clause.size () == 1)
3513 return;
3514 inc_lits (clause);
3515 }
3516 g->pos_lhs_ids.swap (newclauses);
3517
3518 clause.clear ();
3519}
3520
3522 CADICAL_assert (internal->clause.empty ());
3524 if (internal->lrat) {
3525 return;
3526 }
3527 const int lhs = g->lhs;
3528 LOG (g, "checking implied");
3529 auto &clause = internal->clause;
3530 CADICAL_assert (clause.empty ());
3531 for (auto other : g->rhs) {
3532 CADICAL_assert (other > 0);
3533 clause.push_back (other);
3534 }
3535 clause.push_back (-lhs);
3536 const unsigned arity = g->arity ();
3537 const unsigned end = 1u << arity;
3538 const bool parity = (lhs > 0);
3539
3540 for (unsigned i = 0; i != end; ++i) {
3541 while (i && parity_lits (clause) != parity)
3542 inc_lits (clause);
3543 internal->external->check_learned_clause ();
3544 if (internal->proof) {
3545 internal->proof->add_derived_clause (internal->clause_id, false,
3546 clause, {});
3547 internal->proof->delete_clause (internal->clause_id, false, clause);
3548 }
3549 inc_lits (clause);
3550 }
3551 clause.clear ();
3552}
3553
3559
3562 CADICAL_assert (is_sorted (begin (g->rhs), end (g->rhs),
3565}
3566
3568
3570 auto &rhs = g->rhs;
3571 CADICAL_assert (rhs.size () == 3);
3572 if (internal->lrat)
3574 LOG (rhs, "RHS = ");
3575 if (rhs[0] < 0) {
3576 rhs[0] = -rhs[0];
3577 std::swap (rhs[1], rhs[2]);
3578 if (internal->lrat) {
3579 CADICAL_assert (g->pos_lhs_ids.size () == 4);
3580 std::swap (g->pos_lhs_ids[0], g->pos_lhs_ids[2]);
3581 std::swap (g->pos_lhs_ids[1], g->pos_lhs_ids[3]);
3582 const int8_t flag = g->degenerated_ite;
3583 const int8_t plus_then = flag & NO_PLUS_THEN;
3584 const int8_t neg_then = flag & NO_NEG_THEN;
3585 const int8_t plus_else = flag & NO_PLUS_ELSE;
3586 const int8_t neg_else = flag & NO_NEG_ELSE;
3595 CADICAL_assert (g->pos_lhs_ids[0].current_lit == rhs[1]);
3596 CADICAL_assert (g->pos_lhs_ids[2].current_lit == rhs[2]);
3597 if (internal->lrat)
3599 }
3600 }
3601 if (rhs[1] > 0)
3602 return false;
3603 if (internal->lrat)
3605 rhs[1] = -rhs[1];
3606 rhs[2] = -rhs[2];
3607 LOG (rhs, "RHS = ");
3608 if (internal->lrat) {
3609 CADICAL_assert (g->pos_lhs_ids.size () == 4);
3610 std::swap (g->pos_lhs_ids[0], g->pos_lhs_ids[1]);
3611 std::swap (g->pos_lhs_ids[2], g->pos_lhs_ids[3]);
3612 const int8_t flag = g->degenerated_ite;
3613 const int8_t plus_then = flag & NO_PLUS_THEN;
3614 const int8_t neg_then = flag & NO_NEG_THEN;
3615 const int8_t plus_else = flag & NO_PLUS_ELSE;
3616 const int8_t neg_else = flag & NO_NEG_ELSE;
3625 CADICAL_assert (g->pos_lhs_ids[0].current_lit == rhs[1]);
3626 CADICAL_assert (g->pos_lhs_ids[2].current_lit == rhs[2]);
3627 // incorrect as we have not negated the LHS yet!
3628 // check_correct_ite_flags (g);
3629 }
3630
3631 LOG (g->rhs, "g/RHS = ");
3632 return true;
3633}
3634
3635#ifndef CADICAL_NDEBUG
3636bool is_tautological_ite_gate (Gate *g) {
3638 CADICAL_assert (g->rhs.size () == 3);
3639 const int cond_lit = g->rhs[0];
3640 const int then_lit = g->rhs[1];
3641 const int else_lit = g->rhs[2];
3642 return cond_lit == then_lit || cond_lit == else_lit;
3643}
3644#endif
3645
3646Gate *Closure::find_ite_gate (Gate *g, bool &negate_lhs) {
3647 negate_lhs = normalize_ite_lits_gate (g);
3648 LOG (g, "post normalize");
3649 return find_gate_lits (g->rhs, Gate_Type::ITE_Gate, g);
3650}
3651
3653 internal->external->check_learned_clause ();
3654 const LRAT_ID id = ++internal->clause_id;
3655 if (internal->proof) {
3656 if (internal->lrat) {
3657 CADICAL_assert (internal->lrat_chain.empty ());
3658 CADICAL_assert (lrat_chain.size () >= 1);
3659 }
3660 internal->proof->add_derived_clause (id, true, clause, lrat_chain);
3661 lrat_chain.clear ();
3662 }
3663 return id;
3664}
3665
3667 LRAT_ID id) {
3668 const uint32_t id2_higher = (id >> 32);
3669 const uint32_t id2_lower = (uint32_t) (id & (LRAT_ID) (uint32_t) (-1));
3670 CADICAL_assert (id == ((LRAT_ID) id2_higher << 32) + (LRAT_ID) id2_lower);
3671 chain.push_back (id2_higher);
3672 chain.push_back (id2_lower);
3673 LOG (unsimplified, "pushing to chain");
3674 chain.insert (end (chain), begin (unsimplified), end (unsimplified));
3675 chain.push_back (0);
3676}
3677
3679 LRAT_ID delete_id) {
3680 vector<int> &clause = internal->clause;
3681 CADICAL_assert (clause.empty ());
3682#ifndef CADICAL_NDEBUG
3683 for (auto lit : unsimplified) {
3684 CADICAL_assert (!(marked (lit) & 4));
3685 }
3686#endif
3687
3688 bool trivial = false;
3689 for (auto lit : unsimplified) {
3690 signed char &lit_mark = marked (lit);
3691 if (lit_mark & 4)
3692 continue;
3693 signed char &not_lit_mark = marked (-lit);
3694 if (not_lit_mark & 4) {
3695 trivial = true;
3696 break;
3697 }
3698 lit_mark |= 4;
3699 clause.push_back (lit);
3700 }
3701 for (auto lit : clause) {
3702 signed char &mark = marked (lit);
3703 CADICAL_assert (mark & 4);
3704 mark &= ~4u;
3705 }
3706
3707 LRAT_ID id = 0;
3708 if (!trivial) {
3709 if (delete_id) {
3710 if (internal->proof) {
3711 internal->proof->delete_clause (delete_id, true, clause);
3712 lrat_chain.clear ();
3713 }
3714 } else {
3717 }
3718 } else {
3719 LOG ("skipping trivial proof");
3720 lrat_chain.clear ();
3721 }
3722 clause.clear ();
3723 return id;
3724}
3725/*------------------------------------------------------------------------*/
3727 if (!internal->proof)
3728 return;
3729 if (internal->lrat)
3730 return;
3731 LOG ("starting ITE turned AND supporting binary clauses");
3732 CADICAL_assert (unsimplified.empty ());
3733 CADICAL_assert (chain.empty ());
3734 int not_lhs = -g->lhs;
3735 unsimplified.push_back (not_lhs);
3736 unsimplified.push_back (g->rhs[0]);
3738 unsimplified.pop_back ();
3739 unsimplified.push_back (g->rhs[1]);
3741 unsimplified.clear ();
3742}
3744 const vector<LitClausePair> &source, int lhs) {
3745 CADICAL_assert (internal->lrat);
3746 for (auto pair : source) {
3747 compute_rewritten_clause_lrat_simple (pair.clause, lhs);
3748 if (lrat_chain.size ())
3749 break;
3750 }
3751 CADICAL_assert (clause.size () == 1);
3752}
3754 const vector<LitClausePair> &source, vector<LitClausePair> &target,
3755 int lhs, int except2, bool flip) {
3756 CADICAL_assert (internal->lrat);
3757 for (auto pair : source) {
3758 Clause *c = produce_rewritten_clause_lrat (pair.clause, lhs);
3759 if (c) {
3760 target.push_back (LitClausePair (0, c));
3761 }
3762 }
3763 gate_sort_lrat_reasons (target, lhs, except2, flip);
3764}
3766 Gate *g, int lhs1, const vector<LitClausePair> &clauses2, int lhs2,
3767 vector<LRAT_ID> &to_lrat, vector<LRAT_ID> &back_lrat) {
3768 if (lhs1 == lhs2)
3769 return;
3770 if (!internal->proof)
3771 return;
3772 CADICAL_assert (unsimplified.empty ());
3773 unsimplified = g->rhs;
3775 vector<LitClausePair> second;
3776 if (internal->lrat) {
3778 simplify_and_sort_xor_lrat_clauses (clauses2, second, lhs2, 0, 1);
3779 g->pos_lhs_ids = first;
3780 }
3781 LOG ("starting XOR matching proof");
3782 // for lrat
3783 vector<LitIdPair> first_ids;
3784 vector<LitIdPair> second_ids;
3785 for (auto pair : first) {
3786 bool first = pair.current_lit & 1;
3787 int rest = pair.current_lit >> 1;
3788 rest &= ~(1 << (g->rhs.size () - 1));
3789 if (first == (lhs1 > 0)) {
3790 first_ids.push_back (LitIdPair (rest, pair.clause->id));
3791 } else {
3792 second_ids.push_back (LitIdPair (rest, pair.clause->id));
3793 }
3794 LOG (pair.clause, "key %d", pair.current_lit);
3795 }
3796 for (auto pair : second) {
3797 bool first = pair.current_lit & 1;
3798 int rest = pair.current_lit >> 1;
3799 rest &= ~(1 << (g->rhs.size () - 1));
3800 if (first == (lhs2 < 0)) {
3801 first_ids.push_back (LitIdPair (rest, pair.clause->id));
3802 } else {
3803 second_ids.push_back (LitIdPair (rest, pair.clause->id));
3804 }
3805 LOG (pair.clause, "key %d", pair.current_lit);
3806 }
3807 // TODO Florian: resort and ids after every round
3808 do {
3809 vector<LitIdPair> first_tmp;
3810 vector<LitIdPair> second_tmp;
3811 CADICAL_assert (!unsimplified.empty ());
3812 unsimplified.pop_back ();
3813 const size_t size = unsimplified.size ();
3814 CADICAL_assert (size < 32);
3815 const size_t off = 1u << size;
3816 for (size_t i = 0; i != off; ++i) {
3817 int32_t n = 0;
3818 if (internal->lrat) {
3820 CADICAL_assert (lrat_chain.empty ());
3821 for (auto pair : first_ids) {
3822 if (pair.lit == n)
3823 lrat_chain.push_back (pair.id);
3824 }
3825 CADICAL_assert (lrat_chain.size () == 2);
3826 }
3827 unsimplified.push_back (-lhs1);
3828 unsimplified.push_back (lhs2);
3830 unsimplified.resize (unsimplified.size () - 2);
3831 if (internal->lrat) {
3832 int32_t rest = n &= ~(1 << (unsimplified.size () - 1));
3833 first_tmp.push_back (LitIdPair (rest, id1));
3835 lrat_chain.clear ();
3836 for (auto pair : second_ids) {
3837 if (pair.lit == n)
3838 lrat_chain.push_back (pair.id);
3839 }
3840 CADICAL_assert (lrat_chain.size () == 2);
3841 }
3842 unsimplified.push_back (lhs1);
3843 unsimplified.push_back (-lhs2);
3845 unsimplified.resize (unsimplified.size () - 2);
3846 if (internal->lrat) {
3847 lrat_chain.clear ();
3848 int32_t rest = n &= ~(1 << (unsimplified.size () - 1));
3849 second_tmp.push_back (LitIdPair (rest, id2));
3850 }
3852 }
3853 if (internal->lrat) {
3854 first_ids.swap (first_tmp);
3855 second_ids.swap (second_tmp);
3856 }
3857 } while (!unsimplified.empty ());
3858 if (internal->lrat) {
3859 CADICAL_assert (first_ids.size () == 1);
3860 CADICAL_assert (second_ids.size () == 1);
3861 to_lrat.push_back (first_ids.back ().id);
3862 back_lrat.push_back (second_ids.back ().id);
3863 }
3864 CADICAL_assert (!internal->lrat || to_lrat.size () == 1);
3865 CADICAL_assert (!internal->lrat || back_lrat.size () == 1);
3866 LOG ("finished XOR matching proof");
3867 CADICAL_assert (unsimplified.empty ());
3868}
3869
3870// this function needs to either put the clauses from
3871// lrat_chain_and_gate into g->pos_neg_ids or clear it or do something with
3872// it if you merge gates.
3874 int lhs) {
3875 rhs.clear ();
3876
3877 for (auto lit : lits) {
3878 if (lhs != lit && -lhs != lit) {
3879 CADICAL_assert (lit > 0);
3880 rhs.push_back (lit);
3881 }
3882 }
3883 CADICAL_assert (rhs.size () + 1 == lits.size ());
3885 Gate *g = find_xor_lits (this->rhs);
3886 if (g) {
3888 std::vector<LRAT_ID> reasons_implication, reasons_back;
3889 add_xor_matching_proof_chain (g, g->lhs, glauses, lhs,
3890 reasons_implication, reasons_back);
3891 if (merge_literals_lrat (g->lhs, lhs, reasons_implication,
3892 reasons_back)) {
3893 ++internal->stats.congruence.xors;
3894 }
3896 CADICAL_assert (internal->unsat || chain.empty ());
3897 } else {
3898 g = new Gate;
3899 g->lhs = lhs;
3901 g->rhs = {rhs};
3902 g->garbage = false;
3903 g->indexed = true;
3904 g->shrunken = false;
3905 g->hash = hash_lits (nonces, g->rhs);
3906 for (auto pair : glauses)
3907 g->pos_lhs_ids.push_back (pair);
3908 table.insert (g);
3909 ++internal->stats.congruence.gates;
3910#ifdef LOGGING
3911 g->id = fresh_id++;
3912#endif
3913 LOG (g, "creating new");
3915 for (auto lit : g->rhs) {
3916 connect_goccs (g, lit);
3917 }
3918 }
3919 return g;
3920}
3923 uint32_t n = 0;
3924 CADICAL_assert (is_sorted (rhs.rbegin (), rhs.rend (),
3926 CADICAL_assert (rhs.size () <= 32);
3927 for (auto r = rhs.rbegin (); r != rhs.rend (); r++) {
3928 int lit = *r;
3929 n *= 2;
3930 n += !(lit > 0);
3931 }
3932 return n;
3933}
3934
3936 int lhs, int except, bool flip) {
3937 uint32_t n = 0;
3938 CADICAL_assert (is_sorted (
3939 begin (rhs), end (rhs),
3941 (void) lhs, (void) except;
3942 CADICAL_assert (rhs.size () <= 32);
3943 for (auto lit : rhs) {
3944 n *= 2;
3945 n += !(lit > 0) ^ flip;
3946 flip = 0;
3947 }
3948 return n;
3949}
3950
3951// this is how I planned to sort it and produce the number
3952// Look at this first
3954 int except2, bool flip) {
3955 CADICAL_assert (clause.empty ());
3956 std::copy (begin (*litId.clause), end (*litId.clause),
3957 back_inserter (clause));
3958 sort_literals_by_var_except (clause, lhs, except2);
3959 litId.current_lit = number_from_xor_reason (clause, lhs, except2, flip);
3960 clause.clear ();
3961}
3962
3964 typedef size_t Type;
3966};
3967
3968// this is how I planned to sort it and produce the number
3969// Look at this first
3970void Closure::gate_sort_lrat_reasons (std::vector<LitClausePair> &xs,
3971 int lhs, int except2, bool flip) {
3972 CADICAL_assert (clause.empty ());
3973 CADICAL_assert (!xs.empty ());
3974 for (auto &litId : xs) {
3975 gate_sort_lrat_reasons (litId, lhs, except2, flip);
3976 }
3977
3978 rsort (begin (xs), end (xs), smaller_pair_first_rank ());
3979
3980#ifndef CADICAL_NDEBUG
3981 std::for_each (begin (xs), end (xs), [&xs] (const LitClausePair &x) {
3982 CADICAL_assert (x.clause->size == xs[1].clause->size);
3983 });
3984#endif
3985}
3986
3987void Closure::init_xor_gate_extraction (std::vector<Clause *> &candidates) {
3988 const unsigned arity_limit = internal->opts.congruencexorarity;
3989 CADICAL_assert (arity_limit < 32); // we use unsigned int.
3990 const unsigned size_limit = arity_limit + 1;
3991 glargecounts.resize (2 * internal->vsize, 0);
3992
3993 for (auto c : internal->clauses) {
3994 LOG (c, "considering clause for XOR");
3995 if (c->redundant)
3996 continue;
3997 if (c->garbage)
3998 continue;
3999 if (c->size < 3)
4000 continue;
4001 unsigned size = 0;
4002 for (auto lit : *c) {
4003 const signed char v = internal->val (lit);
4004 if (v < 0)
4005 continue;
4006 if (v > 0) {
4007 LOG (c, "satisfied by %d", lit);
4008 internal->mark_garbage (c);
4009 goto CONTINUE_COUNTING_NEXT_CLAUSE;
4010 }
4011 if (size == size_limit)
4012 goto CONTINUE_COUNTING_NEXT_CLAUSE;
4013 ++size;
4014 }
4015
4016 if (size < 3)
4017 continue;
4018 for (auto lit : *c) {
4019 if (internal->val (lit))
4020 continue;
4021 ++largecounts (lit);
4022 }
4023
4024 LOG (c, "considering clause for XOR as candidate");
4025 candidates.push_back (c);
4026 CONTINUE_COUNTING_NEXT_CLAUSE:;
4027 }
4028
4029 LOG ("considering %zd out of %zd", candidates.size (),
4030 internal->irredundant ());
4031 const unsigned rounds = internal->opts.congruencexorcounts;
4032#ifdef LOGGING
4033 const size_t original_size = candidates.size ();
4034#endif
4035 LOG ("resizing glargecounts to size %zd", glargecounts.size ());
4036 for (unsigned round = 0; round < rounds; ++round) {
4037 LOG ("round %d of XOR extraction", round);
4038 size_t removed = 0;
4039 gnew_largecounts.resize (2 * internal->vsize);
4040 unsigned cand_size = candidates.size ();
4041 size_t j = 0;
4042 for (size_t i = 0; i < cand_size; ++i) {
4043 Clause *c = candidates[i];
4044 LOG (c, "considering");
4045 unsigned size = 0;
4046 for (auto lit : *c) {
4047 if (!internal->val (lit))
4048 ++size;
4049 }
4050 CADICAL_assert (3 <= size);
4051 CADICAL_assert (size <= size_limit);
4052 const unsigned arity = size - 1;
4053 const unsigned needed_clauses = 1u << (arity - 1);
4054 for (auto lit : *c) {
4055 if (largecounts (lit) < needed_clauses) {
4056 LOG (c, "not enough occurrences, so ignoring");
4057 removed++;
4058 goto CONTINUE_WITH_NEXT_CANDIDATE_CLAUSE;
4059 }
4060 }
4061 for (auto lit : *c)
4062 if (!internal->val (lit))
4063 new_largecounts (lit)++;
4064 candidates[j++] = candidates[i];
4065
4066 CONTINUE_WITH_NEXT_CANDIDATE_CLAUSE:;
4067 }
4068 candidates.resize (j);
4069 glargecounts = std::move (gnew_largecounts);
4070 gnew_largecounts.clear ();
4071 LOG ("moving counts %zd", glargecounts.size ());
4072 if (!removed)
4073 break;
4074
4075 LOG ("after round %d, %zd (%ld %%) remain", round, candidates.size (),
4076 candidates.size () / (1 + original_size) * 100);
4077 }
4078
4079 for (auto c : candidates) {
4080 for (auto lit : *c)
4081 internal->occs (lit).push_back (c);
4082 }
4083}
4084
4086 unsigned least_occurring_literal = 0;
4087 unsigned count_least_occurring = UINT_MAX;
4088 const size_t size_lits = lits.size ();
4089#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
4090 const unsigned arity = size_lits - 1;
4091#endif
4092#ifndef CADICAL_NDEBUG
4093 const unsigned count_limit = 1u << (arity - 1);
4094#endif
4095 LOG (lits, "trying to find arity %u XOR side clause", arity);
4096 for (auto lit : lits) {
4097 CADICAL_assert (!internal->val (lit));
4098 marked (lit) = 1;
4099 unsigned count = largecount (lit);
4100 CADICAL_assert (count_limit <= count);
4101 if (count >= count_least_occurring)
4102 continue;
4103 count_least_occurring = count;
4104 least_occurring_literal = lit;
4105 }
4106 Clause *res = 0;
4107 CADICAL_assert (least_occurring_literal);
4108 LOG ("searching XOR side clause watched by %d#%u",
4109 least_occurring_literal, count_least_occurring);
4110 LOG ("searching for size %ld", size_lits);
4111 for (auto c : internal->occs (least_occurring_literal)) {
4112 LOG (c, "checking");
4113 CADICAL_assert (c->size != 2); // TODO kissat has break
4114 if (c->garbage)
4115 continue;
4116 if ((size_t) c->size < size_lits)
4117 continue;
4118 size_t found = 0;
4119 for (auto other : *c) {
4120 const signed char value = internal->val (other);
4121 if (value < 0)
4122 continue;
4123 if (value > 0) {
4124 LOG (c, "found satisfied %d in", other);
4125 internal->mark_garbage (c);
4126 CADICAL_assert (c->garbage);
4127 break;
4128 }
4129 if (marked (other))
4130 found++;
4131 else {
4132 LOG ("not marked %d", other);
4133 found = 0;
4134 break;
4135 }
4136 }
4137 if (found == size_lits && !c->garbage) {
4138 res = c;
4139 break;
4140 } else {
4141 LOG ("too few literals");
4142 }
4143 }
4144 for (auto lit : lits)
4145 marked (lit) = 0;
4146 if (res)
4147 LOG (res, "found matching XOR side");
4148 else
4149 LOG ("no matching XOR side clause found");
4150 return res;
4151}
4152
4154 LOG (c, "checking clause");
4155 lits.clear ();
4156 int smallest = 0;
4157 int largest = 0;
4158 const unsigned arity_limit = internal->opts.congruencexorarity;
4159 const unsigned size_limit = arity_limit + 1;
4160 unsigned negated = 0, size = 0;
4161 bool first = true;
4162 for (auto lit : *c) {
4163 const signed char v = internal->val (lit);
4164 if (v < 0)
4165 continue;
4166 if (v > 0) {
4167 internal->mark_garbage (c);
4168 return;
4169 }
4170 if (size == size_limit) {
4171 LOG (c, "size limit reached");
4172 return;
4173 }
4174
4175 if (first) {
4176 largest = smallest = lit;
4177 first = false;
4178 } else {
4179 CADICAL_assert (smallest);
4180 CADICAL_assert (largest);
4181 if (internal->vlit (lit) < internal->vlit (smallest)) {
4182 LOG ("new smallest %d", lit);
4183 smallest = lit;
4184 }
4185 if (internal->vlit (lit) > internal->vlit (largest)) {
4186 if (largest < 0) {
4187 LOG (c, "not largest %d (largest: %d) occurs negated in XOR base",
4188 lit, largest);
4189 return;
4190 }
4191 largest = lit;
4192 }
4193 }
4194 if (lit < 0 && internal->vlit (lit) < internal->vlit (largest)) {
4195 LOG (c, "negated literal %d not largest in XOR base", lit);
4196 return;
4197 }
4198 if (lit < 0 && negated++) {
4199 LOG (c, "more than one negated literal in XOR base");
4200 return;
4201 }
4202 lits.push_back (lit);
4203 ++size;
4204 }
4205 CADICAL_assert (size == lits.size ());
4206 if (size < 3) {
4207 LOG (c, "short XOR base clause");
4208 return;
4209 }
4210
4211 LOG ("double checking if possible");
4212 const unsigned arity = size - 1;
4213 const unsigned needed_clauses = 1u << (arity - 1);
4214 for (auto lit : lits) {
4215 for (int sign = 0; sign != 2; ++sign, lit = -lit) {
4216 unsigned count = largecount (lit);
4217 if (count >= needed_clauses)
4218 continue;
4219 LOG (c,
4220 "literal %d in XOR base clause only occurs %u times in large "
4221 "clause thus skipping",
4222 lit, count);
4223 return;
4224 }
4225 }
4226
4227 LOG ("checking for XOR side clauses");
4228 CADICAL_assert (smallest && largest);
4229 const unsigned end = 1u << arity;
4230 CADICAL_assert (negated == parity_lits (lits));
4231 unsigned found = 0;
4232 vector<LitClausePair> glauses;
4233 glauses.push_back (LitClausePair (0, c));
4234 for (unsigned i = 0; i != end; ++i) {
4235 while (i && parity_lits (lits) != negated)
4236 inc_lits (lits);
4237 if (i) {
4238 // the clause must be stored
4239 // you can use `lrat_chain_and_gate` for this
4241 if (!d)
4242 return;
4244 glauses.push_back (LitClausePair (i, d));
4245 } else
4247 inc_lits (lits);
4248 ++found;
4249 }
4250
4251 while (parity_lits (lits) != negated)
4252 inc_lits (lits);
4253 LOG (lits, "found all needed %u matching clauses:", found);
4254 CADICAL_assert (found == 1u << arity);
4255 if (negated) {
4256 auto p = begin (lits);
4257 int lit;
4258 while ((lit = *p) > 0)
4259 p++;
4260 LOG ("flipping RHS literal %d", (lit));
4261 *p = -lit;
4262 }
4263 LOG (lits, "normalized negations");
4264 unsigned extracted = 0;
4265 for (auto lhs : lits) {
4266 if (!negated)
4267 lhs = -lhs;
4268 Gate *g = new_xor_gate (glauses, lhs);
4269 if (g)
4270 extracted++;
4271 if (internal->unsat)
4272 break;
4273 }
4274 if (!extracted)
4275 LOG ("no arity %u XOR gate extracted", arity);
4276}
4279 if (!internal->opts.congruencexor)
4280 return;
4281 START (extractxors);
4282 LOG ("starting extracting XOR");
4283 std::vector<Clause *> candidates = {};
4284 init_xor_gate_extraction (candidates);
4285 for (auto c : candidates) {
4286 if (internal->unsat)
4287 break;
4288 if (c->garbage)
4289 continue;
4291 }
4293 STOP (extractxors);
4294}
4295
4296/*------------------------------------------------------------------------*/
4298 size_t units = 0;
4299 for (auto v : internal->vars) {
4300 RESTART:
4301 if (!internal->flags (v).active ())
4302 continue;
4303 for (int sgn = -1; sgn < 1; sgn += 2) {
4304 int lit = v * sgn;
4305 for (auto w : internal->watches (lit)) {
4306 if (!w.binary ())
4307 continue; // todo check that binaries first
4308 const int other = w.blit;
4309 if (marked (-other)) {
4310 LOG (w.clause, "binary clause %d %d and %d %d give unit %d", lit,
4311 other, lit, -other, lit);
4312 ++units;
4313 if (internal->lrat) {
4314 lrat_chain.push_back (w.clause->id);
4315 lrat_chain.push_back (marked_mu1 (-other).clause->id);
4316 }
4317 bool failed = !learn_congruence_unit (lit);
4318 unmark_all ();
4319 if (failed)
4320 return;
4321 else
4322 goto RESTART;
4323 }
4324 if (marked (other))
4325 continue;
4326 marked (other) = 1;
4327 set_mu1_reason (other, w.clause);
4328 internal->analyzed.push_back (other);
4329 }
4330 unmark_all ();
4331 }
4332 CADICAL_assert (internal->analyzed.empty ());
4333 }
4334 LOG ("found %zd units", units);
4335}
4336
4338 CADICAL_assert (!internal->unsat);
4339
4340 for (auto v : internal->vars) {
4341 RESTART:
4342 if (!internal->flags (v).active ())
4343 continue;
4344 int lit = v;
4345 for (auto w : internal->watches (lit)) {
4346 if (!w.binary ())
4347 break;
4348 CADICAL_assert (w.size == 2);
4349 const int other = w.blit;
4350 if (internal->vlit (lit) > internal->vlit (other))
4351 continue;
4352 if (marked (other))
4353 continue;
4354 internal->analyzed.push_back (other);
4355 marked (other) = true;
4356 set_mu1_reason (other, w.clause);
4357 }
4358
4359 if (internal->analyzed.empty ())
4360 continue;
4361
4362 for (auto w : internal->watches (-lit)) {
4363 if (!w.binary ())
4364 break; // binary clauses are first
4365 const int other = w.blit;
4366 if (internal->vlit (-lit) > internal->vlit (other))
4367 continue;
4368 CADICAL_assert (-lit != other);
4369 LOG ("binary clause %d %d", -lit, other);
4370 if (marked (-other)) {
4371 int lit_repr = find_representative (lit);
4372 int other_repr = find_representative (other);
4373 LOG ("found equivalence %d %d with %d and %d as the representative",
4374 lit, other, lit_repr, other_repr);
4375 if (lit_repr != other_repr) {
4376 // if (internal->lrat) {
4377 // // This cannot work
4378 // // if you have 2 = 1 and 3=4
4379 // // you cannot add 2=3. You really to connect the
4380 // representatives directly
4381 // // therefore you actually need to learn the clauses 2->3->4
4382 // and -2->1 and vice-versa eager_representative_id (other) =
4383 // marked_mu1 (-other).clause->id; eager_representative_id
4384 // (-other) = w.clause->id; CADICAL_assert (eager_representative_id
4385 // (other) != -1); LOG ("lrat: %d (%zd) %d (%zd)", other,
4386 // eager_representative_id (other), -other,
4387 // eager_representative_id (-other));
4388 // }
4389 promote_clause (marked_mu1 (-other).clause);
4390 promote_clause (w.clause);
4391 LOG (w.clause, "merging");
4392 LOG (marked_mu1 (-other).clause, "with");
4394 lit, other,
4395 internal->lrat ? marked_mu1 (-other).clause : nullptr,
4396 w.clause)) {
4397 ++internal->stats.congruence.congruent;
4398 }
4399 unmark_all ();
4400 if (internal->unsat)
4401 return;
4402 else
4403 goto RESTART;
4404 }
4405 }
4406 }
4407 unmark_all ();
4408 }
4409 CADICAL_assert (internal->analyzed.empty ());
4410 LOG ("found %zd equivalences", schedule.size ());
4411}
4412
4413/*------------------------------------------------------------------------*/
4414// Initialization
4415
4416void Closure::rewrite_and_gate (Gate *g, int dst, int src, LRAT_ID id1,
4417 LRAT_ID id2) {
4418 if (skip_and_gate (g))
4419 return;
4420 if (!gate_contains (g, src))
4421 return;
4422 if (internal->val (src)) {
4423 // In essence the code below does the same thing as simplify_and_gate
4424 // but the necessary LRAT chain are different.
4426 return;
4427 }
4428 CADICAL_assert (src);
4429 CADICAL_assert (dst);
4430 CADICAL_assert (internal->val (src) == internal->val (dst));
4431 GatesTable::iterator git = (g->indexed ? table.find (g) : end (table));
4432 LOG (g, "rewriting %d into %d in", src, dst);
4433 int clashing = 0, falsifies = 0;
4434 unsigned dst_count = 0, not_dst_count = 0;
4435 auto q = begin (g->rhs);
4436 for (int &lit : g->rhs) {
4437 if (lit == src)
4438 lit = dst;
4439 if (lit == -g->lhs) {
4440 LOG ("found negated LHS literal %d", lit);
4441 clashing = lit;
4442 g->degenerated_and_neg = true;
4443 break;
4444 }
4445 if (lit == g->lhs)
4446 g->degenerated_and_pos = true;
4447 const signed char val = internal->val (lit);
4448 if (val > 0) {
4449 continue;
4450 }
4451 if (val < 0) {
4452 LOG ("found falsifying literal %d", (lit));
4453 falsifies = lit;
4454 break;
4455 }
4456 if (lit == dst) {
4457 if (not_dst_count) {
4458 LOG ("clashing literals %d and %d", (-dst), (dst));
4459 clashing = -dst;
4460 break;
4461 }
4462 if (dst_count++)
4463 continue;
4464 }
4465 if (lit == -dst) {
4466 if (dst_count) {
4467 CADICAL_assert (!not_dst_count);
4468 LOG ("clashing literals %d and %d", (dst), (-dst));
4469 clashing = -dst;
4470 break;
4471 }
4472 CADICAL_assert (!not_dst_count);
4473 ++not_dst_count;
4474 }
4475 *q++ = lit;
4476 }
4477 LOG (lrat_chain, "lrat chain after rewriting");
4478
4479 if (internal->lrat) { // updating reasons in the chain.
4480#ifdef LOGGING
4481 for (auto litId : g->pos_lhs_ids) {
4482 LOG (litId.clause, "%d ->", litId.current_lit);
4483 }
4484#endif
4485 // We remove all assigned literals except the falsified literal such
4486 // that we can produce an LRAT chain
4487 size_t i = 0, size = g->pos_lhs_ids.size ();
4488 bool found = false;
4489 CADICAL_assert (!falsifies || !clashing);
4490 const int orig_falsifies = falsifies == dst ? src : falsifies;
4491 const int orig_clashing =
4492 clashing == -dst ? -src : (clashing == dst ? src : clashing);
4493 int keep_clashing = clashing;
4494 LOG ("keeping chain for falsifies: %d aka %d and clashing: %d aka %d",
4495 falsifies, orig_falsifies, clashing, orig_clashing);
4496 for (size_t j = 0; j < size; ++j) {
4497 LOG (g->pos_lhs_ids[j].clause, "looking at %d [%zd %zd] with val %d",
4498 g->pos_lhs_ids[j].current_lit, i, j,
4499 internal->val (g->pos_lhs_ids[i].current_lit));
4500 g->pos_lhs_ids[i] = g->pos_lhs_ids[j];
4501 if (keep_clashing && g->pos_lhs_ids[i].current_lit != orig_clashing &&
4502 g->pos_lhs_ids[i].current_lit != -orig_clashing &&
4503 g->pos_lhs_ids[i].current_lit != keep_clashing &&
4504 g->pos_lhs_ids[i].current_lit != -keep_clashing)
4505 continue;
4506 if (internal->val (g->pos_lhs_ids[i].current_lit) &&
4507 g->pos_lhs_ids[i].current_lit != src &&
4508 g->pos_lhs_ids[i].current_lit != orig_falsifies)
4509 continue;
4510 if (g->pos_lhs_ids[i].current_lit == dst) {
4511 if (!found)
4512 found = true;
4513 else
4514 continue; // we have already one defining clause
4515 }
4516
4517 LOG ("maybe keeping %d [%zd %zd], src: %d, found: %d",
4518 g->pos_lhs_ids[i].current_lit, i, j, src, found);
4519 if (g->pos_lhs_ids[i].current_lit == src) {
4520 if (!found)
4521 g->pos_lhs_ids[i].current_lit = dst, found = true;
4522 else
4523 continue; // we have already one defining clause
4524 }
4525 LOG ("keeping %d [%zd %zd]", g->pos_lhs_ids[i].current_lit, i, j);
4526 ++i;
4527 }
4528 LOG ("resizing to %zd", i);
4529 CADICAL_assert (i);
4530 g->pos_lhs_ids.resize (i);
4531 }
4532
4533 if (q != end (g->rhs)) {
4534 g->rhs.resize (q - begin (g->rhs));
4535 g->shrunken = true;
4536 }
4537 CADICAL_assert (dst_count <= 2);
4538 CADICAL_assert (not_dst_count <= 1);
4539
4540 std::vector<LRAT_ID> reasons_lrat_src, reasons_lrat_usrc;
4541 shrink_and_gate (g, falsifies, clashing);
4542 LOG (g, "rewritten as");
4543 CADICAL_assert (!internal->lrat || !g->pos_lhs_ids.empty ());
4544 // check_and_gate_implied (g);
4545 update_and_gate (g, git, src, dst, id1, id2, falsifies, clashing);
4546 ++internal->stats.congruence.rewritten_ands;
4547}
4548
4549bool Closure::rewrite_gate (Gate *g, int dst, int src, LRAT_ID id1,
4550 LRAT_ID id2) {
4551 switch (g->tag) {
4553 rewrite_and_gate (g, dst, src, id1, id2);
4554 break;
4556 rewrite_xor_gate (g, dst, src);
4557 break;
4559 rewrite_ite_gate (g, dst, src);
4560 break;
4561 default:
4562 CADICAL_assert (false);
4563 break;
4564 }
4565 CADICAL_assert (internal->unsat || lrat_chain.empty ());
4566 return !internal->unsat;
4567}
4568
4569bool Closure::rewrite_gates (int dst, int src, LRAT_ID id1, LRAT_ID id2) {
4570 const auto &occs = goccs (src);
4571 for (auto g : occs) {
4572 CADICAL_assert (lrat_chain.empty ());
4573 if (!rewrite_gate (g, dst, src, id1, id2))
4574 return false;
4575 else if (!g->garbage && gate_contains (g, dst))
4576 goccs (dst).push_back (g);
4577 }
4578 goccs (src).clear ();
4579
4580#ifndef CADICAL_NDEBUG
4581 for (const auto &occs : gtab) {
4582 for (auto g : occs) {
4583 CADICAL_assert (g);
4584 CADICAL_assert (g->garbage || !gate_contains (g, src));
4585 }
4586 }
4587#endif
4588 CADICAL_assert (lrat_chain.empty ());
4589 return true;
4590}
4591
4592bool Closure::rewriting_lhs (Gate *g, int dst) {
4593 if (dst != g->lhs && dst != -g->lhs)
4594 return false;
4595 mark_garbage (g);
4596 return true;
4597}
4598
4599// update to produce proofs
4600void Closure::rewrite_xor_gate (Gate *g, int dst, int src) {
4601 if (skip_xor_gate (g))
4602 return;
4603 if (rewriting_lhs (g, dst))
4604 return;
4605 if (!gate_contains (g, src))
4606 return;
4607 LOG (g, "rewriting (%d -> %d)", src, dst);
4609 GatesTable::iterator git = (g->indexed ? table.find (g) : end (table));
4610 size_t j = 0, dst_count = 0;
4611 bool original_dst_negated = (dst < 0);
4612 dst = abs (dst);
4613 unsigned negate = original_dst_negated;
4614 const size_t size = g->rhs.size ();
4615 for (size_t i = 0; i < size; ++i) {
4616 int lit = g->rhs[i];
4617 CADICAL_assert (lit > 0);
4618 if (lit == src)
4619 lit = dst;
4620 const signed char v = internal->val (lit);
4621 if (v > 0) {
4622 negate ^= true;
4623 }
4624 if (v)
4625 continue;
4626 if (lit == dst)
4627 dst_count++;
4628 LOG ("keeping value %d", lit);
4629 g->rhs[j++] = lit;
4630 }
4631 if (negate) {
4632 LOG ("flipping LHS %d", g->lhs);
4633 g->lhs = -g->lhs;
4634 }
4635 CADICAL_assert (dst_count <= 2);
4636 if (dst_count == 2) {
4637 LOG ("destination found twice, removing");
4638 size_t k = 0;
4639 for (size_t i = 0; i < j; ++i) {
4640 const int lit = g->rhs[i];
4641 if (lit != dst)
4642 g->rhs[k++] = g->rhs[i];
4643 }
4644 CADICAL_assert (k == j - 2);
4645 g->rhs.resize (k);
4646 g->shrunken = true;
4647 CADICAL_assert (is_sorted (begin (g->rhs), end (g->rhs),
4649 g->hash = hash_lits (nonces, g->rhs);
4650 } else if (j != size) {
4651 g->shrunken = true;
4652 g->rhs.resize (j);
4654 g->hash = hash_lits (
4655 nonces,
4656 g->rhs); // all but one (the dst) is sorted correctly actually
4657 } else {
4658 CADICAL_assert (j == size);
4660 }
4661
4662 CADICAL_assert (clause.empty ());
4663 // LRAT for add_xor_shrinking_proof_chain
4664 // this should be unnecessary...
4665 // TODO check if really unnecessary
4666 if (dst_count > 1)
4668 CADICAL_assert (internal->clause.size () <= 1);
4669 update_xor_gate (g, git);
4670
4671 if (!g->garbage && !internal->unsat && original_dst_negated &&
4672 dst_count == 1) {
4673 connect_goccs (g, dst);
4674 }
4675
4677 // TODO stats
4678}
4679
4680// update to produce proofs
4682 LOG (g, "simplifying");
4683 if (skip_xor_gate (g))
4684 return;
4686 unsigned negate = 0;
4687 GatesTable::iterator git = (g->indexed ? table.find (g) : end (table));
4688 const size_t size = g->rhs.size ();
4689 size_t j = 0;
4690 for (size_t i = 0; i < size; ++i) {
4691 int lit = g->rhs[i];
4692 CADICAL_assert (lit > 0);
4693 const signed char v = internal->val (lit);
4694 if (v > 0)
4695 negate ^= 1;
4696 if (!v) {
4697 g->rhs[j++] = lit;
4698 }
4699 }
4700 if (negate) {
4701 LOG ("flipping LHS literal %d", (g->lhs));
4702 g->lhs = -(g->lhs);
4703 }
4704 if (j != size) {
4705 LOG ("shrunken gate");
4706 g->shrunken = true;
4707 g->rhs.resize (j);
4708 CADICAL_assert (is_sorted (begin (g->rhs), end (g->rhs),
4710 g->hash = hash_lits (nonces, g->rhs);
4711 } else {
4712 CADICAL_assert (g->hash == hash_lits (nonces, g->rhs));
4713 }
4714
4716 CADICAL_assert (clause.empty ());
4717 update_xor_gate (g, git);
4718 LOG (g, "simplified");
4720 internal->stats.congruence.simplified++;
4721 internal->stats.congruence.simplified_xors++;
4722}
4723
4724/*------------------------------------------------------------------------*/
4725// propagation of clauses and simplification
4727 const int idx = abs (lit);
4728 if (scheduled[idx])
4729 return;
4730 scheduled[idx] = true;
4731 schedule.push (lit);
4733 LOG ("scheduled literal %d", lit);
4734}
4735
4737 LOG ("propagation of congruence unit %d", lit);
4738 if (internal->lrat)
4739 lazy_propagated (lit) = true;
4740 return simplify_gates (lit) && simplify_gates (-lit);
4741}
4742
4744 while (units !=
4745 internal->trail
4746 .size ()) { // units are added during propagation, so reloading
4747 LOG ("propagating %d over gates", internal->trail[units]);
4748 if (!propagate_unit (internal->trail[units++]))
4749 return false;
4750 }
4751 return true;
4752}
4753
4754// The replacement has to be done eagerly, not lazily to make sure that the
4755// gates are in normalized form. Otherwise, some merges might be missed.
4757 if (internal->val (lit))
4758 return true;
4759 LOG ("propagating literal %d", lit);
4764 CADICAL_assert (lrat_chain.empty ());
4765 return rewrite_gates (repr, lit, id1, id2) &&
4766 rewrite_gates (-repr, -lit, id2, id1);
4767}
4768
4770 START (congruencemerge);
4771 size_t propagated = 0;
4772 LOG ("propagating at least %zd units", schedule.size ());
4773 CADICAL_assert (lrat_chain.empty ());
4774 while (propagate_units () && !schedule.empty ()) {
4775 CADICAL_assert (!internal->unsat);
4776 CADICAL_assert (lrat_chain.empty ());
4777 ++propagated;
4778 int lit = schedule.front ();
4779 schedule.pop ();
4780 scheduled[abs (lit)] = false;
4782 break;
4783 }
4784
4785 CADICAL_assert (internal->unsat || schedule.empty ());
4786 CADICAL_assert (internal->unsat || lrat_chain.empty ());
4787
4788 LOG ("propagated %zu congruence units", units);
4789 LOG ("propagated %zu congruence equivalences", propagated);
4790
4791#ifndef CADICAL_NDEBUG
4792 if (!internal->unsat) {
4793 for (const auto &occs : gtab) {
4794 for (auto g : occs) {
4795 if (g->garbage)
4796 continue;
4798 g->tag == Gate_Type::XOr_Gate ||
4799 !gate_contains (g, -g->lhs));
4800 // TODO: this would be nice to have!
4801 // CADICAL_assert (g->tag != Gate_Type::ITE_Gate || (g->rhs.size() == 3
4802 // && g->rhs[1] != -g->lhs && g->rhs[2] != -g->lhs));
4803 // CADICAL_assert (table.count(g) == 1);
4804 for (auto lit : g->rhs) {
4805 CADICAL_assert (!internal->val (lit));
4807 }
4808 }
4809 }
4810 for (Gate *g : table) {
4811 if (g->garbage)
4812 continue;
4813 if (g->tag == Gate_Type::And_Gate) {
4814 // CADICAL_assert (find_and_lits(g->arity, g->rhs));
4815 }
4816 }
4817 }
4818#endif
4819 STOP (congruencemerge);
4820 return propagated;
4821}
4822
4823std::string string_of_gate (Gate_Type t) {
4824 switch (t) {
4826 return "And";
4828 return "XOr";
4830 return "ITE";
4831 default:
4832 return "buggy";
4833 }
4834}
4835
4837 scheduled.clear ();
4838 for (Gate *g : table) {
4839 CADICAL_assert (g->indexed);
4840 LOG (g, "deleting");
4841 if (!g->garbage)
4842 delete g;
4843 }
4844 table.clear ();
4845
4846 for (auto &occ : gtab) {
4847 occ.clear ();
4848 }
4849 gtab.clear ();
4850
4851 for (auto gate : garbage)
4852 delete gate;
4853 garbage.clear ();
4854
4855 if (internal->lrat) {
4856 CADICAL_assert (internal->proof);
4857 for (auto c : extra_clauses) {
4858 CADICAL_assert (!c->garbage);
4859 internal->proof->delete_clause (c);
4860 delete c;
4861 }
4862 extra_clauses.clear ();
4863 } else {
4864 CADICAL_assert (extra_clauses.empty ());
4865 }
4866}
4867
4869 full_watching = true;
4870 if (!internal->unsat && !internal->propagate ()) {
4871 internal->learn_empty_clause ();
4872 }
4873
4874#if 0
4875 // remove delete watched clauses from the watch list
4876 for (auto v : internal->vars) {
4877 for (auto sgn = -1; sgn <= 1; sgn += 2) {
4878 const int lit = v * sgn;
4879 auto &watchers = internal->watches (lit);
4880 const size_t size = watchers.size ();
4881 size_t j = 0;
4882 for (size_t i = 0; i != size; ++i) {
4883 const auto w = watchers[i];
4884 watchers[j] = watchers[i];
4885 if (!w.clause->garbage)
4886 ++j;
4887 }
4888 watchers.resize(j);
4889 }
4890 }
4891 // watch the remaining non-watched clauses
4892 for (auto c : new_unwatched_binary_clauses)
4893 internal->watch_clause (c);
4895 for (auto c : internal->clauses) {
4896 if (c->garbage)
4897 continue;
4898 if (c->size != 2)
4899 internal->watch_clause (c);
4900 }
4901#else // simpler implementation
4903 internal->clear_watches ();
4904 internal->connect_watches ();
4905#endif
4906}
4907
4909 START (congruencematching);
4910 reset_closure ();
4911 std::vector<signed char> matchable;
4912 matchable.resize (internal->max_var + 1);
4913 size_t count_matchable = 0;
4914
4915 for (auto idx : internal->vars) {
4916 if (!internal->flags (idx).active ())
4917 continue;
4918 const int lit = idx;
4919 const int repr = find_representative (lit);
4920 if (lit == repr)
4921 continue;
4922 const int repr_idx = abs (repr);
4923 if (!matchable[idx]) {
4924 LOG ("matchable %d", idx);
4925 matchable[idx] = true;
4926 count_matchable++;
4927 }
4928
4929 if (!matchable[repr_idx]) {
4930 LOG ("matchable %d", repr_idx);
4931 matchable[repr_idx] = true;
4932 count_matchable++;
4933 }
4934 }
4935
4936 LOG ("found %.0f%%",
4937 (double) count_matchable /
4938 (double) (internal->max_var ? internal->max_var : 1));
4939 std::vector<Clause *> candidates;
4940 auto &analyzed = internal->analyzed;
4941
4942 for (auto *c : internal->clauses) {
4943 if (c->garbage)
4944 continue;
4945 if (c->redundant)
4946 continue;
4947 if (c->size == 2)
4948 continue;
4949 CADICAL_assert (analyzed.empty ());
4950 bool contains_matchable = false;
4951 for (auto lit : *c) {
4952 const signed char v = internal->val (lit);
4953 if (v < 0)
4954 continue;
4955 if (v > 0) {
4956 LOG (c, "mark satisfied");
4957 internal->mark_garbage (c);
4958 break;
4959 }
4960 if (!contains_matchable) {
4961 const int idx = abs (lit);
4962 if (matchable[idx])
4963 contains_matchable = true;
4964 }
4965
4966 const int repr = find_representative (lit);
4967 CADICAL_assert (!internal->val (repr));
4968 if (marked (repr))
4969 continue;
4970 const int not_repr = -repr;
4971 if (marked (not_repr)) {
4972 LOG (c, "matches both %d and %d", (lit), (not_repr));
4973 internal->mark_garbage (c);
4974 break;
4975 }
4976 marked (repr) = 1;
4977 analyzed.push_back (repr);
4978 }
4979
4980 for (auto lit : analyzed)
4981 marked (lit) = 0;
4982 analyzed.clear ();
4983 if (c->garbage)
4984 continue;
4985 if (!contains_matchable) {
4986 LOG ("no matching variable");
4987 continue;
4988 }
4989 LOG (c, "candidate");
4990 candidates.push_back (c);
4991 }
4992
4993 rsort (begin (candidates), end (candidates), smaller_clause_size_rank ());
4994 size_t tried = 0, subsumed = 0;
4995 internal->init_occs ();
4996 for (auto c : candidates) {
4997 CADICAL_assert (c->size != 2);
4998 // TODO if terminated
4999 ++tried;
5000 if (find_subsuming_clause (c)) {
5001 ++subsumed;
5002 }
5003 }
5004 LOG ("[congruence] subsumed %.0f%%",
5005 (double) subsumed / (double) (tried ? tried : 1));
5006 STOP (congruencematching);
5007}
5008
5009/*------------------------------------------------------------------------*/
5010// Candidate clause 'subsumed' is subsumed by 'subsuming'. We need to copy
5011// the function because 'congruence' is too early to include the version
5012// from subsume
5013
5014void Closure::subsume_clause (Clause *subsuming, Clause *subsumed) {
5015 // CADICAL_assert (!subsuming->redundant);
5016 // CADICAL_assert (!subsumed->redundant);
5017 auto &stats = internal->stats;
5018 stats.subsumed++;
5019 CADICAL_assert (subsuming->size <= subsumed->size);
5020 LOG (subsumed, "subsumed");
5021 if (subsumed->redundant)
5022 stats.subred++;
5023 else
5024 stats.subirr++;
5025 if (subsumed->redundant || !subsuming->redundant) {
5026 internal->mark_garbage (subsumed);
5027 return;
5028 }
5029 LOG ("turning redundant subsuming clause into irredundant clause");
5030 subsuming->redundant = false;
5031 if (internal->proof)
5032 internal->proof->strengthen (subsuming->id);
5033 internal->mark_garbage (subsumed);
5034 stats.current.irredundant++;
5035 stats.added.irredundant++;
5036 stats.irrlits += subsuming->size;
5037 CADICAL_assert (stats.current.redundant > 0);
5038 stats.current.redundant--;
5039 CADICAL_assert (stats.added.redundant > 0);
5040 stats.added.redundant--;
5041 // ... and keep 'stats.added.total'.
5042}
5043
5045 CADICAL_assert (!subsumed->garbage);
5046 Clause *subsuming = nullptr;
5047 for (auto lit : *subsumed) {
5048 CADICAL_assert (internal->val (lit) <= 0);
5049 const int repr_lit = find_representative (lit);
5050 const signed char repr_val = internal->val (repr_lit);
5051 CADICAL_assert (repr_val <= 0);
5052 if (repr_val < 0)
5053 continue;
5054 if (marked (repr_lit))
5055 continue;
5056 CADICAL_assert (!marked (-repr_lit));
5057 marked (repr_lit) = 1;
5058 }
5059 int least_occuring_lit = 0;
5060 size_t count_least_occurring = INT_MAX;
5061 LOG (subsumed, "trying to forward subsume");
5062
5063 for (auto lit : *subsumed) {
5064 const int repr_lit = find_representative (lit);
5065 const size_t count = internal->occs (lit).size ();
5066 CADICAL_assert (count <= UINT_MAX);
5067 if (count < count_least_occurring) {
5068 count_least_occurring = count;
5069 least_occuring_lit = repr_lit;
5070 }
5071 for (auto d : internal->occs (lit)) {
5072 CADICAL_assert (!d->garbage);
5073 CADICAL_assert (subsumed != d);
5074 if (!subsumed->redundant && d->redundant)
5075 continue;
5076 for (auto other : *d) {
5077 const signed char v = internal->val (other);
5078 if (v < 0)
5079 continue;
5080 CADICAL_assert (!v);
5081 const int repr_other = find_representative (other);
5082 if (!marked (repr_other))
5083 goto CONTINUE_WITH_NEXT_CLAUSE;
5084 LOG ("subsuming due to %d -> %d", other, repr_other);
5085 }
5086 subsuming = d;
5087 goto FOUND_SUBSUMING;
5088
5089 CONTINUE_WITH_NEXT_CLAUSE:;
5090 }
5091 }
5092 CADICAL_assert (least_occuring_lit);
5093
5094FOUND_SUBSUMING:
5095 for (auto lit : *subsumed) {
5096 const int repr_lit = find_representative (lit);
5097 const signed char v = internal->val (lit);
5098 if (!v)
5099 marked (repr_lit) = 0;
5100 }
5101 if (subsuming) {
5102 LOG (subsumed, "subsumed");
5103 LOG (subsuming, "subsuming");
5104 subsume_clause (subsuming, subsumed);
5105 ++internal->stats.congruence.subsumed;
5106 return true;
5107 } else {
5108 internal->occs (least_occuring_lit).push_back (subsumed);
5109 return false;
5110 }
5111}
5112
5113/*------------------------------------------------------------------------*/
5114static bool skip_ite_gate (Gate *g) {
5116 if (g->garbage)
5117 return true;
5118 return false;
5119}
5120
5122 Gate *g, int src, int dst, std::vector<LRAT_ID> &reasons_implication,
5123 std::vector<LRAT_ID> &reasons_back) {
5124 CADICAL_assert (!g->garbage);
5125 if (!internal->lrat)
5126 return;
5128 // no merge is happening actually
5130 if (find_eager_representative (g->lhs) == g->rhs[1] || find_eager_representative (g->lhs) == g->rhs[2])
5131 return;
5132 if ((g->rhs[1] == src && g->lhs == dst && g->rhs[2] == g->lhs) ||
5133 (g->rhs[2] == src && g->lhs == dst && g->rhs[1] == g->lhs) ||
5134 (g->rhs[1] == -src && g->lhs == -dst && g->rhs[2] == g->lhs) ||
5135 (g->rhs[2] == -src && g->lhs == -dst && g->rhs[1] == g->lhs))
5136 return;
5137 check_ite_lrat_reasons (g, false);
5138 CADICAL_assert (g->rhs.size () == 3);
5139 CADICAL_assert (src == g->rhs[1] || src == g->rhs[2]);
5140 CADICAL_assert (dst == g->rhs[1] || dst == g->rhs[2]);
5141 const int8_t flag = g->degenerated_ite;
5142 CADICAL_assert (!ite_flags_no_then_clauses (flag)); // e = lhs: already merged
5143 CADICAL_assert (!ite_flags_no_else_clauses (flag)); // t = lhs: already merged
5145 if (ite_flags_neg_cond_lhs (flag)) {
5146 LOG ("degenerated case with lhs = -cond");
5147 LOG (g->pos_lhs_ids[0].clause, "1:");
5148 LOG (g->pos_lhs_ids[1].clause, "2:");
5149 reasons_back.push_back (g->pos_lhs_ids[0].clause->id);
5150 reasons_implication.push_back (g->pos_lhs_ids[1].clause->id);
5151 return;
5152 }
5153 if (ite_flags_cond_lhs (flag)) {
5154 LOG ("degenerated case with lhs = cond");
5155 CADICAL_assert (g->pos_lhs_ids[0].clause);
5156 CADICAL_assert (g->pos_lhs_ids[3].clause);
5157 reasons_back.push_back (g->pos_lhs_ids[3].clause->id);
5158 reasons_implication.push_back (g->pos_lhs_ids[0].clause->id);
5159 return;
5160 }
5161 reasons_implication.push_back (g->pos_lhs_ids[0].clause->id);
5162 reasons_implication.push_back (g->pos_lhs_ids[2].clause->id);
5163 reasons_back.push_back (g->pos_lhs_ids[1].clause->id);
5164 reasons_back.push_back (g->pos_lhs_ids[3].clause->id);
5165}
5166
5168 int dst) {
5169 if (!internal->lrat)
5170 return;
5171 LOG (g, "updating lrat from");
5172 for (auto &litId : g->pos_lhs_ids) {
5173 CADICAL_assert (litId.clause);
5174 if (litId.current_lit == src)
5175 litId.current_lit = dst;
5176 if (litId.current_lit == -src)
5177 litId.current_lit = -dst;
5178 }
5179 check_ite_lrat_reasons (g, false);
5180}
5181
5183 Gate *g, int src, int dst, size_t idx1, size_t idx2,
5184 int cond_lit_to_learn_if_degenerated) {
5185 CADICAL_assert (internal->lrat_chain.empty ());
5186 CADICAL_assert (!g->garbage);
5187 LOG (g, "rewriting to proper AND");
5188 if (internal->val (g->lhs) > 0) {
5189 {
5190 const int lit = g->rhs[0];
5191 const char v = internal->val (lit);
5192 if (v > 0) {
5193 } else if (!v) {
5194 if (internal->lrat) {
5196 Rewrite (), lrat_chain);
5197 }
5198 learn_congruence_unit (cond_lit_to_learn_if_degenerated);
5199 } else {
5200 if (internal->lrat)
5202 Rewrite (), lrat_chain);
5204 internal->learn_empty_clause ();
5205 return true;
5206 }
5207 }
5208 if (!internal->unsat) {
5209 const int lit = g->rhs[1];
5210 const char v = internal->val (lit);
5211 CADICAL_assert (dst == g->rhs[0] || dst == g->rhs[1] || -dst == g->rhs[0] ||
5212 -dst == g->rhs[1]);
5213 const int other = (dst == g->rhs[0] || dst == g->rhs[1])
5214 ? dst ^ g->rhs[0] ^ g->rhs[1]
5215 : (-dst) ^ g->rhs[0] ^ g->rhs[1];
5216 if (v > 0) {
5217 // already set by propagation
5218 return true;
5219 } else if (!v) {
5220 if (internal->lrat) {
5222 Rewrite (), lrat_chain);
5223 }
5224 learn_congruence_unit (other);
5225 } else {
5226 if (internal->lrat) {
5227 push_lrat_unit (cond_lit_to_learn_if_degenerated);
5229 Rewrite (), lrat_chain);
5230 }
5231 internal->learn_empty_clause ();
5232 return true;
5233 }
5234 }
5235 return true;
5236 }
5237 if (!internal->lrat)
5238 return false;
5239 LOG ("updating flags");
5240 g->degenerated_and_neg = (g->rhs[1] == -g->lhs || g->rhs[0] == -g->lhs);
5241 g->degenerated_and_pos = (g->rhs[0] == g->lhs || g->rhs[1] == g->lhs);
5242 CADICAL_assert (g->rhs.size () == 3);
5243 CADICAL_assert (g->pos_lhs_ids.size () == 4);
5244 CADICAL_assert (idx1 < g->pos_lhs_ids.size ());
5245 CADICAL_assert (idx2 < g->pos_lhs_ids.size ());
5246 int lit = g->pos_lhs_ids[idx2].current_lit, other = g->lhs;
5247 // TODO: remove argument
5248 (void) src;
5250 idx2, false);
5251
5252 if ((idx1 == (size_t) -1 || idx2 == (size_t) -1)) {
5253 // degenerated and gate
5254 return false;
5255 }
5256
5257 CADICAL_assert (idx1 != (size_t) -1);
5258 CADICAL_assert (idx2 != (size_t) -1);
5259 CADICAL_assert (idx1 < g->pos_lhs_ids.size ());
5260 CADICAL_assert (idx2 < g->pos_lhs_ids.size ());
5261 Clause *c = g->pos_lhs_ids[idx1].clause;
5262 CADICAL_assert (c->size == 2);
5263 Clause *d = g->pos_lhs_ids[idx2].clause;
5264 CADICAL_assert (c != d);
5265 CADICAL_assert (c);
5266 CADICAL_assert (d);
5267 g->pos_lhs_ids.erase (std::remove_if (begin (g->pos_lhs_ids),
5268 end (g->pos_lhs_ids),
5269 [d] (const LitClausePair &p) {
5270 return p.clause == d || !p.clause;
5271 }),
5272 end (g->pos_lhs_ids));
5273 CADICAL_assert (g->pos_lhs_ids.size () == 2);
5275 CADICAL_assert (other);
5276 CADICAL_assert (lit != dst);
5277 CADICAL_assert (other != dst);
5278 CADICAL_assert (lit != other);
5279 lrat_chain.push_back (c->id);
5280 lrat_chain.push_back (d->id);
5282 CADICAL_assert (e);
5283
5284 auto long_clause =
5285 std::find_if (begin (g->pos_lhs_ids), end (g->pos_lhs_ids),
5286 [] (LitClausePair l) { return l.clause->size == 3; });
5287 CADICAL_assert (long_clause != end (g->pos_lhs_ids));
5288 LOG (long_clause->clause, "new long clause");
5289 g->neg_lhs_ids.push_back (*long_clause);
5290 g->pos_lhs_ids.erase (long_clause);
5291
5292 CADICAL_assert (g->pos_lhs_ids.size () == 1);
5293
5294 (void) maybe_promote_tmp_binary_clause (g->pos_lhs_ids[0].clause);
5295 g->pos_lhs_ids.push_back ({lit, e});
5296#ifndef CADICAL_NDEBUG
5297 for (auto litId : g->pos_lhs_ids) {
5298 bool found = false;
5299 CADICAL_assert (litId.clause);
5300 for (auto other : *litId.clause) {
5301 found = (find_eager_representative (other) == litId.current_lit);
5302 if (found)
5303 break;
5304 }
5305 CADICAL_assert (found);
5306 }
5307 for (auto id : g->pos_lhs_ids) {
5308 LOG (id.clause, "clause after rewriting:");
5309 CADICAL_assert (id.clause->size == 2);
5310 }
5311
5312#endif
5313 return false;
5314}
5315
5317 Gate *g, std::vector<LRAT_ID> &reasons_implication,
5318 std::vector<LRAT_ID> &reasons_back, std::vector<LRAT_ID> &reasons_unit,
5319 bool rewritting_then, bool &learn_units) {
5320
5321 const size_t idx1 = rewritting_then ? 0 : 2;
5322 const size_t idx2 = idx1 + 1;
5323 const size_t other_idx1 = rewritting_then ? 2 : 0;
5324 const size_t other_idx2 = other_idx1 + 1;
5325 const int cond_lit = g->rhs[0];
5326 const int lit_to_merge = g->rhs[rewritting_then ? 2 : 1];
5327 const int other_lit = g->rhs[rewritting_then ? 1 : 2];
5328 const int repr_cond_lit = find_eager_representative (g->rhs[0]);
5329 const int repr_lit_to_merge = find_eager_representative (lit_to_merge);
5330 const int repr_other_lit = find_eager_representative (other_lit);
5331 const int repr_lhs = find_eager_representative(g->lhs);
5332 if (!internal->proof)
5333 return;
5334
5335
5336 LOG ("cond: %d, merging %d and rewriting to %d", cond_lit, lit_to_merge,
5337 other_lit);
5338 if (internal->lrat) {
5339 CADICAL_assert (internal->lrat);
5340 CADICAL_assert (g->pos_lhs_ids.size () == 4);
5341
5342 if (repr_lhs == -repr_other_lit) {
5343 LOG ("special case: %s=%s, checking if other: %s %s", LOGLIT (g->lhs),
5344 LOGLIT (-lit_to_merge), LOGLIT (cond_lit), LOGLIT (other_lit));
5345 CADICAL_assert (repr_lit_to_merge != -repr_lhs); // should have been rewritten before
5346
5347 if (rewritting_then && repr_cond_lit == repr_lhs) {
5348 LOG ("t=-lhs/c=lhs");
5349 learn_units = true;
5350 // is a unit
5352 Rewrite (), lrat_chain);
5353 unsimplified.push_back (-cond_lit);
5355 reasons_unit = {id_unit};
5356 // don't bother finding out which one is used
5357 reasons_implication.push_back (id_unit);
5359 g->pos_lhs_ids[3].clause, g->lhs, false);
5360 CADICAL_assert (g->pos_lhs_ids[3].clause);
5361 reasons_implication.push_back (g->pos_lhs_ids[3].clause->id);
5362 unsimplified.clear ();
5363 return;
5364 }
5365 if (!rewritting_then && repr_cond_lit == repr_lhs) {
5366 LOG ("e=-lhs/c=lhs");
5367 learn_units = true;
5368 // is a unit
5370 Rewrite (), lrat_chain);
5371 unsimplified.push_back (cond_lit);
5373 reasons_unit = {id_unit};
5374 // don't bother finding out which one is used
5375 reasons_implication.push_back (id_unit);
5377 g->pos_lhs_ids[0].clause, g->lhs, false);
5378 CADICAL_assert (g->pos_lhs_ids[0].clause);
5379 reasons_implication.push_back (g->pos_lhs_ids[0].clause->id);
5380 unsimplified.clear ();
5381 return;
5382 }
5383 if (!rewritting_then && repr_cond_lit == -repr_lhs) {
5384 LOG ("e=-lhs/c=-lhs");
5385 learn_units = true;
5386 // TODO: this function does not work to produce units for this case
5387 // c LOG 0 rewriting 4 by 3 in gate[42] (arity: 3) -3 := ITE 3 7
5388 // ...
5389 // c LOG 0 clause[50] 4 -3
5390 // c LOG 0 clause[44] 5 3
5391 // c LOG 0 clause[2] -3 -4 -5
5392 // the first two are rewriting, but they are not ordered properly
5393 // and we need the '5' clause to come after
5395 Rewrite (), lrat_chain);
5396 unsimplified.push_back (cond_lit);
5398 reasons_unit = {id_unit};
5400 g->pos_lhs_ids[1].clause, g->lhs, false);
5401 CADICAL_assert (g->pos_lhs_ids[1].clause);
5402
5403 // don't bother finding out which one is used
5404 reasons_implication.push_back (id_unit);
5405 reasons_implication.push_back (g->pos_lhs_ids[1].clause->id);
5406 unsimplified.clear ();
5407 return;
5408 }
5409 if (rewritting_then && repr_cond_lit == -repr_lhs) {
5410 LOG ("t=-lhs/c=-lhs");
5411 learn_units = true;
5413 Rewrite (), lrat_chain);
5414 unsimplified.push_back (-cond_lit);
5416 reasons_unit = {id_unit};
5418 g->pos_lhs_ids[2].clause, g->lhs, false);
5419 CADICAL_assert (g->pos_lhs_ids[2].clause);
5420
5421 reasons_implication.push_back (id_unit);
5422 reasons_implication.push_back (g->pos_lhs_ids[2].clause->id);
5423 unsimplified.clear ();
5424 return;
5425 }
5426 if (rewritting_then && repr_lit_to_merge == repr_lhs) {
5427 LOG ("t=-lhs/e=lhs from rewriting then");
5428 learn_units = true;
5429 g->pos_lhs_ids[idx1].clause = produce_rewritten_clause_lrat (
5430 g->pos_lhs_ids[idx1].clause, g->lhs, false);
5431 g->pos_lhs_ids[idx2].clause = produce_rewritten_clause_lrat (
5432 g->pos_lhs_ids[idx2].clause, g->lhs, false);
5433 CADICAL_assert (g->pos_lhs_ids[idx1].clause);
5434 CADICAL_assert (g->pos_lhs_ids[idx2].clause);
5435 lrat_chain.push_back (g->pos_lhs_ids[idx1].clause->id);
5436 lrat_chain.push_back (g->pos_lhs_ids[idx2].clause->id);
5437 unsimplified.push_back (-cond_lit);
5439 reasons_unit = {id_unit};
5440 unsimplified.clear ();
5441
5442 return;
5443 }
5444 if (!rewritting_then && repr_lit_to_merge == repr_lhs) {
5445 LOG ("t=-lhs/e=lhs from rewriting else");
5446 learn_units = true;
5447 g->pos_lhs_ids[idx1].clause = produce_rewritten_clause_lrat (
5448 g->pos_lhs_ids[idx1].clause, g->lhs, false);
5449 g->pos_lhs_ids[idx2].clause = produce_rewritten_clause_lrat (
5450 g->pos_lhs_ids[idx2].clause, g->lhs, false);
5451 CADICAL_assert (g->pos_lhs_ids[idx1].clause);
5452 CADICAL_assert (g->pos_lhs_ids[idx2].clause);
5453 lrat_chain.push_back (g->pos_lhs_ids[idx1].clause->id);
5454 lrat_chain.push_back (g->pos_lhs_ids[idx2].clause->id);
5455 unsimplified.push_back (cond_lit);
5457 reasons_unit = {id_unit};
5458 unsimplified.clear ();
5459 return;
5460 }
5461
5462 if (other_lit == repr_lhs) {
5463 LOG ("TODO FIX ME t=-lhs/e=lhs");
5464 learn_units = true;
5465 // in the other direction we are merging a literal with itself
5466 g->pos_lhs_ids[idx1].clause = produce_rewritten_clause_lrat (
5467 g->pos_lhs_ids[idx1].clause, g->lhs, false);
5468 g->pos_lhs_ids[idx2].clause = produce_rewritten_clause_lrat (
5469 g->pos_lhs_ids[idx2].clause, g->lhs, false);
5470 CADICAL_assert (g->pos_lhs_ids[idx1].clause);
5471 CADICAL_assert (g->pos_lhs_ids[idx2].clause);
5472 reasons_unit.push_back (g->pos_lhs_ids[idx1].clause->id);
5473 reasons_unit.push_back (g->pos_lhs_ids[idx2].clause->id);
5474 return;
5475 }
5476 // if (other_lit == -g->lhs) {
5477 // CADICAL_assert (false);
5478 // }
5479 // if (other_lit == g->lhs) {
5480 // CADICAL_assert (false);
5481 // }
5482 }
5483
5484 LOG ("normal path");
5486 CADICAL_assert (g->pos_lhs_ids.size () == 4);
5487
5488 reasons_unit.push_back (g->pos_lhs_ids[idx1].clause->id);
5489 reasons_unit.push_back (g->pos_lhs_ids[idx2].clause->id);
5490
5491 // already merged: only unit is important
5492 if (!rewritting_then && repr_lhs == repr_lit_to_merge) {
5493 return;
5494 }
5495
5496 reasons_implication.push_back (g->pos_lhs_ids[other_idx1].clause->id);
5497 reasons_implication.push_back (g->pos_lhs_ids[idx1].clause->id);
5498 reasons_implication.push_back (g->pos_lhs_ids[idx2].clause->id);
5499
5500 reasons_back.push_back (g->pos_lhs_ids[other_idx2].clause->id);
5501 reasons_back.push_back (g->pos_lhs_ids[idx1].clause->id);
5502 reasons_back.push_back (g->pos_lhs_ids[idx2].clause->id);
5503 } else {
5504 LOG ("learn extra clauses XXXXXXXXXXXXXXXXXXXXXXXXX");
5505 const int lhs = g->lhs;
5506 const int cond = g->rhs[0];
5507 if (rewritting_then) {
5508 unsimplified.push_back (-cond);
5509 unsimplified.push_back (lhs);
5511 unsimplified.push_back (-cond);
5512 unsimplified.push_back (-lhs);
5514 } else {
5515 unsimplified.push_back (cond);
5516 unsimplified.push_back (-lhs);
5518 unsimplified.push_back (cond);
5519 unsimplified.push_back (lhs);
5521 }
5522 unsimplified.clear ();
5523 }
5524}
5525
5526void Closure::rewrite_ite_gate (Gate *g, int dst, int src) {
5527 CADICAL_assert (unsimplified.empty ());
5528 if (skip_ite_gate (g))
5529 return;
5530 if (!gate_contains (g, src))
5531 return;
5532 LOG (g, "rewriting %d by %d in", src, dst);
5534 CADICAL_assert (g->rhs.size () == 3);
5535 CADICAL_assert (!internal->lrat || g->pos_lhs_ids.size () == 4);
5536 auto &rhs = g->rhs;
5537 const int lhs = g->lhs;
5538 const int cond = g->rhs[0];
5539 const int then_lit = g->rhs[1];
5540 const int else_lit = g->rhs[2];
5541 const int not_lhs = -(lhs);
5542 const int not_dst = -(dst);
5543 const int not_cond = -(cond);
5544 const int not_then_lit = -(then_lit);
5545 const int not_else_lit = -(else_lit);
5547
5548 bool garbage = false;
5549 bool shrink = true;
5550 const auto git = g->indexed ? table.find (g) : end (table);
5551 CADICAL_assert (!g->indexed || git != end (table));
5552 CADICAL_assert (*git == g);
5553 if (internal->val (cond) && internal->val (then_lit) &&
5554 internal->val (else_lit)) { // propagation has set all value anyway
5555 LOG (g, "all values are set");
5556 CADICAL_assert (internal->val (g->lhs));
5557 garbage = true;
5558 } else if (internal->val (g->lhs) && internal->val (cond)) {
5559 LOG (g, "all values are set 2");
5560 CADICAL_assert (internal->val (g->lhs));
5561 garbage = true;
5562 }
5563 // this code is taken one-to-one from kissat
5564 else if (src == cond) {
5565 if (dst == then_lit) {
5566 // then_lit ? then_lit : else_lit
5567 // then_lit & then_lit | !then_lit & else_lit
5568 // then_lit | !then_lit & else_lit
5569 // then_lit | else_lit
5570 // !(!then_lit & !else_lit)
5571 g->lhs = not_lhs;
5572 rhs[0] = not_then_lit;
5573 rhs[1] = not_else_lit;
5574 if (then_lit == lhs || else_lit == lhs)
5575 garbage = true;
5576 else
5577 garbage = rewrite_ite_gate_to_and (g, src, dst, 1, 3, -dst);
5578 } else if (not_dst == then_lit) {
5579 // !then_lit ? then_lit : else_lit
5580 // !then_lit & then_lit | then_lit & else_lit
5581 // then_lit & else_lit
5582 rhs[0] = else_lit;
5583 CADICAL_assert (rhs[1] == then_lit);
5584 garbage = rewrite_ite_gate_to_and (g, src, dst, 0, 2, -dst);
5585 } else if (dst == else_lit) {
5586 // else_list ? then_lit : else_lit
5587 // else_list & then_lit | !else_list & else_lit
5588 // else_list & then_lit
5589 rhs[0] = else_lit;
5590 CADICAL_assert (rhs[1] == then_lit);
5591 garbage = rewrite_ite_gate_to_and (g, src, dst, 2, 0, dst);
5592 } else if (not_dst == else_lit) {
5593 // !else_list ? then_lit : else_lit
5594 // !else_list & then_lit | else_lit & else_lit
5595 // !else_list & then_lit | else_lit
5596 // then_lit | else_lit
5597 // !(!then_lit & !else_lit)
5598 g->lhs = not_lhs;
5599 rhs[0] = not_then_lit;
5600 rhs[1] = not_else_lit;
5601 if (then_lit == lhs || else_lit == lhs)
5602 garbage = true;
5603 else
5604 garbage = rewrite_ite_gate_to_and (g, src, dst, 3, 1, dst);
5605 } else {
5606 shrink = false;
5607 rhs[0] = dst;
5609 }
5610 } else if (src == then_lit) {
5611 if (not_dst == g->lhs) { // TODO not in kissat
5612 rhs[1] = dst;
5613 check_ite_implied (g->lhs, cond, then_lit, else_lit);
5614 std::vector<LRAT_ID> reasons_implication, reasons_back, reasons_unit;
5615 LOG ("%d = %d ?", g->lhs, -g->rhs[0]);
5616 bool learn_units_instead_of_equivalence = false;
5618 g, reasons_implication, reasons_back, reasons_unit, true,
5619 learn_units_instead_of_equivalence);
5620 if (learn_units_instead_of_equivalence) { // it is too hard to produce
5621 // LRAT chains
5622 // in this case
5623
5624 if (internal->lrat)
5625 lrat_chain = reasons_unit;
5626 learn_congruence_unit (-cond, true);
5627 if (-else_lit == lhs) {
5628 if (internal->lrat)
5629 lrat_chain = reasons_implication;
5630 learn_congruence_unit (cond == -lhs ? -else_lit : else_lit, false, true);
5631 } else fully_propagate ();
5632 } else {
5633 if (merge_literals_lrat (g->lhs, else_lit, reasons_implication,
5634 reasons_back)) {
5635 ++internal->stats.congruence.unaries;
5636 ++internal->stats.congruence.unary_ites;
5637 }
5638 if (!internal->unsat) {
5639 if (internal->lrat)
5640 lrat_chain = reasons_unit;
5641 learn_congruence_unit (-cond);
5642 }
5643 }
5645 garbage = true;
5646 } else if (dst == cond) {
5647 // cond ? cond : else_lit
5648 // cond & cond | !cond & else_lit
5649 // cond | !cond & else_lit
5650 // cond | else_lit
5651 // !(!cond & !else_lit)
5652 g->lhs = not_lhs;
5653 rhs[0] = not_cond;
5654 rhs[1] = not_else_lit;
5655 if (else_lit == lhs || cond == lhs)
5656 garbage = true;
5657 else
5658 garbage = rewrite_ite_gate_to_and (g, src, dst, 1, 3, -cond);
5659 } else if (not_dst == cond) {
5660 // cond ? !cond : else_lit
5661 // cond & !cond | !cond & else_lit
5662 // !cond & else_lit
5663 rhs[0] = not_cond;
5664 rhs[1] = else_lit;
5665 garbage = rewrite_ite_gate_to_and (g, src, dst, 0, 2, -cond);
5666 } else if (dst == else_lit) {
5667 // cond ? else_lit : else_lit
5668 // else_lit
5669 std::vector<LRAT_ID> reasons_implication, reasons_back;
5670 produce_ite_merge_then_else_reasons (g, src, dst, reasons_implication,
5671 reasons_back);
5672 if (merge_literals_lrat (lhs, else_lit, reasons_implication,
5673 reasons_back)) {
5674 ++internal->stats.congruence.unaries;
5675 ++internal->stats.congruence.unary_ites;
5676 }
5678 garbage = true;
5679 } else if (not_dst == else_lit) {
5680 // cond ? !else_lit : else_lit
5681 // cond & !else_lit | !cond & else_lit
5682 // cond ^ else_lit
5683 if (g->lhs == cond) {
5685 false);
5686 if (internal->lrat) {
5687 CADICAL_assert (g->pos_lhs_ids.size () == 2);
5688 lrat_chain.push_back (g->pos_lhs_ids[0].clause->id);
5689 lrat_chain.push_back (g->pos_lhs_ids[1].clause->id);
5690 }
5691 learn_congruence_unit (-else_lit);
5692 garbage = true;
5693 } else {
5694 LOG ("changing to xor");
5695 new_tag = Gate_Type::XOr_Gate;
5696 CADICAL_assert (rhs[0] == cond);
5697 rhs[1] = else_lit;
5698 CADICAL_assert (!internal->lrat || !g->pos_lhs_ids.empty ());
5699 {
5700#ifdef LOGGING
5701 for (auto litId : g->pos_lhs_ids) {
5702 LOG (litId.clause, "%d ->", litId.current_lit);
5703 }
5704#endif
5706 true);
5707#ifdef LOGGING
5708 for (auto litId : g->pos_lhs_ids) {
5709 LOG (litId.clause, "%d ->", litId.current_lit);
5710 }
5711#endif
5712 }
5713 }
5714 } else {
5715 shrink = false;
5716 rhs[1] = dst;
5718 }
5719 } else {
5720 CADICAL_assert (src == else_lit);
5721 if (not_dst == g->lhs) { // TODO not in kissat
5722 rhs[2] = dst;
5723 std::vector<LRAT_ID> reasons_implication, reasons_back, reasons_unit;
5724 bool learn_units_instead_of_equivalence = false;
5726 g, reasons_implication, reasons_back, reasons_unit, false,
5727 learn_units_instead_of_equivalence);
5728 if (learn_units_instead_of_equivalence) { // Too hard to produce LRAT
5729 if (internal->lrat)
5730 lrat_chain = reasons_unit;
5731 learn_congruence_unit (cond, true);
5732 if (then_lit != lhs) {
5733 LOG ("special case, learning %d",cond == -lhs ? -then_lit : then_lit);
5734 if (internal->lrat)
5735 lrat_chain = reasons_implication;
5736 learn_congruence_unit (cond == -lhs ? -then_lit : then_lit, false, true);
5737 } else fully_propagate ();
5738 } else {
5739 if (merge_literals_lrat (lhs, then_lit, reasons_implication,
5740 reasons_back)) {
5741 ++internal->stats.congruence.unaries;
5742 ++internal->stats.congruence.unary_ites;
5743 }
5744 if (!internal->unsat) {
5745 if (internal->lrat)
5746 lrat_chain = reasons_unit;
5747 learn_congruence_unit (cond);
5748 }
5749 }
5751 garbage = true;
5752 } else if (dst == cond) {
5753 // cond ? then_lit : cond
5754 // cond & then_lit | !cond & cond
5755 // cond & then_lit
5756 CADICAL_assert (rhs[0] == cond);
5757 CADICAL_assert (rhs[1] == then_lit);
5758 garbage = rewrite_ite_gate_to_and (g, src, dst, 2, 0, cond);
5759 } else if (not_dst == cond) {
5760 // cond ? then_lit : !cond
5761 // cond & then_lit | !cond & !cond
5762 // cond & then_lit | !cond
5763 // then_lit | !cond
5764 // !(!then_lit & cond)
5765 g->lhs = not_lhs;
5766 CADICAL_assert (rhs[0] == cond);
5767 rhs[1] = not_then_lit;
5768 if (then_lit == lhs || cond == lhs)
5769 garbage = true;
5770 else
5771 garbage = rewrite_ite_gate_to_and (g, src, dst, 3, 1, cond);
5772 } else if (dst == then_lit) {
5773 // cond ? then_lit : then_lit
5774 // then_lit
5775 std::vector<LRAT_ID> reasons_implication, reasons_back;
5776 produce_ite_merge_then_else_reasons (g, src, dst, reasons_implication,
5777 reasons_back);
5778 if (merge_literals_lrat (lhs, then_lit, reasons_implication,
5779 reasons_back)) {
5780 ++internal->stats.congruence.unaries;
5781 ++internal->stats.congruence.unary_ites;
5782 }
5783 garbage = true;
5784 } else if (not_dst == then_lit) {
5785 // cond ? then_lit : !then_lit
5786 // cond & then_lit | !cond & !then_lit
5787 // !(cond ^ then_lit)
5788 if (lhs == cond) {
5790 false);
5791 if (internal->lrat) {
5792 CADICAL_assert (g->pos_lhs_ids.size () == 2);
5793 lrat_chain.push_back (g->pos_lhs_ids[0].clause->id);
5794 lrat_chain.push_back (g->pos_lhs_ids[1].clause->id);
5795 }
5796 learn_congruence_unit (then_lit);
5797 garbage = true;
5798 } else if (not_lhs == cond) {
5800 false);
5801 if (internal->lrat) {
5802 CADICAL_assert (g->pos_lhs_ids.size () == 2);
5803 lrat_chain.push_back (g->pos_lhs_ids[0].clause->id);
5804 lrat_chain.push_back (g->pos_lhs_ids[1].clause->id);
5805 }
5806 learn_congruence_unit (-then_lit);
5807 garbage = true;
5808 } else if (not_lhs == then_lit) {
5810 false);
5811 if (internal->lrat) {
5812 CADICAL_assert (g->pos_lhs_ids.size () == 2);
5813 lrat_chain.push_back (g->pos_lhs_ids[0].clause->id);
5814 lrat_chain.push_back (g->pos_lhs_ids[1].clause->id);
5815 }
5816 learn_congruence_unit (cond);
5817 garbage = true;
5818 } else {
5819 new_tag = Gate_Type::XOr_Gate;
5820 g->lhs = not_lhs;
5821 CADICAL_assert (rhs[0] == cond);
5822 CADICAL_assert (rhs[1] == then_lit);
5823 CADICAL_assert (rhs[0] != g->lhs);
5824 CADICAL_assert (rhs[1] != g->lhs);
5826 false);
5827 }
5828 } else {
5829 shrink = false;
5830 rhs[2] = dst;
5832 }
5833 }
5834 if (!garbage && !internal->unsat) {
5835 CADICAL_assert (new_tag != Gate_Type::ITE_Gate || g->lhs != -rhs[1]);
5836 CADICAL_assert (new_tag != Gate_Type::ITE_Gate || g->lhs != -rhs[2]);
5837 if (shrink) {
5838 if (new_tag == Gate_Type::XOr_Gate) {
5839 bool negate_lhs = false;
5840 if (rhs[0] < 0) {
5841 rhs[0] = -rhs[0];
5842 negate_lhs = !negate_lhs;
5843 }
5844 if (rhs[1] < 0) {
5845 rhs[1] = -rhs[1];
5846 negate_lhs = !negate_lhs;
5847 }
5848 if (negate_lhs)
5849 g->lhs = -g->lhs;
5850 }
5851 if (internal->vlit (rhs[0]) >
5852 internal->vlit (
5853 rhs[1])) { // unlike kissat, we need to do it after negating
5854 std::swap (rhs[0], rhs[1]);
5856 }
5857 CADICAL_assert (internal->vlit (rhs[0]) < internal->vlit (rhs[1]));
5859 g->shrunken = true;
5860 rhs[2] = 0;
5861 g->tag = new_tag;
5862 rhs.resize (2);
5863 CADICAL_assert (rhs[0] != -rhs[1]);
5864 if (new_tag == Gate_Type::XOr_Gate) {
5865 if (rhs[0] == -g->lhs || rhs[1] == -g->lhs) {
5866 LOG (g, "special XOR:");
5867 const int unit = rhs[0] ^ -g->lhs ^ rhs[1];
5869 false);
5870 if (internal->lrat) {
5871 CADICAL_assert (g->pos_lhs_ids.size () == 2);
5872 lrat_chain.push_back (g->pos_lhs_ids[0].clause->id);
5873 lrat_chain.push_back (g->pos_lhs_ids[1].clause->id);
5874 }
5875 learn_congruence_unit (unit);
5876 garbage = true;
5877 } else if (rhs[0] == g->lhs || rhs[1] == g->lhs) {
5878 LOG (g, "special XOR:");
5879 const int unit = rhs[0] ^ g->lhs ^ rhs[1];
5881 false);
5882 if (internal->lrat) {
5883 CADICAL_assert (g->pos_lhs_ids.size () == 2);
5884 lrat_chain.push_back (g->pos_lhs_ids[0].clause->id);
5885 lrat_chain.push_back (g->pos_lhs_ids[1].clause->id);
5886 }
5887 learn_congruence_unit (-unit);
5888 garbage = true;
5889 } else {
5890 int i = 0;
5891 bool negated = false;
5892 for (int j = 0; j < 2; ++i, ++j) {
5893 CADICAL_assert (i <= j);
5894 const int lit = rhs[i] = rhs[j];
5895 const char v = internal->val (lit);
5896 if (v > 0) {
5897 --i;
5898 negated = !negated;
5899 } else if (v < 0) {
5900 --i;
5901 }
5902 }
5903 CADICAL_assert (i <= 2);
5904 rhs.resize (i);
5905 if (negated) {
5906 g->lhs = -g->lhs;
5907 }
5908 if (i != 2) {
5909 LOG (g, "removed units");
5910 }
5911 if (!i)
5912 garbage = true;
5913 else if (i == 1) {
5914#ifdef LOGGING
5915 for (auto litId : g->pos_lhs_ids) {
5916 LOG (litId.clause, "%d ->", litId.current_lit);
5917 }
5918#endif
5920 CADICAL_assert (!internal->lrat || g->pos_lhs_ids.size () == 2);
5921 Clause *c1 = nullptr, *c2 = nullptr;
5922 if (internal->lrat) {
5923 CADICAL_assert (g->pos_lhs_ids[0].clause);
5924 bool rhs_as_src_first =
5925 g->pos_lhs_ids[0].clause->literals[0] == g->lhs ||
5926 g->pos_lhs_ids[0].clause->literals[1] == g->lhs;
5927 c1 = (rhs_as_src_first ? g->pos_lhs_ids[0].clause
5928 : g->pos_lhs_ids[1].clause);
5929 c2 = (rhs_as_src_first ? g->pos_lhs_ids[1].clause
5930 : g->pos_lhs_ids[0].clause);
5933 } else {
5934 maybe_add_binary_clause (-g->lhs, g->rhs[0]);
5935 maybe_add_binary_clause (g->lhs, -g->rhs[0]);
5936 }
5937 merge_literals_equivalence (g->lhs, g->rhs[0], c1, c2);
5938 garbage = true;
5939 }
5940 }
5941 if (!garbage) {
5942 CADICAL_assert (rhs[0] != g->lhs);
5943 CADICAL_assert (rhs[1] != g->lhs);
5944 CADICAL_assert (rhs[0] != -g->lhs);
5945 CADICAL_assert (rhs[1] != -g->lhs);
5946 }
5947 }
5948
5949 if (!garbage) {
5950 g->hash = hash_lits (nonces, g->rhs);
5951 LOG (g, "rewritten");
5952
5953 if (internal->lrat) {
5954 if (new_tag == Gate_Type::XOr_Gate) {
5955#ifndef CADICAL_NDEBUG
5956 std::for_each (begin (g->pos_lhs_ids), end (g->pos_lhs_ids),
5957 [g] (LitClausePair l) {
5958 CADICAL_assert ((size_t) l.clause->size ==
5959 1 + g->arity ());
5960 });
5961#endif
5962 } else if (new_tag == Gate_Type::And_Gate) {
5963 // we have to get rid of one clause, two become binaries, and
5964 // becomes ternary
5965
5966#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
5967 for (auto id : g->pos_lhs_ids) {
5968 LOG (id.clause, "clause after rewriting:");
5969 CADICAL_assert (id.clause->size == 2);
5970 }
5971#endif
5972 CADICAL_assert (g->pos_lhs_ids.size () == 2 ||
5973 gate_contains (g, g->lhs));
5974 CADICAL_assert (g->neg_lhs_ids.size () == 1 ||
5975 gate_contains (g, g->lhs));
5976 CADICAL_assert (g->arity () == 2);
5977#ifndef CADICAL_NDEBUG
5978 std::for_each (
5979 begin (g->pos_lhs_ids), end (g->pos_lhs_ids),
5980 [] (LitClausePair l) { CADICAL_assert (l.clause->size == 2); });
5981#endif
5982 } else {
5983 CADICAL_assert (false);
5984#ifdef WIN32
5985 __assume(false);
5986#else
5987 __builtin_unreachable ();
5988#endif
5989 }
5990 }
5991 Gate *h;
5992 if (new_tag == Gate_Type::And_Gate) {
5994 h = find_and_lits (rhs);
5995 } else {
5998 h = find_xor_gate (g);
5999 }
6000 if (h) {
6001 garbage = true;
6002 if (new_tag == Gate_Type::XOr_Gate) {
6003 std::vector<LRAT_ID> reasons_implication, reasons_back;
6005 reasons_implication,
6006 reasons_back);
6007 if (merge_literals_lrat (g->lhs, h->lhs, reasons_implication,
6008 reasons_back))
6009 ++internal->stats.congruence.xors;
6010 } else {
6012 std::vector<LRAT_ID> reasons_implication, reasons_back;
6013 if (internal->lrat)
6014 merge_and_gate_lrat_produce_lrat (g, h, reasons_implication,
6015 reasons_back, false);
6016 if (merge_literals_lrat (g->lhs, h->lhs, reasons_implication,
6017 reasons_back))
6018 ++internal->stats.congruence.ands;
6019 }
6021 } else {
6022 garbage = false;
6023 if (g->indexed)
6024 remove_gate (git);
6025 index_gate (g);
6026 CADICAL_assert (g->arity () == 2);
6027 for (auto lit : g->rhs)
6028 if (lit != dst)
6029 if (lit != cond && lit != then_lit && lit != else_lit)
6030 connect_goccs (g, lit);
6031 if (g->tag == Gate_Type::And_Gate && !internal->lrat)
6032 for (auto lit : g->rhs)
6034 }
6035 }
6036 } else {
6037 LOG (g, "rewritten");
6038 if (internal->lrat)
6040 CADICAL_assert (rhs[0] != rhs[1]);
6041 CADICAL_assert (rhs[0] != rhs[2]);
6042 CADICAL_assert (rhs[1] != rhs[2]);
6043 CADICAL_assert (rhs[0] != -(rhs[1]));
6044 CADICAL_assert (rhs[0] != -(rhs[2]));
6045 CADICAL_assert (rhs[1] != -(rhs[2]));
6047 check_ite_lrat_reasons (g, false);
6048 bool negate_lhs;
6049 Gate *h = find_ite_gate (g, negate_lhs);
6050 CADICAL_assert (lhs == g->lhs);
6051 CADICAL_assert (not_lhs == -(g->lhs));
6052 if (negate_lhs)
6053 g->lhs = -lhs;
6055 if (internal->lrat)
6057 if (h) {
6058 garbage = true;
6060 check_ite_lrat_reasons (g, false);
6062 check_ite_lrat_reasons (h, false);
6063 int normalized_lhs = negate_lhs ? not_lhs : lhs;
6064 std::vector<LRAT_ID> extra_reasons_lit, extra_reasons_ulit;
6065 add_ite_matching_proof_chain (g, h, normalized_lhs, h->lhs,
6066 extra_reasons_lit,
6067 extra_reasons_ulit);
6068 if (merge_literals_lrat (normalized_lhs, h->lhs, extra_reasons_lit,
6069 extra_reasons_ulit))
6070 ++internal->stats.congruence.ites;
6072 CADICAL_assert (internal->unsat || chain.empty ());
6073 } else {
6074 garbage = false;
6075 if (g->indexed)
6076 remove_gate (git);
6077 LOG (g, "normalized");
6078 g->hash = hash_lits (nonces, g->rhs);
6079 index_gate (g);
6080 CADICAL_assert (g->arity () == 3);
6081 for (auto lit : g->rhs)
6082 if (lit != dst)
6083 if (lit != cond && lit != then_lit && lit != else_lit)
6084 connect_goccs (g, lit);
6085 }
6086 }
6087 }
6088 if (garbage && !internal->unsat)
6089 mark_garbage (g);
6090
6091 CADICAL_assert (chain.empty ());
6092}
6093
6095 size_t idx1,
6096 size_t idx2) {
6097 if (!internal->lrat)
6098 return;
6099 // TODO
6100 if (internal->val (lit) > 0)
6101 return;
6102 CADICAL_assert (internal->lrat);
6103 CADICAL_assert (g);
6104 CADICAL_assert (idx1 < g->pos_lhs_ids.size ());
6105 CADICAL_assert (idx2 < g->pos_lhs_ids.size ());
6106 CADICAL_assert (g->pos_lhs_ids.size () == 4);
6107
6108 CADICAL_assert (idx1 != idx2);
6109 Clause *c = g->pos_lhs_ids[idx1].clause;
6110 Clause *d = g->pos_lhs_ids[idx2].clause;
6111
6112 if (g->lhs == -g->rhs[0]) {
6113 LOG ("special case of LHS=-cond where only one clause in LRAT is needed is needed");
6114 size_t idx = (internal->val (g->rhs[1]) < 0 ? idx2 : idx1);
6115 c = produce_rewritten_clause_lrat (g->pos_lhs_ids[idx].clause, g->lhs, false, false);
6116 CADICAL_assert (c);
6117 // not possible to do this in a single lrat chain
6119 Rewrite (), g->lhs);
6120 CADICAL_assert (d);
6121 return;
6122 }
6123 if (g->lhs == g->rhs[0]) {
6124 LOG ("special case of LHS=cond where only one clause in LRAT is needed is needed");
6125 size_t idx = (internal->val (g->rhs[1]) > 0 ? idx2 : idx1);
6126 c = produce_rewritten_clause_lrat (g->pos_lhs_ids[idx].clause, g->lhs, false, false);
6127 CADICAL_assert (c);
6128 // not possible to do this in a single lrat chain
6130 Rewrite (), g->lhs);
6131 CADICAL_assert (d);
6132 return;
6133 }
6134
6135 c = produce_rewritten_clause_lrat (c, g->lhs, true);
6136 if (c) {
6137 lrat_chain.push_back (c->id);
6138 d = produce_rewritten_clause_lrat (d, g->lhs, true);
6139 if (d)
6140 lrat_chain.push_back (d->id);
6141 } else if (!c) {
6143 Rewrite (), g->lhs);
6144 CADICAL_assert (d);
6145 lrat_chain.push_back (d->id);
6146 }
6147}
6148
6149// TODO merge
6151 Gate *g, Gate *h, std::vector<LRAT_ID> &reasons_lrat_src,
6152 std::vector<LRAT_ID> &reasons_lrat_usrc, bool remove_units) {
6153 CADICAL_assert (internal->lrat);
6156 CADICAL_assert (g->neg_lhs_ids.size () <= 1);
6157 update_and_gate_build_lrat_chain (g, h, reasons_lrat_src,
6158 reasons_lrat_usrc, remove_units);
6159}
6160
6161// odd copy of rewrite_ite_gate_lrat_and
6162bool Closure::simplify_ite_gate_to_and (Gate *g, size_t idx1, size_t idx2,
6163 int removed_lit) {
6164 CADICAL_assert (internal->lrat_chain.empty ());
6165 CADICAL_assert (g->rhs.size () == 3);
6166#ifdef LOGGING
6167 for (auto litId : g->pos_lhs_ids) {
6168 LOG (litId.clause, "%d ->", litId.current_lit);
6169 }
6170#endif
6171 if (g->lhs == -g->rhs[0] || g->lhs == -g->rhs[1]) {
6172 if (internal->lrat) {
6173 Clause *c = g->pos_lhs_ids[idx1].clause;
6175 CADICAL_assert (!lrat_chain.empty ());
6176 }
6178 return true;
6179 }
6180 if (!internal->lrat)
6181 return false;
6182 g->degenerated_and_neg = (g->degenerated_and_neg || g->rhs[1] == -g->lhs || g->rhs[0] == -g->lhs);
6183 g->degenerated_and_pos = (g->degenerated_and_pos || g->rhs[0] == g->lhs || g->rhs[1] == g->lhs);
6184
6185 CADICAL_assert (g->pos_lhs_ids.size () == 4);
6186 CADICAL_assert (idx1 < g->pos_lhs_ids.size ());
6187 CADICAL_assert (idx2 < g->pos_lhs_ids.size ());
6188 int lit = g->pos_lhs_ids[idx2].current_lit, other = g->lhs;
6189 size_t new_idx1 = idx1;
6190 size_t new_idx2 = idx2;
6192 new_idx2);
6193
6194 if (g->pos_lhs_ids.size () == 1) {
6195 LOG (g, "degenerated AND gate");
6196 const int replacement_lit = (g->rhs[1] == g->lhs ? g->rhs[0] : g->rhs[1]);
6197 for (auto &litId : g->pos_lhs_ids) {
6198 CADICAL_assert (litId.clause);
6199 LOG (litId.clause, "%d ->", litId.current_lit);
6200 if (litId.current_lit == removed_lit)
6201 litId.current_lit = -replacement_lit;
6202 if (litId.current_lit == -removed_lit)
6203 litId.current_lit = replacement_lit;
6204 LOG (litId.clause, "%d ->", litId.current_lit);
6205 // TODO we need a replacement index
6206 CADICAL_assert (std::find (begin (*litId.clause), end (*litId.clause), litId.current_lit) !=
6207 end (*litId.clause));
6208 CADICAL_assert (std::find (begin (g->rhs), end (g->rhs), litId.current_lit) !=
6209 end (g->rhs));
6210 }
6211 return false;
6212 }
6213 CADICAL_assert (new_idx1 < g->pos_lhs_ids.size ());
6214 CADICAL_assert (new_idx2 < g->pos_lhs_ids.size ());
6215 Clause *c = g->pos_lhs_ids[new_idx1].clause;
6216 CADICAL_assert (c->size == 2);
6217 CADICAL_assert (new_idx1 != new_idx2);
6218 Clause *d = g->pos_lhs_ids[new_idx2].clause;
6219 CADICAL_assert (c != d);
6220 CADICAL_assert (c);
6221 CADICAL_assert (d);
6222 g->pos_lhs_ids.erase (std::remove_if (begin (g->pos_lhs_ids),
6223 end (g->pos_lhs_ids),
6224 [d] (const LitClausePair &p) {
6225 return p.clause == d;
6226 }),
6227 end (g->pos_lhs_ids));
6228 CADICAL_assert (g->pos_lhs_ids.size () == 2);
6230 CADICAL_assert (other);
6231 CADICAL_assert (lit != other);
6232 lrat_chain.push_back (c->id);
6233 lrat_chain.push_back (d->id);
6234 Clause *e = add_tmp_binary_clause (lit, -other);
6235
6236 auto long_clause =
6237 std::find_if (begin (g->pos_lhs_ids), end (g->pos_lhs_ids),
6238 [] (LitClausePair l) { return l.clause->size == 3; });
6239 CADICAL_assert (long_clause != end (g->pos_lhs_ids));
6240 LOG (long_clause->clause, "new long clause");
6241 g->neg_lhs_ids.push_back (*long_clause);
6242 g->pos_lhs_ids.erase (long_clause);
6243 CADICAL_assert (g->pos_lhs_ids.size () == 1);
6244 g->pos_lhs_ids.push_back ({lit, e});
6245
6246 const int first_lit = g->rhs[0];
6247 const int second_lit = g->rhs[1];
6248 for (auto &litId : g->pos_lhs_ids) {
6249 CADICAL_assert (litId.clause);
6250 LOG (litId.clause, "%s ->", LOGLIT (litId.current_lit));
6251 if (internal->val (litId.current_lit)) {
6252 CADICAL_assert (litId.clause->size == 2);
6253 int replacement_lit = 0;
6254 for (int i = 0; i < 2; ++i) {
6255 if (litId.clause->literals[i] == first_lit) {
6256 replacement_lit = first_lit;
6257 break;
6258 } else if (litId.clause->literals[i] == second_lit) {
6259 replacement_lit = second_lit;
6260 break;
6261 }
6262 }
6263 CADICAL_assert (replacement_lit);
6264
6265 litId.current_lit = replacement_lit;
6266 } else if (litId.current_lit == removed_lit)
6267 litId.current_lit = -g->rhs[0];
6268 else if (litId.current_lit == -removed_lit)
6269 litId.current_lit = g->rhs[0];
6270 LOG (litId.clause, "%d ->", litId.current_lit);
6271 // TODO we need a replacement index
6272 CADICAL_assert (std::find (begin (g->rhs), end (g->rhs), litId.current_lit) !=
6273 end (g->rhs));
6274 CADICAL_assert (std::find (begin (*litId.clause), end (*litId.clause),
6275 litId.current_lit) != end (*litId.clause));
6276 }
6277 return false;
6278}
6279
6281 std::vector<LitClausePair> &clauses,
6282 std::vector<LRAT_ID> &reasons_implication,
6283 std::vector<LRAT_ID> &reasons_back) {
6284 CADICAL_assert (clauses.size () == 4);
6286 CADICAL_assert (clauses.size () == 4);
6287 auto then_imp = clauses[0];
6288 auto neg_then_imp = clauses[1];
6289 auto else_imp = clauses[2];
6290 auto neg_else_imp = clauses[3];
6291 reasons_implication.push_back (then_imp.clause->id);
6292 reasons_implication.push_back (else_imp.clause->id);
6293 reasons_back.push_back (neg_then_imp.clause->id);
6294 reasons_back.push_back (neg_else_imp.clause->id);
6295}
6296
6298 Gate *g, std::vector<LRAT_ID> &reasons_implication,
6299 std::vector<LRAT_ID> &reasons_back, size_t idx1, size_t idx2) {
6300 CADICAL_assert (idx1 < g->pos_lhs_ids.size ());
6301 CADICAL_assert (idx2 < g->pos_lhs_ids.size ());
6302 Clause *c = g->pos_lhs_ids[idx1].clause;
6303 Clause *d = g->pos_lhs_ids[idx2].clause;
6304 push_id_and_rewriting_lrat_unit (c, Rewrite (), reasons_back, true,
6305 Rewrite (), g->lhs);
6306 push_id_and_rewriting_lrat_unit (d, Rewrite (), reasons_implication, true,
6307 Rewrite (), g->lhs);
6308 LOG (reasons_back, "LRAT");
6309 LOG (reasons_implication, "LRAT");
6310 // c = produce_rewritten_clause_lrat (c, g->lhs, false);
6311 // CADICAL_assert (c);
6312 // d = produce_rewritten_clause_lrat (d, g->lhs, false);
6313 // CADICAL_assert (d);
6314 // const int cond = g->rhs[0];
6315 // CADICAL_assert (internal->val (cond));
6316 // reasons_implication.push_back(internal->unit_id (internal->val (cond) >
6317 // 0 ? cond : -cond)); reasons_implication.push_back(c->id);
6318 // reasons_back.push_back(internal->unit_id (internal->val (cond) > 0 ?
6319 // cond : -cond)); reasons_back.push_back(d->id);
6320}
6321
6323 Gate *g, std::vector<LRAT_ID> &reasons_lrat,
6324 std::vector<LRAT_ID> &reasons_back_lrat, size_t idx1, size_t idx2) {
6325 CADICAL_assert (internal->lrat);
6326 Clause *c = g->pos_lhs_ids[idx1].clause;
6327 Clause *d = g->pos_lhs_ids[idx2].clause;
6328#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
6329 const int cond = g->rhs[0];
6330 CADICAL_assert (internal->val (cond));
6331 LOG ("cond = %d", cond);
6332#endif
6333#ifdef LOGGING
6334 for (auto litid : g->pos_lhs_ids)
6335 LOG (litid.clause, "clause in gate:");
6336#endif
6337 push_id_and_rewriting_lrat_unit (c, Rewrite (), reasons_lrat, true,
6338 Rewrite (), -g->lhs);
6339 push_id_and_rewriting_lrat_unit (d, Rewrite (), reasons_back_lrat, true,
6340 Rewrite (), g->lhs);
6341}
6342
6344 if (skip_ite_gate (g))
6345 return;
6346 LOG (g, "simplifying");
6347 CADICAL_assert (g->arity () == 3);
6348 bool garbage = true;
6349 int lhs = g->lhs;
6350 auto &rhs = g->rhs;
6351 const int cond = rhs[0];
6352 const int then_lit = rhs[1];
6353 const int else_lit = rhs[2];
6354 const signed char v_cond = internal->val (cond);
6355 const signed char v_else = internal->val (else_lit);
6356 const signed char v_then = internal->val (then_lit);
6357 std::vector<LRAT_ID> reasons_lrat, reasons_back_lrat;
6358 if (v_cond && v_else && v_then) { // propagation has set all value anyway
6359 LOG (g, "all values are set");
6360 CADICAL_assert (internal->val (g->lhs));
6361 garbage = true;
6362 } else if (v_cond > 0) {
6363 if (internal->lrat)
6364 simplify_ite_gate_condition_set (g, reasons_lrat, reasons_back_lrat,
6365 0, 1);
6366 if (merge_literals_lrat (lhs, then_lit, reasons_lrat,
6367 reasons_back_lrat)) {
6368 ++internal->stats.congruence.unary_ites;
6369 ++internal->stats.congruence.unaries;
6370 }
6371 } else if (v_cond < 0) {
6372 if (internal->lrat)
6373 simplify_ite_gate_condition_set (g, reasons_lrat, reasons_back_lrat,
6374 2, 3);
6375 if (merge_literals_lrat (lhs, else_lit, reasons_lrat,
6376 reasons_back_lrat)) {
6377 ++internal->stats.congruence.unary_ites;
6378 ++internal->stats.congruence.unaries;
6379 }
6380 } else {
6381 LOG ("then %d: %d; else %d: %d", then_lit, v_then, else_lit, v_else);
6382 std::vector<LRAT_ID> extra_reasons, extra_reasons_back;
6383 CADICAL_assert (v_then || v_else);
6384 if (v_then > 0 && v_else > 0) {
6387 } else if (v_then < 0 && v_else < 0) {
6389 learn_congruence_unit (-lhs);
6390 } else if (v_then > 0 && v_else < 0) {
6391 if (internal->lrat)
6392 simplify_ite_gate_then_else_set (g, extra_reasons,
6393 extra_reasons_back, 1, 2);
6394 if (merge_literals_lrat (lhs, cond, extra_reasons,
6395 extra_reasons_back)) {
6396 ++internal->stats.congruence.unary_ites;
6397 ++internal->stats.congruence.unaries;
6398 }
6399 } else if (v_then < 0 && v_else > 0) {
6400 if (internal->lrat)
6401 simplify_ite_gate_then_else_set (g, extra_reasons,
6402 extra_reasons_back, 0, 3);
6403 if (merge_literals_lrat (lhs, -cond, extra_reasons_back,
6404 extra_reasons)) {
6405 ++internal->stats.congruence.unary_ites;
6406 ++internal->stats.congruence.unaries;
6407 }
6408 } else {
6409 CADICAL_assert (!!v_then + !!v_else == 1);
6410 auto git = g->indexed ? table.find (g) : end (table);
6411 CADICAL_assert (!g->indexed || git != end (table));
6412 if (v_then > 0) {
6413 g->lhs = -lhs;
6414 rhs[0] = -cond;
6415 rhs[1] = -else_lit;
6416 simplify_ite_gate_to_and (g, 1, 3, then_lit);
6417 } else if (v_then < 0) {
6418 rhs[0] = -cond;
6419 rhs[1] = else_lit;
6420 simplify_ite_gate_to_and (g, 0, 2, -then_lit);
6421 } else if (v_else > 0) {
6422 g->lhs = -lhs;
6423 rhs[0] = -then_lit;
6424 rhs[1] = cond;
6425 simplify_ite_gate_to_and (g, 3, 1, else_lit);
6426 } else {
6427 CADICAL_assert (v_else < 0);
6428 rhs[0] = then_lit;
6429 rhs[1] = cond;
6430 simplify_ite_gate_to_and (g, 2, 0, -else_lit);
6431 }
6432 if (internal->unsat)
6433 return;
6434 if (internal->vlit (rhs[0]) > internal->vlit (rhs[1]))
6435 std::swap (rhs[0], rhs[1]);
6436 g->shrunken = true;
6438 rhs.resize (2);
6439 CADICAL_assert (is_sorted (begin (rhs), end (rhs),
6441 g->hash = hash_lits (nonces, rhs);
6443 Gate *h = find_and_lits (rhs);
6444 if (h) {
6446 std::vector<LRAT_ID> reasons_lrat, reasons_lrat_back;
6447 if (internal->lrat)
6448 merge_and_gate_lrat_produce_lrat (g, h, reasons_lrat,
6449 reasons_lrat_back, false);
6450 if (merge_literals_lrat (g->lhs, h->lhs, reasons_lrat,
6451 reasons_lrat_back)) {
6452 ++internal->stats.congruence.ites;
6453 }
6454 } else {
6455 remove_gate (git);
6456 index_gate (g);
6457 garbage = false;
6458 g->hash = hash_lits (nonces, g->rhs);
6459 for (auto lit : rhs)
6460 if (lit != cond && lit != then_lit && lit != else_lit) {
6461 connect_goccs (g, lit);
6462 }
6463
6464 if (rhs[0] == -g->lhs || rhs[1] == -g->lhs)
6466 g); // TODO Kissat does not do that, but it has also no
6467 // checks to verify that it cannot happen...
6468 }
6469 }
6470 }
6471 if (garbage && !internal->unsat)
6472 mark_garbage (g);
6473 ++internal->stats.congruence.simplified;
6474 ++internal->stats.congruence.simplified_ites;
6475}
6476
6478 Gate *g, Gate *h, int lhs1, int lhs2, std::vector<LRAT_ID> &reasons1,
6479 std::vector<LRAT_ID> &reasons2) {
6481 check_ite_lrat_reasons (h, false);
6482 CADICAL_assert (g->lhs == lhs1);
6483 CADICAL_assert (h->lhs == lhs2);
6484 if (lhs1 == lhs2)
6485 return;
6486 if (!internal->proof)
6487 return;
6488 LOG (g, "starting ITE matching proof chain");
6489 LOG (h, "starting ITE matching proof chain with");
6490 CADICAL_assert (unsimplified.empty ());
6491 CADICAL_assert (chain.empty ());
6492 if (internal->lrat)
6494 const auto &rhs = g->rhs;
6495 const int8_t flags_g = g->degenerated_ite;
6496 const int8_t flags_h = h->degenerated_ite;
6497 const int cond = rhs[0];
6498 LRAT_ID g_then_id = 0, g_neg_then_id = 0, g_neg_else_id = 0;
6499 LRAT_ID h_then_id = 0, h_neg_then_id = 0, h_else_id = 0;
6500 LRAT_ID g_else_id = 0, h_neg_else_id = 0;
6501 const bool degenerated_g_then = ite_flags_no_then_clauses (flags_g);
6502 const bool degenerated_g_else = ite_flags_no_else_clauses (flags_g);
6503 const bool degenerated_h_then = ite_flags_no_then_clauses (flags_h);
6504 const bool degenerated_h_else = ite_flags_no_else_clauses (flags_h);
6505
6506 const bool degenerated_g_cond = ite_flags_cond_lhs (flags_g);
6507 const bool degenerated_h_cond = ite_flags_cond_lhs (flags_h);
6508 CADICAL_assert (!(degenerated_g_cond && degenerated_h_cond));
6509
6510 const bool degenerated_g_not_cond = ite_flags_neg_cond_lhs (flags_g);
6511 const bool degenerated_h_not_cond = ite_flags_neg_cond_lhs (flags_h);
6512 CADICAL_assert (!(degenerated_g_not_cond && degenerated_h_not_cond));
6513
6514 if (internal->lrat) {
6515 // the code can produce tautologies in the case that:
6516 // a = (c ? a : e)
6517 // b = (c ? a : e)
6518 // (no clauses with (then) index a/-a)
6519 // but also for
6520 // a = (a ? t : e)
6521 // b = (a ? t : e)
6522 // (no clauses with (then) index -a and (else) index e)
6523 // and same for
6524 // a = (c ? t : a)
6525 // b = (c ? t : a)
6526 // (no clauses with (then) index a and (else) index -e)
6527 LOG (g, "get ids from");
6528 CADICAL_assert (g->pos_lhs_ids.size () == 4);
6529 auto &g_then_clause = g->pos_lhs_ids[0].clause;
6530 g_then_clause =
6531 g_then_clause ? produce_rewritten_clause_lrat (g_then_clause, g->lhs, false) : nullptr;
6532 if (g_then_clause)
6533 g_then_id = g_then_clause->id;
6534
6535 auto &g_neg_then_clause = g->pos_lhs_ids[1].clause;
6536 g_neg_then_clause =
6537 g_neg_then_clause ? produce_rewritten_clause_lrat (g_neg_then_clause, g->lhs, false) : nullptr;
6538 if (g_neg_then_clause)
6539 g_neg_then_id = g_neg_then_clause->id;
6540
6541 auto &g_else_clause = g->pos_lhs_ids[2].clause;
6542 g_else_clause =
6543 g_else_clause ? produce_rewritten_clause_lrat (g_else_clause, g->lhs, false) : g_else_clause;
6544 if (g_else_clause)
6545 g_else_id = g_else_clause->id;
6546
6547 auto &g_neg_else_clause = g->pos_lhs_ids[3].clause;
6548 g_neg_else_clause =
6549 g_neg_else_clause ? produce_rewritten_clause_lrat (g_neg_else_clause, g->lhs, false) : nullptr;
6550 if (g_neg_else_clause)
6551 g_neg_else_id = g_neg_else_clause->id;
6552
6553 LOG (h, "now clauses from");
6554 CADICAL_assert (h->pos_lhs_ids.size () == 4);
6555 auto &h_then_clause = h->pos_lhs_ids[0].clause;
6556 h_then_clause =
6557 h_then_clause ? produce_rewritten_clause_lrat (h_then_clause, h->lhs, false) : nullptr;
6558 if (h_then_clause)
6559 h_then_id = h_then_clause->id;
6560
6561 auto &h_neg_then_clause = h->pos_lhs_ids[1].clause;
6562 h_neg_then_clause =
6563 h_neg_then_clause ? produce_rewritten_clause_lrat (h_neg_then_clause, h->lhs, false) : nullptr;
6564 if (h_neg_then_clause)
6565 h_neg_then_id = h_neg_then_clause->id;
6566
6567 auto &h_else_clause = h->pos_lhs_ids[2].clause;
6568 h_else_clause =
6569 h_else_clause ? produce_rewritten_clause_lrat (h_else_clause, h->lhs, false) : nullptr;
6570 if (h_else_clause)
6571 h_else_id = h_else_clause->id;
6572
6573 auto &h_neg_else_clause = h->pos_lhs_ids[3].clause;
6574 h_neg_else_clause =
6575 h_neg_else_clause ? produce_rewritten_clause_lrat (h_neg_else_clause, h->lhs, false) : nullptr;
6576 if (h_neg_else_clause)
6577 h_neg_else_id = h_neg_else_clause->id;
6578
6579 }
6580
6581 if (degenerated_g_cond) {
6582 LOG ("special case: cond = lhs, g degenerated");
6583 unsimplified.push_back (-lhs1);
6584 unsimplified.push_back (lhs2);
6585 LRAT_ID id1 = 0;
6586 if (internal->lrat) {
6587 lrat_chain.push_back (g_then_id);
6588 lrat_chain.push_back (h_neg_then_id);
6589 }
6591
6592 unsimplified.clear ();
6593 unsimplified.push_back (lhs1);
6594 unsimplified.push_back (-lhs2);
6595 LRAT_ID id2 = 0;
6596 if (internal->lrat) {
6597 lrat_chain.push_back (g_neg_else_id);
6598 lrat_chain.push_back (h_else_id);
6599 }
6601
6602 CADICAL_assert (!internal->lrat || id1);
6603 CADICAL_assert (!internal->lrat || id2);
6604 reasons1.push_back (id1);
6605 reasons2.push_back (id2);
6606 unsimplified.clear ();
6607 return;
6608 }
6609
6610 if (degenerated_h_cond) {
6611 LOG ("special case: cond = lhs, h degenerated");
6612 unsimplified.push_back (lhs1); // potentially lhs1 == lhs2
6613 unsimplified.push_back (-lhs2);
6614 LRAT_ID id1 = 0;
6615 if (internal->lrat) {
6616 lrat_chain.push_back (h_then_id);
6617 lrat_chain.push_back (g_neg_then_id);
6618 }
6620
6621 unsimplified.clear ();
6622 unsimplified.push_back (-lhs1);
6623 unsimplified.push_back (lhs2);
6624 LRAT_ID id2 = 0;
6625 if (internal->lrat) {
6626 lrat_chain.push_back (h_neg_else_id);
6627 lrat_chain.push_back (g_else_id);
6628 }
6630
6631 CADICAL_assert (!internal->lrat || id1);
6632 CADICAL_assert (!internal->lrat || id2);
6633 reasons2.push_back (id1);
6634 reasons1.push_back (id2);
6635 unsimplified.clear ();
6636 return;
6637 }
6638
6639 if (degenerated_g_not_cond) {
6640 LOG ("special case: cond = -lhs, g degenerated");
6641 unsimplified.push_back (lhs1);
6642 unsimplified.push_back (-lhs2);
6643 LRAT_ID id1 = 0;
6644 if (internal->lrat) {
6645 CADICAL_assert (g_neg_then_id && h_then_id && g_else_id && h_neg_else_id);
6646 lrat_chain.push_back (g_neg_then_id);
6647 lrat_chain.push_back (h_then_id);
6648 }
6650
6651 unsimplified.clear ();
6652 unsimplified.push_back (-lhs1);
6653 unsimplified.push_back (lhs2);
6654 LRAT_ID id2 = -1;
6655
6656 if (internal->lrat) {
6657 lrat_chain.push_back (g_else_id);
6658 lrat_chain.push_back (h_neg_else_id);
6659 }
6661 CADICAL_assert (!internal->lrat || id1);
6662 CADICAL_assert (!internal->lrat || id2);
6663 reasons2.push_back (id1);
6664 reasons1.push_back (id2);
6665 unsimplified.clear ();
6666 return;
6667 }
6668
6669 if (degenerated_h_not_cond) {
6670 LOG ("special case: cond = -lhs, h degenerated");
6671 unsimplified.push_back (lhs1);
6672 unsimplified.push_back (-lhs2);
6673 LRAT_ID id1 = 0;
6674 if (internal->lrat) {
6675 CADICAL_assert (g_neg_then_id && h_then_id && g_else_id && h_neg_else_id);
6676 lrat_chain.push_back (h_neg_then_id);
6677 lrat_chain.push_back (g_then_id);
6678 }
6680
6681 unsimplified.clear ();
6682 unsimplified.push_back (-lhs1);
6683 unsimplified.push_back (lhs2);
6684 LRAT_ID id2 = -1;
6685
6686 if (internal->lrat) {
6687 lrat_chain.push_back (h_else_id);
6688 lrat_chain.push_back (g_neg_else_id);
6689 }
6691 CADICAL_assert (!internal->lrat || id1);
6692 CADICAL_assert (!internal->lrat || id2);
6693 reasons2.push_back (id1);
6694 reasons1.push_back (id2);
6695 unsimplified.clear ();
6696 return;
6697 }
6698
6699 LOG ("normal path");
6700 CADICAL_assert (!internal->lrat || degenerated_g_then ||
6701 (g_then_id && g_neg_then_id));
6702 CADICAL_assert (!internal->lrat || degenerated_g_else ||
6703 (g_else_id && g_neg_else_id));
6704 CADICAL_assert (!internal->lrat || degenerated_h_then ||
6705 (h_then_id && h_neg_then_id));
6706 CADICAL_assert (!internal->lrat || degenerated_h_else ||
6707 (h_else_id && h_neg_else_id));
6708 CADICAL_assert (!internal->lrat || g_then_id || h_neg_then_id);
6709 CADICAL_assert (!internal->lrat || g_neg_then_id || h_then_id);
6710 unsimplified.push_back (-lhs1);
6711 unsimplified.push_back (lhs2);
6712 unsimplified.push_back (-cond);
6713 LRAT_ID id1 = 0;
6714 if (degenerated_g_then || degenerated_h_then) {
6715 id1 = degenerated_g_then ? h_neg_then_id : g_then_id;
6716 } else {
6717 if (internal->lrat) {
6718 lrat_chain.push_back (g_then_id);
6719 lrat_chain.push_back (h_neg_then_id);
6720 }
6722 }
6723 unsimplified.pop_back ();
6724 unsimplified.push_back (cond);
6725
6726 LRAT_ID id2 = 0;
6727 if (degenerated_g_else || degenerated_h_else) {
6728 id2 = degenerated_g_else ? h_neg_else_id : g_else_id;
6729 } else {
6730 if (internal->lrat) {
6731 lrat_chain.push_back (h_neg_else_id);
6732 lrat_chain.push_back (g_else_id);
6733 }
6735 }
6736 unsimplified.pop_back ();
6737
6738 unsimplified.clear ();
6739 unsimplified.push_back (lhs1);
6740 unsimplified.push_back (-lhs2);
6741 unsimplified.push_back (-cond);
6742 CADICAL_assert (lrat_chain.empty ());
6743
6744 LRAT_ID id3 = 0;
6745 if (degenerated_g_then || degenerated_h_then) {
6746 id3 = degenerated_g_then ? h_then_id : g_neg_then_id;
6747 } else {
6748 if (internal->lrat) {
6749 // lrat_chain.push_back (g_then_id);
6750 // lrat_chain.push_back (h_neg_then_id);
6751 lrat_chain.push_back (g_neg_then_id);
6752 lrat_chain.push_back (h_then_id);
6753 }
6755 }
6756 unsimplified.pop_back ();
6757 unsimplified.push_back (cond);
6758 CADICAL_assert (lrat_chain.empty ());
6759
6760 LRAT_ID id4 = 0;
6761 if (degenerated_g_else || degenerated_h_else) {
6762 id4 = degenerated_g_else ? h_else_id : g_neg_else_id;
6763 } else {
6764 if (internal->lrat) {
6765 lrat_chain.push_back (g_neg_else_id);
6766 lrat_chain.push_back (h_else_id);
6767 }
6769 }
6770 unsimplified.pop_back ();
6771
6772 if (internal->lrat) {
6773 CADICAL_assert (!internal->lrat || (id1 && id2 && id3 && id4));
6774 reasons1.push_back (id1), reasons1.push_back (id2);
6775 reasons2.push_back (id3), reasons2.push_back (id4);
6776 }
6777
6778 unsimplified.clear ();
6779
6780 LOG ("finished ITE matching proof chain");
6781}
6782
6783Gate *Closure::new_ite_gate (int lhs, int cond, int then_lit, int else_lit,
6784 std::vector<LitClausePair> &&clauses) {
6785 CADICAL_assert (chain.empty ());
6786 if (else_lit == -then_lit) {
6787 if (then_lit < 0)
6788 LOG ("skipping ternary XOR %d := %d ^ %d", lhs, cond, -then_lit);
6789 else
6790 LOG ("skipping ternary XOR %d := %d ^ %d", -lhs, cond, then_lit);
6791 return nullptr;
6792 }
6793 if (else_lit == then_lit) {
6794 LOG ("found trivial ITE gate %d := %d ? %d : %d", (lhs), (cond),
6795 (then_lit), (else_lit));
6796 std::vector<LRAT_ID> reasons_implication, reasons_back;
6797 if (internal->lrat) {
6798 merge_ite_gate_same_then_else_lrat (clauses, reasons_implication,
6799 reasons_back);
6800 }
6801 if (merge_literals_lrat (lhs, then_lit, reasons_implication,
6802 reasons_back))
6803 ++internal->stats.congruence.trivial_ite;
6804 return 0;
6805 }
6806
6807 rhs.clear ();
6808 rhs.push_back (cond);
6809 rhs.push_back (then_lit);
6810 rhs.push_back (else_lit);
6811 LOG ("ITE gate %d = %d ? %d : %d", lhs, cond, then_lit, else_lit);
6812
6813 bool negate_lhs = false;
6814 Gate *g = new Gate;
6815 g->lhs = lhs;
6817 g->rhs = {rhs};
6818 g->pos_lhs_ids = clauses;
6819#ifdef LOGGING
6820 g->id = -1;
6821#endif
6822 Gate *h = find_ite_gate (g, negate_lhs);
6823 if (negate_lhs)
6824 lhs = -lhs;
6825 g->lhs = lhs;
6828 g, false); // due to merges done before during AND gate detection!
6829
6830 if (h) {
6832 std::vector<LRAT_ID> extra_reasons_lit, extra_reasons_ulit;
6833 add_ite_matching_proof_chain (h, g, h->lhs, lhs, extra_reasons_lit,
6834 extra_reasons_ulit);
6835 if (merge_literals_lrat (h, g, h->lhs, lhs, extra_reasons_lit,
6836 extra_reasons_ulit)) {
6837 ++internal->stats.congruence.ites;
6838 LOG ("found merged literals");
6839 }
6841 delete g;
6842 return h;
6843 } else {
6844 // do not sort clauses here obviously!
6845 // sort (begin (g->rhs), end (g->rhs));
6846 g->garbage = false;
6847 g->indexed = true;
6848 g->shrunken = false;
6849 g->hash = hash_lits (nonces, g->rhs);
6850 table.insert (g);
6851 ++internal->stats.congruence.gates;
6852#ifdef LOGGING
6853 g->id = fresh_id++;
6854#endif
6855 LOG (g, "creating new");
6856 if (internal->lrat)
6857 update_ite_flags (g);
6859 for (auto lit : g->rhs) {
6860 connect_goccs (g, lit);
6861 }
6862 }
6864 return g;
6865}
6866
6867void check_ite_lits_normalized (const std::vector<int> &lits) {
6868 CADICAL_assert (lits[0] > 0);
6869 CADICAL_assert (lits[1] > 0);
6870 CADICAL_assert (lits[0] != lits[1]);
6871 CADICAL_assert (lits[0] != lits[2]);
6872 CADICAL_assert (lits[1] != lits[2]);
6873 CADICAL_assert (lits[0] != -lits[1]);
6874 CADICAL_assert (lits[0] != -lits[2]);
6875 CADICAL_assert (lits[1] != -lits[2]);
6876#ifdef CADICAL_NDEBUG
6877 (void) lits;
6878#endif
6879}
6880
6881void Closure::check_ite_implied (int lhs, int cond, int then_lit,
6882 int else_lit) {
6883 if (internal->lrat)
6884 return;
6885 check_ternary (cond, -else_lit, lhs);
6886 check_ternary (cond, else_lit, -lhs);
6887 check_ternary (-cond, -then_lit, lhs);
6888 check_ternary (-cond, then_lit, -lhs);
6889}
6890
6892 bool normalized,
6893 int except) {
6894#ifndef CADICAL_NDEBUG
6895 if (lit == except) // happens for degenerated cases
6896 except = 0;
6897 const int normalize_lit =
6898 (lit == except ? except : find_eager_representative (lit));
6899 CADICAL_assert (!normalized || lit == -except || normalize_lit == lit);
6900 bool found = false;
6901 LOG (c, "looking for (normalized) %d in ", lit);
6902 for (auto other : *c) {
6903 const int normalize_other =
6904 (other == except ? except : find_eager_representative (other));
6905 LOG ("%d -> %d ", other, normalize_other);
6906 CADICAL_assert (!normalized || other == -except || normalize_other == other);
6907 if (normalize_other == normalize_lit) {
6908 found = true;
6909 break;
6910 }
6911 }
6912 CADICAL_assert (found);
6913#else
6914 (void) c, (void) lit, (void) normalized, (void) except;
6915#endif
6916}
6917
6918void Closure::check_ite_lrat_reasons (Gate *g, bool normalized) {
6919#ifndef CADICAL_NDEBUG
6921 if (!internal->lrat)
6922 return;
6923 CADICAL_assert (g->rhs.size () == 3);
6924 CADICAL_assert (is_tautological_ite_gate (g) || g->pos_lhs_ids.size () == 4);
6925 CADICAL_assert (g->neg_lhs_ids.empty ());
6926 CADICAL_assert (g->pos_lhs_ids.size () == 4);
6927#else
6928 (void) g, (void) normalized;
6929#endif
6930}
6931
6934 if (internal->lrat)
6935 return;
6936 check_ite_implied (g->lhs, g->rhs[0], g->rhs[1], g->rhs[2]);
6937}
6938
6940 std::vector<ClauseSize> &candidates) {
6941 std::vector<Clause *> ternary;
6942 glargecounts.resize (2 * internal->vsize, 0);
6943 for (auto c : internal->clauses) {
6944 if (c->garbage)
6945 continue;
6946 if (c->redundant)
6947 continue;
6948 if (c->size < 3)
6949 continue;
6950 unsigned size = 0;
6951
6952 CADICAL_assert (!c->garbage);
6953 for (auto lit : *c) {
6954 const signed char v = internal->val (lit);
6955 if (v < 0)
6956 continue;
6957 if (v > 0) {
6958 LOG (c, "deleting as satisfied due to %d", lit);
6959 internal->mark_garbage (c);
6960 goto CONTINUE_COUNTING_NEXT_CLAUSE;
6961 }
6962 if (size == 3)
6963 goto CONTINUE_COUNTING_NEXT_CLAUSE;
6964 size++;
6965 }
6966 if (size < 3)
6967 continue;
6968 CADICAL_assert (size == 3);
6969 ternary.push_back (c);
6970 LOG (c, "counting original ITE gate base");
6971 for (auto lit : *c) {
6972 if (!internal->val (lit))
6973 ++largecount (lit);
6974 }
6975 CONTINUE_COUNTING_NEXT_CLAUSE:;
6976 }
6977
6978 for (auto c : ternary) {
6979 CADICAL_assert (!c->garbage);
6980 CADICAL_assert (!c->redundant);
6981 unsigned positive = 0, negative = 0, twice = 0;
6982 for (auto lit : *c) {
6983 if (internal->val (lit))
6984 continue;
6985 const int count_not_lit = largecount (-lit);
6986 if (!count_not_lit)
6987 goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE;
6988 const unsigned count_lit = largecount (lit);
6989 CADICAL_assert (count_lit);
6990 if (count_lit > 1 && count_not_lit > 1)
6991 ++twice;
6992 if (lit < 0)
6993 ++negative;
6994 else
6995 ++positive;
6996 }
6997 if (twice < 2)
6998 goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE;
6999 CADICAL_assert (c->size != 2);
7000 for (auto lit : *c)
7001 internal->occs (lit).push_back (c);
7002 if (positive && negative)
7003 candidates.push_back (c);
7004 CONTINUE_WITH_NEXT_TERNARY_CLAUSE:;
7005 }
7006
7007 ternary.clear ();
7008}
7009
7011 condbin[0].clear ();
7012 condbin[1].clear ();
7013 condeq[0].clear ();
7014 condeq[1].clear ();
7015 glargecounts.clear ();
7016 internal->clear_occs ();
7017}
7018
7021 CADICAL_assert (condbin.empty ());
7022 for (auto c : internal->occs (lit)) {
7023 CADICAL_assert (c->size != 2);
7024 int first = 0, second = 0;
7025 for (auto other : *c) {
7026 if (internal->val (other))
7027 continue;
7028 if (other == lit)
7029 continue;
7030 if (!first)
7031 first = other;
7032 else {
7033 CADICAL_assert (!second);
7034 second = other;
7035 }
7036 }
7037 CADICAL_assert (first), CADICAL_assert (second);
7038 lit_implication p (first, second, c);
7039
7040 if (internal->vlit (first) < internal->vlit (second)) {
7041 CADICAL_assert (p.first == first);
7042 CADICAL_assert (p.second == second);
7043 } else {
7044 CADICAL_assert (internal->vlit (second) < internal->vlit (first));
7045 p.swap ();
7046 CADICAL_assert (p.first == second);
7047 CADICAL_assert (p.second == first);
7048 }
7049 LOG (c, "literal %d condition binary clause %d %d", lit, first, second);
7050 condbin.push_back (p);
7051 }
7052}
7053
7055 const int a = p.first;
7056 const int b = q.first;
7057 if (a < b)
7058 return true;
7059 if (b > a)
7060 return false;
7061 const int c = p.second;
7062 const int d = q.second;
7063 return (c < d);
7064}
7068 typedef uint64_t Type;
7070 uint64_t lita = internal->vlit (a.first);
7071 uint64_t litb = internal->vlit (a.second);
7072 return (lita << 32) + litb;
7073 }
7074};
7075
7080 const lit_implication &b) const {
7081 const auto s = litpair_rank (internal) (a);
7082 const auto t = litpair_rank (internal) (b);
7083 return s < t;
7084 }
7085};
7086
7087lit_implications::const_iterator
7089 int lit, lit_implications::const_iterator begin,
7090 lit_implications::const_iterator end) {
7091 LOG ("searching for %d in", lit);
7092 for (auto it = begin; it != end; ++it)
7093 LOG ("%d [%d]", it->first, it->second);
7094 lit_implications::const_iterator found = std::lower_bound (
7095 begin, end, lit_implication{lit, lit},
7096 [] (const lit_implication &a, const lit_implication &b) {
7097 return a.second < b.second;
7098 });
7099#ifndef CADICAL_NDEBUG
7100 auto found2 = std::binary_search (
7101 begin, end, lit_implication{lit, lit},
7102 [] (const lit_implication &a, const lit_implication &b) {
7103 return a.second < b.second;
7104 });
7105#endif
7106
7107 if (found < end && found->second == lit) {
7108 CADICAL_assert (found2 == (found < end));
7109 return found;
7110 }
7111 return end;
7112}
7113
7114void Closure::search_condeq (int lit, int pos_lit,
7115 lit_implications::const_iterator pos_begin,
7116 lit_implications::const_iterator pos_end,
7117 int neg_lit,
7118 lit_implications::const_iterator neg_begin,
7119 lit_implications::const_iterator neg_end,
7121 CADICAL_assert (neg_lit == -pos_lit);
7122 CADICAL_assert (pos_begin < pos_end);
7123 CADICAL_assert (neg_begin < neg_end);
7124 CADICAL_assert (pos_begin->first == pos_lit);
7125 CADICAL_assert (neg_begin->first == neg_lit);
7126 CADICAL_assert (pos_end <= neg_begin || neg_end <= pos_begin);
7127 for (lit_implications::const_iterator p = pos_begin; p != pos_end; p++) {
7128 const int other = p->second;
7129 const int not_other = -other;
7130 const lit_implications::const_iterator other_clause =
7131 find_lit_implication_second_literal (not_other, neg_begin, neg_end);
7132 CADICAL_assert (std::find (begin (*p->clause), end (*p->clause), lit) !=
7133 end (*p->clause));
7134 if (other_clause != neg_end) {
7135 CADICAL_assert (std::find (begin (*other_clause->clause),
7136 end (*other_clause->clause),
7137 neg_lit) != end (*other_clause->clause));
7138 CADICAL_assert (std::find (begin (*p->clause), end (*p->clause), other) !=
7139 end (*p->clause));
7140 lit_equivalence equivalence (neg_lit, other_clause->clause, other,
7141 p->clause);
7142 if (pos_lit > 0) {
7143 equivalence.negate_both ();
7144 }
7145 if (internal->lrat)
7146 equivalence.check_invariant ();
7147 LOG ("found conditional %d equivalence %d = %d", lit,
7148 equivalence.first, equivalence.second);
7149 CADICAL_assert (equivalence.first > 0);
7150 CADICAL_assert (internal->vlit (equivalence.first) <
7151 internal->vlit (equivalence.second));
7152 check_ternary (lit, neg_lit, -other);
7153 check_ternary (lit, -neg_lit, other);
7154 condeq.push_back (equivalence);
7155 if (equivalence.second < 0) {
7156 lit_equivalence inverse_equivalence =
7157 equivalence.swap ().negate_both ();
7158 condeq.push_back (inverse_equivalence);
7159 if (internal->lrat)
7160 inverse_equivalence.check_invariant ();
7161 } else {
7162 lit_equivalence inverse_equivalence = equivalence.swap ();
7163 condeq.push_back (inverse_equivalence);
7164 if (internal->lrat)
7165 inverse_equivalence.check_invariant ();
7166 }
7167 }
7168 }
7169#ifndef LOGGING
7170 (void) lit;
7171#endif
7172}
7173
7176 const lit_implications::const_iterator begin = condbin.cbegin ();
7177 const lit_implications::const_iterator end = condbin.cend ();
7178 lit_implications::const_iterator pos_begin = begin;
7179 int next_lit = 0;
7180
7181#ifdef LOGGING
7182 for (const auto &pair : condbin)
7183 LOG ("unsorted conditional %d equivalence %d = %d", lit, pair.first,
7184 pair.second);
7185#endif
7186 LOG ("searching for first positive literal for lit %d", lit);
7187 for (;;) {
7188 if (pos_begin == end)
7189 return;
7190 next_lit = pos_begin->first;
7191 LOG ("checking %d", next_lit);
7192 if (next_lit > 0)
7193 break;
7194 pos_begin++;
7195 }
7196
7197 for (;;) {
7198 CADICAL_assert (pos_begin != end);
7199 CADICAL_assert (next_lit == pos_begin->first);
7200 CADICAL_assert (next_lit > 0);
7201 const int pos_lit = next_lit;
7202 lit_implications::const_iterator pos_end = pos_begin + 1;
7203 LOG ("searching for first other literal after finding lit %d",
7204 next_lit);
7205 for (;;) {
7206 if (pos_end == end)
7207 return;
7208 next_lit = pos_end->first;
7209 if (next_lit != pos_lit)
7210 break;
7211 pos_end++;
7212 }
7213 CADICAL_assert (pos_end != end);
7214 CADICAL_assert (next_lit == pos_end->first);
7215 const int neg_lit = -pos_lit;
7216 if (next_lit != neg_lit) {
7217 if (next_lit < 0) {
7218 pos_begin = pos_end + 1;
7219 LOG ("next_lit %d < 0", next_lit);
7220 for (;;) {
7221 if (pos_begin == end)
7222 return;
7223 next_lit = pos_begin->first;
7224 if (next_lit > 0)
7225 break;
7226 pos_begin++;
7227 }
7228 } else
7229 pos_begin = pos_end;
7230 continue;
7231 }
7232 const lit_implications::const_iterator neg_begin = pos_end;
7233 lit_implications::const_iterator neg_end = neg_begin + 1;
7234 while (neg_end != end) {
7235 next_lit = neg_end->first;
7236 if (next_lit != neg_lit)
7237 break;
7238 neg_end++;
7239 }
7240#ifdef LOGGING
7241 for (lit_implications::const_iterator p = pos_begin; p != pos_end; p++)
7242 LOG ("conditional %d binary clause %d %d with positive %d", (lit),
7243 (p->first), (p->second), (pos_lit));
7244 for (lit_implications::const_iterator p = neg_begin; p != neg_end; p++)
7245 LOG ("conditional %d binary clause %d %d with negative %d", (lit),
7246 (p->first), (p->second), (neg_lit));
7247#endif
7248 const size_t pos_size = pos_end - pos_begin;
7249 const size_t neg_size = neg_end - neg_begin;
7250 if (pos_size <= neg_size) {
7251 LOG ("searching negation of %zu conditional binary clauses "
7252 "with positive %d in %zu conditional binary clauses with %d",
7253 pos_size, (pos_lit), neg_size, (neg_lit));
7254 search_condeq (lit, pos_lit, pos_begin, pos_end, neg_lit, neg_begin,
7255 neg_end, condeq);
7256 } else {
7257 LOG ("searching negation of %zu conditional binary clauses "
7258 "with negative %d in %zu conditional binary clauses with %d",
7259 neg_size, (neg_lit), pos_size, (pos_lit));
7260 search_condeq (lit, neg_lit, neg_begin, neg_end, pos_lit, pos_begin,
7261 pos_end, condeq);
7262 }
7263 if (neg_end == end)
7264 return;
7265 CADICAL_assert (next_lit == neg_end->first);
7266 if (next_lit < 0) {
7267 pos_begin = neg_end + 1;
7268 for (;;) {
7269 if (pos_begin == end)
7270 return;
7271 next_lit = pos_begin->first;
7272 if (next_lit > 0)
7273 break;
7274 pos_begin++;
7275 }
7276 } else
7277 pos_begin = neg_end;
7278 }
7279}
7280
7284 CADICAL_assert (condbin.empty ());
7285 CADICAL_assert (condeq.empty ());
7286 CADICAL_assert (internal->occs (lit).size () > 1);
7288 MSORT (internal->opts.radixsortlim, begin (condbin), end (condbin),
7290
7292 MSORT (internal->opts.radixsortlim, begin (condbin), end (condbin),
7294
7295#ifdef LOGGING
7296 for (auto pair : condeq)
7297 LOG ("sorted conditional %d equivalence %d = %d", lit, pair.first,
7298 pair.second);
7299 LOG ("found %zu conditional %d equivalences", condeq.size (), lit);
7300
7301#endif
7302}
7303
7305 lit_equivalences &not_condeq) {
7306 LOG ("merging cond for literal %d", cond);
7307 auto q = begin (not_condeq);
7308 const auto end_not_condeq = end (not_condeq);
7309 for (auto p : condeq) {
7310 const int lhs = p.first;
7311 const int then_lit = p.second;
7312 if (internal->lrat)
7313 p.check_invariant ();
7314 CADICAL_assert (lhs > 0);
7315 while (q != end_not_condeq && q->first < lhs)
7316 ++q;
7317 while (q != end_not_condeq && q->first == lhs) {
7318 LOG ("looking when %d at p= %d %d", cond, p.first, p.second);
7319 LOG ("looking when %d at %d %d", -cond, q->first, q->second);
7320 lit_equivalence not_cond_pair = *q++;
7321 const int else_lit = not_cond_pair.second;
7322 std::vector<LitClausePair> clauses;
7323 if (internal->lrat) {
7324 // The then/else literal is the second of the pair, hence the swap
7325 // of the reasons
7326 CADICAL_assert (p.first_clause && p.second_clause);
7327 CADICAL_assert (not_cond_pair.first_clause && not_cond_pair.second_clause);
7328 LOG (p.second_clause, "pairing %d", then_lit);
7329 LOG (p.first_clause, "pairing %d", -then_lit);
7330 LOG (not_cond_pair.second_clause, "pairing %d", else_lit);
7331 LOG (not_cond_pair.first_clause, "pairing %d", -else_lit);
7332 clauses.push_back (LitClausePair (then_lit, p.second_clause));
7333 clauses.push_back (LitClausePair (-then_lit, p.first_clause));
7334 clauses.push_back (
7335 LitClausePair (else_lit, not_cond_pair.second_clause));
7336 clauses.push_back (
7337 LitClausePair (-else_lit, not_cond_pair.first_clause));
7338 if (internal->lrat)
7339 not_cond_pair.check_invariant ();
7340 }
7341 new_ite_gate (lhs, cond, then_lit, else_lit, std::move (clauses));
7342 if (internal->unsat)
7343 return;
7344 }
7345 }
7346}
7347
7349 LOG ("search for ITE for literal %d ", lit);
7351 if (!condeq[0].empty ()) {
7353 if (!condeq[1].empty ()) {
7354 if (lit < 0)
7355 merge_condeq (-lit, condeq[0], condeq[1]);
7356 else
7357 merge_condeq (lit, condeq[1], condeq[0]);
7358 }
7359 }
7360
7361 condbin[0].clear ();
7362 condbin[1].clear ();
7363 condeq[0].clear ();
7364 condeq[1].clear ();
7365}
7366
7368 const int lit = idx;
7369 const int not_lit = -idx;
7370
7371 auto lit_watches = internal->occs (lit);
7372 auto not_lit_watches = internal->occs (not_lit);
7373 const size_t size_lit_watches = lit_watches.size ();
7374 const size_t size_not_lit_watches = not_lit_watches.size ();
7375 if (size_lit_watches <= size_not_lit_watches) {
7376 if (size_lit_watches > 1)
7378 } else {
7379 if (size_not_lit_watches > 1)
7381 }
7382}
7383
7386 if (!internal->opts.congruenceite)
7387 return;
7388 START (extractites);
7389 std::vector<ClauseSize> candidates;
7390
7391 init_ite_gate_extraction (candidates);
7392
7393 for (auto idx : internal->vars) {
7394 if (internal->flags (idx).active ()) {
7396 if (internal->unsat)
7397 break;
7398 }
7399 }
7400 // Kissat has an alternative version MERGE_CONDITIONAL_EQUIVALENCES
7402 STOP (extractites);
7403}
7404
7405/*------------------------------------------------------------------------*/
7407 START (extract);
7409 CADICAL_assert (internal->unsat || lrat_chain.empty ());
7410 CADICAL_assert (internal->unsat || chain.empty ());
7411 if (internal->unsat || internal->terminated_asynchronously ()) {
7412 STOP (extract);
7413 return;
7414 }
7416 CADICAL_assert (internal->unsat || lrat_chain.empty ());
7417 CADICAL_assert (internal->unsat || chain.empty ());
7418
7419 if (internal->unsat || internal->terminated_asynchronously ()) {
7420 STOP (extract);
7421 return;
7422 }
7424 STOP (extract);
7425}
7426
7427/*------------------------------------------------------------------------*/
7428// top level function to extract gate
7430 if (unsat)
7431 return false;
7432 if (!opts.congruence)
7433 return false;
7434 if (level)
7435 backtrack ();
7436 if (!propagate ()) {
7438 return false;
7439 }
7440 if (congruence_delay.bumpreasons.limit) {
7441 LOG ("delaying congruence %" PRId64 " more times",
7442 congruence_delay.bumpreasons.limit);
7443 congruence_delay.bumpreasons.limit--;
7444 return false;
7445 }
7446
7447 // to remove false literals from clauses
7448 // It makes the technique stronger as long clauses
7449 // can become binary / ternary
7450 // garbage_collection ();
7451
7452 const int64_t old = stats.congruence.congruent;
7453 const int old_merged = stats.congruence.congruent;
7454
7455 // congruencebinary is already doing it (and more actually)
7456 if (!internal->opts.congruencebinaries) {
7457 const bool dedup = opts.deduplicate;
7458 opts.deduplicate = true;
7460 opts.deduplicate = dedup;
7461 }
7462 ++stats.congruence.rounds;
7463 clear_watches ();
7464 // connect_binary_watches ();
7465
7466 START_SIMPLIFIER (congruence, CONGRUENCE);
7467 Closure closure (this);
7468
7469 closure.init_closure ();
7470 CADICAL_assert (unsat || closure.chain.empty ());
7471 CADICAL_assert (unsat || lrat_chain.empty ());
7472 closure.extract_binaries ();
7473 CADICAL_assert (unsat || closure.chain.empty ());
7474 CADICAL_assert (unsat || lrat_chain.empty ());
7475 closure.extract_gates ();
7476 CADICAL_assert (unsat || closure.chain.empty ());
7477 CADICAL_assert (unsat || lrat_chain.empty ());
7478 internal->clear_watches ();
7479 internal->connect_watches ();
7480 closure.reset_extraction ();
7481
7482 if (!unsat) {
7483 closure.find_units ();
7484 CADICAL_assert (unsat || closure.chain.empty ());
7485 CADICAL_assert (unsat || lrat_chain.empty ());
7486 if (!internal->unsat) {
7487 closure.find_equivalences ();
7488 CADICAL_assert (unsat || closure.chain.empty ());
7489 CADICAL_assert (unsat || lrat_chain.empty ());
7490
7491 if (!unsat) {
7492 const int propagated = closure.propagate_units_and_equivalences ();
7493 CADICAL_assert (unsat || closure.chain.empty ());
7494 if (!unsat && propagated)
7495 closure.forward_subsume_matching_clauses ();
7496 }
7497 }
7498 }
7499
7500 closure.reset_closure ();
7501 internal->clear_watches ();
7502 internal->connect_watches ();
7503 if (!internal->unsat) {
7504 propagated2 = propagated = 0;
7505 propagate ();
7506 }
7507 CADICAL_assert (closure.new_unwatched_binary_clauses.empty ());
7508 internal->reset_occs ();
7509 internal->reset_noccs ();
7510 CADICAL_assert (!internal->occurring ());
7511 CADICAL_assert (lrat_chain.empty ());
7512
7513 const int64_t new_merged = stats.congruence.congruent;
7514
7515#ifndef CADICAL_QUIET
7516 phase ("congruence-phase", stats.congruence.rounds, "merged %ld literals",
7517 new_merged - old_merged);
7518#endif
7519 if (!unsat && !internal->propagate ())
7520 unsat = true;
7521
7522 STOP_SIMPLIFIER (congruence, CONGRUENCE);
7523 report ('c', !opts.reportall && !(stats.congruence.congruent - old));
7524#ifndef CADICAL_NDEBUG
7525 size_t watched = 0;
7526 for (auto v : vars) {
7527 for (auto sgn = -1; sgn <= 1; sgn += 2) {
7528 const int lit = v * sgn;
7529 for (auto w : watches (lit)) {
7530 if (w.binary ())
7531 CADICAL_assert (!w.clause->garbage);
7532 if (w.clause->garbage)
7533 continue;
7534 ++watched;
7535 LOG (w.clause, "watched");
7536 }
7537 }
7538 }
7539 LOG ("and now the clauses:");
7540 size_t nb_clauses = 0;
7541 for (auto c : clauses) {
7542 if (c->garbage)
7543 continue;
7544 LOG (c, "watched");
7545 ++nb_clauses;
7546 }
7547 CADICAL_assert (watched == nb_clauses * 2);
7548#endif
7549 CADICAL_assert (!internal->occurring ());
7550
7551 if (new_merged == old_merged) {
7552 congruence_delay.bumpreasons.interval++;
7553 } else {
7554 congruence_delay.bumpreasons.interval /= 2;
7555 }
7556
7557 LOG ("delay congruence internal %" PRId64,
7558 congruence_delay.bumpreasons.interval);
7559 congruence_delay.bumpreasons.limit =
7560 congruence_delay.bumpreasons.interval;
7561
7562 return new_merged != old_merged;
7563}
7564
7565} // namespace CaDiCaL
7566
unsigned int uint32_t
Definition Fxch.h:32
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define UINT32_MAX
Definition pstdint.h:388
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
ABC_NAMESPACE_IMPL_START typedef signed char value
uint64_t next()
Definition random.hpp:36
#define add_ite_matching_proof_chain(...)
#define check_ternary
Definition congruence.c:728
#define check_ite_lits_normalized
Definition congruence.c:339
#define check_and_gate_implied(...)
Definition congruence.c:723
#define add_xor_shrinking_proof_chain(...)
#define add_ite_turned_and_binary_clauses
struct closure closure
Definition congruence.c:145
#define check_ite_implied
Definition congruence.c:729
#define add_xor_matching_proof_chain(...)
#define check_ite_gate_implied
Definition congruence.c:730
#define check_xor_gate_implied
Definition congruence.c:727
#define MAX_ARITY
bool tautology()
bool pos
Definition globals.c:30
Cube * p
Definition exorList.c:222
#define LOGLIT(...)
Definition logging.hpp:99
bool ite_flags_neg_cond_lhs(int8_t flag)
bool ite_flags_cond_lhs(int8_t flag)
int sign(int lit)
Definition util.hpp:22
void inc_lits(vector< int > &lits)
std::vector< lit_equivalence > lit_equivalences
bool less_litpair(lit_equivalence p, lit_equivalence q)
void update_ite_flags(Gate *g)
bool gate_contains(Gate *g, int lit)
std::vector< lit_implication > lit_implications
bool ite_flags_no_then_clauses(int8_t flag)
void check_correct_ite_flags(const Gate *const g)
bool ite_flags_no_else_clauses(int8_t flag)
bool parity(unsigned a)
Definition util.hpp:71
vector< Gate * > GOccs
std::string string_of_gate(Gate_Type t)
int64_t LRAT_ID
bool parity_lits(const vector< int > &lits)
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
#define MSORT(LIMIT, FIRST, LAST, RANK, LESS)
Definition radix.hpp:173
int lit
Definition satVec.h:130
size_t bytes() const
Definition clause.hpp:157
literal_iterator begin()
Definition clause.hpp:131
static size_t bytes(int size)
Definition clause.hpp:137
unsigned used
Definition clause.hpp:59
bool instantiated
Definition clause.hpp:51
literal_iterator end()
Definition clause.hpp:132
vector< LRAT_ID > eager_representant_id
LRAT_ID & representative_id(int lit)
void simplify_ite_gate_condition_set(Gate *g, std::vector< LRAT_ID > &reasons_lrat, std::vector< LRAT_ID > &reasons_back_lrat, size_t idx1, size_t idx2)
vector< int > lits
Gate * find_xor_gate(Gate *)
void produce_representative_lrat(int lit)
vector< LRAT_ID > lrat_chain
void simplify_xor_gate(Gate *g)
void search_condeq(int lit, int pos_lit, lit_implications::const_iterator pos_begin, lit_implications::const_iterator pos_end, int neg_lit, lit_implications::const_iterator neg_begin, lit_implications::const_iterator neg_end, lit_equivalences &condeq)
Gate * find_ite_gate(Gate *, bool &)
void merge_condeq(int cond, lit_equivalences &condeq, lit_equivalences &not_condeq)
bool simplify_ite_gate_to_and(Gate *g, size_t idx1, size_t idx2, int removed)
vector< int > unsimplified
Gate * new_xor_gate(const vector< LitClausePair > &, int)
vector< LitClausePair > lrat_chain_and_gate
void check_and_gate_implied(Gate *g)
vector< int > chain
bool rewriting_lhs(Gate *g, int dst)
Gate * find_and_lits(const vector< int > &rhs, Gate *except=nullptr)
void simplify_and_gate(Gate *g)
void simplify_unit_xor_lrat_clauses(const vector< LitClausePair > &, int)
Clause * learn_binary_tmp_or_full_clause(int a, int b)
Clause * add_tmp_binary_clause(int a, int b)
LRAT_ID find_eager_representative_lrat(int lit)
int & representative(int lit)
void extract_ite_gates_of_variable(int idx)
vector< GOccs > gtab
void set_mu4_reason(int lit, Clause *c)
void set_mu2_reason(int lit, Clause *c)
LRAT_ID simplify_and_add_to_proof_chain(vector< int > &unsimplified, LRAT_ID delete_id=0)
void produce_eager_representative_lrat(int lit)
void merge_ite_gate_same_then_else_lrat(std::vector< LitClausePair > &clauses, std::vector< LRAT_ID > &reasons_implication, std::vector< LRAT_ID > &reasons_back)
Clause * find_large_xor_side_clause(std::vector< int > &lits)
void push_id_and_rewriting_lrat_unit(Clause *c, Rewrite rewrite1, std::vector< LRAT_ID > &chain, bool=true, Rewrite rewrite2=Rewrite(), int execept_lhs=0, int except_lhs2=0)
void check_ite_implied(int lhs, int cond, int then_lit, int else_lit)
void compute_rewritten_clause_lrat_simple(Clause *c, int except)
void init_xor_gate_extraction(std::vector< Clause * > &candidates)
vector< int > representant
void check_binary_implied(int a, int b)
char & lazy_propagated(int lit)
void push_id_on_chain(std::vector< LRAT_ID > &chain, Clause *c)
void push_lrat_unit(int lit)
void push_id_and_rewriting_lrat_full(Clause *c, Rewrite rewrite1, std::vector< LRAT_ID > &chain, bool=true, Rewrite rewrite2=Rewrite(), int execept_lhs=0, int except_lhs2=0)
void merge_and_gate_lrat_produce_lrat(Gate *g, Gate *h, std::vector< LRAT_ID > &reasons_lrat, std::vector< LRAT_ID > &reasons_lrat_back, bool remove_units=true)
uint64_t & new_largecounts(int lit)
std::array< lit_equivalences, 2 > condeq
void rewrite_xor_gate(Gate *g, int dst, int src)
void update_and_gate_unit_build_lrat_chain(Gate *g, int src, LRAT_ID id1, LRAT_ID id2, int dst, std::vector< LRAT_ID > &extra_reasons_lit, std::vector< LRAT_ID > &extra_reasons_ulit)
void shrink_and_gate(Gate *g, int falsified=0, int clashing=0)
bool rewrite_gates(int dst, int src, LRAT_ID id1, LRAT_ID id2)
std::array< int, 16 > nonces
vector< uint64_t > glargecounts
int find_representative_and_compress(int, bool update_eager=true)
bool normalize_ite_lits_gate(Gate *rhs)
void produce_ite_merge_lhs_then_else_reasons(Gate *g, std::vector< LRAT_ID > &reasons_implication, std::vector< LRAT_ID > &reasons_back, std::vector< LRAT_ID > &reasons_unit, bool, bool &)
void extract_xor_gates_with_base_clause(Clause *c)
void import_lazy_and_find_eager_representative_and_compress_both(int)
Gate * find_first_and_gate(Clause *base_clause, int lhs)
void add_ite_matching_proof_chain(Gate *g, Gate *h, int lhs1, int lhs2, std::vector< LRAT_ID > &reasons1, std::vector< LRAT_ID > &reasons2)
void learn_congruence_unit_when_lhs_set(Gate *g, int src, LRAT_ID id1, LRAT_ID id2, int dst)
uint32_t number_from_xor_reason(const std::vector< int > &rhs, int, int except2=0, bool flip=0)
std::array< lit_implications, 2 > condbin
void check_contained_module_rewriting(Clause *c, int lit, bool, int except)
LRAT_ID & eager_representative_id(int lit)
vector< signed char > marks
vector< int > eager_representant
void update_and_gate(Gate *g, GatesTable::iterator, int src, int dst, LRAT_ID id1, LRAT_ID id2, int falsified=0, int clashing=0)
int find_lrat_representative_with_marks(int lit)
queue< int > schedule
LitClausePair marked_mu1(int lit)
Clause * maybe_add_binary_clause(int a, int b)
vector< CompactBinary > binaries
bool learn_congruence_unit(int unit, bool=false, bool=false)
void learn_congruence_unit_falsifies_lrat_chain(Gate *g, int src, int dst, int clashing, int falsified, int unit)
bool rewrite_gate(Gate *g, int dst, int src, LRAT_ID id1, LRAT_ID id2)
void init_ite_gate_extraction(std::vector< ClauseSize > &candidates)
vector< Clause * > extra_clauses
vector< LRAT_ID > representant_id
void sort_literals_by_var(vector< int > &rhs)
bool merge_literals_lrat(Gate *g, Gate *h, int lit, int other, const std::vector< LRAT_ID > &={}, const std::vector< LRAT_ID > &={})
Internal *const internal
bool find_binary(int, int) const
void check_not_tmp_binary_clause(Clause *c)
void simplify_ite_gate_produce_unit_lrat(Gate *g, int lit, size_t idx1, size_t idx2)
int find_eager_representative_and_compress(int)
void check_ternary(int a, int b, int c)
void produce_rewritten_clause_lrat_and_clean(vector< LitClausePair > &, int execept_lhs=0, bool=true)
uint64_t & largecount(int lit)
bool merge_literals_equivalence(int lit, int other, Clause *c1, Clause *c2)
void rewrite_ite_gate_update_lrat_reasons(Gate *g, int src, int dst)
vector< int > clause
Gate * new_ite_gate(int lhs, int cond, int then_lit, int else_lit, std::vector< LitClausePair > &&clauses)
void add_xor_matching_proof_chain(Gate *g, int lhs1, const vector< LitClausePair > &, int lhs2, vector< LRAT_ID > &, vector< LRAT_ID > &)
vector< int > rhs
void rewrite_ite_gate(Gate *g, int dst, int src)
void update_and_gate_build_lrat_chain(Gate *g, Gate *h, std::vector< LRAT_ID > &extra_reasons_lit, std::vector< LRAT_ID > &extra_reasons_ulit, bool remove_units=true)
int & eager_representative(int lit)
lit_implications::const_iterator find_lit_implication_second_literal(int lit, lit_implications::const_iterator begin, lit_implications::const_iterator end)
void check_ite_lrat_reasons(Gate *g, bool=false)
void simplify_ite_gate(Gate *g)
bool rewrite_ite_gate_to_and(Gate *g, int dst, int src, size_t c, size_t d, int cond_lit_to_learn_if_degenerated)
uint64_t & largecounts(int lit)
void rewrite_and_gate(Gate *g, int dst, int src, LRAT_ID id1, LRAT_ID id2)
void promote_clause(Clause *)
LitClausePair marked_mu2(int lit)
LRAT_ID check_and_add_to_proof_chain(vector< int > &clause)
uint32_t number_from_xor_reason_reversed(const std::vector< int > &rhs)
void add_clause_to_chain(std::vector< int >, LRAT_ID)
Clause * maybe_promote_tmp_binary_clause(Clause *)
void simplify_and_sort_xor_lrat_clauses(const vector< LitClausePair > &, vector< LitClausePair > &, int, int except2=0, bool flip=0)
vector< uint64_t > gnew_largecounts
void schedule_literal(int lit)
int find_representative(int lit)
void extract_ite_gates_of_literal(int)
void produce_ite_merge_then_else_reasons(Gate *g, int dst, int src, std::vector< LRAT_ID > &reasons_implication, std::vector< LRAT_ID > &reasons_back)
LitClausePair marked_mu4(int lit)
bool find_subsuming_clause(Clause *c)
void find_conditional_equivalences(int lit, lit_implications &condbin, lit_equivalences &condeq)
std::vector< std::pair< size_t, size_t > > offsetsize
std::vector< char > lazy_propagated_idx
size_t propagate_units_and_equivalences()
void gate_sort_lrat_reasons(std::vector< LitClausePair > &, int, int except2=0, bool flip=0)
void update_xor_gate(Gate *g, GatesTable::iterator)
void check_ite_gate_implied(Gate *g)
vector< bool > scheduled
void connect_goccs(Gate *g, int lit)
Clause * add_binary_clause(int a, int b)
void subsume_clause(Clause *subsuming, Clause *subsumed)
void sort_literals_by_var_except(vector< int > &rhs, int, int except2=0)
LRAT_ID find_representative_lrat(int lit)
Gate * find_gate_lits(const vector< int > &rhs, Gate_Type typ, Gate *except=nullptr)
Gate * new_and_gate(Clause *, int)
void find_representative_and_compress_both(int)
vector< LitClausePair > mu2_ids
void add_xor_shrinking_proof_chain(Gate *g, int src)
Clause * new_tmp_clause(std::vector< int > &clause)
void simplify_ite_gate_then_else_set(Gate *g, std::vector< LRAT_ID > &reasons_implication, std::vector< LRAT_ID > &reasons_back, size_t idx1, size_t idx2)
bool propagate_equivalence(int lit)
void check_xor_gate_implied(Gate const *const)
std::vector< Clause * > new_unwatched_binary_clauses
void set_mu1_reason(int lit, Clause *c)
Clause * produce_rewritten_clause_lrat(Clause *c, int execept_lhs=0, bool remove_units=true, bool=true)
signed char & marked(int lit)
void add_ite_turned_and_binary_clauses(Gate *g)
void copy_conditional_equivalences(int lit, lit_implications &condbin)
vector< LitClausePair > mu1_ids
void extract_and_gates_with_base_clause(Clause *c)
vector< Gate * > garbage
vector< LitClausePair > mu4_ids
Gate * find_remaining_and_gate(Clause *base_clause, int lhs)
void extract_condeq_pairs(int lit, lit_implications &condbin, lit_equivalences &condeq)
Gate * find_xor_lits(const vector< int > &rhs)
vector< int > rhs
bool degenerated_and_neg
int8_t degenerated_ite
vector< LitClausePair > pos_lhs_ids
Gate_Type tag
vector< LitClausePair > neg_lhs_ids
bool degenerated_and_pos
size_t arity() const
size_t operator()(const Gate *const g) const
std::array< int, 16 > & nonces
void mark_duplicated_binary_clauses_as_garbage()
vector< int64_t > lrat_chain
Definition internal.hpp:210
void report(char type, int verbose_level=0)
void phase(int lit)
void backtrack(int target_level=0)
vector< Clause * > clauses
Definition internal.hpp:283
const Range vars
Definition internal.hpp:324
Internal * internal
Definition internal.hpp:311
Watches & watches(int lit)
Definition internal.hpp:467
bool operator()(const CompactBinary &a, const CompactBinary &b)
uint64_t operator()(const CompactBinary &a)
bool operator()(const int &a, const int &b) const
lit_equivalence swap()
lit_equivalence negate_both()
Type operator()(const lit_implication &a) const
CaDiCaL::Internal * internal
bool operator()(const lit_implication &a, const lit_implication &b) const
Type operator()(const LitClausePair &a)
sort_literals_by_var_rank_except(Internal *i, int my_lhs, int except2)
sort_literals_by_var_rank_except(Internal *i, int my_lhs)
sort_literals_by_var_smaller_except(Internal *i, int my_lhs, int except2)
bool operator()(const int &a, const int &b) const
bool operator()(const int &a, const int &b) const
unsigned size
Definition vector.h:35
#define smaller(tree, n, m, depth)
Definition trees.c:455
signed char mark
Definition value.h:8