1 /*-----------------------------------------------------------------------
2
3 File : pcl_proofcheck.c
4
5 Author: Stephan Schulz
6
7 Contents
8
9 Data types and algorithms to realize proof checking for PCL2
10 protocols.
11
12 Copyright 1998, 1999 by the author.
13 This code is released under the GNU General Public Licence and
14 the GNU Lesser General Public License.
15 See the file COPYING in the main E directory for details..
16 Run "eprover -h" for contact information.
17
18 Changes
19
20 <1> Mon Apr 3 23:02:28 GMT 2000
21 New
22
23 -----------------------------------------------------------------------*/
24
25 #include "pcl_proofcheck.h"
26
27
28
29 /*---------------------------------------------------------------------*/
30 /* Global Variables */
31 /*---------------------------------------------------------------------*/
32
33
34 /*---------------------------------------------------------------------*/
35 /* Forward Declarations */
36 /*---------------------------------------------------------------------*/
37
38
39 /*---------------------------------------------------------------------*/
40 /* Internal Functions */
41 /*---------------------------------------------------------------------*/
42
43 /*-----------------------------------------------------------------------
44 //
45 // Function: pcl_run_prover()
46 //
47 // Execute command and scan the output for success. If found, return
48 // true, else return false;
49 //
50 // Global Variables:
51 //
52 // Side Effects :
53 //
54 /----------------------------------------------------------------------*/
55
pcl_run_prover(char * command,char * success)56 static bool pcl_run_prover(char* command, char*success)
57 {
58 bool res=false;
59 char line[180],*l;
60 FILE* ppipe;
61
62 if(OutputLevel>1)
63 {
64 fprintf(GlobalOut, "# Running %s\n", command);
65 }
66 ppipe=popen(command, "r");
67 if(!ppipe)
68 {
69 TmpErrno = errno;
70 SysError("Cannot open pipe", SYS_ERROR);
71 }
72 while((l=fgets(line, 180, ppipe)))
73 {
74 if(strstr(line,success))
75 {
76 res = true;
77 }
78 if(OutputLevel >= 3)
79 {
80 fprintf(GlobalOut, "#> %s", line);
81 }
82 }
83 pclose(ppipe);
84
85 return res;
86 }
87
88 /*-----------------------------------------------------------------------
89 //
90 // Function: pcl_verify_eprover()
91 //
92 // Run E on the problem, return true if a proof is found.
93 //
94 // Global Variables: -
95 //
96 // Side Effects : Memory operations, by subroutines.
97 //
98 /----------------------------------------------------------------------*/
99
pcl_verify_eprover(ClauseSet_p problem,char * executable,long time_limit)100 static bool pcl_verify_eprover(ClauseSet_p problem,char *executable,
101 long time_limit)
102 {
103 bool res;
104 DStr_p command = DStrAlloc();
105 char* name=TempFileName();
106 FILE* problemfile;
107
108 assert(OutputFormat == TPTPFormat);
109
110 if(!executable)
111 {
112 executable=E_EXEC_DEFAULT;
113 }
114 problemfile = OutOpen(name);
115 ClauseSetPrint(problemfile, problem, true);
116 OutClose(problemfile);
117
118 DStrAppendStr(command, executable);
119 DStrAppendStr(command, " --tptp-in --prefer-initial-clauses --ac-handling=None"
120 " --cpu-limit=");
121 DStrAppendInt(command, time_limit);
122 DStrAppendChar(command, ' ');
123 DStrAppendStr(command, name);
124
125 res = pcl_run_prover(DStrView(command),"# Proof found!");
126
127 if(!res)
128 {
129 fprintf(GlobalOut, "# ------------Problem begin--------------\n");
130 FilePrint(GlobalOut, name);
131 fprintf(GlobalOut, "# ------------Problem end----------------\n");
132 }
133
134 TempFileRemove(name);
135 FREE(name);
136 DStrFree(command);
137 return res;
138 }
139
140
141 /*-----------------------------------------------------------------------
142 //
143 // Function: eqn_print_otter()
144 //
145 // Print a literal in Otter format.
146 //
147 // Global Variables: -
148 //
149 // Side Effects : Output
150 //
151 /----------------------------------------------------------------------*/
152
eqn_print_otter(FILE * out,Eqn_p eqn)153 static void eqn_print_otter(FILE* out, Eqn_p eqn)
154 {
155 assert(OutputFormat == LOPFormat);
156
157 if(EqnIsEquLit(eqn))
158 {
159 if(EqnIsPositive(eqn))
160 {
161 EqnPrint(out, eqn, false, true);
162 }
163 else
164 {
165 fputc('-', out);
166 EqnPrint(out, eqn, true, true);
167 }
168 }
169 else
170 {
171 if(eqn->lterm==eqn->bank->true_term)
172 {
173 assert(eqn->rterm==eqn->bank->true_term);
174 /* Special case, one more hack */;
175 if(EqnIsPositive(eqn))
176 {
177 fputs("$T", out);
178 }
179 else
180 {
181 fputs("$F", out);
182 }
183 }
184 else
185 {
186 /* Nonequational literal */
187 if(EqnIsNegative(eqn))
188 {
189 fputc('-', out);
190 }
191 else
192 {
193 fputc(' ', out);
194 }
195 TBPrintTerm(out, eqn->bank, eqn->lterm, true);
196 }
197 }
198 }
199
200 /*-----------------------------------------------------------------------
201 //
202 // Function: clause_print_otter()
203 //
204 // Print a clause in Otter format.
205 //
206 // Global Variables: -
207 //
208 // Side Effects : Output
209 //
210 /----------------------------------------------------------------------*/
211
clause_print_otter(FILE * out,Clause_p clause)212 static void clause_print_otter(FILE* out, Clause_p clause)
213 {
214 Eqn_p handle;
215
216 if(ClauseIsEmpty(clause))
217 {
218 /* For otter, the empty clause is propositional false: */
219
220 fputs("$F.", out);
221 }
222 else
223 {
224 handle=clause->literals;
225 eqn_print_otter(out, handle);
226 handle=handle->next;
227 while(handle)
228 {
229 fputs("|\n", out);
230 eqn_print_otter(out, handle);
231 handle=handle->next;
232 }
233 fputs(".\n", out);
234 }
235 }
236
237 /*-----------------------------------------------------------------------
238 //
239 // Function: clause_set_print_otter()
240 //
241 // Print a set of clauses in Otter format (with prolog-variables).
242 //
243 // Global Variables: -
244 //
245 // Side Effects : Output
246 //
247 /----------------------------------------------------------------------*/
248
clause_set_print_otter(FILE * out,ClauseSet_p set)249 static void clause_set_print_otter(FILE* out, ClauseSet_p set)
250 {
251 Clause_p handle;
252
253 for(handle = set->anchor->succ; handle!=set->anchor; handle =
254 handle->succ)
255 {
256 clause_print_otter(out, handle);
257 fputc('\n', out);
258 }
259 }
260
261
262 /*-----------------------------------------------------------------------
263 //
264 // Function: pcl_verify_otter()
265 //
266 // Run Otter on the problem, return true if a proof is found.
267 //
268 // Global Variables: -
269 //
270 // Side Effects : Memory operations, by subroutines.
271 //
272 /----------------------------------------------------------------------*/
273
pcl_verify_otter(ClauseSet_p problem,char * executable,long time_limit)274 static bool pcl_verify_otter(ClauseSet_p problem,char *executable,
275 long time_limit)
276 {
277 bool res;
278 DStr_p command = DStrAlloc();
279 char* name=TempFileName();
280 FILE* problemfile;
281
282 if(!executable)
283 {
284 executable=OTTER_EXEC_DEFAULT;
285 }
286 problemfile = OutOpen(name);
287 fprintf(problemfile,
288 "set(prolog_style_variables).\n"
289 "clear(print_kept).\n"
290 "clear(print_new_demod).\n"
291 "clear(print_back_demod).\n"
292 "clear(print_back_sub).\n"
293 "set(auto).\n"
294 "set(input_sos_first).\n"
295 /* "set(para_from_vars).\n" */
296 "assign(max_seconds, %ld).\n\n"
297 "assign(max_mem, 100000).\n\n"
298 "list(usable).\n\n"
299 "equal(X,X).\n",time_limit);
300 clause_set_print_otter(problemfile, problem);
301 fprintf(problemfile,
302 "end_of_list.\n");
303 OutClose(problemfile);
304
305 DStrAppendStr(command, executable);
306 DStrAppendStr(command, " < ");
307 DStrAppendStr(command, name);
308 DStrAppendStr(command, " 2> /dev/null");
309
310 res = pcl_run_prover(DStrView(command), "-------- PROOF --------");
311
312 if(!res)
313 {
314 fprintf(GlobalOut, "# ------------Problem begin--------------\n");
315 FilePrint(GlobalOut, name);
316 fprintf(GlobalOut, "# ------------Problem end----------------\n");
317 }
318
319 TempFileRemove(name);
320 FREE(name);
321 DStrFree(command);
322 return res;
323 }
324
325
326 /*-----------------------------------------------------------------------
327 //
328 // Function: sig_print_dfg()
329 //
330 // Collect function symbols from set and print them in DFG syntax.
331 //
332 // Global Variables: -
333 //
334 // Side Effects : Output
335 //
336 /----------------------------------------------------------------------*/
337
sig_print_dfg(FILE * out,ClauseSet_p set,Sig_p sig)338 static void sig_print_dfg(FILE* out, ClauseSet_p set, Sig_p sig)
339 {
340 long *symbol_distrib;
341 FunCode i;
342
343 symbol_distrib = SizeMalloc((sig->size)*sizeof(long));
344 for(i=0; i< sig->size; i++)
345 {
346 symbol_distrib[i] = 0;
347 }
348 ClauseSetAddSymbolDistribution(set, symbol_distrib);
349
350 fprintf(out,"list_of_symbols.\nfunctions[(spass_hack,0)");
351 for(i=sig->internal_symbols+1; i<sig->size; i++)
352 {
353 if(symbol_distrib[i]&&!SigIsPredicate(sig,i))
354 {
355 fprintf(out, ",(%s,%d)",
356 SigFindName(sig, i),
357 SigFindArity(sig, i));
358 }
359 }
360 fprintf(out,"].\npredicates[(spass_pred_dummy,0)");
361 for(i=sig->internal_symbols+1; i<sig->size; i++)
362 {
363 if(symbol_distrib[i]&&SigIsPredicate(sig,i))
364 {
365 fprintf(out, ",(%s,%d)",
366 SigFindName(sig, i),
367 SigFindArity(sig, i));
368 }
369 }
370 fprintf(out,"].\nend_of_list.\n");
371 }
372
373
374 /*-----------------------------------------------------------------------
375 //
376 // Function: eqn_print_dfg()
377 //
378 // Print an equation in DFG syntax.
379 //
380 // Global Variables: -
381 //
382 // Side Effects : Output
383 //
384 /----------------------------------------------------------------------*/
385
eqn_print_dfg(FILE * out,Eqn_p eqn)386 static void eqn_print_dfg(FILE* out, Eqn_p eqn)
387 {
388 assert(OutputFormat == LOPFormat);
389 assert(!EqnUseInfix);
390
391 if(EqnIsNegative(eqn))
392 {
393 fputs("not(", out);
394 }
395 if(eqn->lterm==eqn->bank->true_term)
396 {
397 assert(eqn->rterm==eqn->bank->true_term);
398 /* Special case, one more hack */;
399 fputs("equal(spass_hack,spass_hack)", out);
400 }
401 else
402 {
403 EqnPrint(out,eqn,EqnIsNegative(eqn),true);
404 }
405 if(EqnIsNegative(eqn))
406 {
407 fputc(')', out);
408 }
409 }
410
411
412 /*-----------------------------------------------------------------------
413 //
414 // Function: clause_print_dfg()
415 //
416 // Print a clause in dfg format.
417 //
418 // Global Variables: -
419 //
420 // Side Effects : Output
421 //
422 /----------------------------------------------------------------------*/
423
clause_print_dfg(FILE * out,Clause_p clause)424 static void clause_print_dfg(FILE* out, Clause_p clause)
425 {
426 Eqn_p handle;
427 PTree_p variables = NULL, cell;
428 PStack_p stack;
429 Term_p var;
430 long var_no;
431
432 fprintf(out, "clause(");
433 var_no = ClauseCollectVariables(clause, &variables);
434 if(var_no)
435 {
436 fprintf(out, "forall([");
437 stack=PTreeTraverseInit(variables);
438 cell = PTreeTraverseNext(stack);
439 if(cell)
440 {
441 assert(clause->literals);
442 var = cell->key;
443 TBPrintTerm(out, clause->literals->bank, var, true);
444 while((cell=PTreeTraverseNext(stack)))
445 {
446 fputc(',', out);
447 var = cell->key;
448 TBPrintTerm(out, clause->literals->bank, var, true);
449 }
450 }
451 PTreeTraverseExit(stack);
452 PTreeFree(variables);
453 fprintf(out, "],");
454 }
455 fprintf(out, "or(");
456
457 handle=clause->literals;
458 if(handle)
459 {
460 eqn_print_dfg(out, handle);
461 handle=handle->next;
462 while(handle)
463 {
464 fputs(",", out);
465 eqn_print_dfg(out, handle);
466 handle=handle->next;
467 }
468 }
469 else
470 {
471 fputs("not(equal(spass_hack,spass_hack))",out);
472 }
473 fprintf(out, ")%c, c%ld ).", (var_no?')':' '), clause->ident);
474 }
475
476
477 /*-----------------------------------------------------------------------
478 //
479 // Function: clause_set_print_dfg()
480 //
481 // Print a set of clauses in DFG format.
482 //
483 // Global Variables: -
484 //
485 // Side Effects : Output
486 //
487 /----------------------------------------------------------------------*/
488
clause_set_print_dfg(FILE * out,ClauseSet_p set)489 static void clause_set_print_dfg(FILE* out, ClauseSet_p set)
490 {
491 Clause_p handle;
492
493 for(handle = set->anchor->succ; handle!=set->anchor; handle =
494 handle->succ)
495 {
496 clause_print_dfg(out, handle);
497 fputc('\n', out);
498 }
499 }
500
501
502 /*-----------------------------------------------------------------------
503 //
504 // Function: pcl_verify_spass()
505 //
506 // Run SPASS on the problem, return true if a proof is found.
507 //
508 // Global Variables: -
509 //
510 // Side Effects : Memory operations, by subroutines.
511 //
512 /----------------------------------------------------------------------*/
513
pcl_verify_spass(ClauseSet_p problem,char * executable,long time_limit,Sig_p sig)514 static bool pcl_verify_spass(ClauseSet_p problem,char *executable,
515 long time_limit, Sig_p sig)
516 {
517 bool res;
518 DStr_p command = DStrAlloc();
519 char* name=TempFileName();
520 FILE* problemfile;
521
522 if(!executable)
523 {
524 executable=SPASS_EXEC_DEFAULT;
525 }
526 problemfile = OutOpen(name);
527 fprintf(problemfile,
528 "begin_problem(Unknown).\n");
529
530 sig_print_dfg(problemfile, problem, sig);
531
532 fprintf(problemfile, "list_of_clauses(axioms,cnf).\n");
533 clause_set_print_dfg(problemfile, problem);
534 fprintf(problemfile, "end_of_list.\n"
535 "list_of_settings(SPASS).\n"
536 "set_flag(TimeLimit, %ld).\n"
537 "end_of_list.\n"
538 "end_problem.\n", time_limit);
539 OutClose(problemfile);
540
541 DStrAppendStr(command, executable);
542 DStrAppendStr(command, " ");
543 DStrAppendStr(command, name);
544
545 res = pcl_run_prover(DStrView(command), "Proof found.");
546 if(!res)
547 {
548 fprintf(GlobalOut, "# ------------Problem begin--------------\n");
549 FilePrint(GlobalOut, name);
550 fprintf(GlobalOut, "# ------------Problem end----------------\n");
551 }
552
553 TempFileRemove(name);
554 FREE(name);
555 DStrFree(command);
556 return res;
557 }
558
559
560 /*---------------------------------------------------------------------*/
561 /* Exported Functions */
562 /*---------------------------------------------------------------------*/
563
564 /*-----------------------------------------------------------------------
565 //
566 // Function: PCLCollectPreconds()
567 //
568 // Collect copies of all clauses quoted in the justification of step
569 // in set. Return number of clauses.
570 //
571 // Global Variables: -
572 //
573 // Side Effects : Memory operations, changes set.
574 //
575 /----------------------------------------------------------------------*/
576
PCLCollectPreconds(PCLProt_p prot,PCLStep_p step,ClauseSet_p set)577 long PCLCollectPreconds(PCLProt_p prot, PCLStep_p step, ClauseSet_p
578 set)
579 {
580 PTree_p tree = NULL;
581 PCLStep_p handle;
582 Clause_p clause;
583 long res = 0;
584
585 assert(prot && step && set);
586
587 PCLExprCollectPreconds(prot, step->just, &tree);
588 while(tree)
589 {
590 handle = PTreeExtractRootKey(&tree);
591 if(PCLStepIsClausal(handle))
592 {
593 clause = ClauseCopy(handle->logic.clause, prot->terms);
594 ClauseSetInsert(set, clause);
595 res++;
596 }
597 else
598 {
599 Warning("Cannot currently handle full first-order format!");
600 }
601 }
602 return res;
603 }
604
605
606 /*-----------------------------------------------------------------------
607 //
608 // Function: PCLNegSkolemizeClause()
609 //
610 // Add the clauses resulting from negating and skolemizing
611 // step->clause to set. The implementation is not very efficient,
612 // but that should not matter for our application.
613 //
614 // Global Variables: -
615 //
616 // Side Effects : Memory operations.
617 //
618 /----------------------------------------------------------------------*/
619
PCLNegSkolemizeClause(PCLProt_p prot,PCLStep_p step,ClauseSet_p set)620 long PCLNegSkolemizeClause(PCLProt_p prot, PCLStep_p step, ClauseSet_p
621 set)
622 {
623 long res = 0;
624 Clause_p clause, new_clause;
625 Eqn_p handle, copy;
626
627 if(PCLStepIsClausal(step))
628 {
629 clause = ClauseSkolemize(step->logic.clause, prot->terms);
630
631 for(handle=clause->literals; handle; handle=handle->next)
632 {
633 copy = EqnCopy(handle,prot->terms);
634 EqnFlipProp(copy, EPIsPositive);
635 new_clause=ClauseAlloc(copy);
636 ClauseSetTPTPType(new_clause, CPTypeHypothesis);
637 ClauseSetInsert(set, new_clause);
638 res++;
639 }
640 ClauseFree(clause);
641 }
642 else
643 {
644 Warning("Cannot currently handle full first-order format!");
645 }
646 return res;
647 }
648
649
650 /*-----------------------------------------------------------------------
651 //
652 // Function: PCLGenerateCheck()
653 //
654 // Generate a clause set that is unsatisfiable if the clause in step
655 // is a logical conclusion of the precondition. For initial steps,
656 // return NULL.
657 //
658 // Global Variables: -
659 //
660 // Side Effects : Memory operations.
661 //
662 /----------------------------------------------------------------------*/
663
PCLGenerateCheck(PCLProt_p prot,PCLStep_p step)664 ClauseSet_p PCLGenerateCheck(PCLProt_p prot, PCLStep_p step)
665 {
666 ClauseSet_p set = ClauseSetAlloc();
667
668 if(PCLCollectPreconds(prot, step, set))
669 {
670 PCLNegSkolemizeClause(prot, step, set);
671 }
672 else
673 {
674 ClauseSetFree(set);
675 set = NULL;
676 }
677 return set;
678 }
679
680
681 /*-----------------------------------------------------------------------
682 //
683 // Function: PCLStepCheck()
684 //
685 // Check the validity of a single PCL step. Return true if it checks
686 // ok, false otherwise. At the moment, just print the generated
687 // problem.
688 //
689 // Global Variables: -
690 //
691 // Side Effects : By called functions, may print output.
692 //
693 /----------------------------------------------------------------------*/
694
PCLStepCheck(PCLProt_p prot,PCLStep_p step,ProverType prover,char * executable,long time_limit)695 PCLCheckType PCLStepCheck(PCLProt_p prot, PCLStep_p step, ProverType
696 prover, char* executable, long time_limit)
697 {
698 ClauseSet_p problem;
699 PCLCheckType res=CheckFail;
700
701 if(step->just->op==PCLOpSplitClause)
702 {
703 return CheckNotImplemented;
704 }
705 problem = PCLGenerateCheck(prot, step);
706 if(!problem)
707 {
708 return CheckByAssumption;
709 }
710 else
711 {
712 switch(prover)
713 {
714 case EProver:
715 if(pcl_verify_eprover(problem,executable,time_limit))
716 {
717 res = CheckOk;
718 }
719 break;
720 case Otter:
721 if(pcl_verify_otter(problem,executable,time_limit))
722 {
723 res = CheckOk;
724 }
725 break;
726 case Spass:
727 if(pcl_verify_spass(problem,executable,time_limit,prot->terms->sig))
728 {
729 res = CheckOk;
730 }
731 break;
732 default:
733 assert(false && "Not yet implemented");
734 break;
735 }
736 ClauseSetFree(problem);
737 }
738 return res;
739 }
740
741
742 /*-----------------------------------------------------------------------
743 //
744 // Function: PCLProtCheck()
745 //
746 // Check all steps in a PCL listing. Return number of successful
747 // steps.
748 //
749 // Global Variables: -
750 //
751 // Side Effects : -
752 //
753 /----------------------------------------------------------------------*/
754
PCLProtCheck(PCLProt_p prot,ProverType prover,char * executable,long time_limit,long * unchecked)755 long PCLProtCheck(PCLProt_p prot, ProverType prover, char* executable,
756 long time_limit, long *unchecked)
757 {
758 PStack_p trav_stack,stack = PStackAlloc();
759 PStackPointer i;
760 PTree_p cell;
761 PCLStep_p step;
762 long res=0;
763 PCLCheckType check;
764
765 *unchecked = 0;
766 trav_stack = PTreeTraverseInit(prot->steps);
767 while((cell=PTreeTraverseNext(trav_stack)))
768 {
769 step=cell->key;
770 PStackPushP(stack, step);
771 }
772 PTreeTraverseExit(trav_stack);
773
774 for(i=0; i<PStackGetSP(stack); i++)
775 {
776 step = PStackElementP(stack,i);
777 if(OutputLevel)
778 {
779 fprintf(GlobalOut, "# Checking ");
780 PCLStepPrint(GlobalOut, step);
781 fputc('\n', GlobalOut);
782 }
783 check = PCLStepCheck(prot, step, prover, executable,
784 time_limit);
785 switch(check)
786 {
787 case CheckByAssumption:
788 OUTPRINT(1,"# Checked (by assumption)\n\n");
789 res++;
790 break;
791 case CheckOk:
792 OUTPRINT(1,"# Checked (by prover)\n\n");
793 res++;
794 break;
795 case CheckFail:
796 OUTPRINT(1,"# FAILED\n\n");
797 break;
798 case CheckNotImplemented:
799 OUTPRINT(1,"# Check not implemented, assuming true!\n\n");
800 (*unchecked)++;
801 break;
802 default:
803 assert(false);
804 break;
805 }
806 }
807 PStackFree(stack);
808 return res;
809 }
810
811
812 /*---------------------------------------------------------------------*/
813 /* End of File */
814 /*---------------------------------------------------------------------*/
815
816
817
818
819
820