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,160 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
/*------------------------------------------------------------------------*/
|
|
4
|
+
|
|
5
|
+
// This is operating system specific code. We mostly develop on Linux and
|
|
6
|
+
// there it should be fine and mostly works out-of-the-box on MacOS too but
|
|
7
|
+
// Windows needs special treatment (as probably other operating systems
|
|
8
|
+
// too).
|
|
9
|
+
|
|
10
|
+
extern "C" {
|
|
11
|
+
|
|
12
|
+
#ifdef _WIN32
|
|
13
|
+
|
|
14
|
+
#ifndef _WIN32_WINNT
|
|
15
|
+
#define _WIN32_WINNT 0x0600
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
// Clang-format would reorder the includes which breaks the Windows code
|
|
19
|
+
// as it expects 'windows.h' to be included first. So disable it here.
|
|
20
|
+
|
|
21
|
+
// clang-format off
|
|
22
|
+
|
|
23
|
+
#include <windows.h>
|
|
24
|
+
#include <psapi.h>
|
|
25
|
+
|
|
26
|
+
// clang-format on
|
|
27
|
+
|
|
28
|
+
#else
|
|
29
|
+
|
|
30
|
+
#include <sys/resource.h>
|
|
31
|
+
#include <sys/time.h>
|
|
32
|
+
#include <sys/types.h>
|
|
33
|
+
#include <unistd.h>
|
|
34
|
+
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
#include <string.h>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
namespace CaDiCaL {
|
|
41
|
+
|
|
42
|
+
/*------------------------------------------------------------------------*/
|
|
43
|
+
|
|
44
|
+
#ifdef _WIN32
|
|
45
|
+
|
|
46
|
+
double absolute_real_time () {
|
|
47
|
+
FILETIME f;
|
|
48
|
+
GetSystemTimeAsFileTime (&f);
|
|
49
|
+
ULARGE_INTEGER t;
|
|
50
|
+
t.LowPart = f.dwLowDateTime;
|
|
51
|
+
t.HighPart = f.dwHighDateTime;
|
|
52
|
+
double res = (__int64) t.QuadPart;
|
|
53
|
+
res *= 1e-7;
|
|
54
|
+
return res;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
double absolute_process_time () {
|
|
58
|
+
double res = 0;
|
|
59
|
+
FILETIME fc, fe, fu, fs;
|
|
60
|
+
if (GetProcessTimes (GetCurrentProcess (), &fc, &fe, &fu, &fs)) {
|
|
61
|
+
ULARGE_INTEGER u, s;
|
|
62
|
+
u.LowPart = fu.dwLowDateTime;
|
|
63
|
+
u.HighPart = fu.dwHighDateTime;
|
|
64
|
+
s.LowPart = fs.dwLowDateTime;
|
|
65
|
+
s.HighPart = fs.dwHighDateTime;
|
|
66
|
+
res = (__int64) u.QuadPart + (__int64) s.QuadPart;
|
|
67
|
+
res *= 1e-7;
|
|
68
|
+
}
|
|
69
|
+
return res;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#else
|
|
73
|
+
|
|
74
|
+
double absolute_real_time () {
|
|
75
|
+
struct timeval tv;
|
|
76
|
+
if (gettimeofday (&tv, 0))
|
|
77
|
+
return 0;
|
|
78
|
+
return 1e-6 * tv.tv_usec + tv.tv_sec;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// We use 'getrusage' for 'process_time' and 'maximum_resident_set_size'
|
|
82
|
+
// which is pretty standard on Unix but probably not available on Windows
|
|
83
|
+
// etc. For different variants of Unix not all fields are meaningful.
|
|
84
|
+
|
|
85
|
+
double absolute_process_time () {
|
|
86
|
+
double res;
|
|
87
|
+
struct rusage u;
|
|
88
|
+
if (getrusage (RUSAGE_SELF, &u))
|
|
89
|
+
return 0;
|
|
90
|
+
res = u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec; // user time
|
|
91
|
+
res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec; // + system time
|
|
92
|
+
return res;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#endif
|
|
96
|
+
|
|
97
|
+
double Internal::real_time () const {
|
|
98
|
+
return absolute_real_time () - stats.time.real;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
double Internal::process_time () const {
|
|
102
|
+
return absolute_process_time () - stats.time.process;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/*------------------------------------------------------------------------*/
|
|
106
|
+
|
|
107
|
+
#ifdef _WIN32
|
|
108
|
+
|
|
109
|
+
uint64_t current_resident_set_size () {
|
|
110
|
+
PROCESS_MEMORY_COUNTERS pmc;
|
|
111
|
+
if (GetProcessMemoryInfo (GetCurrentProcess (), &pmc, sizeof (pmc))) {
|
|
112
|
+
return pmc.WorkingSetSize;
|
|
113
|
+
} else
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
uint64_t maximum_resident_set_size () {
|
|
118
|
+
PROCESS_MEMORY_COUNTERS pmc;
|
|
119
|
+
if (GetProcessMemoryInfo (GetCurrentProcess (), &pmc, sizeof (pmc))) {
|
|
120
|
+
return pmc.PeakWorkingSetSize;
|
|
121
|
+
} else
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#else
|
|
126
|
+
|
|
127
|
+
// This seems to work on Linux (man page says since Linux 2.6.32).
|
|
128
|
+
|
|
129
|
+
uint64_t maximum_resident_set_size () {
|
|
130
|
+
struct rusage u;
|
|
131
|
+
if (getrusage (RUSAGE_SELF, &u))
|
|
132
|
+
return 0;
|
|
133
|
+
return ((uint64_t) u.ru_maxrss) << 10;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Unfortunately 'getrusage' on Linux does not support current resident set
|
|
137
|
+
// size (the field 'ru_ixrss' is there but according to the man page
|
|
138
|
+
// 'unused'). Thus we fall back to use the '/proc' file system instead. So
|
|
139
|
+
// this is not portable at all and needs to be replaced on other systems
|
|
140
|
+
// The code would still compile though (assuming 'sysconf' and
|
|
141
|
+
// '_SC_PAGESIZE' are available).
|
|
142
|
+
|
|
143
|
+
uint64_t current_resident_set_size () {
|
|
144
|
+
char path[64];
|
|
145
|
+
snprintf (path, sizeof path, "/proc/%" PRId64 "/statm",
|
|
146
|
+
(int64_t) getpid ());
|
|
147
|
+
FILE *file = fopen (path, "r");
|
|
148
|
+
if (!file)
|
|
149
|
+
return 0;
|
|
150
|
+
uint64_t dummy, rss;
|
|
151
|
+
int scanned = fscanf (file, "%" PRIu64 " %" PRIu64 "", &dummy, &rss);
|
|
152
|
+
fclose (file);
|
|
153
|
+
return scanned == 2 ? rss * sysconf (_SC_PAGESIZE) : 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#endif
|
|
157
|
+
|
|
158
|
+
/*------------------------------------------------------------------------*/
|
|
159
|
+
|
|
160
|
+
} // namespace CaDiCaL
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#ifndef _resources_hpp_INCLUDED
|
|
2
|
+
#define _resources_hpp_INCLUDED
|
|
3
|
+
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
|
|
6
|
+
namespace CaDiCaL {
|
|
7
|
+
|
|
8
|
+
double absolute_real_time ();
|
|
9
|
+
double absolute_process_time ();
|
|
10
|
+
|
|
11
|
+
uint64_t maximum_resident_set_size ();
|
|
12
|
+
uint64_t current_resident_set_size ();
|
|
13
|
+
|
|
14
|
+
} // namespace CaDiCaL
|
|
15
|
+
|
|
16
|
+
#endif // ifndef _resources_hpp_INCLUDED
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
namespace CaDiCaL {
|
|
4
|
+
|
|
5
|
+
// As observed by Chanseok Oh and implemented in MapleSAT solvers too,
|
|
6
|
+
// various mostly satisfiable instances benefit from long quiet phases
|
|
7
|
+
// with less or almost no restarts. We implement this idea by prohibiting
|
|
8
|
+
// the Glucose style restart scheme in a geometric fashion, which is very
|
|
9
|
+
// similar to how originally restarts were scheduled in MiniSAT and earlier
|
|
10
|
+
// solvers. We start with say 1e3 = 1000 (opts.stabilizeinit) conflicts of
|
|
11
|
+
// Glucose restarts. Then in a "stabilizing" phase we disable these
|
|
12
|
+
// until 1e4 = 2000 conflicts (if 'opts.stabilizefactor' is '200' percent)
|
|
13
|
+
// have passed. After that we switch back to regular Glucose style restarts
|
|
14
|
+
// until again 2 times more conflicts than the previous limit are reached.
|
|
15
|
+
// Actually, in the latest version we still restarts during stabilization
|
|
16
|
+
// but only in a reluctant doubling scheme with a rather high interval.
|
|
17
|
+
|
|
18
|
+
bool Internal::stabilizing () {
|
|
19
|
+
if (!opts.stabilize)
|
|
20
|
+
return false;
|
|
21
|
+
if (stable && opts.stabilizeonly)
|
|
22
|
+
return true;
|
|
23
|
+
if (!inc.stabilize) {
|
|
24
|
+
assert (!stable);
|
|
25
|
+
if (stats.conflicts <= lim.stabilize)
|
|
26
|
+
return false;
|
|
27
|
+
} else if (stats.ticks.search[stable] <= lim.stabilize)
|
|
28
|
+
return stable;
|
|
29
|
+
report (stable ? ']' : '}');
|
|
30
|
+
if (stable)
|
|
31
|
+
STOP (stable);
|
|
32
|
+
else
|
|
33
|
+
STOP (unstable);
|
|
34
|
+
|
|
35
|
+
assert (last.stabilize.ticks >= 0);
|
|
36
|
+
assert (last.stabilize.conflicts >= 0 &&
|
|
37
|
+
last.stabilize.conflicts <= stats.conflicts);
|
|
38
|
+
assert (last.stabilize.ticks <= stats.ticks.search[stable]);
|
|
39
|
+
const int64_t delta_ticks =
|
|
40
|
+
stats.ticks.search[stable] - last.stabilize.ticks;
|
|
41
|
+
#ifndef QUIET
|
|
42
|
+
const int64_t delta_conflicts =
|
|
43
|
+
stats.conflicts - last.stabilize.conflicts;
|
|
44
|
+
const char *current_mode = stable ? "stable" : "unstable";
|
|
45
|
+
const char *next_mode = stable ? "unstable" : "stable";
|
|
46
|
+
#endif
|
|
47
|
+
PHASE ("stabilizing", stats.stabphases,
|
|
48
|
+
"reached %s stabilization limit %" PRId64 " after %" PRId64
|
|
49
|
+
" conflicts and %" PRId64 " ticks at %" PRId64
|
|
50
|
+
" conflicts and %" PRId64 " ticks",
|
|
51
|
+
current_mode, lim.stabilize, delta_conflicts, delta_ticks,
|
|
52
|
+
stats.conflicts, stats.ticks.search[stable]);
|
|
53
|
+
if (!inc.stabilize)
|
|
54
|
+
inc.stabilize = delta_ticks;
|
|
55
|
+
if (!inc.stabilize) // rare occurence in incremental calls requiring no
|
|
56
|
+
// ticks
|
|
57
|
+
inc.stabilize = 1;
|
|
58
|
+
|
|
59
|
+
int64_t next_delta_ticks = inc.stabilize;
|
|
60
|
+
int64_t stabphases = stats.stabphases + 1;
|
|
61
|
+
next_delta_ticks *= stabphases * stabphases;
|
|
62
|
+
|
|
63
|
+
const bool next_stable = !stable;
|
|
64
|
+
lim.stabilize = stats.ticks.search[next_stable] + next_delta_ticks;
|
|
65
|
+
last.stabilize.ticks = stats.ticks.search[next_stable];
|
|
66
|
+
if (lim.stabilize <= stats.ticks.search[next_stable])
|
|
67
|
+
lim.stabilize = stats.ticks.search[next_stable] + 1;
|
|
68
|
+
PHASE ("stabilizing", stats.stabphases,
|
|
69
|
+
"next %s stabilization limit %" PRId64
|
|
70
|
+
" at ticks interval %" PRId64,
|
|
71
|
+
next_mode, lim.stabilize, next_delta_ticks);
|
|
72
|
+
|
|
73
|
+
stable = !stable; // Switch!!!!!
|
|
74
|
+
|
|
75
|
+
if (stable)
|
|
76
|
+
stats.stabphases++;
|
|
77
|
+
|
|
78
|
+
swap_averages ();
|
|
79
|
+
report (stable ? '[' : '{');
|
|
80
|
+
if (stable)
|
|
81
|
+
START (stable);
|
|
82
|
+
else
|
|
83
|
+
START (unstable);
|
|
84
|
+
return stable;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Restarts are scheduled by a variant of the Glucose scheme as presented
|
|
88
|
+
// in our POS'15 paper using exponential moving averages. There is a slow
|
|
89
|
+
// moving average of the average recent glucose level of learned clauses
|
|
90
|
+
// as well as a fast moving average of those glues. If the end of a base
|
|
91
|
+
// restart conflict interval has passed and the fast moving average is
|
|
92
|
+
// above a certain margin over the slow moving average then we restart.
|
|
93
|
+
|
|
94
|
+
bool Internal::restarting () {
|
|
95
|
+
if (!opts.restart)
|
|
96
|
+
return false;
|
|
97
|
+
if ((size_t) level < assumptions.size () + 2)
|
|
98
|
+
return false;
|
|
99
|
+
if (stabilizing () && opts.reluctant)
|
|
100
|
+
return reluctant;
|
|
101
|
+
if (stats.conflicts <= lim.restart)
|
|
102
|
+
return false;
|
|
103
|
+
double f = averages.current.glue.fast;
|
|
104
|
+
int p = stable ? opts.restartmarginstable : opts.restartmarginfocused;
|
|
105
|
+
double m = (100.0 + p) / 100.0;
|
|
106
|
+
double s = averages.current.glue.slow;
|
|
107
|
+
double l = m * s;
|
|
108
|
+
|
|
109
|
+
#ifndef QUIET
|
|
110
|
+
char c = l > f ? '>' : l < f ? '<' : '=';
|
|
111
|
+
VERBOSE (3,
|
|
112
|
+
"restart glue limit "
|
|
113
|
+
"%g = %.2f * %g (slow glue) %c %g (fast glue)",
|
|
114
|
+
l, m, s, c, f);
|
|
115
|
+
#endif
|
|
116
|
+
|
|
117
|
+
return l <= f;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// This is Marijn's reuse trail idea. Instead of always backtracking to
|
|
121
|
+
// the top we figure out which decisions will be made again anyhow and
|
|
122
|
+
// only backtrack to the level of the last such decision or to the top if
|
|
123
|
+
// no such decision exists top (in which case we do not reuse any level).
|
|
124
|
+
|
|
125
|
+
int Internal::reuse_trail () {
|
|
126
|
+
const int trivial_decisions =
|
|
127
|
+
assumptions.size ()
|
|
128
|
+
// Plus 1 if the constraint is satisfied via implications of
|
|
129
|
+
// assumptions and a pseudo-decision level was introduced.
|
|
130
|
+
+ !control[assumptions.size () + 1].decision;
|
|
131
|
+
if (!opts.restartreusetrail)
|
|
132
|
+
return trivial_decisions;
|
|
133
|
+
int next_decision = next_decision_variable ();
|
|
134
|
+
assert (1 <= next_decision);
|
|
135
|
+
int res = trivial_decisions;
|
|
136
|
+
if (use_scores ()) {
|
|
137
|
+
while (res < level) {
|
|
138
|
+
int decision = control[res + 1].decision;
|
|
139
|
+
if (decision && score_smaller (this) (abs (decision), next_decision))
|
|
140
|
+
break;
|
|
141
|
+
res++;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
int64_t limit = bumped (next_decision);
|
|
145
|
+
while (res < level) {
|
|
146
|
+
int decision = control[res + 1].decision;
|
|
147
|
+
if (decision && bumped (decision) < limit)
|
|
148
|
+
break;
|
|
149
|
+
res++;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
int reused = res - trivial_decisions;
|
|
153
|
+
if (reused > 0) {
|
|
154
|
+
stats.reused++;
|
|
155
|
+
stats.reusedlevels += reused;
|
|
156
|
+
if (stable)
|
|
157
|
+
stats.reusedstable++;
|
|
158
|
+
}
|
|
159
|
+
return res;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
void Internal::restart () {
|
|
163
|
+
START (restart);
|
|
164
|
+
stats.restarts++;
|
|
165
|
+
stats.restartlevels += level;
|
|
166
|
+
if (stable)
|
|
167
|
+
stats.restartstable++;
|
|
168
|
+
LOG ("restart %" PRId64 "", stats.restarts);
|
|
169
|
+
backtrack (reuse_trail ());
|
|
170
|
+
|
|
171
|
+
lim.restart = stats.conflicts + opts.restartint;
|
|
172
|
+
LOG ("new restart limit at %" PRId64 " conflicts", lim.restart);
|
|
173
|
+
|
|
174
|
+
report ('R', 2);
|
|
175
|
+
STOP (restart);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
} // namespace CaDiCaL
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
namespace CaDiCaL {
|
|
4
|
+
|
|
5
|
+
/*------------------------------------------------------------------------*/
|
|
6
|
+
|
|
7
|
+
// In incremental solving after a first call to 'solve' has finished and
|
|
8
|
+
// before calling the internal 'solve' again incrementally we have to
|
|
9
|
+
// restore clauses which have the negation of a literal as a witness literal
|
|
10
|
+
// on the extension stack, which was added as original literal in a new
|
|
11
|
+
// clause or in an assumption. This procedure has to be applied
|
|
12
|
+
// recursively, i.e., the literals of restored clauses are treated in the
|
|
13
|
+
// same way as literals of a new original clause.
|
|
14
|
+
//
|
|
15
|
+
// To figure out whether literals are such witnesses we have a 'witness'
|
|
16
|
+
// bit for each external literal, which is set in 'block', 'elim', and
|
|
17
|
+
// 'decompose' if a clause is pushed on the extension stack. The witness
|
|
18
|
+
// bits are recomputed after restoring clauses.
|
|
19
|
+
//
|
|
20
|
+
// We further mark in the external solver newly internalized external
|
|
21
|
+
// literals in 'add' and 'assume' since the last call to 'solve' as tainted
|
|
22
|
+
// if they occur negated as a witness literal on the extension stack. Then
|
|
23
|
+
// we go through the extension stack and restore all clauses which have a
|
|
24
|
+
// tainted literal (and its negation a marked as witness).
|
|
25
|
+
//
|
|
26
|
+
// Since the API contract disallows to call 'val' and 'failed' in an
|
|
27
|
+
// 'UNKNOWN' state. We do not have to internalize literals there.
|
|
28
|
+
//
|
|
29
|
+
// In order to have tainted literals accepted by the internal solver they
|
|
30
|
+
// have to be active and thus we might need to 'reactivate' them before
|
|
31
|
+
// restoring clauses if they are inactive. In case they have completely
|
|
32
|
+
// been eliminated and removed from the internal solver in 'compact', then
|
|
33
|
+
// we just use a new internal variable. This is performed in 'internalize'
|
|
34
|
+
// during marking external literals as tainted.
|
|
35
|
+
//
|
|
36
|
+
// To check that this approach is correct the external solver can maintain a
|
|
37
|
+
// stack of original clauses and current assumptions both in terms of
|
|
38
|
+
// external literals. Whenever 'solve' determines that the current
|
|
39
|
+
// incremental call is satisfiable we check that the (extended) witness does
|
|
40
|
+
// satisfy the saved original clauses, as well as all the assumptions. To
|
|
41
|
+
// enable these checks set 'opts.check' as well as 'opts.checkwitness' and
|
|
42
|
+
// 'opts.checkassumptions' all to 'true'. The model based tester actually
|
|
43
|
+
// prefers to enable the 'opts.check' option and the other two are 'true' by
|
|
44
|
+
// default anyhow.
|
|
45
|
+
//
|
|
46
|
+
// See our SAT'19 paper [FazekasBiereScholl-SAT'19] for more details.
|
|
47
|
+
|
|
48
|
+
/*------------------------------------------------------------------------*/
|
|
49
|
+
|
|
50
|
+
void External::restore_clause (const vector<int>::const_iterator &begin,
|
|
51
|
+
const vector<int>::const_iterator &end,
|
|
52
|
+
const int64_t id) {
|
|
53
|
+
LOG (begin, end, "restoring external clause[%" PRId64 "]", id);
|
|
54
|
+
assert (eclause.empty ());
|
|
55
|
+
assert (id);
|
|
56
|
+
for (auto p = begin; p != end; p++) {
|
|
57
|
+
eclause.push_back (*p);
|
|
58
|
+
if (internal->proof && internal->lrat) {
|
|
59
|
+
const auto &elit = *p;
|
|
60
|
+
unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit);
|
|
61
|
+
assert ((size_t) eidx < ext_units.size ());
|
|
62
|
+
const int64_t id = ext_units[eidx];
|
|
63
|
+
bool added = ext_flags[abs (elit)];
|
|
64
|
+
if (id && !added) {
|
|
65
|
+
ext_flags[abs (elit)] = true;
|
|
66
|
+
internal->lrat_chain.push_back (id);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
int ilit = internalize (*p);
|
|
70
|
+
internal->add_original_lit (ilit), internal->stats.restoredlits++;
|
|
71
|
+
}
|
|
72
|
+
if (internal->proof && internal->lrat) {
|
|
73
|
+
for (const auto &elit : eclause) {
|
|
74
|
+
ext_flags[abs (elit)] = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
internal->finish_added_clause_with_id (id, true);
|
|
78
|
+
eclause.clear ();
|
|
79
|
+
internal->stats.restored++;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*------------------------------------------------------------------------*/
|
|
83
|
+
|
|
84
|
+
void External::restore_clauses () {
|
|
85
|
+
|
|
86
|
+
assert (internal->opts.restoreall == 2 || !tainted.empty ());
|
|
87
|
+
|
|
88
|
+
START (restore);
|
|
89
|
+
internal->stats.restorations++;
|
|
90
|
+
|
|
91
|
+
struct {
|
|
92
|
+
int64_t weakened, satisfied, restored, removed;
|
|
93
|
+
} clauses;
|
|
94
|
+
memset (&clauses, 0, sizeof clauses);
|
|
95
|
+
|
|
96
|
+
if (internal->opts.restoreall && tainted.empty ())
|
|
97
|
+
PHASE ("restore", internal->stats.restorations,
|
|
98
|
+
"forced to restore all clauses");
|
|
99
|
+
|
|
100
|
+
#ifndef QUIET
|
|
101
|
+
{
|
|
102
|
+
unsigned numtainted = 0;
|
|
103
|
+
for (const auto b : tainted)
|
|
104
|
+
if (b)
|
|
105
|
+
numtainted++;
|
|
106
|
+
|
|
107
|
+
PHASE ("restore", internal->stats.restorations,
|
|
108
|
+
"starting with %u tainted literals %.0f%%", numtainted,
|
|
109
|
+
percent (numtainted, 2u * max_var));
|
|
110
|
+
}
|
|
111
|
+
#endif
|
|
112
|
+
|
|
113
|
+
auto end_of_extension = extension.end ();
|
|
114
|
+
auto p = extension.begin (), q = p;
|
|
115
|
+
|
|
116
|
+
// Go over all witness labelled clauses on the extension stack, restore
|
|
117
|
+
// those necessary, remove restored and flush satisfied clauses.
|
|
118
|
+
//
|
|
119
|
+
while (p != end_of_extension) {
|
|
120
|
+
|
|
121
|
+
clauses.weakened++;
|
|
122
|
+
|
|
123
|
+
assert (!*p);
|
|
124
|
+
const auto saved = q; // Save old start.
|
|
125
|
+
*q++ = *p++; // Copy zero '0'.
|
|
126
|
+
|
|
127
|
+
// Copy witness part and try to find a tainted witness literal in it.
|
|
128
|
+
//
|
|
129
|
+
int tlit = 0; // Negation tainted.
|
|
130
|
+
int elit;
|
|
131
|
+
//
|
|
132
|
+
assert (p != end_of_extension);
|
|
133
|
+
//
|
|
134
|
+
while ((elit = *q++ = *p++)) {
|
|
135
|
+
|
|
136
|
+
if (marked (tainted, -elit)) {
|
|
137
|
+
tlit = elit;
|
|
138
|
+
LOG ("negation of witness literal %d tainted", tlit);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
assert (p != end_of_extension);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// now copy the id of the clause
|
|
145
|
+
const int64_t id = ((int64_t) (*p) << 32) + (int64_t) * (p + 1);
|
|
146
|
+
LOG ("id is %" PRId64, id);
|
|
147
|
+
*q++ = *p++;
|
|
148
|
+
*q++ = *p++;
|
|
149
|
+
assert (id);
|
|
150
|
+
assert (!*p);
|
|
151
|
+
*q++ = *p++;
|
|
152
|
+
|
|
153
|
+
// Now find 'end_of_clause' (clause starts at 'p') and at the same time
|
|
154
|
+
// figure out whether the clause is actually root level satisfied.
|
|
155
|
+
//
|
|
156
|
+
int satisfied = 0;
|
|
157
|
+
auto end_of_clause = p;
|
|
158
|
+
while (end_of_clause != end_of_extension && (elit = *end_of_clause)) {
|
|
159
|
+
if (!satisfied && fixed (elit) > 0)
|
|
160
|
+
satisfied = elit;
|
|
161
|
+
end_of_clause++;
|
|
162
|
+
}
|
|
163
|
+
assert (id);
|
|
164
|
+
|
|
165
|
+
// Do not apply our 'FLUSH' rule to remove satisfied (implied) clauses
|
|
166
|
+
// if the corresponding option is set simply by resetting 'satisfied'.
|
|
167
|
+
//
|
|
168
|
+
if (satisfied && !internal->opts.restoreflush) {
|
|
169
|
+
LOG (p, end_of_clause, "forced to not remove %d satisfied",
|
|
170
|
+
satisfied);
|
|
171
|
+
satisfied = 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (satisfied || tlit || internal->opts.restoreall) {
|
|
175
|
+
|
|
176
|
+
if (satisfied) {
|
|
177
|
+
LOG (p, end_of_clause,
|
|
178
|
+
"flushing implied clause satisfied by %d from extension stack",
|
|
179
|
+
satisfied);
|
|
180
|
+
clauses.satisfied++;
|
|
181
|
+
} else {
|
|
182
|
+
restore_clause (p, end_of_clause, id); // Might taint literals.
|
|
183
|
+
clauses.restored++;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
clauses.removed++;
|
|
187
|
+
p = end_of_clause;
|
|
188
|
+
q = saved;
|
|
189
|
+
|
|
190
|
+
} else {
|
|
191
|
+
|
|
192
|
+
LOG (p, end_of_clause, "keeping clause on extension stack");
|
|
193
|
+
|
|
194
|
+
while (p != end_of_clause) // Copy clause too.
|
|
195
|
+
*q++ = *p++;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
extension.resize (q - extension.begin ());
|
|
200
|
+
shrink_vector (extension);
|
|
201
|
+
|
|
202
|
+
#ifndef QUIET
|
|
203
|
+
if (clauses.satisfied)
|
|
204
|
+
PHASE ("restore", internal->stats.restorations,
|
|
205
|
+
"removed %" PRId64 " satisfied %.0f%% of %" PRId64
|
|
206
|
+
" weakened clauses",
|
|
207
|
+
clauses.satisfied, percent (clauses.satisfied, clauses.weakened),
|
|
208
|
+
clauses.weakened);
|
|
209
|
+
else
|
|
210
|
+
PHASE ("restore", internal->stats.restorations,
|
|
211
|
+
"no satisfied clause removed out of %" PRId64
|
|
212
|
+
" weakened clauses",
|
|
213
|
+
clauses.weakened);
|
|
214
|
+
|
|
215
|
+
if (clauses.restored)
|
|
216
|
+
PHASE ("restore", internal->stats.restorations,
|
|
217
|
+
"restored %" PRId64 " clauses %.0f%% out of %" PRId64
|
|
218
|
+
" weakened clauses",
|
|
219
|
+
clauses.restored, percent (clauses.restored, clauses.weakened),
|
|
220
|
+
clauses.weakened);
|
|
221
|
+
else
|
|
222
|
+
PHASE ("restore", internal->stats.restorations,
|
|
223
|
+
"no clause restored out of %" PRId64 " weakened clauses",
|
|
224
|
+
clauses.weakened);
|
|
225
|
+
{
|
|
226
|
+
unsigned numtainted = 0;
|
|
227
|
+
for (const auto &b : tainted)
|
|
228
|
+
if (b)
|
|
229
|
+
numtainted++;
|
|
230
|
+
|
|
231
|
+
PHASE ("restore", internal->stats.restorations,
|
|
232
|
+
"finishing with %u tainted literals %.0f%%", numtainted,
|
|
233
|
+
percent (numtainted, 2u * max_var));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
#endif
|
|
237
|
+
LOG ("extension stack clean");
|
|
238
|
+
tainted.clear ();
|
|
239
|
+
|
|
240
|
+
// Finally recompute the witness bits.
|
|
241
|
+
//
|
|
242
|
+
witness.clear ();
|
|
243
|
+
const auto begin_of_extension = extension.begin ();
|
|
244
|
+
p = extension.end ();
|
|
245
|
+
while (p != begin_of_extension) {
|
|
246
|
+
while (*--p)
|
|
247
|
+
assert (p != begin_of_extension);
|
|
248
|
+
int elit;
|
|
249
|
+
assert (p != begin_of_extension);
|
|
250
|
+
--p;
|
|
251
|
+
assert (p != begin_of_extension);
|
|
252
|
+
assert (*p || *(p - 1));
|
|
253
|
+
--p;
|
|
254
|
+
assert (p != begin_of_extension);
|
|
255
|
+
assert (!*p);
|
|
256
|
+
--p;
|
|
257
|
+
assert (p != begin_of_extension);
|
|
258
|
+
while ((elit = *--p)) {
|
|
259
|
+
mark (witness, elit);
|
|
260
|
+
assert (p != begin_of_extension);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
STOP (restore);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
} // namespace CaDiCaL
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
namespace CaDiCaL {
|
|
4
|
+
|
|
5
|
+
// This initializes variables on the binary 'scores' heap also with
|
|
6
|
+
// smallest variable index first (thus picked first) and larger indices at
|
|
7
|
+
// the end.
|
|
8
|
+
//
|
|
9
|
+
void Internal::init_scores (int old_max_var, int new_max_var) {
|
|
10
|
+
LOG ("initializing EVSIDS scores from %d to %d", old_max_var + 1,
|
|
11
|
+
new_max_var);
|
|
12
|
+
for (int i = old_max_var; i < new_max_var; i++)
|
|
13
|
+
scores.push_back (i + 1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Shuffle the EVSIDS heap.
|
|
17
|
+
|
|
18
|
+
void Internal::shuffle_scores () {
|
|
19
|
+
if (!opts.shuffle)
|
|
20
|
+
return;
|
|
21
|
+
if (!opts.shufflescores)
|
|
22
|
+
return;
|
|
23
|
+
assert (!level);
|
|
24
|
+
stats.shuffled++;
|
|
25
|
+
LOG ("shuffling scores");
|
|
26
|
+
vector<int> shuffle;
|
|
27
|
+
if (opts.shufflerandom) {
|
|
28
|
+
scores.erase ();
|
|
29
|
+
for (int idx = max_var; idx; idx--)
|
|
30
|
+
shuffle.push_back (idx);
|
|
31
|
+
Random random (opts.seed); // global seed
|
|
32
|
+
random += stats.shuffled; // different every time
|
|
33
|
+
for (int i = 0; i <= max_var - 2; i++) {
|
|
34
|
+
const int j = random.pick_int (i, max_var - 1);
|
|
35
|
+
swap (shuffle[i], shuffle[j]);
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
while (!scores.empty ()) {
|
|
39
|
+
int idx = scores.front ();
|
|
40
|
+
(void) scores.pop_front ();
|
|
41
|
+
shuffle.push_back (idx);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
score_inc = 0;
|
|
45
|
+
for (const auto &idx : shuffle) {
|
|
46
|
+
stab[idx] = score_inc++;
|
|
47
|
+
scores.push_back (idx);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
} // namespace CaDiCaL
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#ifndef _score_hpp_INCLUDED
|
|
2
|
+
#define _score_hpp_INCLUDED
|
|
3
|
+
|
|
4
|
+
namespace CaDiCaL {
|
|
5
|
+
|
|
6
|
+
struct score_smaller {
|
|
7
|
+
Internal *internal;
|
|
8
|
+
score_smaller (Internal *i) : internal (i) {}
|
|
9
|
+
bool operator() (unsigned a, unsigned b);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
typedef heap<score_smaller> ScoreSchedule;
|
|
13
|
+
|
|
14
|
+
} // namespace CaDiCaL
|
|
15
|
+
|
|
16
|
+
#endif
|