ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
forward.c
Go to the documentation of this file.
1#include "forward.h"
2#include "allocate.h"
3#include "eliminate.h"
4#include "inline.h"
5#include "print.h"
6#include "rank.h"
7#include "report.h"
8#include "sort.h"
9#include "terminate.h"
10
11#include <inttypes.h>
12
14
15static size_t remove_duplicated_binaries_with_literal (kissat *solver,
16 unsigned lit) {
18 value *marks = solver->marks;
19 flags *flags = solver->flags;
20
21 watch *begin = BEGIN_WATCHES (*watches), *q = begin;
22 const watch *const end = END_WATCHES (*watches), *p = q;
23
24 while (p != end) {
25 const watch watch = *q++ = *p++;
27 const unsigned other = watch.binary.lit;
28 struct flags *f = flags + IDX (other);
29 if (!f->active)
30 continue;
31 if (!f->subsume)
32 continue;
33 const value marked = marks[other];
34 if (marked) {
35 q--;
36 if (lit < other) {
38 INC (duplicated);
39 }
40 } else {
41 const unsigned not_other = NOT (other);
42 if (marks[not_other]) {
43 LOGBINARY (lit, other,
44 "duplicate hyper unary resolution on %s "
45 "first antecedent",
46 LOGLIT (other));
47 LOGBINARY (lit, not_other,
48 "duplicate hyper unary resolution on %s "
49 "second antecedent",
50 LOGLIT (not_other));
51 PUSH_STACK (solver->delayed, lit);
52 }
53 marks[other] = 1;
54 }
55 }
56
57 for (const watch *r = begin; r != q; r++)
58 marks[r->binary.lit] = 0;
59
60 if (q == end)
61 return 0;
62
63 size_t removed = end - q;
65 LOG ("removed %zu watches with literal %s", removed, LOGLIT (lit));
66
67 return removed;
68}
69
70static void remove_all_duplicated_binary_clauses (kissat *solver) {
71 LOG ("removing all duplicated irredundant binary clauses");
72#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
73 size_t removed = 0;
74#endif
75 KISSAT_assert (EMPTY_STACK (solver->delayed));
76
77 const flags *const all_flags = solver->flags;
78
79 for (all_variables (idx)) {
80 const flags *const flags = all_flags + idx;
81 if (!flags->active)
82 continue;
83 if (!flags->subsume)
84 continue;
85 const unsigned int lit = LIT (idx);
86 const unsigned int not_lit = NOT (lit);
87#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
88 removed +=
89#endif
90 remove_duplicated_binaries_with_literal (solver, lit);
91#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
92 removed +=
93#endif
94 remove_duplicated_binaries_with_literal (solver, not_lit);
95 }
96 KISSAT_assert (!(removed & 1));
97
98 size_t units = SIZE_STACK (solver->delayed);
99 if (units) {
100 LOG ("found %zu hyper unary resolved units", units);
101 const value *const values = solver->values;
102 for (all_stack (unsigned, unit, solver->delayed)) {
103
104 const value value = values[unit];
105 if (value > 0) {
106 LOG ("skipping satisfied resolved unit %s", LOGLIT (unit));
107 continue;
108 }
109 if (value < 0) {
110 LOG ("found falsified resolved unit %s", LOGLIT (unit));
113 solver->inconsistent = true;
114 break;
115 }
116 LOG ("new resolved unit clause %s", LOGLIT (unit));
118 }
119 CLEAR_STACK (solver->delayed);
120 if (!solver->inconsistent)
122 }
123
124 REPORT (!removed && !units, '2');
125}
126
127static void find_forward_subsumption_candidates (kissat *solver,
128 references *candidates) {
129 const unsigned clslim = GET_OPTION (subsumeclslim);
130
131 const value *const values = solver->values;
132 const flags *const flags = solver->flags;
133
134 clause *last_irredundant = kissat_last_irredundant_clause (solver);
135
136 for (all_clauses (c)) {
137 if (last_irredundant && c > last_irredundant)
138 break;
139 if (c->garbage)
140 continue;
141 c->subsume = false;
142 if (c->redundant)
143 continue;
144 if (c->size > clslim)
145 continue;
146 KISSAT_assert (c->size > 2);
147 unsigned subsume = 0;
148 for (all_literals_in_clause (lit, c)) {
149 const unsigned idx = IDX (lit);
150 const struct flags *f = flags + idx;
151 if (f->subsume)
152 subsume++;
153 if (values[lit] > 0) {
154 LOGCLS (c, "satisfied by %s", LOGLIT (lit));
156 KISSAT_assert (c->garbage);
157 break;
158 }
159 }
160 if (c->garbage)
161 continue;
162 if (subsume < 2)
163 continue;
164 const unsigned ref = kissat_reference_clause (solver, c);
165 PUSH_STACK (*candidates, ref);
166 }
167}
168
169static inline unsigned
170get_size_of_reference (kissat *solver, ward *const arena, reference ref) {
171 KISSAT_assert (ref < SIZE_STACK (solver->arena));
172 const clause *const c = (clause *) (arena + ref);
173 (void) solver;
174 return c->size;
175}
176
177#define GET_SIZE_OF_REFERENCE(REF) \
178 get_size_of_reference (solver, arena, (REF))
179
180static void sort_forward_subsumption_candidates (kissat *solver,
181 references *candidates) {
182 reference *references = BEGIN_STACK (*candidates);
183 size_t size = SIZE_STACK (*candidates);
184 ward *const arena = BEGIN_STACK (solver->arena);
185 RADIX_SORT (reference, unsigned, size, references, GET_SIZE_OF_REFERENCE);
186}
187
188static inline bool forward_literal (kissat *solver, unsigned lit,
189 bool binaries, unsigned *remove,
190 unsigned limit) {
192 const size_t size_watches = SIZE_WATCHES (*watches);
193
194 if (!size_watches)
195 return false;
196
197 if (size_watches > limit)
198 return false;
199
200 watch *begin = BEGIN_WATCHES (*watches), *q = begin;
201 const watch *const end = END_WATCHES (*watches), *p = q;
202
203 uint64_t steps = 1 + kissat_cache_lines (size_watches, sizeof (watch));
204 uint64_t checks = 0;
205
206 const value *const values = solver->values;
207 const value *const marks = solver->marks;
208 ward *const arena = BEGIN_STACK (solver->arena);
209
210 bool subsume = false;
211
212 while (p != end) {
213 const watch watch = *q++ = *p++;
214
215 if (watch.type.binary) {
216 if (!binaries)
217 continue;
218
219 const unsigned other = watch.binary.lit;
220 if (marks[other]) {
221 LOGBINARY (lit, other, "forward subsuming");
222 subsume = true;
223 break;
224 } else {
225 const unsigned not_other = NOT (other);
226 if (marks[not_other]) {
227 LOGBINARY (lit, other, "forward %s strengthener", LOGLIT (other));
229 *remove = not_other;
230 break;
231 }
232 }
233 } else {
234 const reference ref = watch.large.ref;
235 KISSAT_assert (ref < SIZE_STACK (solver->arena));
236 clause *d = (clause *) (arena + ref);
237 steps++;
238
239 if (d->garbage) {
240 q--;
241 continue;
242 }
243
244 checks++;
245 subsume = true;
246
247 unsigned candidate = INVALID_LIT;
248
249 for (all_literals_in_clause (other, d)) {
250 if (marks[other])
251 continue;
252 const value value = values[other];
253 if (value < 0)
254 continue;
255 if (value > 0) {
256 LOGCLS (d, "satisfied by %s", LOGLIT (other));
260 subsume = false;
261 break;
262 }
263 if (!subsume) {
266 break;
267 }
268 subsume = false;
269 const unsigned not_other = NOT (other);
270 if (!marks[not_other]) {
272 break;
273 }
274 candidate = not_other;
275 }
276
277 if (d->garbage) {
279 q--;
280 break;
281 }
282
283 if (subsume) {
284 LOGCLS (d, "forward subsuming");
286 break;
287 }
288
289 if (candidate != INVALID_LIT) {
290 LOGCLS (d, "forward %s strengthener", LOGLIT (candidate));
291 *remove = candidate;
292 }
293 }
294 }
295
296 if (p != q) {
297 while (p != end)
298 *q++ = *p++;
299
301 }
302
303 ADD (subsumption_checks, checks);
304 ADD (forward_checks, checks);
305 ADD (forward_steps, steps);
306
307 return subsume;
308}
309
310static inline bool forward_marked_clause (kissat *solver, clause *c,
311 unsigned *remove) {
312 const unsigned limit = GET_OPTION (subsumeocclim);
313 const flags *const flags = solver->flags;
314 INC (forward_steps);
315
316 for (all_literals_in_clause (lit, c)) {
317 const unsigned idx = IDX (lit);
318 if (!flags[idx].active)
319 continue;
320
322
323 if (forward_literal (solver, lit, true, remove, limit))
324 return true;
325
326 if (forward_literal (solver, NOT (lit), false, remove, limit))
327 return true;
328 }
329 return false;
330}
331
332static bool forward_subsumed_clause (kissat *solver, clause *c,
333 bool *strengthened,
334 unsigneds *new_binaries) {
336 LOGCLS2 (c, "trying to forward subsume");
337
338 value *marks = solver->marks;
339 const value *const values = solver->values;
340 unsigned non_false = 0, unit = INVALID_LIT;
341
342 for (all_literals_in_clause (lit, c)) {
343 const value value = values[lit];
344 if (value < 0)
345 continue;
346 if (value > 0) {
347 LOGCLS (c, "satisfied by %s", LOGLIT (lit));
350 break;
351 }
352 marks[lit] = 1;
353 if (non_false++)
354 unit ^= lit;
355 else
356 unit = lit;
357 }
358
359 if (c->garbage || non_false <= 1)
360 for (all_literals_in_clause (lit, c))
361 marks[lit] = 0;
362
363 if (c->garbage)
364 return false;
365
366 if (!non_false) {
367 LOGCLS (c, "found falsified clause");
370 solver->inconsistent = true;
371 return false;
372 }
373
374 if (non_false == 1) {
376 LOG ("new remaining non-false literal unit clause %s", LOGLIT (unit));
380 return false;
381 }
382
383 unsigned remove = INVALID_LIT;
384 const bool subsume = forward_marked_clause (solver, c, &remove);
385
386 for (all_literals_in_clause (lit, c))
387 marks[lit] = 0;
388
389 if (subsume) {
390 LOGCLS (c, "forward subsumed");
392 INC (subsumed);
393 INC (forward_subsumed);
394 } else if (remove != INVALID_LIT) {
395 *strengthened = true;
396 INC (strengthened);
397 INC (forward_strengthened);
398 LOGCLS (c, "forward strengthening by removing %s in", LOGLIT (remove));
399 if (non_false == 2) {
400 unit ^= remove;
402 LOG ("forward strengthened unit clause %s", LOGLIT (unit));
406 LOGCLS (c, "%s satisfied", LOGLIT (unit));
407 } else {
409 CHECK_SHRINK_CLAUSE (c, remove, INVALID_LIT);
410 kissat_mark_removed_literal (solver, remove);
411 if (non_false > 3) {
412 unsigned *lits = c->lits;
413 unsigned new_size = 0;
414 for (unsigned i = 0; i < c->size; i++) {
415 const unsigned lit = lits[i];
416 if (remove == lit)
417 continue;
418 const value value = values[lit];
419 if (value < 0)
420 continue;
422 lits[new_size++] = lit;
423 kissat_mark_added_literal (solver, lit);
424 }
425 KISSAT_assert (new_size == non_false - 1);
426 KISSAT_assert (new_size > 2);
427 if (!c->shrunken) {
428 c->shrunken = true;
429 lits[c->size - 1] = INVALID_LIT;
430 }
431 c->size = new_size;
432 c->searched = 2;
433 c->subsume = true;
434 LOGCLS (c, "forward strengthened");
435 } else {
436 KISSAT_assert (non_false == 3);
437 LOGCLS (c, "garbage");
439 const size_t bytes = kissat_actual_bytes_of_clause (c);
440 ADD (arena_garbage, bytes);
441 c->garbage = true;
442 unsigned first = INVALID_LIT, second = INVALID_LIT;
443 for (all_literals_in_clause (lit, c)) {
444 if (lit == remove)
445 continue;
446 const value value = values[lit];
447 if (value < 0)
448 continue;
450 if (first == INVALID_LIT)
451 first = lit;
452 else {
453 KISSAT_assert (second == INVALID_LIT);
454 second = lit;
455 }
456 kissat_mark_added_literal (solver, lit);
457 }
458 KISSAT_assert (first != INVALID_LIT);
459 KISSAT_assert (second != INVALID_LIT);
460 LOGBINARY (first, second, "forward strengthened");
461 kissat_watch_other (solver, first, second);
462 kissat_watch_other (solver, second, first);
463 KISSAT_assert (new_binaries);
464 KISSAT_assert (solver->statistics_.clauses_irredundant);
465 solver->statistics_.clauses_irredundant--;
466 KISSAT_assert (solver->statistics_.clauses_binary < UINT64_MAX);
467 solver->statistics_.clauses_binary++;
468 PUSH_STACK (*new_binaries, first);
469 PUSH_STACK (*new_binaries, second);
470 }
471 }
472 }
473
474 return subsume;
475}
476
477static void connect_subsuming (kissat *solver, unsigned occlim, clause *c) {
479
480 unsigned min_lit = INVALID_LIT;
481 size_t min_occs = MAX_SIZE_T;
482
483 const flags *const all_flags = solver->flags;
484
485 bool subsume = true;
486
487 for (all_literals_in_clause (lit, c)) {
488 const unsigned idx = IDX (lit);
489 const flags *const flags = all_flags + idx;
490 if (!flags->active)
491 continue;
492 if (!flags->subsume) {
493 subsume = false;
494 break;
495 }
497 const size_t occs = SIZE_WATCHES (*watches);
498 if (min_lit != INVALID_LIT && occs > min_occs)
499 continue;
500 min_lit = lit;
501 min_occs = occs;
502 }
503 if (!subsume)
504 return;
505
506 if (min_occs > occlim)
507 return;
508 LOG ("connecting %s with %zu occurrences", LOGLIT (min_lit), min_occs);
509 const reference ref = kissat_reference_clause (solver, c);
510 kissat_connect_literal (solver, min_lit, ref);
511}
512
513static bool forward_subsume_all_clauses (kissat *solver) {
514 references candidates;
515 INIT_STACK (candidates);
516
517 find_forward_subsumption_candidates (solver, &candidates);
518#ifndef KISSAT_QUIET
519 size_t scheduled = SIZE_STACK (candidates);
521 solver, "forward", GET (forward_subsumptions),
522 "scheduled %zu irredundant clauses %.0f%%", scheduled,
523 kissat_percent (scheduled, solver->statistics_.clauses_irredundant));
524#endif
525 sort_forward_subsumption_candidates (solver, &candidates);
526
527 const reference *const end_of_candidates = END_STACK (candidates);
528 reference *p = BEGIN_STACK (candidates);
529
530#ifndef KISSAT_QUIET
531 size_t subsumed = 0;
532 size_t strengthened = 0;
533 size_t checked = 0;
534#endif
535 const unsigned occlim = GET_OPTION (subsumeocclim);
536
537 unsigneds new_binaries;
538 INIT_STACK (new_binaries);
539
540 {
541 SET_EFFORT_LIMIT (steps_limit, forward, forward_steps);
542
543 ward *arena = BEGIN_STACK (solver->arena);
544
545 while (p != end_of_candidates) {
546 if (solver->statistics_.forward_steps > steps_limit)
547 break;
549 break;
550 reference ref = *p++;
551 clause *c = (clause *) (arena + ref);
552 KISSAT_assert (kissat_clause_in_arena (solver, c));
554#ifndef KISSAT_QUIET
555 checked++;
556#endif
557 bool not_subsumed_but_strengthened = false;
558 if (forward_subsumed_clause (
559 solver, c, &not_subsumed_but_strengthened, &new_binaries)) {
560#ifndef KISSAT_QUIET
561 subsumed++;
562#endif
563 } else if (not_subsumed_but_strengthened) {
564#ifndef KISSAT_QUIET
565 strengthened++;
566#endif
567 }
568 if (solver->inconsistent)
569 break;
570 if (!c->garbage)
571 connect_subsuming (solver, occlim, c);
572 }
573 }
574#ifndef KISSAT_QUIET
575 if (subsumed)
576 kissat_phase (solver, "forward", GET (forward_subsumptions),
577 "subsumed %zu clauses %.2f%% of %zu checked %.0f%%",
578 subsumed, kissat_percent (subsumed, checked), checked,
579 kissat_percent (checked, scheduled));
580 if (strengthened)
581 kissat_phase (solver, "forward", GET (forward_subsumptions),
582 "strengthened %zu clauses %.2f%% of %zu checked %.0f%%",
583 strengthened, kissat_percent (strengthened, checked),
584 checked, kissat_percent (checked, scheduled));
585 if (!subsumed && !strengthened)
586 kissat_phase (solver, "forward", GET (forward_subsumptions),
587 "no clause subsumed nor strengthened "
588 "out of %zu checked %.0f%%",
589 checked, kissat_percent (checked, scheduled));
590#endif
591 struct flags *flags = solver->flags;
592
593 for (all_variables (idx))
594 flags[idx].subsume = false;
595
596 ward *arena = BEGIN_STACK (solver->arena);
597 unsigned reactivated = 0;
598#ifndef KISSAT_QUIET
599 size_t remain = 0;
600#endif
601 for (reference *q = BEGIN_STACK (candidates); q != end_of_candidates;
602 q++) {
603 const reference ref = *q;
604 clause *c = (clause *) (arena + ref);
605 KISSAT_assert (kissat_clause_in_arena (solver, c));
606 if (c->garbage)
607 continue;
608 if (q < p && !c->subsume)
609 continue;
610#ifndef KISSAT_QUIET
611 remain++;
612#endif
613 for (all_literals_in_clause (lit, c)) {
614 const unsigned idx = IDX (lit);
615 struct flags *f = flags + idx;
616 if (f->subsume)
617 continue;
618 LOGCLS (c,
619 "reactivating subsume flag of %s "
620 "in remaining or strengthened",
621 LOGVAR (idx));
622 f->subsume = true;
623 KISSAT_assert (reactivated < UINT_MAX);
624 reactivated++;
625 }
626 }
627
628 while (!EMPTY_STACK (new_binaries)) {
629 unsigned lits[2];
630 lits[1] = POP_STACK (new_binaries);
631 lits[0] = POP_STACK (new_binaries);
632 for (unsigned i = 0; i < 2; i++) {
633 const unsigned lit = lits[i];
634 const unsigned idx = IDX (lit);
635 struct flags *f = flags + idx;
636 if (f->subsume)
637 continue;
638 LOGBINARY (lits[0], lits[1],
639 "reactivating subsume flag of %s "
640 "in strengthened binary clause",
641 LOGVAR (idx));
642 f->subsume = true;
643 KISSAT_assert (reactivated < UINT_MAX);
644 reactivated++;
645 }
646 }
647 RELEASE_STACK (new_binaries);
648
650 "marked %u variables %.0f%% to be reconsidered "
651 "in next forward subsumption",
652 reactivated,
653 kissat_percent (reactivated, solver->active));
654#ifndef KISSAT_QUIET
655 if (remain)
656 kissat_phase (solver, "forward", GET (forward_subsumptions),
657 "%zu unchecked clauses remain %.0f%%", remain,
658 kissat_percent (remain, scheduled));
659 else
660 kissat_phase (solver, "forward", GET (forward_subsumptions),
661 "all %zu scheduled clauses checked", scheduled);
662#endif
663 RELEASE_STACK (candidates);
664 REPORT (!subsumed, 's');
665
666 bool completed;
667 if (solver->inconsistent)
668 completed = true;
669 else if (reactivated)
670 completed = false;
671 else
672 completed = true;
673#ifndef KISSAT_QUIET
674 kissat_very_verbose (solver, "forward subsumption considered %scomplete",
675 completed ? "" : "in");
676#endif
677 return completed;
678}
679
681 START (subsume);
682 START (forward);
683 KISSAT_assert (GET_OPTION (forward));
684 INC (forward_subsumptions);
685 KISSAT_assert (!solver->watching);
686 remove_all_duplicated_binary_clauses (solver);
687 bool complete = true;
688 if (!solver->inconsistent)
689 complete = forward_subsume_all_clauses (solver);
690 STOP (forward);
691 STOP (subsume);
692 return complete;
693}
694
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
ABC_NAMESPACE_HEADER_START typedef word ward
Definition arena.h:12
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 all_stack(T, E, S)
Definition stack.h:94
#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 INVALID_LIT
#define ADD(NAME, DELTA)
#define INC(NAME)
#define LOG(...)
ABC_NAMESPACE_IMPL_START typedef signed char value
#define CHECK_AND_ADD_EMPTY(...)
Definition check.h:146
#define CHECK_SHRINK_CLAUSE(...)
Definition check.h:158
void kissat_mark_clause_as_garbage(kissat *solver, clause *c)
Definition clause.c:164
void kissat_delete_binary(kissat *solver, unsigned a, unsigned b)
Definition clause.c:181
void kissat_flush_units_while_connected(kissat *solver)
Definition eliminate.c:162
Cube * p
Definition exorList.c:222
bool kissat_forward_subsume_during_elimination(kissat *solver)
Definition forward.c:680
#define GET_SIZE_OF_REFERENCE(REF)
Definition forward.c:177
#define all_variables(IDX)
Definition internal.h:269
#define all_clauses(C)
Definition internal.h:279
#define all_literals_in_clause(LIT, C)
Definition clause.h:47
#define KISSAT_assert(ignore)
Definition global.h:13
#define solver
Definition kitten.c:211
#define SET_EFFORT_LIMIT(LIMIT, NAME, THRESHHOLD)
Definition limit.hpp:131
#define LOGBINARY(...)
Definition logging.h:442
#define LOGCLS(...)
Definition logging.h:415
#define LOGCLS2(...)
Definition logging.h:418
#define LOGLIT(...)
Definition logging.hpp:99
unsigned short ref
Definition giaNewBdd.h:38
#define GET_OPTION(N)
Definition options.h:295
#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
#define ADD_EMPTY_TO_PROOF(...)
Definition proof.h:135
#define SHRINK_CLAUSE_IN_PROOF(...)
Definition proof.h:145
#define RADIX_SORT(VTYPE, RTYPE, N, V, RANK)
Definition rank.h:25
ABC_NAMESPACE_HEADER_START typedef unsigned reference
Definition reference.h:9
#define REPORT(...)
Definition report.h:10
int lit
Definition satVec.h:130
#define LIT(IDX)
Definition literal.h:31
#define VALID_INTERNAL_LITERAL(LIT)
Definition literal.h:23
#define IDX(LIT)
Definition literal.h:28
#define NOT(LIT)
Definition literal.h:33
#define GET(NAME)
Definition statistics.h:416
unsigned lits[3]
Definition clause.h:39
unsigned searched
Definition clause.h:36
bool subsume
Definition clause.h:30
unsigned size
Definition clause.h:37
bool shrunken
Definition clause.h:29
bool garbage
Definition clause.h:25
Definition flags.h:11
bool active
Definition flags.h:12
bool subsume
Definition flags.h:19
#define TERMINATED(BIT)
Definition terminate.h:42
#define forward_terminated_1
Definition terminate.h:64
Definition watch.h:41
large_watch large
Definition watch.h:45
watch_type type
Definition watch.h:42
binary_watch binary
Definition watch.h:43
#define MAX_SIZE_T
Definition utilities.h:45
#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 SET_END_OF_WATCHES(WS, P)
Definition watch.h:128
vector watches
Definition watch.h:49
#define WATCHES(LIT)
Definition watch.h:137