ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_clause.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "internal.hpp"
4
6
7namespace CaDiCaL {
8
9/*------------------------------------------------------------------------*/
10
11// Signed marking or unmarking of a clause or the global 'clause'.
12
14 for (const auto &lit : *c)
15 mark (lit);
16}
17
19 for (const auto &lit : *c)
20 mark2 (lit);
21}
22
24 for (const auto &lit : *c)
25 unmark (lit);
26}
27
29 for (const auto &lit : clause)
30 mark (lit);
31}
32
34 for (const auto &lit : clause)
35 unmark (lit);
36}
37
38/*------------------------------------------------------------------------*/
39
40// Mark the variables of an irredundant clause to 'have been removed', which
41// will trigger these variables to be considered again in the next bounded
42// variable elimination phase. This is called from 'mark_garbage' below.
43// Note that 'mark_removed (int lit)' will also mark the blocking flag of
44// '-lit' to trigger reconsidering blocking clauses on '-lit'.
45
46void Internal::mark_removed (Clause *c, int except) {
47 LOG (c, "marking removed");
49 for (const auto &lit : *c)
50 if (lit != except)
52}
53
54// Mark the variables of a (redundant or irredundant) clause to 'have been
55// added', which triggers clauses with such a variables, to be considered
56// both as a subsumed or subsuming clause in the next subsumption phase.
57// This function is called from 'new_clause' below as well as in situations
58// where a clause is shrunken (and thus needs to be at least considered
59// again to subsume a larger clause). We also use this to tell
60// 'ternary' preprocessing reconsider clauses on an added literal as well as
61// trying to block clauses on it.
62
63inline void Internal::mark_added (int lit, int size, bool redundant) {
65 if (size == 3)
67 if (!redundant)
69 if (!redundant || size == 2)
71}
72
74 LOG (c, "marking added");
76 for (const auto &lit : *c)
77 mark_added (lit, c->size, c->redundant);
78}
79
80/*------------------------------------------------------------------------*/
81
82Clause *Internal::new_clause (bool red, int glue) {
83
84 CADICAL_assert (clause.size () <= (size_t) INT_MAX);
85 const int size = (int) clause.size ();
86 CADICAL_assert (size >= 2);
87
88 if (glue > size)
89 glue = size;
90
91 size_t bytes = Clause::bytes (size);
92 Clause *c = (Clause *) new char[bytes];
93 DeferDeleteArray<char> clause_delete ((char *) c);
94
95 c->id = ++clause_id;
96
97 c->conditioned = false;
98 c->covered = false;
99 c->enqueued = false;
100 c->frozen = false;
101 c->garbage = false;
102 c->gate = false;
103 c->hyper = false;
104 c->instantiated = false;
105 c->moved = false;
106 c->reason = false;
107 c->redundant = red;
108 c->transred = false;
109 c->subsume = false;
110 c->swept = false;
111 c->flushed = false;
112 c->vivified = false;
113 c->vivify = false;
114 c->used = 0;
115
116 c->glue = glue;
117 c->size = size;
118 c->pos = 2;
119
120 for (int i = 0; i < size; i++)
121 c->literals[i] = clause[i];
122
123 // Just checking that we did not mess up our sophisticated memory layout.
124 // This might be compiler dependent though. Crucial for correctness.
125 //
126 CADICAL_assert (c->bytes () == bytes);
127
128 stats.current.total++;
129 stats.added.total++;
130
131 if (red) {
132 stats.current.redundant++;
133 stats.added.redundant++;
134 } else {
135 stats.irrlits += size;
136 stats.current.irredundant++;
137 stats.added.irredundant++;
138 }
139
140 clauses.push_back (c);
141 clause_delete.release ();
142 LOG (c, "new pointer %p", (void *) c);
143
145 mark_added (c);
146
147 return c;
148}
149
150/*------------------------------------------------------------------------*/
151
152void Internal::promote_clause (Clause *c, int new_glue) {
154 const int tier1limit = tier1[false];
155 const int tier2limit = max (tier1limit, tier2[false]);
156 if (!c->redundant)
157 return;
158 if (c->hyper)
159 return;
160 int old_glue = c->glue;
161 if (new_glue >= old_glue)
162 return;
163 if (old_glue > tier1limit && new_glue <= tier1limit) {
164 LOG (c, "promoting with new glue %d to tier1", new_glue);
165 stats.promoted1++;
166 c->used = max_used;
167 } else if (old_glue > tier2limit && new_glue <= tier2limit) {
168 LOG (c, "promoting with new glue %d to tier2", new_glue);
169 stats.promoted2++;
170 } else if (old_glue <= tier2limit)
171 LOG (c, "keeping with new glue %d in tier2", new_glue);
172 else
173 LOG (c, "keeping with new glue %d in tier3", new_glue);
174 stats.improvedglue++;
175 c->glue = new_glue;
176}
177/*------------------------------------------------------------------------*/
178
181 if (c->hyper)
182 return;
183 int old_glue = c->glue;
184 const int tier1limit = tier1[false];
185 const int tier2limit = max (tier1limit, tier2[false]);
186 if (new_glue >= old_glue)
187 return;
188 if (new_glue <= tier1limit) {
189 LOG (c, "promoting with new glue %d to tier1", new_glue);
190 stats.promoted1++;
191 c->used = max_used;
192 } else if (old_glue > tier2limit && new_glue <= tier2limit) {
193 LOG (c, "promoting with new glue %d to tier2", new_glue);
194 stats.promoted2++;
195 } else if (old_glue <= tier2limit)
196 LOG (c, "keeping with new glue %d in tier2", new_glue);
197 else
198 LOG (c, "keeping with new glue %d in tier3", new_glue);
199 stats.improvedglue++;
200 c->glue = new_glue;
201}
202
203/*------------------------------------------------------------------------*/
204
205// Shrinking a clause, e.g., removing one or more literals, requires to fix
206// the 'pos' field, if it exists and points after the new last literal. We
207// also have adjust the global statistics counter of irredundant literals
208// for irredundant clauses, and also adjust the glue value of redundant
209// clauses if the size becomes smaller than the glue. Also mark the
210// literals in the resulting clause as 'added'. The result is the number of
211// (aligned) removed bytes, resulting from shrinking the clause.
212//
213size_t Internal::shrink_clause (Clause *c, int new_size) {
214 if (opts.check && is_external_forgettable (c->id))
216 CADICAL_assert (new_size >= 2);
217 int old_size = c->size;
218 CADICAL_assert (new_size < old_size);
219#ifndef CADICAL_NDEBUG
220 for (int i = c->size; i < new_size; i++)
221 c->literals[i] = 0;
222#endif
223
224 if (c->pos >= new_size)
225 c->pos = 2;
226
227 size_t old_bytes = c->bytes ();
228 c->size = new_size;
229 size_t new_bytes = c->bytes ();
230 size_t res = old_bytes - new_bytes;
231
232 if (c->redundant)
233 promote_clause_glue_only (c, min (c->size - 1, c->glue));
234 else {
235 int delta_size = old_size - new_size;
236 CADICAL_assert (stats.irrlits >= delta_size);
237 stats.irrlits -= delta_size;
238 }
239
241 mark_added (c);
242
243 return res;
244}
245
246// This is the 'raw' deallocation of a clause. If the clause is in the
247// arena nothing happens. If the clause is not in the arena its memory is
248// reclaimed immediately.
249
251 char *p = (char *) c;
252 if (arena.contains (p))
253 return;
254 LOG (c, "deallocate pointer %p", (void *) c);
255 delete[] p;
256}
257
259 LOG (c, "delete pointer %p", (void *) c);
260 size_t bytes = c->bytes ();
261 stats.collected += bytes;
262 if (c->garbage) {
263 CADICAL_assert (stats.garbage.bytes >= (int64_t) bytes);
264 stats.garbage.bytes -= bytes;
265 CADICAL_assert (stats.garbage.clauses > 0);
266 stats.garbage.clauses--;
267 CADICAL_assert (stats.garbage.literals >= c->size);
268 stats.garbage.literals -= c->size;
269
270 // See the discussion in 'propagate' on avoiding to eagerly trace binary
271 // clauses as deleted (produce 'd ...' lines) as soon they are marked
272 // garbage. We avoid this and only trace them as deleted when they are
273 // actually deleted here. This allows the solver to propagate binary
274 // garbage clauses without producing incorrect 'd' lines. The effect
275 // from the proof perspective is that the deletion of these binary
276 // clauses occurs later in the proof file.
277 //
278 if (proof && c->size == 2 && !c->flushed) {
279 proof->delete_clause (c);
280 }
281 }
283}
284
285// We want to eagerly update statistics as soon clauses are marked garbage.
286// Otherwise 'report' for instance gives wrong numbers after 'subsume'
287// before the next 'reduce'. Thus we factored out marking and accounting
288// for garbage clauses.
289//
290// Eagerly deleting clauses instead is problematic, since references to
291// these clauses need to be flushed, which is too costly to do eagerly.
292//
293// We also update garbage statistics at this point. This helps to
294// determine whether the garbage collector should be called during for
295// instance bounded variable elimination, which usually generates lots of
296// garbage clauses.
297//
298// In order not to miss any update to these clause statistics we call
299// 'check_clause_stats' after garbage collection in debugging mode.
300//
302
304
305 // Delay tracing deletion of binary clauses. See the discussion above in
306 // 'delete_clause' and also in 'propagate'.
307 //
308 if (proof && (c->size != 2 || !watching ())) {
309 c->flushed = true;
310 proof->delete_clause (c);
311 }
312
313 // Because of the internal model checking, external forgettable clauses
314 // must be marked as removed already upon mark_garbage, can not wait until
315 // actual deletion.
316 if (opts.check && is_external_forgettable (c->id))
318
319 CADICAL_assert (stats.current.total > 0);
320 stats.current.total--;
321
322 size_t bytes = c->bytes ();
323 if (c->redundant) {
324 CADICAL_assert (stats.current.redundant > 0);
325 stats.current.redundant--;
326 } else {
327 CADICAL_assert (stats.current.irredundant > 0);
328 stats.current.irredundant--;
329 CADICAL_assert (stats.irrlits >= c->size);
330 stats.irrlits -= c->size;
331 mark_removed (c);
332 }
333 stats.garbage.bytes += bytes;
334 stats.garbage.clauses++;
335 stats.garbage.literals += c->size;
336 c->garbage = true;
337 c->used = 0;
338
339 LOG (c, "marked garbage pointer %p", (void *) c);
340}
341
342/*------------------------------------------------------------------------*/
343
344// Almost the same function as 'search_assign' except that we do not pretend
345// to learn a new unit clause (which was confusing in log files).
346
347void Internal::assign_original_unit (int64_t id, int lit) {
348 CADICAL_assert (!level || opts.chrono);
350 const int idx = vidx (lit);
351 CADICAL_assert (!vals[idx]);
352 CADICAL_assert (!flags (idx).eliminated ());
353 Var &v = var (idx);
354 v.level = 0;
355 v.trail = (int) trail.size ();
356 v.reason = 0;
357 const signed char tmp = sign (lit);
358 set_val (idx, tmp);
359 trail.push_back (lit);
360 num_assigned++;
361 const unsigned uidx = vlit (lit);
362 if (lrat || frat)
363 unit_clauses (uidx) = id;
364 LOG ("original unit assign %d", lit);
365 CADICAL_assert (num_assigned == trail.size () || level);
366 mark_fixed (lit);
367 if (level)
368 return;
369 if (propagate ())
370 return;
372 LOG ("propagation of original unit results in conflict");
374}
375
376// New clause added through the API, e.g., while parsing a DIMACS file.
377// Also used by external_propagate in various different modes.
378// clause, original, lrat_chain and external->eclause are set.
379// from_propagator and force_no_backtrack change the behaviour.
380// sometimes the pointer to the new clause is needed, therefore it is
381// made sure that newest_clause points to the new clause upon return.
382//
383// TODO: Find another name for 'tainted' in the context of ilb, tainted
384// is reconstruction related already and they should not mix.
386
387 if (!from_propagator && level && !opts.ilb) {
388 backtrack ();
389 } else if (tainted_literal) {
391 int new_level = var (tainted_literal).level - 1;
392 CADICAL_assert (new_level >= 0);
393 backtrack (new_level);
394 }
396 LOG (original, "original clause");
397 CADICAL_assert (clause.empty ());
398 bool skip = false;
399 unordered_set<int> learned_levels;
400 size_t unassigned = 0;
401 newest_clause = 0;
402 if (unsat) {
403 LOG ("skipping clause since formula is already inconsistent");
404 skip = true;
405 } else {
406 CADICAL_assert (clause.empty ());
407 for (const auto &lit : original) {
408 int tmp = marked (lit);
409 if (tmp > 0) {
410 LOG ("removing duplicated literal %d", lit);
411 } else if (tmp < 0) {
412 LOG ("tautological since both %d and %d occur", -lit, lit);
413 skip = true;
414 } else {
415 mark (lit);
416 tmp = fixed (lit);
417 if (tmp < 0) {
418 LOG ("removing falsified literal %d", lit);
419 if (lrat) {
420 int elit = externalize (lit);
421 unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit);
422 if (!external->ext_units[eidx]) {
423 int64_t uid = unit_id (-lit);
424 lrat_chain.push_back (uid);
425 }
426 }
427 } else if (tmp > 0) {
428 LOG ("satisfied since literal %d true", lit);
429 skip = true;
430 } else {
431 clause.push_back (lit);
433 tmp = val (lit);
434 if (tmp)
435 learned_levels.insert (var (lit).level);
436 else
437 unassigned++;
438 }
439 }
440 }
441 for (const auto &lit : original)
442 unmark (lit);
443 }
444 if (skip) {
445 if (from_propagator) {
446 stats.ext_prop.elearn_conf++;
447
448 // In case it was a skipped external forgettable, we need to mark it
449 // immediately as removed
450
451 if (opts.check && is_external_forgettable (id))
453 }
454 if (proof) {
455 proof->delete_external_original_clause (id, false, external->eclause);
456 }
457 } else {
458 int64_t new_id = id;
459 const size_t size = clause.size ();
460 if (original.size () > size) {
461 new_id = ++clause_id;
462 if (proof) {
463 if (lrat)
464 lrat_chain.push_back (id);
465 proof->add_derived_clause (new_id, false, clause, lrat_chain);
466 proof->delete_external_original_clause (id, false,
467 external->eclause);
468 }
469 external->check_learned_clause ();
470
471 if (from_propagator) {
472 // The original form of the added clause is immediately forgotten
473 // TODO: shall we save and check the simplified form? (one with
474 // new_id)
475 if (opts.check && is_external_forgettable (id))
477 }
478 }
479 external->eclause.clear ();
480 lrat_chain.clear ();
481 if (!size) {
482 if (from_propagator)
483 stats.ext_prop.elearn_conf++;
485 if (!original.size ())
486 VERBOSE (1, "found empty original clause");
487 else
488 VERBOSE (1, "found falsified original clause");
489 unsat = true;
490 conflict_id = new_id;
491 marked_failed = true;
492 conclusion.push_back (new_id);
493 } else if (size == 1) {
494 if (force_no_backtrack) {
496 const int idx = vidx (clause[0]);
497 CADICAL_assert (val (clause[0]) >= 0);
498 CADICAL_assert (!flags (idx).eliminated ());
499 Var &v = var (idx);
501 v.level = 0;
502 v.reason = 0;
503 const unsigned uidx = vlit (clause[0]);
504 if (lrat || frat)
505 unit_clauses (uidx) = new_id;
506 mark_fixed (clause[0]);
507 } else {
508 const int lit = clause[0];
509 CADICAL_assert (!val (lit) || var (lit).level);
510 if (val (lit) < 0)
511 backtrack (var (lit).level - 1);
512 CADICAL_assert (val (lit) >= 0);
514 assign_original_unit (new_id, lit);
515 }
516 } else {
518#ifndef CADICAL_NDEBUG
520#endif
521 int glue = (int) (learned_levels.size () + unassigned);
522 CADICAL_assert (glue <= (int) clause.size ());
523 bool clause_redundancy = from_propagator && ext_clause_forgettable;
524 Clause *c = new_clause (clause_redundancy, glue);
525 c->id = new_id;
526 clause_id--;
527 watch_clause (c);
528 clause.clear ();
529 original.clear ();
531 newest_clause = c;
532 }
533 }
534 clause.clear ();
535 lrat_chain.clear ();
536}
537
538// Add learned new clause during conflict analysis and watch it. Requires
539// that the clause is at least of size 2, and the first two literals
540// are assigned at the highest decision level.
541//
543 CADICAL_assert (clause.size () > 1);
544#ifndef CADICAL_NDEBUG
545 for (size_t i = 2; i < clause.size (); i++)
548#endif
549 external->check_learned_clause ();
550 Clause *res = new_clause (true, glue);
551 if (proof) {
552 proof->add_derived_clause (res, lrat_chain);
553 }
555 watch_clause (res);
556 return res;
557}
558
559// Add hyper binary resolved clause during 'probing'.
560//
562 external->check_learned_clause ();
563 Clause *res = new_clause (red, glue);
564 if (proof) {
565 proof->add_derived_clause (res, lrat_chain);
566 }
568 watch_clause (res);
569 return res;
570}
571
572// Add hyper ternary resolved clause during 'ternary'.
573//
575 external->check_learned_clause ();
576 size_t size = clause.size ();
577 Clause *res = new_clause (red, size);
578 if (proof) {
579 proof->add_derived_clause (res, lrat_chain);
580 }
582 return res;
583}
584
586 external->check_learned_clause ();
587 stats.factor_added++;
588 stats.literals_factored += clause.size ();
589 Clause *res = new_clause (false, 0);
590 if (proof) {
591 proof->add_derived_clause (res, lrat_chain);
592 }
595 for (const auto &lit : *res) {
596 occs (lit).push_back (res);
597 }
598 return res;
599}
600
601// Add hyper ternary resolved clause during 'congruence' and watch it
602//
603Clause *
605 bool full_watching) {
606 external->check_learned_clause ();
607 size_t size = clause.size ();
608 Clause *res = new_clause (red, size);
609 if (proof) {
610 proof->add_derived_clause (res, lrat_chain);
611 }
612 if (full_watching) {
614 watch_clause (res);
615 }
616 return res;
617}
618
619// Add a new clause with same glue and redundancy as 'orig' but literals are
620// assumed to be in 'clause' in 'decompose' and 'vivify'.
621//
623 external->check_learned_clause ();
624 const int new_glue = orig->glue;
625 Clause *res = new_clause (orig->redundant, new_glue);
626 if (proof) {
627 proof->add_derived_clause (res, lrat_chain);
628 }
630 watch_clause (res);
631 return res;
632}
633
634// Add resolved clause during resolution, e.g., bounded variable
635// elimination, but do not connect its occurrences here.
636//
638 external->check_learned_clause ();
639 if (proof) {
640 proof->add_derived_clause (clause_id + 1, false, clause, lrat_chain);
641 }
642 Clause *res = new_clause (false);
644 return res;
645}
646
647} // namespace CaDiCaL
648
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
Cube * p
Definition exorList.c:222
#define VERBOSE(...)
Definition message.hpp:58
int sign(int lit)
Definition util.hpp:22
int lit
Definition satVec.h:130
size_t bytes() const
Definition clause.hpp:157
static size_t bytes(int size)
Definition clause.hpp:137
unsigned used
Definition clause.hpp:59
bool instantiated
Definition clause.hpp:51
Clause * new_factor_clause()
External * external
Definition internal.hpp:312
void promote_clause_glue_only(Clause *, int new_glue)
Var & var(int lit)
Definition internal.hpp:452
Clause * new_hyper_ternary_resolved_clause_and_watch(bool red, bool)
void mark_garbage(Clause *)
bool ext_clause_forgettable
Definition internal.hpp:249
vector< int64_t > lrat_chain
Definition internal.hpp:210
int vidx(int lit) const
Definition internal.hpp:395
Clause * new_learned_redundant_clause(int glue)
void mark_ternary(int lit)
void unmark(int lit)
Definition internal.hpp:490
Flags & flags(int lit)
Definition internal.hpp:454
vector< int > trail
Definition internal.hpp:259
void mark(int lit)
Definition internal.hpp:484
int fixed(int lit)
const unsigned max_used
Definition internal.hpp:314
void mark_removed(int lit)
void promote_clause(Clause *, int new_glue)
void add_new_original_clause(int64_t)
int externalize(int lit)
void mark_garbage_external_forgettable(int64_t id)
void watch_clause(Clause *c)
Definition internal.hpp:633
vector< int64_t > conclusion
Definition internal.hpp:207
bool watching() const
Definition internal.hpp:462
signed char val(int lit) const
signed char marked(int lit) const
Definition internal.hpp:478
int64_t unit_id(int lit) const
Definition internal.hpp:434
void set_val(int lit, signed char val)
Clause * new_clause(bool red, int glue=0)
void deallocate_clause(Clause *)
Clause * newest_clause
Definition internal.hpp:246
void backtrack(int target_level=0)
unsigned vlit(int lit) const
Definition internal.hpp:408
void mark2(int lit)
Definition internal.hpp:561
vector< Clause * > clauses
Definition internal.hpp:283
signed char * vals
Definition internal.hpp:221
Clause * new_resolved_irredundant_clause()
Clause * new_hyper_binary_resolved_clause(bool red, int glue)
void mark_block(int lit)
vector< int > original
Definition internal.hpp:265
int64_t & unit_clauses(int uidx)
Definition internal.hpp:443
Occs & occs(int lit)
Definition internal.hpp:465
bool occurring() const
Definition internal.hpp:461
size_t shrink_clause(Clause *, int new_size)
void mark_subsume(int lit)
void mark_factor(int lit)
void mark_added(int lit, int size, bool redundant)
Clause * new_clause_as(const Clause *orig)
void assign_original_unit(int64_t, int)
Clause * new_hyper_ternary_resolved_clause(bool red)
bool likely_to_be_kept_clause(Clause *c)
void delete_clause(Clause *)
int64_t redundant() const
Definition internal.hpp:381
vector< int > clause
Definition internal.hpp:260
int level
Definition var.hpp:19
int trail
Definition var.hpp:20
Clause * reason
Definition var.hpp:21
signed char mark
Definition value.h:8