1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
#ifndef _external_hpp_INCLUDED
#define _external_hpp_INCLUDED
/*------------------------------------------------------------------------*/
#include "range.hpp"
#include <cstdint>
#include <unordered_map>
#include <vector>
/*------------------------------------------------------------------------*/
namespace CaDiCaL {
using namespace std;
/*------------------------------------------------------------------------*/
// The CaDiCaL code is split into three layers:
//
// Solver: facade object providing the actual API of the solver
// External: communication layer between 'Solver' and 'Internal'
// Internal: the actual solver code
//
// Note, that 'Solver' is defined in 'cadical.hpp' and 'solver.cpp', while
// 'External' and 'Internal' in '{external,internal}.{hpp,cpp}'.
//
// Also note, that any user should access the library only through the
// 'Solver' API. For the library internal 'Parser' code we make an
// exception and allow access to both 'External' and 'Internal'. The former
// to enforce the same external to internal mapping of variables and the
// latter for profiling and messages. The same applies to 'App'.
//
// The 'External' class provided here stores the information needed to map
// external variable indices to internal variables (actually literals).
// This is helpful for shrinking the working size of the internal solver
// after many variables become inactive. It will also help to provide
// support for extended resolution in the future, since it allows to
// introduce only internally visible variables (even though we do not know
// how to support generating incremental proofs in this situation yet).
//
// External literals are usually called 'elit' and internal 'ilit'.
/*------------------------------------------------------------------------*/
struct Clause;
struct Internal;
struct CubesWithStatus;
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
struct External {
/*==== start of state ==================================================*/
Internal *internal; // The actual internal solver.
int max_var; // External maximum variable index.
size_t vsize; // Allocated external size.
vector<bool> vals; // Current external (extended) assignment.
vector<int> e2i; // External 'idx' to internal 'lit'.
vector<int> assumptions; // External assumptions.
vector<int> constraint; // External constraint. Terminated by zero.
vector<int64_t>
ext_units; // External units. Needed to compute LRAT for eclause
vector<bool> ext_flags; // to avoid duplicate units
vector<int> eclause; // External version of original input clause.
// The extension stack for reconstructing complete satisfying assignments
// (models) of the original external formula is kept in this external
// solver object. It keeps track of blocked clauses and clauses containing
// eliminated variable. These irredundant clauses are stored in terms of
// external literals on the 'extension' stack after mapping the
// internal literals given as arguments with 'externalize'.
bool extended; // Have been extended.
bool concluded;
vector<int> extension; // Solution reconstruction extension stack.
vector<bool> witness; // Literal witness on extension stack.
vector<bool> tainted; // Literal tainted in adding literals.
vector<bool> ervars; // Variables added through Extended Resolution.
vector<unsigned> frozentab; // Reference counts for frozen variables.
// Regularly checked terminator if non-zero. The terminator is set from
// 'Solver::set (Terminator *)' and checked by 'Internal::terminating ()'.
Terminator *terminator;
// If there is a learner export learned clauses.
Learner *learner;
void export_learned_empty_clause ();
void export_learned_unit_clause (int ilit);
void export_learned_large_clause (const vector<int> &);
// If there is a listener for fixed assignments.
FixedAssignmentListener *fixed_listener;
// If there is an external propagator.
ExternalPropagator *propagator;
vector<bool> is_observed; // Quick flag for each external variable
// Saved 'forgettable' original clauses coming from the external
// propagator. The value of the map starts with a Boolean flag indicating
// if the clause is still present or got already deleted, and then
// followed by the literals of the clause.
unordered_map<uint64_t, vector<int>> forgettable_original;
void add_observed_var (int elit);
void remove_observed_var (int elit);
void reset_observed_vars ();
bool observed (int elit);
bool is_witness (int elit);
bool is_decision (int elit);
void force_backtrack (int new_level);
//----------------------------------------------------------------------//
signed char *solution; // Given solution checking for debugging.
int solution_size; // Given solution checking for debugging.
vector<int> original; // Saved original formula for checking.
// If 'opts.checkfrozen' is set make sure that only literals are added
// which were never completely molten before. These molten literals are
// marked at the beginning of the 'solve' call. Note that variables
// larger than 'max_var' are not molten and can thus always be used in the
// future. Only needed to check and debug old style freeze semantics.
//
vector<bool> moltentab;
//----------------------------------------------------------------------//
const Range vars; // Provides safe variable iterations.
/*==== end of state ====================================================*/
// These two just factor out common sanity (assertion) checking code.
inline int vidx (int elit) const {
assert (elit);
assert (elit != INT_MIN);
int res = abs (elit);
assert (res <= max_var);
return res;
}
inline int vlit (int elit) const {
assert (elit);
assert (elit != INT_MIN);
assert (abs (elit) <= max_var);
return elit;
}
inline bool is_valid_input (int elit) {
assert (elit);
assert (elit != INT_MIN);
int eidx = abs (elit);
return eidx > max_var || !ervars[eidx];
}
/*----------------------------------------------------------------------*/
// The following five functions push individual literals or clauses on the
// extension stack. They all take internal literals as argument, and map
// them back to external literals first, before pushing them on the stack.
void push_zero_on_extension_stack ();
// Our general version of extension stacks always pushes a set of witness
// literals (for variable elimination the literal of the eliminated
// literal and for blocked clauses the blocking literal) followed by all
// the clause literals starting with and separated by zero.
//
void push_clause_literal_on_extension_stack (int ilit);
void push_witness_literal_on_extension_stack (int ilit);
void push_clause_on_extension_stack (Clause *);
void push_clause_on_extension_stack (Clause *, int witness);
void push_binary_clause_on_extension_stack (int64_t id, int witness,
int other);
// The main 'extend' function which extends an internal assignment to an
// external assignment using the extension stack (and sets 'extended').
//
void extend ();
void conclude_sat ();
/*----------------------------------------------------------------------*/
// Marking external literals.
unsigned elit2ulit (int elit) const {
assert (elit);
assert (elit != INT_MIN);
const int idx = abs (elit) - 1;
assert (idx <= max_var);
return 2u * idx + (elit < 0);
}
bool marked (const vector<bool> &map, int elit) const {
const unsigned ulit = elit2ulit (elit);
return ulit < map.size () ? map[ulit] : false;
}
void mark (vector<bool> &map, int elit) {
const unsigned ulit = elit2ulit (elit);
if (ulit >= map.size ())
map.resize (ulit + 1, false);
map[ulit] = true;
}
void unmark (vector<bool> &map, int elit) {
const unsigned ulit = elit2ulit (elit);
if (ulit < map.size ())
map[ulit] = false;
}
/*----------------------------------------------------------------------*/
void push_external_clause_and_witness_on_extension_stack (
const vector<int> &clause, const vector<int> &witness, int64_t id);
void push_id_on_extension_stack (int64_t id);
// Restore a clause, which was pushed on the extension stack.
void restore_clause (const vector<int>::const_iterator &begin,
const vector<int>::const_iterator &end,
const int64_t id);
void restore_clauses ();
/*----------------------------------------------------------------------*/
// Explicitly freeze and melt literals (instead of just freezing
// internally and implicitly assumed literals). Passes on freezing and
// melting to the internal solver, which has separate frozen counters.
void freeze (int elit);
void melt (int elit);
bool frozen (int elit) {
assert (elit);
assert (elit != INT_MIN);
int eidx = abs (elit);
if (eidx > max_var)
return false;
if (eidx >= (int) frozentab.size ())
return false;
return frozentab[eidx] > 0;
}
/*----------------------------------------------------------------------*/
External (Internal *);
~External ();
void enlarge (int new_max_var); // Enlarge allocated 'vsize'.
void init (int new_max_var,
bool extension = false); // Initialize up-to 'new_max_var'.
int internalize (
int,
bool extension = false); // Translate external to internal literal.
/*----------------------------------------------------------------------*/
// According to the CaDiCaL API contract (as well as IPASIR) we have to
// forget about the previous assumptions after a 'solve' call. This
// should however be delayed until we transition out of an 'UNSATISFIED'
// state, i.e., after no more 'failed' calls are expected. Note that
// 'failed' requires to know the failing assumptions, and the 'failed'
// status of those should cleared before at start of the next 'solve'.
// As a consequence 'reset_assumptions' is only called from
// 'transition_to_unknown_state' in API calls in 'solver.cpp'.
void reset_assumptions ();
// Similarly to 'failed', 'conclude' needs to know about failing
// assumptions and therefore needs to be reset when leaving the
// 'UNSATISFIED' state.
//
void reset_concluded ();
// Similarly a valid external assignment obtained through 'extend' has to
// be reset at each point it risks to become invalid. This is done
// in the external layer in 'external.cpp' functions..
void reset_extended ();
// Finally, the semantics of incremental solving also require that limits
// are only valid for the next 'solve' call. Since the limits can not
// really be queried, handling them is less complex and they are just
// reset immediately at the end of 'External::solve'.
void reset_limits ();
/*----------------------------------------------------------------------*/
// Proxies to IPASIR functions.
void add (int elit);
void assume (int elit);
int solve (bool preprocess_only);
// We call it 'ival' as abbreviation for 'val' with 'int' return type to
// avoid bugs due to using 'signed char tmp = val (lit)', which might turn
// a negative value into a positive one (happened in 'extend').
// This is due to the IPASIR semantics which returns 'elit' if it is
// 'true' and '-elit' if it is 'false'. This is a bit confusing but has
// been standardized in IPASIR:
//
// Consiert 'eidx = 13' and 'vals[13] == false' then '13' is 'false' in
// this terminology of the IPASIR interface. Accordingly we get
//
// ival (13) = -13
//
// However and this is the confusing thing, as '-13' is true the 'ival'
// function should also return '-13':
//
// ival (-13) = -13
//
// Now with '13' assumed 'true' so 'vals[13] = true' we similarly have
//
// ival (13) = 13 as '13' is true'
//
// ival (-13) = 13 as '-13' is false
//
// To summarize we can think of the IPASIR 'ipasir_val' function, which
// 'CaDiCaL' follows as returning the phase of the literal which is true
// under the current assignment no matter whether you give the positive
// literal or its negation and thus 'ival (lit) == ival (-lit))"
inline int ival (int elit) const {
assert (elit != INT_MIN);
int eidx = abs (elit);
bool val = false;
if (eidx <= max_var && (size_t) eidx < vals.size ())
val = vals[eidx];
if (elit < 0)
val = !val;
return val ? elit : -elit;
}
bool flip (int elit);
bool flippable (int elit);
bool failed (int elit);
void terminate ();
// Other important non IPASIR functions.
/*----------------------------------------------------------------------*/
// Add literal to external constraint.
//
void constrain (int elit);
// Returns true if 'solve' returned 20 because of the constraint.
//
bool failed_constraint ();
// Deletes the current constraint clause. Called on
// 'transition_to_unknown_state' and if a new constraint is added. Can be
// called directly using the API.
//
void reset_constraint ();
/*----------------------------------------------------------------------*/
int propagate_assumptions ();
void implied (std::vector<int> &entrailed);
void conclude_unknown ();
/*----------------------------------------------------------------------*/
int lookahead ();
CaDiCaL::CubesWithStatus generate_cubes (int, int);
int fixed (int elit) const; // Implemented in 'internal.hpp'.
/*----------------------------------------------------------------------*/
void phase (int elit);
void unphase (int elit);
/*----------------------------------------------------------------------*/
// Traversal functions for the witness stack and units. The explanation
// in 'external.cpp' for why we have to distinguish these cases.
bool traverse_all_frozen_units_as_clauses (ClauseIterator &);
bool traverse_all_non_frozen_units_as_witnesses (WitnessIterator &);
bool traverse_witnesses_backward (WitnessIterator &);
bool traverse_witnesses_forward (WitnessIterator &);
/*----------------------------------------------------------------------*/
// Copy flags for determining preprocessing state.
void copy_flags (External &other) const;
/*----------------------------------------------------------------------*/
// Check solver behaves as expected during testing and debugging.
void check_assumptions_satisfied ();
void check_constraint_satisfied ();
void check_failing ();
void check_solution_on_learned_clause ();
void check_solution_on_shrunken_clause (Clause *);
void check_solution_on_learned_unit_clause (int unit);
void check_no_solution_after_learning_empty_clause ();
void check_learned_empty_clause () {
if (solution)
check_no_solution_after_learning_empty_clause ();
}
void check_learned_unit_clause (int unit) {
if (solution)
check_solution_on_learned_unit_clause (unit);
}
void check_learned_clause () {
if (solution)
check_solution_on_learned_clause ();
}
void check_shrunken_clause (Clause *c) {
if (solution)
check_solution_on_shrunken_clause (c);
}
void check_assignment (int (External::*assignment) (int) const);
void check_satisfiable ();
void check_unsatisfiable ();
void check_solve_result (int res);
void update_molten_literals ();
/*----------------------------------------------------------------------*/
// For debugging and testing only. See 'solution.hpp' for more details.
// TODO: if elit > solution_size, elit is an extension variable. For now
// the clause will count as satisfied regardless. For the future one
// should check that actually there is one consistent extension for the
// solution that satisfies the clauses with this extension variable (by
// setting it to a value once a clause is learned which is not satisfied
// already).
//
inline int sol (int elit) const {
assert (solution);
assert (elit != INT_MIN);
int eidx = abs (elit);
if (eidx > max_var)
return 0;
else if (eidx > solution_size)
return elit;
signed char value = solution[eidx];
if (!value)
return 0;
if (elit < 0)
value = -value;
return value > 0 ? elit : -elit;
}
};
} // namespace CaDiCaL
#endif