src/HOL/Tools/res_reconstruct.ML
changeset 22012 adf68479ae1b
parent 21999 0cf192e489e2
child 22044 6c0702a96076
equal deleted inserted replaced
22011:3d4ea1819cb7 22012:adf68479ae1b
     8 (***************************************************************************)
     8 (***************************************************************************)
     9 signature RES_RECONSTRUCT =
     9 signature RES_RECONSTRUCT =
    10   sig
    10   sig
    11     val checkEProofFound: 
    11     val checkEProofFound: 
    12           TextIO.instream * TextIO.outstream * Posix.Process.pid * 
    12           TextIO.instream * TextIO.outstream * Posix.Process.pid * 
    13           string * thm * int * string Vector.vector -> bool
    13           string * Proof.context * thm * int * string Vector.vector -> bool
    14     val checkVampProofFound: 
    14     val checkVampProofFound: 
    15           TextIO.instream * TextIO.outstream * Posix.Process.pid * 
    15           TextIO.instream * TextIO.outstream * Posix.Process.pid * 
    16           string * thm * int * string Vector.vector -> bool
    16           string * Proof.context * thm * int * string Vector.vector -> bool
    17     val checkSpassProofFound:  
    17     val checkSpassProofFound:  
    18           TextIO.instream * TextIO.outstream * Posix.Process.pid * 
    18           TextIO.instream * TextIO.outstream * Posix.Process.pid * 
    19           string * thm * int * string Vector.vector -> bool
    19           string * Proof.context * thm * int * string Vector.vector -> bool
    20     val signal_parent:  
    20     val signal_parent:  
    21           TextIO.outstream * Posix.Process.pid * string * string -> unit
    21           TextIO.outstream * Posix.Process.pid * string * string -> unit
    22     val nospaces: string -> string
       
    23 
    22 
    24   end;
    23   end;
    25 
    24 
    26 structure ResReconstruct =
    25 structure ResReconstruct =
    27 struct
    26 struct
   243 
   242 
   244 (*False literals (which E includes in its proofs) are deleted*)
   243 (*False literals (which E includes in its proofs) are deleted*)
   245 val nofalses = filter (not o equal HOLogic.false_const);
   244 val nofalses = filter (not o equal HOLogic.false_const);
   246 
   245 
   247 (*Accumulate sort constraints in vt, with "real" literals in lits.*)
   246 (*Accumulate sort constraints in vt, with "real" literals in lits.*)
   248 fun lits_of_strees thy (vt, lits) [] = (vt, rev (nofalses lits))
   247 fun lits_of_strees ctxt (vt, lits) [] = (vt, rev (nofalses lits))
   249   | lits_of_strees thy (vt, lits) (t::ts) = 
   248   | lits_of_strees ctxt (vt, lits) (t::ts) = 
   250       lits_of_strees thy (add_constraint (constraint_of_stree true t, vt), lits) ts
   249       lits_of_strees ctxt (add_constraint (constraint_of_stree true t, vt), lits) ts
   251       handle STREE _ => 
   250       handle STREE _ => 
   252       lits_of_strees thy (vt, term_of_stree thy t :: lits) ts;
   251       lits_of_strees ctxt (vt, term_of_stree (ProofContext.theory_of ctxt) t :: lits) ts;
   253 
   252 
   254 (*Update TVars/TFrees with detected sort constraints.*)
   253 (*Update TVars/TFrees with detected sort constraints.*)
   255 fun fix_sorts vt =
   254 fun fix_sorts vt =
   256   let fun tysubst (Type (a, Ts)) = Type (a, map tysubst Ts)
   255   let fun tysubst (Type (a, Ts)) = Type (a, map tysubst Ts)
   257         | tysubst (TVar (xi, s)) = TVar (xi, getOpt (Vartab.lookup vt xi, s))
   256         | tysubst (TVar (xi, s)) = TVar (xi, getOpt (Vartab.lookup vt xi, s))
   264         | tmsubst (t $ u) = tmsubst t $ tmsubst u;
   263         | tmsubst (t $ u) = tmsubst t $ tmsubst u;
   265   in fn t => if Vartab.is_empty vt then t else tmsubst t end;
   264   in fn t => if Vartab.is_empty vt then t else tmsubst t end;
   266 
   265 
   267 (*Interpret a list of syntax trees as a clause, given by "real" literals and sort constraints.
   266 (*Interpret a list of syntax trees as a clause, given by "real" literals and sort constraints.
   268   vt0 holds the initial sort constraints, from the conjecture clauses.*)
   267   vt0 holds the initial sort constraints, from the conjecture clauses.*)
   269 fun clause_of_strees_aux thy vt0 ts = 
   268 fun clause_of_strees_aux ctxt vt0 ts = 
   270   case lits_of_strees thy (vt0,[]) ts of
   269   case lits_of_strees ctxt (vt0,[]) ts of
   271       (_, []) => HOLogic.false_const
   270       (_, []) => HOLogic.false_const
   272     | (vt, lits) => 
   271     | (vt, lits) => 
   273         let val dt = fix_sorts vt (foldr1 HOLogic.mk_disj lits)
   272         let val dt = fix_sorts vt (foldr1 HOLogic.mk_disj lits)
   274             val infer = Sign.infer_types (Sign.pp thy) thy (Sign.consts_of thy)
   273             val infer = Sign.infer_types (ProofContext.pp ctxt) (ProofContext.theory_of ctxt)
       
   274                             (ProofContext.consts_of ctxt) (Variable.def_type ctxt false)
       
   275                             (Variable.def_sort ctxt) (Variable.names_of ctxt) true
   275         in 
   276         in 
   276            #1(infer (K NONE) (K NONE) (Name.make_context []) true ([dt], HOLogic.boolT))
   277            #1(infer ([dt], HOLogic.boolT))
   277         end; 
   278         end; 
   278 
   279 
   279 (*Quantification over a list of Vars. FUXNE: for term.ML??*)
   280 (*Quantification over a list of Vars. FUXNE: for term.ML??*)
   280 fun list_all_var ([], t: term) = t
   281 fun list_all_var ([], t: term) = t
   281   | list_all_var ((v as Var(ix,T)) :: vars, t) =
   282   | list_all_var ((v as Var(ix,T)) :: vars, t) =
   289 fun ints_of_stree_aux (Int n, ns) = n::ns
   290 fun ints_of_stree_aux (Int n, ns) = n::ns
   290   | ints_of_stree_aux (Br(_,ts), ns) = foldl ints_of_stree_aux ns ts;
   291   | ints_of_stree_aux (Br(_,ts), ns) = foldl ints_of_stree_aux ns ts;
   291 
   292 
   292 fun ints_of_stree t = ints_of_stree_aux (t, []);
   293 fun ints_of_stree t = ints_of_stree_aux (t, []);
   293 
   294 
   294 fun decode_tstp thy vt0 (name, role, ts, annots) =
   295 fun decode_tstp ctxt vt0 (name, role, ts, annots) =
   295   let val deps = case annots of NONE => [] | SOME (source,_) => ints_of_stree source
   296   let val deps = case annots of NONE => [] | SOME (source,_) => ints_of_stree source
   296   in  (name, role, clause_of_strees thy vt0 ts, deps)  end;
   297   in  (name, role, clause_of_strees ctxt vt0 ts, deps)  end;
   297 
   298 
   298 fun dest_tstp ((((name, role), ts), annots), chs) =
   299 fun dest_tstp ((((name, role), ts), annots), chs) =
   299   case chs of
   300   case chs of
   300           "."::_ => (name, role, ts, annots)
   301           "."::_ => (name, role, ts, annots)
   301         | _ => error ("TSTP line not terminated by \".\": " ^ implode chs);
   302         | _ => error ("TSTP line not terminated by \".\": " ^ implode chs);
   314   | tfree_constraints_of_clauses vt (_::tss) = tfree_constraints_of_clauses vt tss;
   315   | tfree_constraints_of_clauses vt (_::tss) = tfree_constraints_of_clauses vt tss;
   315 
   316 
   316 
   317 
   317 (**** Translation of TSTP files to Isar Proofs ****)
   318 (**** Translation of TSTP files to Isar Proofs ****)
   318 
   319 
   319 fun decode_tstp_list thy tuples =
   320 fun decode_tstp_list ctxt tuples =
   320   let val vt0 = tfree_constraints_of_clauses Vartab.empty (map #3 tuples)
   321   let val vt0 = tfree_constraints_of_clauses Vartab.empty (map #3 tuples)
   321   in  map (decode_tstp thy vt0) tuples  end;
   322   in  map (decode_tstp ctxt vt0) tuples  end;
   322 
   323 
   323 (*FIXME: simmilar function in res_atp. Move to HOLogic?*)
   324 (*FIXME: simmilar function in res_atp. Move to HOLogic?*)
   324 fun dest_disj_aux (Const ("op |", _) $ t $ t') disjs = dest_disj_aux t (dest_disj_aux t' disjs)
   325 fun dest_disj_aux (Const ("op |", _) $ t $ t') disjs = dest_disj_aux t (dest_disj_aux t' disjs)
   325   | dest_disj_aux t disjs = t::disjs;
   326   | dest_disj_aux t disjs = t::disjs;
   326 
   327 
   327 fun dest_disj t = dest_disj_aux t [];
   328 fun dest_disj t = dest_disj_aux t [];
   328 
   329 
   329 val sort_lits = sort Term.fast_term_ord o dest_disj o HOLogic.dest_Trueprop o strip_all_body;
   330 (*Remove types from a term, to eliminate the randomness of type inference*)
       
   331 fun smash_types (Const(a,_)) = Const(a,dummyT)
       
   332   | smash_types (Free(a,_)) = Free(a,dummyT)
       
   333   | smash_types (Var(a,_)) = Var(a,dummyT)
       
   334   | smash_types (f$t) = smash_types f $ smash_types t
       
   335   | smash_types t = t;
       
   336 
       
   337 val sort_lits = sort Term.fast_term_ord o dest_disj o 
       
   338                 smash_types o HOLogic.dest_Trueprop o strip_all_body;
   330 
   339 
   331 fun permuted_clause t =
   340 fun permuted_clause t =
   332   let val lits = sort_lits t
   341   let val lits = sort_lits t
   333       fun perm [] = NONE
   342       fun perm [] = NONE
   334         | perm (ctm::ctms) = 
   343         | perm (ctm::ctms) = 
   398 val proofstart = "\nproof (neg_clausify)\n";
   407 val proofstart = "\nproof (neg_clausify)\n";
   399 
   408 
   400 fun isar_header [] = proofstart
   409 fun isar_header [] = proofstart
   401   | isar_header ts = proofstart ^ "fix " ^ space_implode " " ts ^ "\n";
   410   | isar_header ts = proofstart ^ "fix " ^ space_implode " " ts ^ "\n";
   402 
   411 
   403 fun decode_tstp_file cnfs th sgno thm_names =
   412 fun decode_tstp_file cnfs ctxt th sgno thm_names =
   404   let val tuples = map (dest_tstp o tstp_line o explode) cnfs
   413   let val tuples = map (dest_tstp o tstp_line o explode) cnfs
   405       and ctxt = ProofContext.init (Thm.theory_of_thm th)
   414       val lines = foldr add_prfline [] (decode_tstp_list ctxt tuples)
   406        (*The full context could be sent from ResAtp.isar_atp_body to Watcher.createWatcher,
       
   407          then to setupWatcher and checkChildren...but is it really needed?*)
       
   408       val decoded_tuples = decode_tstp_list (ProofContext.theory_of ctxt) tuples
       
   409       val (ccls,fixes) = ResAxioms.neg_conjecture_clauses th sgno
   415       val (ccls,fixes) = ResAxioms.neg_conjecture_clauses th sgno
   410       val ccls = map forall_intr_vars ccls
   416       val ccls = map forall_intr_vars ccls
   411       val lines = foldr add_prfline [] decoded_tuples
       
   412       and clines = map (fn th => string_of_thm th ^ "\n") ccls
       
   413   in  
   417   in  
       
   418       if !Output.show_debug_msgs
       
   419       then app (Output.debug o string_of_thm) ccls
       
   420       else ();
   414       isar_header (map #1 fixes) ^ 
   421       isar_header (map #1 fixes) ^ 
   415       String.concat (clines @ isar_lines ctxt (map prop_of ccls) (stringify_deps thm_names [] lines))
   422       String.concat (isar_lines ctxt (map prop_of ccls) (stringify_deps thm_names [] lines))
   416   end;
   423   end;
   417 
   424 
   418 (*Could use split_lines, but it can return blank lines...*)
   425 (*Could use split_lines, but it can return blank lines...*)
   419 val lines = String.tokens (equal #"\n");
   426 val lines = String.tokens (equal #"\n");
   420 
   427 
   429    TextIO.output (toParent, "Success. " ^ encode_newlines msg ^ "\n");
   436    TextIO.output (toParent, "Success. " ^ encode_newlines msg ^ "\n");
   430    TextIO.output (toParent, probfile ^ "\n");
   437    TextIO.output (toParent, probfile ^ "\n");
   431    TextIO.flushOut toParent;
   438    TextIO.flushOut toParent;
   432    Posix.Process.kill(Posix.Process.K_PROC ppid, Posix.Signal.usr2));
   439    Posix.Process.kill(Posix.Process.K_PROC ppid, Posix.Signal.usr2));
   433 
   440 
   434 fun tstp_extract proofextract probfile toParent ppid th sgno thm_names = 
   441 fun tstp_extract proofextract probfile toParent ppid ctxt th sgno thm_names = 
   435   let val cnfs = filter (String.isPrefix "cnf(") (map nospaces (lines proofextract))
   442   let val cnfs = filter (String.isPrefix "cnf(") (map nospaces (lines proofextract))
   436   in  
   443   in  
   437     signal_success probfile toParent ppid 
   444     signal_success probfile toParent ppid 
   438       (decode_tstp_file cnfs th sgno thm_names)
   445       (decode_tstp_file cnfs ctxt th sgno thm_names)
   439   end;
   446   end;
   440 
   447 
   441 
   448 
   442 (**** retrieve the axioms that were used in the proof ****)
   449 (**** retrieve the axioms that were used in the proof ****)
   443 
   450 
   543 (*  and if so, transfer output to the input pipe of the main Isabelle process    *)
   550 (*  and if so, transfer output to the input pipe of the main Isabelle process    *)
   544 (*********************************************************************************)
   551 (*********************************************************************************)
   545 
   552 
   546 (*Returns "true" if it successfully returns a lemma list, otherwise "false", but this
   553 (*Returns "true" if it successfully returns a lemma list, otherwise "false", but this
   547   return value is currently never used!*)
   554   return value is currently never used!*)
   548 fun startTransfer (endS, fromChild, toParent, ppid, probfile, th, sgno, thm_names) =
   555 fun startTransfer endS (fromChild, toParent, ppid, probfile, ctxt, th, sgno, thm_names) =
   549  let fun transferInput currentString =
   556  let fun transferInput currentString =
   550       let val thisLine = TextIO.inputLine fromChild
   557       let val thisLine = TextIO.inputLine fromChild
   551       in
   558       in
   552 	if thisLine = "" (*end of file?*)
   559 	if thisLine = "" (*end of file?*)
   553 	then (trace ("\n extraction_failed.  End bracket: " ^ endS ^
   560 	then (trace ("\n extraction_failed.  End bracket: " ^ endS ^
   559 			  	  else if endS = end_SPASS then spass_lemma_list
   566 			  	  else if endS = end_SPASS then spass_lemma_list
   560 			  	  else e_lemma_list
   567 			  	  else e_lemma_list
   561 	     in
   568 	     in
   562 	       trace ("\nExtracted proof:\n" ^ proofextract); 
   569 	       trace ("\nExtracted proof:\n" ^ proofextract); 
   563 	       if !full andalso String.isPrefix "cnf(" proofextract
   570 	       if !full andalso String.isPrefix "cnf(" proofextract
   564 	       then tstp_extract proofextract probfile toParent ppid th sgno thm_names
   571 	       then tstp_extract proofextract probfile toParent ppid ctxt th sgno thm_names
   565 	       else lemma_list proofextract probfile toParent ppid thm_names;
   572 	       else lemma_list proofextract probfile toParent ppid thm_names;
   566 	       true
   573 	       true
   567 	     end
   574 	     end
   568 	else transferInput (currentString^thisLine)
   575 	else transferInput (currentString^thisLine)
   569       end
   576       end
   580   trace ("\nSignalled parent: " ^ msg ^ probfile);
   587   trace ("\nSignalled parent: " ^ msg ^ probfile);
   581   Posix.Process.kill(Posix.Process.K_PROC ppid, Posix.Signal.usr2);
   588   Posix.Process.kill(Posix.Process.K_PROC ppid, Posix.Signal.usr2);
   582   (*Give the parent time to respond before possibly sending another signal*)
   589   (*Give the parent time to respond before possibly sending another signal*)
   583   OS.Process.sleep (Time.fromMilliseconds 600));
   590   OS.Process.sleep (Time.fromMilliseconds 600));
   584 
   591 
       
   592 (*FIXME: once TSTP output is produced by all ATPs, these three functions can be combined.*)
       
   593 
   585 (*Called from watcher. Returns true if the Vampire process has returned a verdict.*)
   594 (*Called from watcher. Returns true if the Vampire process has returned a verdict.*)
   586 fun checkVampProofFound (fromChild, toParent, ppid, probfile, th, sgno, thm_names) =
   595 fun checkVampProofFound (arg as (fromChild, toParent, ppid, probfile, ctxt, th, sgno, thm_names)) =
   587  let val thisLine = TextIO.inputLine fromChild
   596  let val thisLine = TextIO.inputLine fromChild
   588  in   
   597  in   
   589      trace thisLine;
   598      trace thisLine;
   590      if thisLine = "" 
   599      if thisLine = "" 
   591      then (trace "\nNo proof output seen"; false)
   600      then (trace "\nNo proof output seen"; false)
   592      else if String.isPrefix start_V8 thisLine
   601      else if String.isPrefix start_V8 thisLine
   593      then startTransfer (end_V8, fromChild, toParent, ppid, probfile, th, sgno, thm_names)
   602      then startTransfer end_V8 arg
   594      else if (String.isPrefix "Satisfiability detected" thisLine) orelse
   603      else if (String.isPrefix "Satisfiability detected" thisLine) orelse
   595              (String.isPrefix "Refutation not found" thisLine)
   604              (String.isPrefix "Refutation not found" thisLine)
   596      then (signal_parent (toParent, ppid, "Failure\n", probfile);
   605      then (signal_parent (toParent, ppid, "Failure\n", probfile);
   597 	   true)
   606 	   true)
   598      else checkVampProofFound  (fromChild, toParent, ppid, probfile, th, sgno, thm_names)
   607      else checkVampProofFound arg
   599   end
   608   end
   600 
   609 
   601 (*Called from watcher. Returns true if the E process has returned a verdict.*)
   610 (*Called from watcher. Returns true if the E process has returned a verdict.*)
   602 fun checkEProofFound (fromChild, toParent, ppid, probfile, th, sgno, thm_names) = 
   611 fun checkEProofFound (arg as (fromChild, toParent, ppid, probfile, ctxt, th, sgno, thm_names)) = 
   603  let val thisLine = TextIO.inputLine fromChild  
   612  let val thisLine = TextIO.inputLine fromChild  
   604  in   
   613  in   
   605      trace thisLine;
   614      trace thisLine;
   606      if thisLine = "" then (trace "\nNo proof output seen"; false)
   615      if thisLine = "" then (trace "\nNo proof output seen"; false)
   607      else if String.isPrefix start_E thisLine
   616      else if String.isPrefix start_E thisLine
   608      then startTransfer (end_E, fromChild, toParent, ppid, probfile, th, sgno, thm_names)
   617      then startTransfer end_E arg
   609      else if String.isPrefix "# Problem is satisfiable" thisLine
   618      else if String.isPrefix "# Problem is satisfiable" thisLine
   610      then (signal_parent (toParent, ppid, "Invalid\n", probfile);
   619      then (signal_parent (toParent, ppid, "Invalid\n", probfile);
   611 	   true)
   620 	   true)
   612      else if String.isPrefix "# Cannot determine problem status within resource limit" thisLine
   621      else if String.isPrefix "# Cannot determine problem status within resource limit" thisLine
   613      then (signal_parent (toParent, ppid, "Failure\n", probfile);
   622      then (signal_parent (toParent, ppid, "Failure\n", probfile);
   614 	   true)
   623 	   true)
   615      else checkEProofFound (fromChild, toParent, ppid, probfile, th, sgno, thm_names)
   624      else checkEProofFound arg
   616  end;
   625  end;
   617 
   626 
   618 (*Called from watcher. Returns true if the SPASS process has returned a verdict.*)
   627 (*Called from watcher. Returns true if the SPASS process has returned a verdict.*)
   619 fun checkSpassProofFound (fromChild, toParent, ppid, probfile, th, sgno, thm_names) = 
   628 fun checkSpassProofFound (arg as (fromChild, toParent, ppid, probfile, ctxt, th, sgno, thm_names)) = 
   620  let val thisLine = TextIO.inputLine fromChild  
   629  let val thisLine = TextIO.inputLine fromChild  
   621  in    
   630  in    
   622      trace thisLine;
   631      trace thisLine;
   623      if thisLine = "" then (trace "\nNo proof output seen"; false)
   632      if thisLine = "" then (trace "\nNo proof output seen"; false)
   624      else if String.isPrefix "Here is a proof" thisLine
   633      else if String.isPrefix "Here is a proof" thisLine
   625      then      
   634      then startTransfer end_SPASS arg
   626         startTransfer (end_SPASS, fromChild, toParent, ppid, probfile, th, sgno, thm_names)
       
   627      else if thisLine = "SPASS beiseite: Completion found.\n"
   635      else if thisLine = "SPASS beiseite: Completion found.\n"
   628      then (signal_parent (toParent, ppid, "Invalid\n", probfile);
   636      then (signal_parent (toParent, ppid, "Invalid\n", probfile);
   629 	   true)
   637 	   true)
   630      else if thisLine = "SPASS beiseite: Ran out of time.\n" orelse
   638      else if thisLine = "SPASS beiseite: Ran out of time.\n" orelse
   631              thisLine = "SPASS beiseite: Maximal number of loops exceeded.\n"
   639              thisLine = "SPASS beiseite: Maximal number of loops exceeded.\n"
   632      then (signal_parent (toParent, ppid, "Failure\n", probfile);
   640      then (signal_parent (toParent, ppid, "Failure\n", probfile);
   633 	   true)
   641 	   true)
   634     else checkSpassProofFound (fromChild, toParent, ppid, probfile, th, sgno, thm_names)
   642     else checkSpassProofFound arg
   635  end
   643  end
   636 
   644 
   637 end;
   645 end;