cadical 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +26 -0
- data/README.md +101 -0
- data/ext/cadical/cadical/LICENSE +28 -0
- data/ext/cadical/cadical/README.md +65 -0
- data/ext/cadical/cadical/VERSION +1 -0
- data/ext/cadical/cadical/src/analyze.cpp +1360 -0
- data/ext/cadical/cadical/src/arena.cpp +30 -0
- data/ext/cadical/cadical/src/arena.hpp +105 -0
- data/ext/cadical/cadical/src/assume.cpp +616 -0
- data/ext/cadical/cadical/src/averages.cpp +34 -0
- data/ext/cadical/cadical/src/averages.hpp +37 -0
- data/ext/cadical/cadical/src/backbone.cpp +631 -0
- data/ext/cadical/cadical/src/backtrack.cpp +177 -0
- data/ext/cadical/cadical/src/backward.cpp +231 -0
- data/ext/cadical/cadical/src/bins.cpp +22 -0
- data/ext/cadical/cadical/src/bins.hpp +22 -0
- data/ext/cadical/cadical/src/block.cpp +824 -0
- data/ext/cadical/cadical/src/block.hpp +37 -0
- data/ext/cadical/cadical/src/cadical.cpp +1026 -0
- data/ext/cadical/cadical/src/cadical.hpp +1419 -0
- data/ext/cadical/cadical/src/ccadical.cpp +208 -0
- data/ext/cadical/cadical/src/ccadical.h +74 -0
- data/ext/cadical/cadical/src/checker.cpp +649 -0
- data/ext/cadical/cadical/src/checker.hpp +173 -0
- data/ext/cadical/cadical/src/clause.cpp +689 -0
- data/ext/cadical/cadical/src/clause.hpp +190 -0
- data/ext/cadical/cadical/src/collect.cpp +545 -0
- data/ext/cadical/cadical/src/compact.cpp +550 -0
- data/ext/cadical/cadical/src/condition.cpp +940 -0
- data/ext/cadical/cadical/src/config.cpp +101 -0
- data/ext/cadical/cadical/src/config.hpp +20 -0
- data/ext/cadical/cadical/src/congruence.cpp +7880 -0
- data/ext/cadical/cadical/src/congruence.hpp +757 -0
- data/ext/cadical/cadical/src/constrain.cpp +64 -0
- data/ext/cadical/cadical/src/contract.cpp +27 -0
- data/ext/cadical/cadical/src/contract.hpp +139 -0
- data/ext/cadical/cadical/src/cover.cpp +704 -0
- data/ext/cadical/cadical/src/cover.hpp +34 -0
- data/ext/cadical/cadical/src/decide.cpp +347 -0
- data/ext/cadical/cadical/src/decompose.cpp +738 -0
- data/ext/cadical/cadical/src/decompose.hpp +23 -0
- data/ext/cadical/cadical/src/deduplicate.cpp +275 -0
- data/ext/cadical/cadical/src/definition.cpp +283 -0
- data/ext/cadical/cadical/src/delay.hpp +38 -0
- data/ext/cadical/cadical/src/drattracer.cpp +153 -0
- data/ext/cadical/cadical/src/drattracer.hpp +55 -0
- data/ext/cadical/cadical/src/elim.cpp +1171 -0
- data/ext/cadical/cadical/src/elim.hpp +53 -0
- data/ext/cadical/cadical/src/elimfast.cpp +570 -0
- data/ext/cadical/cadical/src/ema.cpp +95 -0
- data/ext/cadical/cadical/src/ema.hpp +68 -0
- data/ext/cadical/cadical/src/extend.cpp +289 -0
- data/ext/cadical/cadical/src/external.cpp +1034 -0
- data/ext/cadical/cadical/src/external.hpp +487 -0
- data/ext/cadical/cadical/src/external_propagate.cpp +1316 -0
- data/ext/cadical/cadical/src/factor.cpp +1011 -0
- data/ext/cadical/cadical/src/factor.hpp +54 -0
- data/ext/cadical/cadical/src/file.cpp +506 -0
- data/ext/cadical/cadical/src/file.hpp +210 -0
- data/ext/cadical/cadical/src/flags.cpp +135 -0
- data/ext/cadical/cadical/src/flags.hpp +93 -0
- data/ext/cadical/cadical/src/flip.cpp +269 -0
- data/ext/cadical/cadical/src/format.cpp +89 -0
- data/ext/cadical/cadical/src/format.hpp +36 -0
- data/ext/cadical/cadical/src/frattracer.cpp +277 -0
- data/ext/cadical/cadical/src/frattracer.hpp +67 -0
- data/ext/cadical/cadical/src/gates.cpp +766 -0
- data/ext/cadical/cadical/src/heap.hpp +212 -0
- data/ext/cadical/cadical/src/idruptracer.cpp +566 -0
- data/ext/cadical/cadical/src/idruptracer.hpp +112 -0
- data/ext/cadical/cadical/src/instantiate.cpp +365 -0
- data/ext/cadical/cadical/src/instantiate.hpp +45 -0
- data/ext/cadical/cadical/src/internal.cpp +1265 -0
- data/ext/cadical/cadical/src/internal.hpp +1941 -0
- data/ext/cadical/cadical/src/inttypes.hpp +34 -0
- data/ext/cadical/cadical/src/ipasir.cpp +47 -0
- data/ext/cadical/cadical/src/ipasir.h +37 -0
- data/ext/cadical/cadical/src/kitten.c +2599 -0
- data/ext/cadical/cadical/src/kitten.h +97 -0
- data/ext/cadical/cadical/src/level.hpp +33 -0
- data/ext/cadical/cadical/src/lidruptracer.cpp +657 -0
- data/ext/cadical/cadical/src/lidruptracer.hpp +122 -0
- data/ext/cadical/cadical/src/limit.cpp +146 -0
- data/ext/cadical/cadical/src/limit.hpp +168 -0
- data/ext/cadical/cadical/src/logging.cpp +214 -0
- data/ext/cadical/cadical/src/logging.hpp +98 -0
- data/ext/cadical/cadical/src/lookahead.cpp +520 -0
- data/ext/cadical/cadical/src/lratchecker.cpp +833 -0
- data/ext/cadical/cadical/src/lratchecker.hpp +168 -0
- data/ext/cadical/cadical/src/lrattracer.cpp +200 -0
- data/ext/cadical/cadical/src/lrattracer.hpp +61 -0
- data/ext/cadical/cadical/src/lucky.cpp +506 -0
- data/ext/cadical/cadical/src/message.cpp +218 -0
- data/ext/cadical/cadical/src/message.hpp +65 -0
- data/ext/cadical/cadical/src/minimize.cpp +224 -0
- data/ext/cadical/cadical/src/mobical.cpp +5588 -0
- data/ext/cadical/cadical/src/occs.cpp +52 -0
- data/ext/cadical/cadical/src/occs.hpp +36 -0
- data/ext/cadical/cadical/src/options.cpp +359 -0
- data/ext/cadical/cadical/src/options.hpp +442 -0
- data/ext/cadical/cadical/src/parse.cpp +471 -0
- data/ext/cadical/cadical/src/parse.hpp +75 -0
- data/ext/cadical/cadical/src/phases.cpp +56 -0
- data/ext/cadical/cadical/src/phases.hpp +19 -0
- data/ext/cadical/cadical/src/probe.cpp +990 -0
- data/ext/cadical/cadical/src/profile.cpp +107 -0
- data/ext/cadical/cadical/src/profile.hpp +283 -0
- data/ext/cadical/cadical/src/proof.cpp +691 -0
- data/ext/cadical/cadical/src/proof.hpp +125 -0
- data/ext/cadical/cadical/src/propagate.cpp +584 -0
- data/ext/cadical/cadical/src/queue.cpp +90 -0
- data/ext/cadical/cadical/src/queue.hpp +74 -0
- data/ext/cadical/cadical/src/radix.hpp +180 -0
- data/ext/cadical/cadical/src/random.cpp +207 -0
- data/ext/cadical/cadical/src/random.h +44 -0
- data/ext/cadical/cadical/src/random.hpp +98 -0
- data/ext/cadical/cadical/src/range.hpp +125 -0
- data/ext/cadical/cadical/src/reap.cpp +127 -0
- data/ext/cadical/cadical/src/reap.hpp +28 -0
- data/ext/cadical/cadical/src/reduce.cpp +278 -0
- data/ext/cadical/cadical/src/reluctant.hpp +82 -0
- data/ext/cadical/cadical/src/rephase.cpp +402 -0
- data/ext/cadical/cadical/src/report.cpp +313 -0
- data/ext/cadical/cadical/src/resources.cpp +160 -0
- data/ext/cadical/cadical/src/resources.hpp +16 -0
- data/ext/cadical/cadical/src/restart.cpp +178 -0
- data/ext/cadical/cadical/src/restore.cpp +267 -0
- data/ext/cadical/cadical/src/score.cpp +51 -0
- data/ext/cadical/cadical/src/score.hpp +16 -0
- data/ext/cadical/cadical/src/shrink.cpp +507 -0
- data/ext/cadical/cadical/src/signal.cpp +136 -0
- data/ext/cadical/cadical/src/signal.hpp +33 -0
- data/ext/cadical/cadical/src/solution.cpp +50 -0
- data/ext/cadical/cadical/src/solver.cpp +1871 -0
- data/ext/cadical/cadical/src/stable.cpp +31 -0
- data/ext/cadical/cadical/src/stack.h +110 -0
- data/ext/cadical/cadical/src/stats.cpp +920 -0
- data/ext/cadical/cadical/src/stats.hpp +418 -0
- data/ext/cadical/cadical/src/subsume.cpp +645 -0
- data/ext/cadical/cadical/src/sweep.cpp +1960 -0
- data/ext/cadical/cadical/src/sweep.hpp +61 -0
- data/ext/cadical/cadical/src/terminal.cpp +38 -0
- data/ext/cadical/cadical/src/terminal.hpp +96 -0
- data/ext/cadical/cadical/src/ternary.cpp +450 -0
- data/ext/cadical/cadical/src/testing.hpp +24 -0
- data/ext/cadical/cadical/src/tier.cpp +189 -0
- data/ext/cadical/cadical/src/tracer.hpp +186 -0
- data/ext/cadical/cadical/src/transred.cpp +253 -0
- data/ext/cadical/cadical/src/unstable.cpp +29 -0
- data/ext/cadical/cadical/src/util.cpp +129 -0
- data/ext/cadical/cadical/src/util.hpp +181 -0
- data/ext/cadical/cadical/src/var.cpp +39 -0
- data/ext/cadical/cadical/src/var.hpp +22 -0
- data/ext/cadical/cadical/src/veripbtracer.cpp +427 -0
- data/ext/cadical/cadical/src/veripbtracer.hpp +106 -0
- data/ext/cadical/cadical/src/version.cpp +107 -0
- data/ext/cadical/cadical/src/version.hpp +13 -0
- data/ext/cadical/cadical/src/vivify.cpp +1893 -0
- data/ext/cadical/cadical/src/vivify.hpp +50 -0
- data/ext/cadical/cadical/src/walk.cpp +1088 -0
- data/ext/cadical/cadical/src/walk.hpp +91 -0
- data/ext/cadical/cadical/src/walk_full_occs.cpp +966 -0
- data/ext/cadical/cadical/src/warmup.cpp +403 -0
- data/ext/cadical/cadical/src/watch.cpp +126 -0
- data/ext/cadical/cadical/src/watch.hpp +77 -0
- data/ext/cadical/cadical_ext.c +778 -0
- data/ext/cadical/extconf.rb +26 -0
- data/lib/cadical/version.rb +3 -0
- data/lib/cadical.rb +12 -0
- metadata +218 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#ifndef _proof_h_INCLUDED
|
|
2
|
+
#define _proof_h_INCLUDED
|
|
3
|
+
|
|
4
|
+
#include "tracer.hpp"
|
|
5
|
+
#include <stdint.h>
|
|
6
|
+
|
|
7
|
+
namespace CaDiCaL {
|
|
8
|
+
|
|
9
|
+
/*------------------------------------------------------------------------*/
|
|
10
|
+
|
|
11
|
+
class File;
|
|
12
|
+
struct Clause;
|
|
13
|
+
struct Internal;
|
|
14
|
+
class Tracer;
|
|
15
|
+
class FileTracer;
|
|
16
|
+
|
|
17
|
+
/*------------------------------------------------------------------------*/
|
|
18
|
+
|
|
19
|
+
// Provides proof checking and writing.
|
|
20
|
+
|
|
21
|
+
class Proof {
|
|
22
|
+
|
|
23
|
+
Internal *internal;
|
|
24
|
+
|
|
25
|
+
std::vector<int> clause; // of external literals
|
|
26
|
+
std::vector<int64_t> proof_chain; // LRAT style proof chain of clause
|
|
27
|
+
int64_t clause_id; // id of added clause
|
|
28
|
+
bool redundant;
|
|
29
|
+
int witness;
|
|
30
|
+
|
|
31
|
+
// the 'tracers'
|
|
32
|
+
std::vector<Tracer *> tracers; // tracers (ie checker)
|
|
33
|
+
std::vector<FileTracer *> file_tracers; // file tracers (ie LRAT tracer)
|
|
34
|
+
|
|
35
|
+
void add_literal (int internal_lit); // add to 'clause'
|
|
36
|
+
void add_literals (Clause *); // add to 'clause'
|
|
37
|
+
|
|
38
|
+
void add_literals (const std::vector<int> &); // ditto
|
|
39
|
+
|
|
40
|
+
void add_original_clause (
|
|
41
|
+
bool restore = false); // notify observers of original clauses
|
|
42
|
+
void add_derived_clause ();
|
|
43
|
+
void add_assumption_clause ();
|
|
44
|
+
void delete_clause ();
|
|
45
|
+
void demote_clause ();
|
|
46
|
+
void weaken_minus ();
|
|
47
|
+
void strengthen ();
|
|
48
|
+
void finalize_clause ();
|
|
49
|
+
void add_assumption ();
|
|
50
|
+
void add_constraint ();
|
|
51
|
+
|
|
52
|
+
public:
|
|
53
|
+
Proof (Internal *);
|
|
54
|
+
~Proof ();
|
|
55
|
+
|
|
56
|
+
void connect (Tracer *t) { tracers.push_back (t); }
|
|
57
|
+
void disconnect (Tracer *t);
|
|
58
|
+
// Add original clauses to the proof (for online proof checking).
|
|
59
|
+
//
|
|
60
|
+
void add_original_clause (int64_t, bool, const std::vector<int> &);
|
|
61
|
+
|
|
62
|
+
void add_assumption_clause (int64_t, const std::vector<int> &,
|
|
63
|
+
const std::vector<int64_t> &);
|
|
64
|
+
void add_assumption_clause (int64_t, int, const std::vector<int64_t> &);
|
|
65
|
+
void add_assumption (int);
|
|
66
|
+
void add_constraint (const std::vector<int> &);
|
|
67
|
+
void reset_assumptions ();
|
|
68
|
+
|
|
69
|
+
// Add/delete original clauses to/from the proof using their original
|
|
70
|
+
// external literals (from external->eclause)
|
|
71
|
+
//
|
|
72
|
+
void add_external_original_clause (int64_t, bool,
|
|
73
|
+
const std::vector<int> &,
|
|
74
|
+
bool restore = false);
|
|
75
|
+
void delete_external_original_clause (int64_t, bool,
|
|
76
|
+
const std::vector<int> &);
|
|
77
|
+
|
|
78
|
+
// Add derived (such as learned) clauses to the proof.
|
|
79
|
+
//
|
|
80
|
+
void add_derived_empty_clause (int64_t, const std::vector<int64_t> &);
|
|
81
|
+
void add_derived_unit_clause (int64_t, int unit,
|
|
82
|
+
const std::vector<int64_t> &);
|
|
83
|
+
void add_derived_clause (Clause *c, const std::vector<int64_t> &);
|
|
84
|
+
void add_derived_clause (int64_t, bool, const std::vector<int> &,
|
|
85
|
+
const std::vector<int64_t> &);
|
|
86
|
+
void add_derived_rat_clause (int64_t, bool, int, const std::vector<int> &,
|
|
87
|
+
const std::vector<int64_t> &);
|
|
88
|
+
void add_derived_rat_clause (Clause *c, int w,
|
|
89
|
+
const std::vector<int64_t> &);
|
|
90
|
+
|
|
91
|
+
// deletion of clauses. It comes in several variants, depending if the
|
|
92
|
+
// clause should be restored or not
|
|
93
|
+
void delete_clause (int64_t, bool, const std::vector<int> &);
|
|
94
|
+
void weaken_minus (int64_t, const std::vector<int> &);
|
|
95
|
+
void weaken_plus (int64_t, const std::vector<int> &);
|
|
96
|
+
void delete_unit_clause (int64_t id, const int lit);
|
|
97
|
+
void delete_clause (Clause *);
|
|
98
|
+
void weaken_minus (Clause *);
|
|
99
|
+
void weaken_plus (Clause *);
|
|
100
|
+
void strengthen (int64_t);
|
|
101
|
+
|
|
102
|
+
void finalize_unit (int64_t, int);
|
|
103
|
+
void finalize_external_unit (int64_t, int);
|
|
104
|
+
void finalize_clause (int64_t, const std::vector<int> &c);
|
|
105
|
+
void finalize_clause (Clause *);
|
|
106
|
+
|
|
107
|
+
void report_status (int, int64_t);
|
|
108
|
+
void begin_proof (int64_t);
|
|
109
|
+
void conclude_unsat (ConclusionType, const std::vector<int64_t> &);
|
|
110
|
+
void conclude_sat (const std::vector<int> &model);
|
|
111
|
+
void conclude_unknown (const std::vector<int> &trace);
|
|
112
|
+
void solve_query ();
|
|
113
|
+
// These two actually pretend to add and remove a clause.
|
|
114
|
+
//
|
|
115
|
+
void flush_clause (Clause *); // remove falsified literals
|
|
116
|
+
void strengthen_clause (Clause *, int, const std::vector<int64_t> &);
|
|
117
|
+
void otfs_strengthen_clause (Clause *, const std::vector<int> &,
|
|
118
|
+
const std::vector<int64_t> &);
|
|
119
|
+
|
|
120
|
+
void flush ();
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
} // namespace CaDiCaL
|
|
124
|
+
|
|
125
|
+
#endif
|
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
namespace CaDiCaL {
|
|
4
|
+
|
|
5
|
+
/*------------------------------------------------------------------------*/
|
|
6
|
+
|
|
7
|
+
// We are using the address of 'decision_reason' as pseudo reason for
|
|
8
|
+
// decisions to distinguish assignment decisions from other assignments.
|
|
9
|
+
// Before we added chronological backtracking all learned units were
|
|
10
|
+
// assigned at decision level zero ('Solver.level == 0') and we just used a
|
|
11
|
+
// zero pointer as reason. After allowing chronological backtracking units
|
|
12
|
+
// were also assigned at higher decision level (but with assignment level
|
|
13
|
+
// zero), and it was not possible anymore to just distinguish the case
|
|
14
|
+
// 'unit' versus 'decision' by just looking at the current level. Both had
|
|
15
|
+
// a zero pointer as reason. Now only units have a zero reason and
|
|
16
|
+
// decisions need to use the pseudo reason 'decision_reason'.
|
|
17
|
+
|
|
18
|
+
// External propagation steps use the pseudo reason 'external_reason'.
|
|
19
|
+
// The corresponding actual reason clauses are learned only when they are
|
|
20
|
+
// relevant in conflict analysis or in root-level fixing steps.
|
|
21
|
+
|
|
22
|
+
static Clause decision_reason_clause;
|
|
23
|
+
Clause *Internal::decision_reason = &decision_reason_clause;
|
|
24
|
+
|
|
25
|
+
// If chronological backtracking is used the actual assignment level might
|
|
26
|
+
// be lower than the current decision level. In this case the assignment
|
|
27
|
+
// level is defined as the maximum level of the literals in the reason
|
|
28
|
+
// clause except the literal for which the clause is a reason. This
|
|
29
|
+
// function determines this assignment level. For non-chronological
|
|
30
|
+
// backtracking as in classical CDCL this function always returns the
|
|
31
|
+
// current decision level, the concept of assignment level does not make
|
|
32
|
+
// sense, and accordingly this function can be skipped.
|
|
33
|
+
|
|
34
|
+
// In case of external propagation, it is implicitly assumed that the
|
|
35
|
+
// assignment level is the level of the literal (since the reason clause,
|
|
36
|
+
// i.e., the set of other literals, is unknown).
|
|
37
|
+
|
|
38
|
+
inline int Internal::assignment_level (int lit, Clause *reason) {
|
|
39
|
+
|
|
40
|
+
assert (opts.chrono || external_prop);
|
|
41
|
+
if (!reason || reason == external_reason)
|
|
42
|
+
return level;
|
|
43
|
+
|
|
44
|
+
int res = 0;
|
|
45
|
+
|
|
46
|
+
for (const auto &other : *reason) {
|
|
47
|
+
if (other == lit)
|
|
48
|
+
continue;
|
|
49
|
+
assert (val (other));
|
|
50
|
+
int tmp = var (other).level;
|
|
51
|
+
if (tmp > res)
|
|
52
|
+
res = tmp;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return res;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// calculate lrat_chain
|
|
59
|
+
//
|
|
60
|
+
void Internal::build_chain_for_units (int lit, Clause *reason,
|
|
61
|
+
bool forced) {
|
|
62
|
+
if (!lrat)
|
|
63
|
+
return;
|
|
64
|
+
if (opts.chrono && assignment_level (lit, reason) && !forced)
|
|
65
|
+
return;
|
|
66
|
+
else if (!opts.chrono && level && !forced)
|
|
67
|
+
return; // not decision level 0
|
|
68
|
+
assert (lrat_chain.empty ());
|
|
69
|
+
for (auto &reason_lit : *reason) {
|
|
70
|
+
if (lit == reason_lit)
|
|
71
|
+
continue;
|
|
72
|
+
assert (val (reason_lit));
|
|
73
|
+
if (!val (reason_lit))
|
|
74
|
+
continue;
|
|
75
|
+
const int signed_reason_lit = val (reason_lit) * reason_lit;
|
|
76
|
+
int64_t id = unit_id (signed_reason_lit);
|
|
77
|
+
lrat_chain.push_back (id);
|
|
78
|
+
}
|
|
79
|
+
lrat_chain.push_back (reason->id);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// same code as above but reason is assumed to be conflict and lit is not
|
|
83
|
+
// needed
|
|
84
|
+
//
|
|
85
|
+
void Internal::build_chain_for_empty () {
|
|
86
|
+
if (!lrat || !lrat_chain.empty ())
|
|
87
|
+
return;
|
|
88
|
+
assert (!level || in_mode (BACKBONE));
|
|
89
|
+
assert (lrat_chain.empty ());
|
|
90
|
+
assert (conflict);
|
|
91
|
+
LOG (conflict, "lrat for global empty clause with conflict");
|
|
92
|
+
for (auto &lit : *conflict) {
|
|
93
|
+
assert (val (lit) < 0);
|
|
94
|
+
int64_t id = unit_id (-lit);
|
|
95
|
+
lrat_chain.push_back (id);
|
|
96
|
+
}
|
|
97
|
+
lrat_chain.push_back (conflict->id);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/*------------------------------------------------------------------------*/
|
|
101
|
+
|
|
102
|
+
inline void Internal::search_assign (int lit, Clause *reason) {
|
|
103
|
+
|
|
104
|
+
if (level)
|
|
105
|
+
require_mode (SEARCH);
|
|
106
|
+
|
|
107
|
+
const int idx = vidx (lit);
|
|
108
|
+
const bool from_external = reason == external_reason;
|
|
109
|
+
assert (!val (idx));
|
|
110
|
+
assert (!flags (idx).eliminated () || reason == decision_reason ||
|
|
111
|
+
reason == external_reason);
|
|
112
|
+
Var &v = var (idx);
|
|
113
|
+
int lit_level;
|
|
114
|
+
assert (!lrat || level || reason == external_reason ||
|
|
115
|
+
reason == decision_reason || !lrat_chain.empty ());
|
|
116
|
+
// The following cases are explained in the two comments above before
|
|
117
|
+
// 'decision_reason' and 'assignment_level'.
|
|
118
|
+
//
|
|
119
|
+
// External decision reason means that the propagation was done by
|
|
120
|
+
// an external propagation and the reason clause not known (yet).
|
|
121
|
+
// In that case it is assumed that the propagation is NOT out of
|
|
122
|
+
// order (i.e. lit_level = level), because due to lazy explanation,
|
|
123
|
+
// we can not calculate the real assignment level.
|
|
124
|
+
// The function assignment_level () will also assign the current level
|
|
125
|
+
// to literals with external reason.
|
|
126
|
+
if (!reason)
|
|
127
|
+
lit_level = 0; // unit
|
|
128
|
+
else if (reason == decision_reason)
|
|
129
|
+
lit_level = level, reason = 0;
|
|
130
|
+
else if (opts.chrono)
|
|
131
|
+
lit_level = assignment_level (lit, reason);
|
|
132
|
+
else
|
|
133
|
+
lit_level = level;
|
|
134
|
+
if (!lit_level)
|
|
135
|
+
reason = 0;
|
|
136
|
+
|
|
137
|
+
v.level = lit_level;
|
|
138
|
+
v.trail = trail.size ();
|
|
139
|
+
v.reason = reason;
|
|
140
|
+
assert ((int) num_assigned < max_var);
|
|
141
|
+
assert (num_assigned == trail.size ());
|
|
142
|
+
num_assigned++;
|
|
143
|
+
if (!lit_level && !from_external)
|
|
144
|
+
learn_unit_clause (lit); // increases 'stats.fixed'
|
|
145
|
+
assert (lit_level || !from_external);
|
|
146
|
+
const signed char tmp = sign (lit);
|
|
147
|
+
set_val (idx, tmp);
|
|
148
|
+
assert (val (lit) > 0); // Just a bit paranoid but useful.
|
|
149
|
+
assert (val (-lit) < 0); // Ditto.
|
|
150
|
+
if (!searching_lucky_phases)
|
|
151
|
+
phases.saved[idx] = tmp; // phase saving during search
|
|
152
|
+
trail.push_back (lit);
|
|
153
|
+
#ifdef LOGGING
|
|
154
|
+
if (!lit_level)
|
|
155
|
+
LOG ("root-level unit assign %d @ 0", lit);
|
|
156
|
+
else
|
|
157
|
+
LOG (reason, "search assign %d @ %d", lit, lit_level);
|
|
158
|
+
#endif
|
|
159
|
+
|
|
160
|
+
if (watching ()) {
|
|
161
|
+
const Watches &ws = watches (-lit);
|
|
162
|
+
if (!ws.empty ()) {
|
|
163
|
+
const Watch &w = ws[0];
|
|
164
|
+
__builtin_prefetch (&w, 0, 1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
lrat_chain.clear ();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/*------------------------------------------------------------------------*/
|
|
171
|
+
|
|
172
|
+
// External versions of 'search_assign' which are not inlined. They either
|
|
173
|
+
// are used to assign unit clauses on the root-level, in 'decide' to assign
|
|
174
|
+
// a decision or in 'analyze' to assign the literal 'driven' by a learned
|
|
175
|
+
// clause. This happens far less frequently than the 'search_assign' above,
|
|
176
|
+
// which is called directly in 'propagate' below and thus is inlined.
|
|
177
|
+
|
|
178
|
+
void Internal::assign_unit (int lit) {
|
|
179
|
+
assert (!level);
|
|
180
|
+
search_assign (lit, 0);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Just assume the given literal as decision (increase decision level and
|
|
184
|
+
// assign it). This is used below in 'decide'.
|
|
185
|
+
|
|
186
|
+
void Internal::search_assume_decision (int lit) {
|
|
187
|
+
require_mode (SEARCH);
|
|
188
|
+
assert (propagated == trail.size ());
|
|
189
|
+
new_trail_level (lit);
|
|
190
|
+
notify_decision ();
|
|
191
|
+
LOG ("search decide %d", lit);
|
|
192
|
+
search_assign (lit, decision_reason);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
void Internal::search_assign_driving (int lit, Clause *c) {
|
|
196
|
+
require_mode (SEARCH);
|
|
197
|
+
search_assign (lit, c);
|
|
198
|
+
notify_assignments ();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void Internal::search_assign_external (int lit) {
|
|
202
|
+
require_mode (SEARCH);
|
|
203
|
+
search_assign (lit, external_reason);
|
|
204
|
+
notify_assignments ();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/*------------------------------------------------------------------------*/
|
|
208
|
+
|
|
209
|
+
// The 'propagate' function is usually the hot-spot of a CDCL SAT solver.
|
|
210
|
+
// The 'trail' stack saves assigned variables and is used here as BFS queue
|
|
211
|
+
// for checking clauses with the negation of assigned variables for being in
|
|
212
|
+
// conflict or whether they produce additional assignments.
|
|
213
|
+
|
|
214
|
+
// This version of 'propagate' uses lazy watches and keeps two watched
|
|
215
|
+
// literals at the beginning of the clause. We also use 'blocking literals'
|
|
216
|
+
// to reduce the number of times clauses have to be visited (2008 JSAT paper
|
|
217
|
+
// by Chu, Harwood and Stuckey). The watches know if a watched clause is
|
|
218
|
+
// binary, in which case it never has to be visited. If a binary clause is
|
|
219
|
+
// falsified we continue propagating.
|
|
220
|
+
|
|
221
|
+
// Finally, for long clauses we save the position of the last watch
|
|
222
|
+
// replacement in 'pos', which in turn reduces certain quadratic accumulated
|
|
223
|
+
// propagation costs (2013 JAIR article by Ian Gent) at the expense of four
|
|
224
|
+
// more bytes for each clause.
|
|
225
|
+
|
|
226
|
+
bool Internal::propagate () {
|
|
227
|
+
|
|
228
|
+
if (level)
|
|
229
|
+
require_mode (SEARCH);
|
|
230
|
+
assert (!unsat);
|
|
231
|
+
LOG ("starting propagate");
|
|
232
|
+
START (propagate);
|
|
233
|
+
|
|
234
|
+
// Updating statistics counter in the propagation loops is costly so we
|
|
235
|
+
// delay until propagation ran to completion.
|
|
236
|
+
//
|
|
237
|
+
int64_t before = propagated;
|
|
238
|
+
int64_t ticks = 0;
|
|
239
|
+
|
|
240
|
+
while (!conflict && propagated != trail.size ()) {
|
|
241
|
+
|
|
242
|
+
const int lit = -trail[propagated++];
|
|
243
|
+
LOG ("propagating %d", -lit);
|
|
244
|
+
Watches &ws = watches (lit);
|
|
245
|
+
|
|
246
|
+
const const_watch_iterator eow = ws.end ();
|
|
247
|
+
watch_iterator j = ws.begin ();
|
|
248
|
+
const_watch_iterator i = j;
|
|
249
|
+
ticks += 1 + cache_lines (ws.size (), sizeof *i);
|
|
250
|
+
|
|
251
|
+
while (i != eow) {
|
|
252
|
+
|
|
253
|
+
const Watch w = *j++ = *i++;
|
|
254
|
+
const signed char b = val (w.blit);
|
|
255
|
+
LOG (w.clause, "checking");
|
|
256
|
+
|
|
257
|
+
if (b > 0)
|
|
258
|
+
continue; // blocking literal satisfied
|
|
259
|
+
|
|
260
|
+
if (w.binary ()) {
|
|
261
|
+
|
|
262
|
+
// assert (w.clause->redundant || !w.clause->garbage);
|
|
263
|
+
|
|
264
|
+
// In principle we can ignore garbage binary clauses too, but that
|
|
265
|
+
// would require to dereference the clause pointer all the time with
|
|
266
|
+
//
|
|
267
|
+
// if (w.clause->garbage) { j--; continue; } // (*)
|
|
268
|
+
//
|
|
269
|
+
// This is too costly. It is however necessary to produce correct
|
|
270
|
+
// proof traces if binary clauses are traced to be deleted ('d ...'
|
|
271
|
+
// line) immediately as soon they are marked as garbage. Actually
|
|
272
|
+
// finding instances where this happens is pretty difficult (six
|
|
273
|
+
// parallel fuzzing jobs in parallel took an hour), but it does
|
|
274
|
+
// occur. Our strategy to avoid generating incorrect proofs now is
|
|
275
|
+
// to delay tracing the deletion of binary clauses marked as garbage
|
|
276
|
+
// until they are really deleted from memory. For large clauses
|
|
277
|
+
// this is not necessary since we have to access the clause anyhow.
|
|
278
|
+
//
|
|
279
|
+
// Thanks go to Mathias Fleury, who wanted me to explain why the
|
|
280
|
+
// line '(*)' above was in the code. Removing it actually really
|
|
281
|
+
// improved running times and thus I tried to find concrete
|
|
282
|
+
// instances where this happens (which I found), and then
|
|
283
|
+
// implemented the described fix.
|
|
284
|
+
|
|
285
|
+
// Binary clauses are treated separately since they do not require
|
|
286
|
+
// to access the clause at all (only during conflict analysis, and
|
|
287
|
+
// there also only to simplify the code).
|
|
288
|
+
|
|
289
|
+
if (b < 0)
|
|
290
|
+
conflict = w.clause; // but continue ...
|
|
291
|
+
else {
|
|
292
|
+
build_chain_for_units (w.blit, w.clause, 0);
|
|
293
|
+
search_assign (w.blit, w.clause);
|
|
294
|
+
// lrat_chain.clear (); done in search_assign
|
|
295
|
+
ticks++;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
} else {
|
|
299
|
+
assert (w.clause->size > 2);
|
|
300
|
+
|
|
301
|
+
if (conflict)
|
|
302
|
+
break; // Stop if there was a binary conflict already.
|
|
303
|
+
|
|
304
|
+
// The cache line with the clause data is forced to be loaded here
|
|
305
|
+
// and thus this first memory access below is the real hot-spot of
|
|
306
|
+
// the solver. Note, that this check is positive very rarely and
|
|
307
|
+
// thus branch prediction should be almost perfect here.
|
|
308
|
+
|
|
309
|
+
ticks++;
|
|
310
|
+
|
|
311
|
+
if (w.clause->garbage) {
|
|
312
|
+
j--;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
literal_iterator lits = w.clause->begin ();
|
|
317
|
+
assert (lits[0] == lit || lits[1] == lit);
|
|
318
|
+
|
|
319
|
+
// Simplify code by forcing 'lit' to be the second literal in the
|
|
320
|
+
// clause. This goes back to MiniSAT. We use a branch-less version
|
|
321
|
+
// for conditionally swapping the first two literals, since it
|
|
322
|
+
// turned out to be substantially faster than this one
|
|
323
|
+
//
|
|
324
|
+
// if (lits[0] == lit) swap (lits[0], lits[1]);
|
|
325
|
+
//
|
|
326
|
+
// which achieves the same effect, but needs a branch.
|
|
327
|
+
//
|
|
328
|
+
const int other = lits[0] ^ lits[1] ^ lit;
|
|
329
|
+
const signed char u = val (other); // value of the other watch
|
|
330
|
+
|
|
331
|
+
if (u > 0)
|
|
332
|
+
j[-1].blit = other; // satisfied, just replace blit
|
|
333
|
+
else {
|
|
334
|
+
|
|
335
|
+
// This follows Ian Gent's (JAIR'13) idea of saving the position
|
|
336
|
+
// of the last watch replacement. In essence it needs two copies
|
|
337
|
+
// of the default search for a watch replacement (in essence the
|
|
338
|
+
// code in the 'if (v < 0) { ... }' block below), one starting at
|
|
339
|
+
// the saved position until the end of the clause and then if that
|
|
340
|
+
// one failed to find a replacement another one starting at the
|
|
341
|
+
// first non-watched literal until the saved position.
|
|
342
|
+
|
|
343
|
+
const int size = w.clause->size;
|
|
344
|
+
const literal_iterator middle = lits + w.clause->pos;
|
|
345
|
+
const const_literal_iterator end = lits + size;
|
|
346
|
+
literal_iterator k = middle;
|
|
347
|
+
|
|
348
|
+
// Find replacement watch 'r' at position 'k' with value 'v'.
|
|
349
|
+
assert (lits + 2 <= k);
|
|
350
|
+
LOG (w.clause, "search starting at %d", w.clause->pos);
|
|
351
|
+
int r = 0;
|
|
352
|
+
signed char v = -1;
|
|
353
|
+
|
|
354
|
+
while (k != end && (v = val (r = *k)) < 0)
|
|
355
|
+
k++;
|
|
356
|
+
|
|
357
|
+
if (v < 0) { // need second search starting at the head?
|
|
358
|
+
|
|
359
|
+
k = lits + 2;
|
|
360
|
+
assert (w.clause->pos <= size);
|
|
361
|
+
while (k != middle && (v = val (r = *k)) < 0)
|
|
362
|
+
k++;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
w.clause->pos = k - lits; // always save position
|
|
366
|
+
|
|
367
|
+
assert (lits + 2 <= k), assert (k <= w.clause->end ());
|
|
368
|
+
|
|
369
|
+
if (v > 0) {
|
|
370
|
+
|
|
371
|
+
// Replacement satisfied, so just replace 'blit'.
|
|
372
|
+
|
|
373
|
+
j[-1].blit = r;
|
|
374
|
+
|
|
375
|
+
} else if (!v) {
|
|
376
|
+
|
|
377
|
+
// Found new unassigned replacement literal to be watched.
|
|
378
|
+
|
|
379
|
+
LOG (w.clause, "unwatch %d in", lit);
|
|
380
|
+
|
|
381
|
+
lits[0] = other;
|
|
382
|
+
lits[1] = r;
|
|
383
|
+
*k = lit;
|
|
384
|
+
|
|
385
|
+
watch_literal (r, lit, w.clause);
|
|
386
|
+
|
|
387
|
+
j--; // Drop this watch from the watch list of 'lit'.
|
|
388
|
+
|
|
389
|
+
ticks++;
|
|
390
|
+
|
|
391
|
+
} else if (!u) {
|
|
392
|
+
|
|
393
|
+
assert (v < 0);
|
|
394
|
+
|
|
395
|
+
// The other watch is unassigned ('!u') and all other literals
|
|
396
|
+
// assigned to false (still 'v < 0'), thus we found a unit.
|
|
397
|
+
//
|
|
398
|
+
build_chain_for_units (other, w.clause, 0);
|
|
399
|
+
search_assign (other, w.clause);
|
|
400
|
+
// lrat_chain.clear (); done in search_assign
|
|
401
|
+
ticks++;
|
|
402
|
+
|
|
403
|
+
// Similar code is in the implementation of the SAT'18 paper on
|
|
404
|
+
// chronological backtracking but in our experience, this code
|
|
405
|
+
// first does not really seem to be necessary for correctness,
|
|
406
|
+
// and further does not improve running time either.
|
|
407
|
+
//
|
|
408
|
+
if (opts.chrono > 1) {
|
|
409
|
+
|
|
410
|
+
const int other_level = var (other).level;
|
|
411
|
+
|
|
412
|
+
if (other_level > var (lit).level) {
|
|
413
|
+
|
|
414
|
+
// The assignment level of the new unit 'other' is larger
|
|
415
|
+
// than the assignment level of 'lit'. Thus we should find
|
|
416
|
+
// another literal in the clause at that higher assignment
|
|
417
|
+
// level and watch that instead of 'lit'.
|
|
418
|
+
|
|
419
|
+
assert (size > 2);
|
|
420
|
+
|
|
421
|
+
int pos, s = 0;
|
|
422
|
+
|
|
423
|
+
for (pos = 2; pos < size; pos++)
|
|
424
|
+
if (var (s = lits[pos]).level == other_level)
|
|
425
|
+
break;
|
|
426
|
+
|
|
427
|
+
assert (s);
|
|
428
|
+
assert (pos < size);
|
|
429
|
+
|
|
430
|
+
LOG (w.clause, "unwatch %d in", lit);
|
|
431
|
+
lits[pos] = lit;
|
|
432
|
+
lits[0] = other;
|
|
433
|
+
lits[1] = s;
|
|
434
|
+
watch_literal (s, lit, w.clause);
|
|
435
|
+
|
|
436
|
+
j--; // Drop this watch from the watch list of 'lit'.
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
|
|
441
|
+
assert (u < 0);
|
|
442
|
+
assert (v < 0);
|
|
443
|
+
|
|
444
|
+
// The other watch is assigned false ('u < 0') and all other
|
|
445
|
+
// literals as well (still 'v < 0'), thus we found a conflict.
|
|
446
|
+
|
|
447
|
+
conflict = w.clause;
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (j != i) {
|
|
455
|
+
|
|
456
|
+
while (i != eow)
|
|
457
|
+
*j++ = *i++;
|
|
458
|
+
|
|
459
|
+
ws.resize (j - ws.begin ());
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (searching_lucky_phases) {
|
|
464
|
+
|
|
465
|
+
if (conflict)
|
|
466
|
+
LOG (conflict, "ignoring lucky conflict");
|
|
467
|
+
|
|
468
|
+
} else {
|
|
469
|
+
|
|
470
|
+
// Avoid updating stats eagerly in the hot-spot of the solver.
|
|
471
|
+
//
|
|
472
|
+
stats.propagations.search += propagated - before;
|
|
473
|
+
stats.ticks.search[stable] += ticks;
|
|
474
|
+
|
|
475
|
+
if (!conflict)
|
|
476
|
+
no_conflict_until = propagated;
|
|
477
|
+
else {
|
|
478
|
+
|
|
479
|
+
if (stable)
|
|
480
|
+
stats.stabconflicts++;
|
|
481
|
+
stats.conflicts++;
|
|
482
|
+
|
|
483
|
+
LOG (conflict, "conflict");
|
|
484
|
+
|
|
485
|
+
// The trail before the current decision level was conflict free.
|
|
486
|
+
//
|
|
487
|
+
no_conflict_until = control[level].trail;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (conflict && randomized_deciding) {
|
|
492
|
+
if (!--randomized_deciding)
|
|
493
|
+
VERBOSE (3, "last random decision conflict");
|
|
494
|
+
}
|
|
495
|
+
STOP (propagate);
|
|
496
|
+
|
|
497
|
+
return !conflict;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/*------------------------------------------------------------------------*/
|
|
501
|
+
|
|
502
|
+
void Internal::propergate () {
|
|
503
|
+
|
|
504
|
+
assert (!conflict);
|
|
505
|
+
assert (propagated == trail.size ());
|
|
506
|
+
|
|
507
|
+
while (propergated != trail.size ()) {
|
|
508
|
+
|
|
509
|
+
const int lit = -trail[propergated++];
|
|
510
|
+
LOG ("propergating %d", -lit);
|
|
511
|
+
Watches &ws = watches (lit);
|
|
512
|
+
|
|
513
|
+
const const_watch_iterator eow = ws.end ();
|
|
514
|
+
watch_iterator j = ws.begin ();
|
|
515
|
+
const_watch_iterator i = j;
|
|
516
|
+
|
|
517
|
+
while (i != eow) {
|
|
518
|
+
|
|
519
|
+
const Watch w = *j++ = *i++;
|
|
520
|
+
LOG (w.clause, "propergate");
|
|
521
|
+
if (w.binary ()) {
|
|
522
|
+
assert (val (w.blit) > 0);
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (w.clause->garbage) {
|
|
526
|
+
j--;
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
literal_iterator lits = w.clause->begin ();
|
|
531
|
+
|
|
532
|
+
const int other = lits[0] ^ lits[1] ^ lit;
|
|
533
|
+
const signed char u = val (other);
|
|
534
|
+
|
|
535
|
+
// TODO: check if u == 0 can happen.
|
|
536
|
+
if (u > 0)
|
|
537
|
+
continue;
|
|
538
|
+
assert (u < 0);
|
|
539
|
+
|
|
540
|
+
const int size = w.clause->size;
|
|
541
|
+
const literal_iterator middle = lits + w.clause->pos;
|
|
542
|
+
const const_literal_iterator end = lits + size;
|
|
543
|
+
literal_iterator k = middle;
|
|
544
|
+
|
|
545
|
+
int r = 0;
|
|
546
|
+
signed char v = -1;
|
|
547
|
+
|
|
548
|
+
while (k != end && (v = val (r = *k)) < 0)
|
|
549
|
+
k++;
|
|
550
|
+
|
|
551
|
+
if (v < 0) {
|
|
552
|
+
k = lits + 2;
|
|
553
|
+
assert (w.clause->pos <= size);
|
|
554
|
+
while (k != middle && (v = val (r = *k)) < 0)
|
|
555
|
+
k++;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
assert (lits + 2 <= k), assert (k <= w.clause->end ());
|
|
559
|
+
w.clause->pos = k - lits;
|
|
560
|
+
|
|
561
|
+
assert (v > 0);
|
|
562
|
+
|
|
563
|
+
LOG (w.clause, "unwatch %d in", lit);
|
|
564
|
+
|
|
565
|
+
lits[0] = other;
|
|
566
|
+
lits[1] = r;
|
|
567
|
+
*k = lit;
|
|
568
|
+
|
|
569
|
+
watch_literal (r, lit, w.clause);
|
|
570
|
+
|
|
571
|
+
j--;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (j != i) {
|
|
575
|
+
|
|
576
|
+
while (i != eow)
|
|
577
|
+
*j++ = *i++;
|
|
578
|
+
|
|
579
|
+
ws.resize (j - ws.begin ());
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
} // namespace CaDiCaL
|