1 /*
2 * case.c - case splitting
3 *
4 */
5
6 #include "header.h"
7
8 #ifdef TP_FORK /* for calls to fork() and wait() */
9 # include <sys/types.h>
10 # include <sys/wait.h>
11 # include <unistd.h>
12 #endif
13
14 #define MAX_SPLIT_DEPTH 255 /* see SPLIT_DEPTH in options.c */
15
16 #define POS_CLAUSE 1
17 #define NEG_CLAUSE 2
18 #define MIX_CLAUSE 3
19
20 #define FORK_FAIL 0
21 #define PARENT 1
22 #define CHILD 2
23 #define CHILD_FAIL 3
24
25 /* Current_case is a sequence of integers, e.g., Case [2.1.3.2]. */
26
27 struct ilist *Current_case = NULL;
28
29 /* The literal_data structure is used for atom splitting. When
30 * deciding which atom to split, all ground literal occurrences
31 * are considered, and for each, the data in the structure is
32 * collected. See routines get_literal_data(), compare_literal_data(),
33 * find_atom_to_split().
34 */
35
36 struct literal_data {
37 struct term *atom;
38 int sign;
39 int equality;
40 int atom_weight;
41 int clause_id;
42 int clause_weight;
43 int clause_type;
44 int clause_variables;
45 int pos_occurrences;
46 int neg_occurrences;
47 int pos_binary_occurrences;
48 int neg_binary_occurrences;
49 };
50
51 /* These are file descriptors (from pipe()), which are used to
52 * communicate with child and parent processes. The main use is
53 * for a child to tell its parent what case assumptions were
54 * used for a refutation, which allows ancestors to sometimes
55 * skip further cases. See assumps_to_parent(), prover_forks().
56 */
57
58 int To_parent, From_parent; /* pipe for communicating with parent */
59 int To_children, From_children; /* pipe for communicating with children */
60
61 /*************
62 *
63 * splitting() -- Is slitting enabled?
64 *
65 *************/
66
splitting(void)67 int splitting(void)
68 {
69 return(Flags[SPLIT_CLAUSE].val ||
70 Flags[SPLIT_ATOM].val ||
71 Flags[SPLIT_WHEN_GIVEN].val);
72 } /* splitting */
73
74 /*************
75 *
76 * max_split_depth() -- Return the maximum depth allowed for splitting.
77 *
78 *************/
79
max_split_depth(void)80 int max_split_depth(void)
81 {
82 return(MAX_SPLIT_DEPTH);
83 } /* max_split_depth */
84
85 /*************
86 *
87 * splitable_literal(clause, lit) -- Is the atom splittable?
88 *
89 * The test is done on an occurrence of a literal.
90 *
91 *************/
92
splitable_literal(struct clause * c,struct literal * l)93 int splitable_literal(struct clause *c,
94 struct literal *l)
95 {
96 if (num_literals(c) < 2 || !ground(l->atom))
97 return 0;
98 else {
99 int ok = 1;
100 if (ok && Flags[SPLIT_POS].val)
101 ok = pos_clause(c);
102 if (ok && Flags[SPLIT_NEG].val)
103 ok = neg_clause(c);
104 if (ok && Flags[SPLIT_NONHORN].val)
105 ok = l->sign && !horn_clause(c);
106 return ok;
107 }
108 } /* splitable_literal */
109
110 /*************
111 *
112 * compare_literal_data(d1, d2) -- Compare two splittable literal occurrences.
113 *
114 * Return the better literal_data. If neither is better, return d1.
115 *
116 *************/
117
compare_literal_data(struct literal_data d1,struct literal_data d2)118 static struct literal_data compare_literal_data(struct literal_data d1,
119 struct literal_data d2)
120 {
121 if (d1.atom == NULL)
122 return d2;
123 else if (d2.atom == NULL)
124 return d1;
125 else if (Flags[SPLIT_POPULAR].val) {
126 if (d2.pos_occurrences + d2.neg_occurrences >
127 d1.pos_occurrences + d1.neg_occurrences)
128 return d2;
129 else
130 return d1;
131 }
132 else {
133 if (d2.clause_weight < d1.clause_weight)
134 return d2;
135 else if (d1.clause_weight < d2.clause_weight)
136 return d1;
137 else if (d2.atom_weight < d1.atom_weight)
138 return d2;
139 else
140 return d1;
141 }
142 } /* compare_literal_data */
143
144 /*************
145 *
146 * splitable_clause(c) -- Is this clause splittable?
147 *
148 *************/
149
splitable_clause(struct clause * c)150 int splitable_clause(struct clause *c)
151 {
152 if (!ground_clause(c))
153 return 0;
154 else if (num_literals(c) < 2)
155 return 0;
156 else {
157 int ok = 1;
158 if (ok && Flags[SPLIT_POS].val)
159 ok = pos_clause(c);
160 if (ok && Flags[SPLIT_NEG].val)
161 ok = neg_clause(c);
162 if (ok && Flags[SPLIT_NONHORN].val)
163 ok = !horn_clause(c);
164 return ok;
165 }
166 } /* splitable_clause */
167
168 /*************
169 *
170 * compare_splitable_clauses(c, d) -- Compare two splittable clauses.
171 *
172 * Return the better clause. If neither is better, return c.
173 *
174 *************/
175
compare_splitable_clauses(struct clause * c,struct clause * d)176 struct clause *compare_splitable_clauses(struct clause *c,
177 struct clause *d)
178 {
179 if (c == NULL)
180 return d;
181 else if (d == NULL)
182 return c;
183 else if (Flags[SPLIT_MIN_MAX].val) {
184
185 /* Return the clause with the smaller maximum literal.
186 * If maxes are the same, return the smaller clause
187 * if clauses are the same weight, return c.
188 */
189
190 int cm = max_literal_weight(c, Weight_pick_given_index);
191 int dm = max_literal_weight(c, Weight_pick_given_index);
192 /* printf("maxes: %4d=%4d, %4d=%4d\n", c->id, cm, d->id, dm); */
193 if (cm < dm) {
194 return c;
195 }
196 else if (dm < cm) {
197 return d;
198 }
199 else
200 return (d->pick_weight < c->pick_weight ? d : c);
201 }
202 else {
203 /* Return smaller clause; if clauses are the same weight, return c. */
204 return (d->pick_weight < c->pick_weight ? d : c);
205 }
206 } /* compare_splitable_clauses */
207
208 /*************
209 *
210 * init_literal_data(p) -- Initialize a literal_data structure.
211 *
212 *************/
213
init_literal_data(struct literal_data * p)214 static void init_literal_data(struct literal_data *p)
215 {
216 p->atom = NULL;
217 } /* init_literal_data */
218
219 /*************
220 *
221 * p_literal_data(data) -- Print a literal_data structure to stdout.
222 *
223 *************/
224
p_literal_data(struct literal_data data)225 static void p_literal_data(struct literal_data data)
226 {
227 printf("Atom: "); print_term(stdout, data.atom);
228 printf(" sign=%d, equality=%d, atom_wt=%d, cl_id=%d, cl_wt=%d, cl_type=%d, variables=%d, pos=%d, neg=%d, pos_binary=%d, neg_binary=%d\n",
229 data.sign,data.equality,data.atom_weight,data.clause_id,
230 data.clause_weight,
231 data.clause_type,data.clause_variables,
232 data.pos_occurrences,data.neg_occurrences,
233 data.pos_binary_occurrences,data.neg_binary_occurrences);
234 } /* p_literal_data */
235
236 /*************
237 *
238 * get_literal_data(lit, p)
239 *
240 * Given a ground literal occurrence, fill in the data.
241 *
242 *************/
243
get_literal_data(struct literal * lit,struct literal_data * p)244 static void get_literal_data(struct literal *lit,
245 struct literal_data *p)
246 {
247 struct clause *c = lit->container;
248 struct term *a;
249 struct fpa_tree *ut;
250 int n, m;
251
252 p->atom = lit->atom;
253 p->sign = lit->sign;
254 p->equality = is_eq(lit->atom->sym_num);
255 p->atom_weight = weight(lit->atom, Weight_pick_given_index);
256
257 p->clause_id = c->id;
258 p->clause_weight = weight_cl(c, Weight_pick_given_index);
259 p->clause_variables = distinct_vars(c);
260 if (pos_clause(c))
261 p->clause_type = POS_CLAUSE;
262 else if (neg_clause(c))
263 p->clause_type = NEG_CLAUSE;
264 else
265 p->clause_type = MIX_CLAUSE;
266
267 if (!Flags[SPLIT_POPULAR].val) {
268 p->pos_occurrences = 0;
269 p->neg_occurrences = 0;
270 p->pos_binary_occurrences = 0;
271 p->neg_binary_occurrences = 0;
272 }
273 else {
274 ut = build_tree(lit->atom, INSTANCE, Parms[FPA_LITERALS].val, Fpa_pos_lits);
275 n = 0; m = 0;
276 a = next_term(ut, 0);
277 while (a != NULL) {
278 n++;
279 if (num_literals(a->occ.lit->container) == 2)
280 m++;
281 a = next_term(ut, 0);
282 }
283 p->pos_occurrences = n;
284 p->pos_binary_occurrences = m;
285
286 ut = build_tree(lit->atom, INSTANCE, Parms[FPA_LITERALS].val, Fpa_neg_lits);
287 n = 0; m = 0;
288 a = next_term(ut, 0);
289 while (a != NULL) {
290 n++;
291 if (num_literals(a->occ.lit->container) == 2)
292 m++;
293 a = next_term(ut, 0);
294 }
295 p->neg_occurrences = n;
296 p->neg_binary_occurrences = m;
297 }
298 } /* get_literal_data */
299
300 /*************
301 *
302 * print_case() -- print the current case, e.g., [2.1.3], to a file
303 *
304 *************/
305
print_case(FILE * fp)306 void print_case(FILE *fp)
307 {
308 struct ilist *ip;
309 fprintf(fp, "[");
310 for (ip = Current_case; ip; ip = ip->next)
311 fprintf(fp, "%d%s", ip->i, ip->next == NULL ? "" : ".");
312 fprintf(fp, "]");
313 } /* print_case */
314
315 /*************
316 *
317 * p_case()
318 *
319 *************/
320
p_case(void)321 void p_case(void)
322 {
323 print_case(stdout);
324 } /* p_case */
325
326 /*************
327 *
328 * print_case_n() -- Like print_case, but add the argument.
329 *
330 *************/
331
print_case_n(FILE * fp,int n)332 void print_case_n(FILE *fp,
333 int n)
334 {
335 struct ilist *ip;
336 fprintf(fp, "[");
337 for (ip = Current_case; ip; ip = ip->next)
338 fprintf(fp, "%d.", ip->i);
339 fprintf(fp, "%d]", n);
340 } /* print_case_n */
341
342 /*************
343 *
344 * p_case_n()
345 *
346 *************/
347
p_case_n(int n)348 void p_case_n(int n)
349 {
350 print_case_n(stdout, n);
351 } /* p_case_n */
352
353 /*************
354 *
355 * p_assumption_depths()
356 *
357 *************/
358
p_assumption_depths(char assumptions[])359 void p_assumption_depths(char assumptions[])
360 {
361 #if 0
362 int i;
363 printf("Assumptions at the following depths were used to refute this branch:");
364 for (i = 0; i <= MAX_SPLIT_DEPTH; i++) {
365 if (assumptions[i])
366 printf(" %d", i);
367 }
368 printf(".\n");
369 #endif
370 } /* p_assumption_depths */
371
372 /*************
373 *
374 * current_case() -- Return Current_case.
375 *
376 *************/
377
current_case(void)378 struct ilist *current_case(void)
379 {
380 return(Current_case);
381 } /* current_case */
382
383 /*************
384 *
385 * add_subcase(i) -- Append an integer to Current_case.
386 *
387 *************/
388
add_subcase(int i)389 void add_subcase(int i)
390 {
391 struct ilist *p1, *p2;
392
393 p1 = get_ilist();
394 p1->i = i;
395 if (Current_case == NULL)
396 Current_case = p1;
397 else {
398 for (p2 = Current_case; p2->next != NULL; p2 = p2->next);
399 p2->next = p1;
400 }
401 } /* add_subcase */
402
403 /*************
404 *
405 * case_depth() -- What is the depth of the current case?
406 *
407 *************/
408
case_depth(void)409 int case_depth(void)
410 {
411 return ilist_length(Current_case);
412 } /* case_depth */
413
414 /*************
415 *
416 * find_clause_to_split()
417 *
418 * Go through Usable, then Sos, and find the best splittable clause.
419 *
420 *************/
421
find_clause_to_split(void)422 struct clause *find_clause_to_split(void)
423 {
424 struct clause *c;
425 struct clause *best_so_far = NULL;
426
427 for (c = Usable->first_cl; c != NULL; c = c->next_cl) {
428 if (splitable_clause(c)) {
429 best_so_far = compare_splitable_clauses(best_so_far, c);
430 }
431 }
432
433 for (c = Sos->first_cl; c != NULL; c = c->next_cl) {
434 if (splitable_clause(c)) {
435 best_so_far = compare_splitable_clauses(best_so_far, c);
436 }
437 }
438
439 return(best_so_far); /* may be NULL */
440
441 } /* find_clause_to_split */
442
443 /*************
444 *
445 * find_atom_to_split()
446 *
447 * Go through all literal occurrences in Usable+Sos, and return
448 * the atom of the best splittable literal occurrence.
449 *
450 *************/
451
find_atom_to_split(void)452 struct term *find_atom_to_split(void)
453 {
454 if (Split_atoms != NULL) {
455 int i;
456 struct term *t;
457
458 /* Split_atoms is a proper list. If the case_depth is n,
459 * return the n-th member of split_atoms.
460 */
461 for (t = Split_atoms, i = 0;
462 t->sym_num != Nil_sym_num && i < case_depth();
463 t = t->farg->narg->argval, i++);
464 return (t->sym_num == Nil_sym_num ? NULL : t->farg->argval);
465 }
466 else {
467 struct clause *c;
468 struct literal *lit;
469 struct literal_data min, curr;
470
471 init_literal_data(&min);
472
473 for (c = Usable->first_cl; c != NULL; c = c->next_cl) {
474 for (lit = c->first_lit; lit != NULL; lit = lit->next_lit) {
475 if (splitable_literal(c, lit)) {
476 get_literal_data(lit, &curr);
477 min = compare_literal_data(min, curr);
478 }
479 }
480 }
481
482 for (c = Sos->first_cl; c != NULL; c = c->next_cl) {
483 for (lit = c->first_lit; lit != NULL; lit = lit->next_lit) {
484 if (splitable_literal(c, lit)) {
485 get_literal_data(lit, &curr);
486 min = compare_literal_data(min, curr);
487 }
488 }
489 }
490 return min.atom; /* NULL if no ground lits found */
491 }
492 } /* find_atom_to_split */
493
494 /*************
495 *
496 * prover_forks(int n, int *ip, char assumptions[])
497 *
498 * This is the guts of the splitting. It is used for both clause
499 * splitting and atom splitting. Parameter n tells how many cases
500 * to do. This routine also takes care of skipping redundant cases
501 * when assumptions are not used. For example, if we split on
502 * clause p|q, and the p case is refuted without using p, then we
503 * skip the q case.
504 *
505 * This routine does not return when a child returns without
506 * a proof. When this happens, we just exit,
507 * sending the same exit code to the parent.
508 *
509 * When this routine does return to its caller, the return value is:
510 *
511 * CHILD Return as child process ready to do its case.
512 * Also, integer *ip is set to the case number.
513 * PARENT Return as parent process---all children succeeded.
514 * Also, fill in the Boolean array assumptions, which
515 * tells which ancestor case assumptions were used to
516 * refute the child cases.
517 * FORK_FAIL Operating system would not allow process to fork.
518 * CHILD_FAIL A child did not exit normally (WIFEXITED(status) nonzero).
519 *
520 *************/
521
prover_forks(int n,int * ip,char assumptions[])522 int prover_forks(int n,
523 int *ip,
524 char assumptions[])
525 {
526 #ifndef TP_FORK
527 return FORK_FAIL;
528 #else
529 int child_status, rc;
530 int parent = 1;
531 int i = 1;
532 int fd[2];
533 char assumptions_descendents[MAX_SPLIT_DEPTH+1];
534 int j;
535
536 for (j = 0; j <= MAX_SPLIT_DEPTH; j++)
537 assumptions[j] = 0;
538
539 /* Set up pipe for communicating with children. The child processes
540 * will inherit these values and immediately use them to set up a
541 * pipe to the parent (that is, copy them to To_parent and From_parent).
542 */
543
544 rc = pipe(fd); From_children = fd[0]; To_children = fd[1];
545 if (rc != 0) {
546 return FORK_FAIL;
547 }
548
549 while (i <= n && parent) {
550 fflush(stdout); fflush(stderr);
551 rc = fork();
552 if (rc < 0) {
553 return FORK_FAIL;
554 }
555 else if (rc > 0) {
556 /* This is the parent process */
557 int depth = case_depth();
558
559 wait(&child_status);
560 if (WIFEXITED(child_status)) {
561 int child_exit_code = WEXITSTATUS(child_status);
562
563 if (child_exit_code==PROOF_EXIT) {
564 /* all is well---the child proved its case */
565 printf("Refuted case ");
566 p_case_n(i);
567 printf(".\n");
568 fflush(stdout);
569
570 if (Flags[REALLY_DELETE_CLAUSES].val) {
571 /* Really_delete_clauses is incompatable with the assumption
572 redundancy check. We'll just go on to the next case
573 in stead of checking if the assumption for the previous
574 case was used for the refutation.
575 */
576 i++;
577 }
578 else {
579 rc = read(From_children, assumptions_descendents,MAX_SPLIT_DEPTH+1);
580 if (assumptions_descendents[depth+1])
581 i++;
582 else if (i == n)
583 i++; /* assumption for last case was not used */
584
585 else {
586
587 printf("\nThe Assumption for case ");
588 p_case_n(i);
589 printf(" was not used;\n");
590 printf("therefore we skip case%s", (i == n-1 ? ": " : "s:"));
591 for (j = i+1; j <= n; j++) {
592 printf(" ");
593 p_case_n(j);
594 }
595 printf(".\n");
596
597 i = n+1;
598 }
599
600 /* "or" in the assumptions used. */
601 for (j = 0; j <= depth; j++)
602 assumptions[j] = (assumptions[j] | assumptions_descendents[j]);
603 }
604 } /* child found proof */
605 else {
606 /* Child exited without a proof. Exit with same code to parent. */
607 output_stats(stdout, Parms[STATS_LEVEL].val);
608 printf("\nProcess %d finished %s", my_process_id(), get_time());
609 exit(child_exit_code);
610 }
611 } /* WIFEXITED */
612 else {
613 /* Child fails for some other reason. */
614 return CHILD_FAIL;
615 }
616 } /* if parent */
617
618 else {
619 /* This is the child process. */
620 /* Set up pipe to parent. */
621 To_parent = To_children; From_parent = From_children;
622 /* Exit loop and do the case. */
623 parent = 0;
624 }
625 } /* while */
626
627 *ip = i;
628 return (parent ? PARENT : CHILD);
629 #endif
630 } /* prover_forks */
631
632 /*************
633 *
634 * split_clause(c)
635 *
636 * If (c == NULL), look for a clause to split.
637 * If (c != NULL), split on c.
638 *
639 * If success (i.e., split, and each child refutes its case), exit process.
640 *
641 * Return value:
642 * 0: no split
643 * 1: split, child returns
644 * 2: split, parent returns failure (this might not be used)
645 *
646 *************/
647
split_clause(struct clause * giv_cl)648 int split_clause(struct clause *giv_cl)
649 {
650 #ifndef TP_FORK
651 return 0;
652 #else
653 struct clause *c;
654 char assumptions[MAX_SPLIT_DEPTH+1];
655
656 if (giv_cl == NULL)
657 c = find_clause_to_split();
658 else
659 c = giv_cl;
660
661 if (c == NULL) {
662 printf("\nI tried to split, but I could not find a suitable clause.\n");
663 return 0;
664 }
665 else {
666 int rc, n, case_number;
667
668 printf("\nSplitting on clause "); p_clause(c);
669 n = num_literals(c);
670 rc = prover_forks(n, &case_number, assumptions);
671
672 if (rc == FORK_FAIL) {
673 printf("Case splitting (fork) failed. Returning to search.\n");
674 return 0;
675 }
676 else if (rc == PARENT) {
677 if (Current_case == NULL) {
678 printf("\nThat finishes the proof of the theorem.\n");
679 fprintf(stderr, "%c\nThat finishes the proof of the theorem.\n", Bell);
680 }
681 else {
682 /* Tell the parent the assumptions used to refute this
683 * branch. We don't send the actual assumptions; instead,
684 * we send a set of integers giving the depths of the
685 * assumptions. This is implemented as a Boolean array
686 * indexed by depth.
687 */
688
689 rc = write(To_parent, assumptions, MAX_SPLIT_DEPTH+1);
690 p_assumption_depths(assumptions);
691 }
692 output_stats(stdout, Parms[STATS_LEVEL].val);
693 printf("\nProcess %d finished %s", my_process_id(), get_time());
694 exit(PROOF_EXIT);
695 }
696 else if (rc == CHILD) {
697 /* We are the child. Assert units for this case, then continue search. */
698 int j;
699 struct literal *c_lit, *d_lit;
700 struct clause *d, *sos_pos;
701
702 clock_init(); /* reset all clocks to 0 */
703 add_subcase(case_number); /* Update the case vector. */
704 printf("\nCase "); p_case();
705 printf(" (process %d):\n", my_process_id());
706
707 /* Disable the clause being split. */
708
709 un_index_lits_all(c);
710 if (c->container == Usable)
711 un_index_lits_clash(c);
712 rem_from_list(c);
713 hide_clause(c);
714
715 /* Add negated units for cases already done. */
716 /* Then add the unit for this case. */
717
718 sos_pos = Sos->last_cl; /* save position for post processing */
719
720 for (j = 1; j <= case_number; j++) {
721 c_lit = ith_literal(c, j);
722 d = get_clause();
723 d_lit = get_literal();
724 d->first_lit = d_lit;
725 d_lit->container = d;
726 d_lit->atom = copy_term(c_lit->atom);
727 d_lit->atom->occ.lit = d_lit;
728 d_lit->sign = c_lit->sign;
729 d_lit->atom->varnum = c_lit->atom->varnum; /* copy type of atom */
730 if (j != case_number) {
731 /* negate literal */
732 d_lit->sign = !d_lit->sign;
733 if (d_lit->atom->varnum == POS_EQ)
734 d_lit->atom->varnum = NEG_EQ;
735 else if (d_lit->atom->varnum == NEG_EQ)
736 d_lit->atom->varnum = POS_EQ;
737 }
738
739 d->parents = get_ilist();
740 d->parents->i = c->id;
741
742 d->parents->next = get_ilist();
743 d->parents->next->i = (j == case_number ? SPLIT_RULE : SPLIT_NEG_RULE);
744 d->parents->next->next = get_ilist();
745 d->parents->next->next->i = LIST_RULE - ilist_length(Current_case);;
746 d->parents->next->next->next = copy_ilist(Current_case);
747
748 pre_process(d, 0, Sos);
749 if (j == case_number && d->container == Sos) {
750 printf("Assumption: ");
751 p_clause(d);
752 }
753 }
754 post_proc_all(sos_pos, 0, Sos);
755 return 1;
756 }
757 else { /* rc == CHILD_FAIL */
758 abend("case failure");
759 return -1;
760 }
761 }
762 #endif
763 } /* split_clause */
764
765 /*************
766 *
767 * split_atom()
768 *
769 * If success (i.e., split, and each child refutes its case), exit process.
770 *
771 * Return value:
772 * 0: no split
773 * 1: split, child returns
774 * 2: split, parent returns failure (this might not be used)
775 *
776 *************/
777
split_atom(void)778 int split_atom(void)
779 {
780 #ifndef TP_FORK
781 return 0;
782 #else
783 struct term *atom;
784 char assumptions[MAX_SPLIT_DEPTH+1];
785
786 atom = find_atom_to_split();
787
788 if (atom == NULL) {
789 printf("\nI tried to split, but I could not find a suitable atom.\n");
790 return 0;
791 }
792 else {
793 int rc, case_number;
794
795 printf("\nSplitting on atom "); p_term(atom);
796
797 rc = prover_forks(2, &case_number, assumptions);
798
799 if (rc == FORK_FAIL) {
800 printf("Case splitting (fork) failed. Returning to search.\n");
801 return 0;
802 }
803 else if (rc == PARENT) {
804 if (Current_case == NULL) {
805 printf("\nThat finishes the proof of the theorem.\n");
806 fprintf(stderr, "%c\nThat finishes the proof of the theorem.\n", Bell);
807 }
808 else {
809 rc = write(To_parent, assumptions, MAX_SPLIT_DEPTH+1);
810 p_assumption_depths(assumptions);
811 }
812 output_stats(stdout, Parms[STATS_LEVEL].val);
813 printf("\nProcess %d finished %s", my_process_id(), get_time());
814 exit(PROOF_EXIT);
815 } /* parent */
816 else if (rc == CHILD) {
817 /* We are the child. Assert units for this case, then continue search. */
818 struct literal *d_lit;
819 struct clause *d, *sos_pos;
820
821 clock_init(); /* reset all clocks to 0 */
822 add_subcase(case_number); /* Update the case vector. */
823 printf("\nCase "); p_case();
824 printf(" (process %d):\n", my_process_id());
825
826 sos_pos = Sos->last_cl; /* save position for post processing */
827
828 d = get_clause();
829 d_lit = get_literal();
830 d->first_lit = d_lit;
831 d_lit->container = d;
832 d_lit->atom = copy_term(atom);
833 d_lit->atom->occ.lit = d_lit;
834 d_lit->sign = (case_number == 1 ? 1 : 0);
835 if (is_eq(atom->sym_num))
836 d_lit->atom->varnum = d_lit->sign ? POS_EQ : NEG_EQ;
837 else
838 d_lit->atom->varnum = NORM_ATOM;
839
840 d->parents = get_ilist();
841 d->parents->i = SPLIT_RULE;
842 d->parents->next = get_ilist();
843 d->parents->next->i = LIST_RULE - ilist_length(Current_case);
844 d->parents->next->next = copy_ilist(Current_case);
845
846 pre_process(d, 0, Sos);
847 if (d->container == Sos) {
848 printf("Assumption: ");
849 p_clause(d);
850 }
851 post_proc_all(sos_pos, 0, Sos);
852 return 1;
853 } /* child */
854 else { /* rc == CHILD_FAIL */
855 abend("case failure");
856 return -1;
857 }
858 }
859 #endif
860 } /* split_atom */
861
862 /*************
863 *
864 * possible_split()
865 *
866 * Check if it is time to split, and if so, try to split.
867 *
868 * If a split occurs, children return to continue searching.
869 * If all children find proofs, parent calls exit(PROOF_EXIT).
870 * If any child fails, parent abends. (This may change.)
871 *
872 *************/
873
possible_split(void)874 void possible_split(void)
875 {
876 static int next_attempt = 0;
877 int ok = 0;
878
879 #ifndef TP_FORK
880 abend("case splitting is not compiled into this Otter");
881 #endif
882
883 if (Flags[SPLIT_CLAUSE].val || Flags[SPLIT_ATOM].val) {
884 if (Parms[SPLIT_SECONDS].val != -1) {
885 int runtime = run_time() / 1000;
886 if (next_attempt == 0)
887 next_attempt = Parms[SPLIT_SECONDS].val;
888 if (runtime >= next_attempt) {
889 ok = 1;
890 next_attempt += Parms[SPLIT_SECONDS].val;
891 }
892 }
893 else if (Parms[SPLIT_GIVEN].val != -1) {
894 int n = Parms[SPLIT_GIVEN].val;
895 if (n == 0 || Stats[CL_GIVEN] % n == 0) {
896 ok = 1;
897 }
898 }
899
900 if (ok) {
901 int rc;
902 if (case_depth() < Parms[SPLIT_DEPTH].val) {
903 if (Flags[SPLIT_ATOM].val)
904 rc = split_atom();
905 else
906 rc = split_clause((struct clause *) NULL);
907 }
908 }
909 }
910 } /* possible_split */
911
912 /*************
913 *
914 * always_split()
915 *
916 * Unconditional splitting, and keep splitting as long as possible.
917 *
918 *************/
919
always_split(void)920 void always_split(void)
921 {
922 int rc;
923
924 #ifndef TP_FORK
925 abend("case splitting is not compiled into this Otter");
926 #endif
927
928 if (Flags[SPLIT_ATOM].val)
929 rc = split_atom();
930 else
931 rc = split_clause((struct clause *) NULL);
932
933 if (rc == 1)
934 always_split(); /* We are the child; all is well; split again. */
935 else {
936 printf("\nalways_split: returning because no splitting is possible at this time.\n");
937 return;
938 }
939 } /* always_split */
940
941 /*************
942 *
943 * possible_given_split(c)
944 *
945 * c has just been selected as the given clause.
946 *
947 *************/
948
possible_given_split(struct clause * c)949 void possible_given_split(struct clause *c)
950 {
951 #ifndef TP_FORK
952 abend("case splitting is not compiled into this Otter");
953 #endif
954
955 if (Flags[SPLIT_WHEN_GIVEN].val && ground_clause(c) && num_literals(c) > 1) {
956 int ok = 1;
957
958 if (ok && Flags[SPLIT_POS].val)
959 ok = pos_clause(c);
960 if (ok && Flags[SPLIT_NEG].val)
961 ok = neg_clause(c);
962 if (ok && Flags[SPLIT_NONHORN].val)
963 ok = !horn_clause(c);
964
965 if (ok) {
966 int rc;
967 if (case_depth() < Parms[SPLIT_DEPTH].val) {
968 if (Flags[SPLIT_ATOM].val) {
969 /* This is a little strange. We're allowing splitting on an
970 atom. We'll first move the clause back to Sos.
971 */
972 un_index_lits_clash(c);
973 rem_from_list(c);
974 append_cl(Sos, c);
975 rc = split_atom();
976 }
977 else
978 rc = split_clause(c);
979 }
980 }
981 }
982 } /* possible_given_split */
983
984 /*************
985 *
986 * assumps_to_parent()
987 *
988 * This routine is called when a proof is found during case splitting.
989 *
990 * Tell the parent the assumptions used to refute this
991 * leaf. We don't send the actual assumptions; instead,
992 * we send a set of integers giving the depths of the
993 * assumptions. This is implemented as a Boolean array
994 * indexed by depth.
995 *
996 *************/
997
assumps_to_parent(struct clause * e)998 void assumps_to_parent(struct clause *e)
999 {
1000 struct clause_ptr *p, *q;
1001 struct ilist *r;
1002 int i;
1003 char assumptions[MAX_SPLIT_DEPTH+1];
1004
1005 p = NULL;
1006 i = get_ancestors(e, &p, &r); /* i (level), r (level list) won't be used */
1007
1008 for (i = 0; i <= MAX_SPLIT_DEPTH; i++)
1009 assumptions[i] = 0;
1010
1011 for (q = p; q != NULL; q = q->next) {
1012 r = q->c->parents;
1013 /* SPLIT_RULE code is either first (atom split) or second (clause split) */
1014 if (r != NULL && r->i == SPLIT_RULE) {
1015 i = LIST_RULE - r->next->i;
1016 }
1017 else if (r!= NULL && r->next != NULL && r->next->i == SPLIT_RULE) {
1018 i = LIST_RULE - r->next->next->i;
1019 }
1020 else
1021 i = 0;
1022 if (i != 0) {
1023 /* The current clause is a split assumption, and i is the
1024 * depth. This does not include SPLIT_NEG assumptions from
1025 * previous sibling cases.
1026 */
1027 assumptions[i] = 1;
1028 }
1029 }
1030 i = write(To_parent, assumptions, MAX_SPLIT_DEPTH+1);
1031 printf("\n\n"); p_assumption_depths(assumptions);
1032 } /* assumps_to_parent */
1033
1034 /*************
1035 *
1036 * exit_with_possible_model()
1037 *
1038 *************/
1039
exit_with_possible_model(void)1040 void exit_with_possible_model(void)
1041 {
1042 printf("\nPossible model detected on branch ");
1043 p_case(); printf(".\n");
1044 fprintf(stderr, "\n%cPossible model detected on branch ", Bell);
1045 print_case(stderr); fprintf(stderr, ".\n");
1046
1047 printf("\nHere are the clauses in Usable and SoS. It seems that no more\n");
1048 printf("inferences or splitting can be done. If the search strategy is\n");
1049 printf("complete, these clauses should lead to a model of the input.\n");
1050
1051 printf("\nlist(usable).\n");
1052 print_cl_list(stdout, Usable);
1053 printf("\nlist(sos).\n");
1054 print_cl_list(stdout, Sos);
1055
1056 output_stats(stdout, Parms[STATS_LEVEL].val);
1057
1058 printf("\nProcess %d finished %s", my_process_id(), get_time());
1059 exit(POSSIBLE_MODEL_EXIT);
1060 } /* exit_with_possible_model */
1061
1062 /*************************************************************************/
1063 /* The rest of this file is some documentation on the code in this file. */
1064 /*************************************************************************/
1065
1066 /*
1067
1068 CASE SPLITTING IN OTTER
1069
1070 William McCune, Dale Myers, Rusty Lusk, Mohammed Alumlla
1071 December 1997
1072
1073 This implementation uses the UNIX fork() command to make copies of the
1074 current state of the process for the cases. This avoids having to
1075 explicitly save the state and restore it for the next case. (That is,
1076 it was easy to implement.)
1077
1078 When enabled, splitting occurs periodically during the search. The
1079 default is to split after every 5 given clauses. This can be changed
1080 to some other number of given clauses, say 10, with the command
1081
1082 assign(split_given, 10). % default 5
1083
1084 Instead, one can split after a specified number of seconds, with
1085 a command such as
1086
1087 assign(split_seconds, 10). % default infinity
1088
1089 which asks Otter to attempt a split every (approximately) 10 seconds.
1090 (Jobs that use split_seconds are usually not repeatable.)
1091
1092 A third method is to split when a nonunit ground clause is selected
1093 as the given clause. This option is specified with the command
1094
1095 set(split_when_given).
1096
1097 which causes splitting on the given clause if (1) it is ground, (2) it
1098 is within the split_depth bound (see below), and (3) it satisfies the
1099 split_pos and split_neg flags (see below).
1100
1101 If you wish to limit the depth of splitting, use a command such as
1102
1103 assign(split_depth, 3). % default 256 (which is also the maximum)
1104
1105 which will not allow a case such as "Case [1.1.1.1]".
1106
1107 There are two kinds of splitting: on ground clauses and on ground
1108 atoms. Clause splitting constructs one case for each literal, and
1109 atom splitting, say on p, constructs two cases: p is true; p is false
1110 (or, as Larry Wos says, splitting on a tautology).
1111
1112 Sequence of Splitting Processes
1113
1114 Say Otter decides to split the search into n cases. For each case,
1115 the fork() command creates a child process for the case, then the
1116 parent process waits for the child to exit. If any child fails to
1117 refute its case, the parent exits in failure (causing all
1118 ancestor processes to fail as well). If each child refutes its case,
1119 the parent exits with success.
1120
1121 The Output File
1122
1123 Various messages about the splitting events are sent to the output file.
1124 To get an overview of the search from an output file, say problem.out,
1125 one can use the following command.
1126
1127 egrep "Splitting|Assumption|Refuted|skip|That" problem.out
1128
1129 Splitting Clauses
1130
1131 The following commands enables splitting on clauses after some number
1132 of given clauses have been used (see split_given), or after some
1133 number of seconds (see split_seconds).
1134
1135 set(split_clause). % default clear
1136
1137 The following command simply asks Otter to split on ground given clauses.
1138
1139 set(split_when_given). % default clear
1140
1141 (I suppose one could use both of the preceding commands at the same
1142 time---I haven't tried it.)
1143
1144 If Otter finds a suitable (see flags below) nonunit ground clause
1145 for splitting, say "p | q | r", the assumptions for three cases
1146 are
1147
1148 Case 1: p.
1149 Case 2: -p & q.
1150 Case 3: -p & -q & r.
1151
1152 Eligible Clauses for Splitting
1153
1154 Otter splits on ground nonunit clauses only. They can
1155 occur in Usable or in Sos. The following commands can be used
1156 to specify the type of clause to split.
1157
1158 set(split_pos). % split on positive clauses only (default clear)
1159 set(split_neg). % split on negative clauses only (default clear)
1160 set(split_nonhorn). % split on nonhorn clauses only (default clear)
1161
1162 If none of the preceding flags are set, all ground clauses are eligible.
1163
1164 Selecting the Best Eligible Clause
1165
1166 The default method for selecting the best eligible clause for
1167 splitting is simply to take the first, lowest weight (using the
1168 pick_given scale) clause from Usable+Sos.
1169
1170 Instead, one can use The command
1171
1172 set(split_min_max). % default clear
1173
1174 which says to use the following method to compare two eligible clauses
1175 C and D. Prefer the clause with the lighter heaviest literal
1176 (pick_given scale); if the heaviest literals have the same
1177 weight, use the lighter clause; if the clauses have the same
1178 weight, use the first in Usable+Sos.
1179
1180 Splitting Atoms
1181
1182 The following commands enables splitting on atoms after some number
1183 of given clauses have been used (see split_given), or after some
1184 number of seconds (see split_seconds).
1185
1186 set(split_atom).
1187
1188 (For propositional problems with assign(split_given, 0), this will
1189 cause Otter to perform a (not very speedy) Davis-Putnam search.)
1190 To select an atom for splitting, we consider OCCURRENCES of
1191 atoms within clauses.
1192
1193 Eligible Atoms
1194
1195 Otter splits on atoms that occur in nonunit ground clauses.
1196 The command
1197
1198 set(split_pos). % default clear
1199
1200 says to split on atoms the occur only in positive clauses,
1201
1202 set(split_neg). % default clear
1203
1204 says to split on atoms the occur only in negative clauses, and
1205
1206 set(split_nonhorn). % default clear
1207
1208 says to split on atoms that occur positively in nonHorn clauses.
1209
1210 Selecting the Best Eligible Atom
1211
1212 Default method for comparing two eligible atom-occurrences:
1213 Prefer the atom that occurs in the lower weight clause.
1214 If the clauses have the same weight, prefer the atom
1215 with the lower weight.
1216
1217 An optional method for selecting an atom considers the number
1218 of occurrences of the atom. The command
1219
1220 set(split_popular). % default clear
1221
1222 says to prefer the atom that occurs in the greatest number
1223 of clauses. All clauses in Usable+Sos containing the atom
1224 are counted.
1225
1226 Another Way to Split Atoms
1227
1228 If the user has an idea of how atom splitting should occur, he/she
1229 can give a sequence of atoms in the input file, and Otter will
1230 split accordingly. (As above, the TIME of splitting is determined
1231 as above with the split_given and split_seconds parameters.)
1232
1233 For example, with the commands
1234
1235 set(split_atom).
1236 split_atoms([P, a=b, R]).
1237 assign(split_given, 0).
1238
1239 Otter will immediately (because of split_given) split the
1240 search into 8 cases (because there are 3 atoms), then do no
1241 more splitting.
1242
1243 Problems With This Implementation
1244
1245 Splitting is permanent. That is, if a case fails, the whole
1246 search fails (no backing up to try a different split).
1247
1248 If Otter fails to find a proof for a particular case (e.g., the Sos
1249 empties or some limit is reached), the whole attempt fails. If
1250 the search strategy is complete, then an empty Sos indicates
1251 satisfiability, and the set of assumptions introduced by splitting
1252 give you a partial model; however, it is up to the user to figure this
1253 out.
1254
1255 When splitting is enabled, max_seconds (for the initial process and
1256 all descendent processes) is checked against the wall clock (from the
1257 start of the initial process) instead of against the process clock.
1258 This is problematic if the computer is busy with other processes.
1259
1260 Getting the Total Process Time
1261
1262 The process clock ("user CPU" statistic) is initialized at the
1263 start of the process, and each process prints statistics once at the
1264 end of its life. Therefore, one can get the total process by
1265 summing all of the "user CPU" times in the output file. The command
1266
1267 grep "user CPU" problem.out | awk '{sum += $4}END{print sum}'
1268
1269 can be used to get the approximate total process time from an
1270 output file problem.out.
1271
1272 Advice on Using Otter's Splitting (from McCune)
1273
1274 At this time, we don't have much data. A general strategy
1275 for nonground problems is the following.
1276
1277 set(split_when_given).
1278 set(split_pos). % Also try it without this command.
1279 assign(split_depth, 10).
1280
1281 For ground (propositional) problems, try the following, which
1282 is essentially a Davis-Putnam procedure.
1283
1284 set(split_atom).
1285 set(split_pos).
1286 assign(split_given, 0).
1287
1288 */
1289