ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
transitive.c
Go to the documentation of this file.
1#include "transitive.h"
2#include "allocate.h"
3#include "analyze.h"
4#include "heap.h"
5#include "inline.h"
6#include "inlinevector.h"
7#include "logging.h"
8#include "print.h"
9#include "proprobe.h"
10#include "report.h"
11#include "sort.h"
12#include "terminate.h"
13#include "trail.h"
14
15#include <stddef.h>
16
18
19static void transitive_assign (kissat *solver, unsigned lit) {
20 LOG ("transitive assign %s", LOGLIT (lit));
21 value *values = solver->values;
22 const unsigned not_lit = NOT (lit);
23 KISSAT_assert (!values[lit]);
24 KISSAT_assert (!values[not_lit]);
25 values[lit] = 1;
26 values[not_lit] = -1;
27 PUSH_ARRAY (solver->trail, lit);
28}
29
30static void transitive_backtrack (kissat *solver, unsigned *saved) {
31 value *values = solver->values;
32
33 unsigned *end_trail = END_ARRAY (solver->trail);
34 KISSAT_assert (saved <= end_trail);
35
36 while (end_trail != saved) {
37 const unsigned lit = *--end_trail;
38 LOG ("transitive unassign %s", LOGLIT (lit));
39 const unsigned not_lit = NOT (lit);
40 KISSAT_assert (values[lit] > 0);
41 KISSAT_assert (values[not_lit] < 0);
42 values[lit] = values[not_lit] = 0;
43 }
44
45 SET_END_OF_ARRAY (solver->trail, saved);
46 solver->propagate = saved;
47 solver->level = 0;
48}
49
50static void prioritize_binaries (kissat *solver) {
51 KISSAT_assert (solver->watching);
52 statches large;
53 INIT_STACK (large);
54 watches *all_watches = solver->watches;
55 for (all_literals (lit)) {
56 KISSAT_assert (EMPTY_STACK (large));
57 watches *watches = all_watches + lit;
58 watch *begin_watches = BEGIN_WATCHES (*watches), *q = begin_watches;
59 const watch *const end_watches = END_WATCHES (*watches), *p = q;
60 while (p != end_watches) {
61 const watch head = *q++ = *p++;
62 if (head.type.binary)
63 continue;
64 const watch tail = *p++;
65 PUSH_STACK (large, head);
66 PUSH_STACK (large, tail);
67 q--;
68 }
69 const watch *const end_large = END_STACK (large);
70 watch const *r = BEGIN_STACK (large);
71 while (r != end_large)
72 *q++ = *r++;
73 KISSAT_assert (q == end_watches);
74 CLEAR_STACK (large);
75 }
76 RELEASE_STACK (large);
77}
78
79static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit,
80 uint64_t *reduced_ptr, unsigned *units) {
81 bool res = false;
82 KISSAT_assert (!VALUE (src));
83 LOG ("transitive reduce %s", LOGLIT (src));
84 watches *all_watches = solver->watches;
85 watches *src_watches = all_watches + src;
86 watch *end_src = END_WATCHES (*src_watches);
87 watch *begin_src = BEGIN_WATCHES (*src_watches);
88 const size_t size_src_watches = SIZE_WATCHES (*src_watches);
89 const unsigned src_ticks =
90 1 + kissat_cache_lines (size_src_watches, sizeof (watch));
91 ADD (transitive_ticks, src_ticks);
92 ADD (probing_ticks, src_ticks);
93 ADD (ticks, src_ticks);
94 INC (transitive_probes);
95 const unsigned not_src = NOT (src);
96 unsigned reduced = 0;
97 bool failed = false;
98 for (watch *p = begin_src; p != end_src; p++) {
99 const watch src_watch = *p;
100 if (!src_watch.type.binary)
101 break;
102 const unsigned dst = src_watch.binary.lit;
103 if (dst < src)
104 continue;
105 if (VALUE (dst))
106 continue;
107 KISSAT_assert (kissat_propagated (solver));
108 unsigned *saved = solver->propagate;
109 KISSAT_assert (!solver->level);
110 solver->level = 1;
111 transitive_assign (solver, not_src);
112 bool transitive = false;
113 unsigned inner_ticks = 0;
114 unsigned *propagate = solver->propagate;
115 while (!transitive && !failed &&
116 propagate != END_ARRAY (solver->trail)) {
117 const unsigned lit = *propagate++;
118 LOG ("transitive propagate %s", LOGLIT (lit));
119 KISSAT_assert (VALUE (lit) > 0);
120 const unsigned not_lit = NOT (lit);
121 watches *lit_watches = all_watches + not_lit;
122 const watch *const end_lit = END_WATCHES (*lit_watches);
123 const watch *const begin_lit = BEGIN_WATCHES (*lit_watches);
124 const size_t size_lit_watches = SIZE_WATCHES (*lit_watches);
125 inner_ticks +=
126 1 + kissat_cache_lines (size_lit_watches, sizeof (watch));
127 for (const watch *q = begin_lit; q != end_lit; q++) {
128 if (p == q)
129 continue;
130 const watch lit_watch = *q;
131 if (!lit_watch.type.binary)
132 break;
133 if (not_lit == src && lit_watch.binary.lit == ILLEGAL_LIT)
134 continue;
135 const unsigned other = lit_watch.binary.lit;
136 if (other == dst) {
137 transitive = true;
138 break;
139 }
140 const value value = VALUE (other);
141 if (value < 0) {
142 LOG ("both %s and %s reachable from %s", LOGLIT (NOT (other)),
143 LOGLIT (other), LOGLIT (src));
144 failed = true;
145 break;
146 }
147 if (!value)
148 transitive_assign (solver, other);
149 }
150 }
151
152 KISSAT_assert (solver->probing);
153
154 KISSAT_assert (solver->propagate <= propagate);
155 const unsigned propagated = propagate - solver->propagate;
156
157 ADD (transitive_propagations, propagated);
158 ADD (probing_propagations, propagated);
159 ADD (propagations, propagated);
160
161 ADD (transitive_ticks, inner_ticks);
162 ADD (probing_ticks, inner_ticks);
163 ADD (ticks, inner_ticks);
164
165 transitive_backtrack (solver, saved);
166
167 if (transitive) {
168 LOGBINARY (src, dst, "transitive reduce");
169 INC (transitive_reduced);
170 watches *dst_watches = all_watches + dst;
171 watch dst_watch = src_watch;
172 KISSAT_assert (dst_watch.binary.lit == dst);
173 dst_watch.binary.lit = src;
174 REMOVE_WATCHES (*dst_watches, dst_watch);
175 kissat_delete_binary (solver, src, dst);
176 p->binary.lit = ILLEGAL_LIT;
177 reduced++;
178 res = true;
179 }
180
181 if (failed)
182 break;
183 if (solver->statistics_.transitive_ticks > limit)
184 break;
186 break;
187 }
188
189 if (reduced) {
190 *reduced_ptr += reduced;
191 KISSAT_assert (begin_src == BEGIN_WATCHES (WATCHES (src)));
192 KISSAT_assert (end_src == END_WATCHES (WATCHES (src)));
193 watch *q = begin_src;
194 for (const watch *p = begin_src; p != end_src; p++) {
195 const watch src_watch = *q++ = *p;
196 if (!src_watch.type.binary) {
197 *q++ = *++p;
198 continue;
199 }
200 if (src_watch.binary.lit == ILLEGAL_LIT)
201 q--;
202 }
203 KISSAT_assert (end_src - q == (ptrdiff_t) reduced);
204 SET_END_OF_WATCHES (*src_watches, q);
205 }
206
207 if (failed) {
208 LOG ("transitive failed literal %s", LOGLIT (not_src));
209 INC (transitive_units);
210 *units += 1;
211 res = true;
212
214
215 KISSAT_assert (!solver->level);
216 (void) kissat_probing_propagate (solver, 0, true);
217 }
218
219 return res;
220}
221
222static inline bool less_stable_transitive (kissat *solver,
223 const flags *const flags,
224 const heap *scores, unsigned a,
225 unsigned b) {
226#ifdef KISSAT_NDEBUG
227 (void) solver;
228#endif
229 const unsigned i = IDX (a);
230 const unsigned j = IDX (b);
231 const bool p = flags[i].transitive;
232 const bool q = flags[j].transitive;
233 if (!p && q)
234 return true;
235 if (p && !q)
236 return false;
237 const double s = kissat_get_heap_score (scores, i);
238 const double t = kissat_get_heap_score (scores, j);
239 if (s < t)
240 return true;
241 if (s > t)
242 return false;
243 return i < j;
244}
245
246static inline unsigned less_focused_transitive (kissat *solver,
247 const flags *const flags,
248 const links *links,
249 unsigned a, unsigned b) {
250#ifdef KISSAT_NDEBUG
251 (void) solver;
252#endif
253 const unsigned i = IDX (a);
254 const unsigned j = IDX (b);
255 const bool p = flags[i].transitive;
256 const bool q = flags[j].transitive;
257 if (!p && q)
258 return true;
259 if (p && !q)
260 return false;
261 const unsigned s = links[i].stamp;
262 const unsigned t = links[j].stamp;
263 return s < t;
264}
265
266#define LESS_STABLE_PROBE(A, B) \
267 less_stable_transitive (solver, flags, scores, (A), (B))
268
269#define LESS_FOCUSED_PROBE(A, B) \
270 less_focused_transitive (solver, flags, links, (A), (B))
271
272static void sort_stable_transitive (kissat *solver, unsigneds *probes) {
273 const flags *const flags = solver->flags;
274 const heap *const scores = SCORES;
275 SORT_STACK (unsigned, *probes, LESS_STABLE_PROBE);
276}
277
278static void sort_focused_transitive (kissat *solver, unsigneds *probes) {
279 const flags *const flags = solver->flags;
280 const links *const links = solver->links;
281 SORT_STACK (unsigned, *probes, LESS_FOCUSED_PROBE);
282}
283
284static void sort_transitive (kissat *solver, unsigneds *probes) {
285 if (solver->stable)
286 sort_stable_transitive (solver, probes);
287 else
288 sort_focused_transitive (solver, probes);
289}
290
291static void schedule_transitive (kissat *solver, unsigneds *probes) {
292 KISSAT_assert (EMPTY_STACK (*probes));
293 for (all_variables (idx))
294 if (ACTIVE (idx))
295 PUSH_STACK (*probes, idx);
296 sort_transitive (solver, probes);
297 kissat_very_verbose (solver, "scheduled %zu transitive probes",
298 SIZE_STACK (*probes));
299}
300
302 if (solver->inconsistent)
303 return;
304 KISSAT_assert (solver->watching);
305 KISSAT_assert (solver->probing);
306 KISSAT_assert (!solver->level);
307 if (!GET_OPTION (transitive))
308 return;
310 return;
311 START (transitive);
312 INC (transitive_reductions);
313#if !defined(KISSAT_NDEBUG) || defined(METRICS)
314 KISSAT_assert (!solver->transitive_reducing);
315 solver->transitive_reducing = true;
316#endif
317 prioritize_binaries (solver);
318 bool success = false;
319 uint64_t reduced = 0;
320 unsigned units = 0;
321
322 SET_EFFORT_LIMIT (limit, transitive, transitive_ticks);
323
324#ifndef KISSAT_QUIET
325 const unsigned active = solver->active;
326 const uint64_t old_ticks = solver->statistics_.transitive_ticks;
328 solver, "starting with %" PRIu64 " transitive ticks", old_ticks);
329 unsigned probed = 0;
330#endif
331 unsigneds probes;
332 INIT_STACK (probes);
333 schedule_transitive (solver, &probes);
334 bool terminate = false;
335 while (!terminate && !EMPTY_STACK (probes)) {
336 const unsigned idx = POP_STACK (probes);
337 solver->flags[idx].transitive = false;
338 if (!ACTIVE (idx))
339 continue;
340 for (unsigned sign = 0; !terminate && sign < 2; sign++) {
341 const unsigned lit = 2 * idx + sign;
342 if (solver->values[lit])
343 continue;
344#ifndef KISSAT_QUIET
345 probed++;
346#endif
347 if (transitive_reduce (solver, lit, limit, &reduced, &units))
348 success = true;
349 if (solver->inconsistent)
350 terminate = true;
351 else if (solver->statistics_.transitive_ticks > limit)
352 terminate = true;
354 terminate = true;
355 }
356 }
357 const size_t remain = SIZE_STACK (probes);
358 if (remain) {
359 if (!GET_OPTION (transitivekeep)) {
361 solver, "dropping remaining %zu transitive candidates", remain);
362 while (!EMPTY_STACK (probes)) {
363 const unsigned idx = POP_STACK (probes);
364 solver->flags[idx].transitive = false;
365 }
366 }
367 } else
368 kissat_very_verbose (solver, "transitive reduction complete");
369 RELEASE_STACK (probes);
370
371#ifndef KISSAT_QUIET
372 const uint64_t new_ticks = solver->statistics_.transitive_ticks;
373 const uint64_t delta_ticks = new_ticks - old_ticks;
375 solver, "finished at %" PRIu64 " after %" PRIu64 " transitive ticks",
376 new_ticks, delta_ticks);
377#endif
378 kissat_phase (solver, "transitive", GET (probings),
379 "probed %u (%.0f%%): reduced %" PRIu64 ", units %u", probed,
380 kissat_percent (probed, 2 * active), reduced, units);
381
382#if !defined(KISSAT_NDEBUG) || defined(METRICS)
383 KISSAT_assert (solver->transitive_reducing);
384 solver->transitive_reducing = false;
385#endif
386 REPORT (!success, 't');
387 STOP (transitive);
388#ifdef KISSAT_QUIET
389 (void) success;
390#endif
391}
392
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define PUSH_ARRAY(A, E)
Definition array.h:26
#define SET_END_OF_ARRAY
Definition array.h:53
#define END_ARRAY
Definition array.h:51
void kissat_learned_unit(kissat *solver, unsigned lit)
Definition assign.c:18
#define BEGIN_STACK(S)
Definition stack.h:46
#define POP_STACK(S)
Definition stack.h:37
#define SIZE_STACK(S)
Definition stack.h:19
#define EMPTY_STACK(S)
Definition stack.h:18
#define RELEASE_STACK(S)
Definition stack.h:71
#define CLEAR_STACK(S)
Definition stack.h:50
#define PUSH_STACK(S, E)
Definition stack.h:39
#define INIT_STACK(S)
Definition stack.h:22
#define END_STACK(S)
Definition stack.h:48
#define ADD(NAME, DELTA)
#define INC(NAME)
#define LOG(...)
ABC_NAMESPACE_IMPL_START typedef signed char value
void kissat_delete_binary(kissat *solver, unsigned a, unsigned b)
Definition clause.c:181
#define ACTIVE
Definition espresso.h:129
Cube * p
Definition exorList.c:222
#define all_variables(IDX)
Definition internal.h:269
#define all_literals(LIT)
Definition internal.h:274
#define SCORES
Definition internal.h:262
#define KISSAT_assert(ignore)
Definition global.h:13
#define SORT_STACK(TYPE, S, LESS)
Definition sort.h:148
#define solver
Definition kitten.c:211
#define SET_EFFORT_LIMIT(LIMIT, NAME, THRESHHOLD)
Definition limit.hpp:131
#define LOGBINARY(...)
Definition logging.h:442
#define LOGLIT(...)
Definition logging.hpp:99
#define GET_OPTION(N)
Definition options.h:295
#define kissat_extremely_verbose(...)
Definition print.h:53
#define kissat_very_verbose(...)
Definition print.h:52
#define kissat_phase(...)
Definition print.h:48
#define STOP(P)
Definition profile.hpp:158
#define START(P)
Definition profile.hpp:150
clause * kissat_probing_propagate(kissat *solver, clause *ignore, bool flush)
Definition proprobe.c:37
#define REPORT(...)
Definition report.h:10
int lit
Definition satVec.h:130
#define ILLEGAL_LIT
Definition literal.h:16
#define IDX(LIT)
Definition literal.h:28
#define NOT(LIT)
Definition literal.h:33
#define GET(NAME)
Definition statistics.h:416
Definition flags.h:11
bool transitive
Definition flags.h:21
Definition heap.h:19
#define TERMINATED(BIT)
Definition terminate.h:42
#define transitive_terminated_2
Definition terminate.h:79
#define transitive_terminated_3
Definition terminate.h:80
#define transitive_terminated_1
Definition terminate.h:78
#define LESS_FOCUSED_PROBE(A, B)
Definition transitive.c:269
void kissat_transitive_reduction(kissat *solver)
Definition transitive.c:301
#define LESS_STABLE_PROBE(A, B)
Definition transitive.c:266
Definition watch.h:41
watch_type type
Definition watch.h:42
binary_watch binary
Definition watch.h:43
#define VALUE(LIT)
Definition value.h:10
#define SIZE_WATCHES(W)
Definition watch.h:104
#define BEGIN_WATCHES(WS)
Definition watch.h:115
#define END_WATCHES(WS)
Definition watch.h:118
#define REMOVE_WATCHES(W, E)
Definition watch.h:134
#define SET_END_OF_WATCHES(WS, P)
Definition watch.h:128
vector watches
Definition watch.h:49
#define WATCHES(LIT)
Definition watch.h:137