src/HOL/Tools/res_atp.ML
changeset 22130 0906fd95e0b5
parent 22012 adf68479ae1b
child 22193 62753ae847a2
equal deleted inserted replaced
22129:bb2203c93316 22130:0906fd95e0b5
    54 end;
    54 end;
    55 
    55 
    56 structure ResAtp =
    56 structure ResAtp =
    57 struct
    57 struct
    58 
    58 
    59 fun timestamp s = Output.debug ("At " ^ Time.toString (Time.now()) ^ ": " ^ s);
    59 fun timestamp s = Output.debug (fn () => ("At " ^ Time.toString (Time.now()) ^ ": " ^ s));
    60 
    60 
    61 (********************************************************************)
    61 (********************************************************************)
    62 (* some settings for both background automatic ATP calling procedure*)
    62 (* some settings for both background automatic ATP calling procedure*)
    63 (* and also explicit ATP invocation methods                         *)
    63 (* and also explicit ATP invocation methods                         *)
    64 (********************************************************************)
    64 (********************************************************************)
   235       let val (f,args) = strip_comb tm
   235       let val (f,args) = strip_comb tm
   236           val (lg',seen') = if f mem seen then (FOL,seen)
   236           val (lg',seen') = if f mem seen then (FOL,seen)
   237                             else fn_lg f (FOL,seen)
   237                             else fn_lg f (FOL,seen)
   238       in
   238       in
   239         if is_fol_logic lg' then ()
   239         if is_fol_logic lg' then ()
   240         else Output.debug ("Found a HOL term: " ^ Display.raw_string_of_term f);
   240         else Output.debug (fn () => ("Found a HOL term: " ^ Display.raw_string_of_term f));
   241         term_lg (args@tms) (lg',seen')
   241         term_lg (args@tms) (lg',seen')
   242       end
   242       end
   243   | term_lg _ (lg,seen) = (lg,seen)
   243   | term_lg _ (lg,seen) = (lg,seen)
   244 
   244 
   245 exception PRED_LG of term;
   245 exception PRED_LG of term;
   259       let val (pred,args) = strip_comb P
   259       let val (pred,args) = strip_comb P
   260           val (lg',seen') = if pred mem seen then (lg,seen)
   260           val (lg',seen') = if pred mem seen then (lg,seen)
   261                             else pred_lg pred (lg,seen)
   261                             else pred_lg pred (lg,seen)
   262       in
   262       in
   263         if is_fol_logic lg' then ()
   263         if is_fol_logic lg' then ()
   264         else Output.debug ("Found a HOL predicate: " ^ Display.raw_string_of_term pred);
   264         else Output.debug (fn () => ("Found a HOL predicate: " ^ Display.raw_string_of_term pred));
   265         term_lg args (lg',seen')
   265         term_lg args (lg',seen')
   266       end;
   266       end;
   267 
   267 
   268 fun lits_lg [] (lg,seen) = (lg,seen)
   268 fun lits_lg [] (lg,seen) = (lg,seen)
   269   | lits_lg (lit::lits) (FOL,seen) =
   269   | lits_lg (lit::lits) (FOL,seen) =
   270       let val (lg,seen') = lit_lg lit (FOL,seen)
   270       let val (lg,seen') = lit_lg lit (FOL,seen)
   271       in
   271       in
   272         if is_fol_logic lg then ()
   272         if is_fol_logic lg then ()
   273         else Output.debug ("Found a HOL literal: " ^ Display.raw_string_of_term lit);
   273         else Output.debug (fn () => ("Found a HOL literal: " ^ Display.raw_string_of_term lit));
   274         lits_lg lits (lg,seen')
   274         lits_lg lits (lg,seen')
   275       end
   275       end
   276   | lits_lg lits (lg,seen) = (lg,seen);
   276   | lits_lg lits (lg,seen) = (lg,seen);
   277 
   277 
   278 fun dest_disj_aux (Const("Trueprop",_) $ t) disjs = dest_disj_aux t disjs
   278 fun dest_disj_aux (Const("Trueprop",_) $ t) disjs = dest_disj_aux t disjs
   286 fun logic_of_clauses [] (lg,seen) = (lg,seen)
   286 fun logic_of_clauses [] (lg,seen) = (lg,seen)
   287   | logic_of_clauses (cls::clss) (FOL,seen) =
   287   | logic_of_clauses (cls::clss) (FOL,seen) =
   288     let val (lg,seen') = logic_of_clause cls (FOL,seen)
   288     let val (lg,seen') = logic_of_clause cls (FOL,seen)
   289         val _ =
   289         val _ =
   290           if is_fol_logic lg then ()
   290           if is_fol_logic lg then ()
   291           else Output.debug ("Found a HOL clause: " ^ Display.raw_string_of_term cls)
   291           else Output.debug (fn () => ("Found a HOL clause: " ^ Display.raw_string_of_term cls))
   292     in
   292     in
   293         logic_of_clauses clss (lg,seen')
   293         logic_of_clauses clss (lg,seen')
   294     end
   294     end
   295   | logic_of_clauses (cls::clss) (lg,seen) = (lg,seen);
   295   | logic_of_clauses (cls::clss) (lg,seen) = (lg,seen);
   296 
   296 
   504 (*Use a hash table to eliminate duplicates from xs. Argument is a list of
   504 (*Use a hash table to eliminate duplicates from xs. Argument is a list of
   505   (thm * (string * int)) tuples. The theorems are hashed into the table. *)
   505   (thm * (string * int)) tuples. The theorems are hashed into the table. *)
   506 fun make_unique xs =
   506 fun make_unique xs =
   507   let val ht = mk_clause_table 7000
   507   let val ht = mk_clause_table 7000
   508   in
   508   in
   509       Output.debug("make_unique gets " ^ Int.toString (length xs) ^ " clauses");
   509       Output.debug (fn () => ("make_unique gets " ^ Int.toString (length xs) ^ " clauses"));
   510       app (ignore o Polyhash.peekInsert ht) xs;
   510       app (ignore o Polyhash.peekInsert ht) xs;
   511       Polyhash.listItems ht
   511       Polyhash.listItems ht
   512   end;
   512   end;
   513 
   513 
   514 (*Remove existing axiom clauses from the conjecture clauses, as this can dramatically
   514 (*Remove existing axiom clauses from the conjecture clauses, as this can dramatically
   527   white_cls @ (ReduceAxiomsN.relevance_filter thy cls_thms goals);
   527   white_cls @ (ReduceAxiomsN.relevance_filter thy cls_thms goals);
   528 
   528 
   529 fun display_thms [] = ()
   529 fun display_thms [] = ()
   530   | display_thms ((name,thm)::nthms) =
   530   | display_thms ((name,thm)::nthms) =
   531       let val nthm = name ^ ": " ^ (string_of_thm thm)
   531       let val nthm = name ^ ": " ^ (string_of_thm thm)
   532       in Output.debug nthm; display_thms nthms  end;
   532       in Output.debug (fn () => nthm); display_thms nthms  end;
   533 
   533 
   534 fun all_valid_thms ctxt =
   534 fun all_valid_thms ctxt =
   535   PureThy.thms_containing (ProofContext.theory_of ctxt) ([], []) @
   535   PureThy.thms_containing (ProofContext.theory_of ctxt) ([], []) @
   536   filter (ProofContext.valid_thms ctxt)
   536   filter (ProofContext.valid_thms ctxt)
   537     (FactIndex.find (ProofContext.fact_index_of ctxt) ([], []));
   537     (FactIndex.find (ProofContext.fact_index_of ctxt) ([], []));
   569 (* get lemmas from claset, simpset, atpset and extra supplied rules *)
   569 (* get lemmas from claset, simpset, atpset and extra supplied rules *)
   570 fun get_clasimp_atp_lemmas ctxt user_thms =
   570 fun get_clasimp_atp_lemmas ctxt user_thms =
   571   let val included_thms =
   571   let val included_thms =
   572         if !include_all
   572         if !include_all
   573         then (tap (fn ths => Output.debug
   573         then (tap (fn ths => Output.debug
   574                      ("Including all " ^ Int.toString (length ths) ^ " theorems"))
   574                      (fn () => ("Including all " ^ Int.toString (length ths) ^ " theorems")))
   575                   (name_thm_pairs ctxt))
   575                   (name_thm_pairs ctxt))
   576         else
   576         else
   577         let val claset_thms =
   577         let val claset_thms =
   578                 if !include_claset then ResAxioms.claset_rules_of ctxt
   578                 if !include_claset then ResAxioms.claset_rules_of ctxt
   579                 else []
   579                 else []
   581                 if !include_simpset then ResAxioms.simpset_rules_of ctxt
   581                 if !include_simpset then ResAxioms.simpset_rules_of ctxt
   582                 else []
   582                 else []
   583             val atpset_thms =
   583             val atpset_thms =
   584                 if !include_atpset then ResAxioms.atpset_rules_of ctxt
   584                 if !include_atpset then ResAxioms.atpset_rules_of ctxt
   585                 else []
   585                 else []
   586             val _ = if !Output.show_debug_msgs
   586             val _ = if !Output.debugging
   587                     then (Output.debug "ATP theorems: "; display_thms atpset_thms)
   587                     then (Output.debug (fn () => "ATP theorems: "); display_thms atpset_thms)
   588                     else ()
   588                     else ()
   589         in  claset_thms @ simpset_thms @ atpset_thms  end
   589         in  claset_thms @ simpset_thms @ atpset_thms  end
   590       val user_rules = filter check_named
   590       val user_rules = filter check_named
   591                          (map (ResAxioms.pairname)
   591                          (map (ResAxioms.pairname)
   592                            (if null user_thms then !whitelist else user_thms))
   592                            (if null user_thms then !whitelist else user_thms))
   598 fun blacklist_filter ths =
   598 fun blacklist_filter ths =
   599   if !run_blacklist_filter then
   599   if !run_blacklist_filter then
   600       let val banned = make_banned_test (map #1 ths)
   600       let val banned = make_banned_test (map #1 ths)
   601           fun ok (a,_) = not (banned a)
   601           fun ok (a,_) = not (banned a)
   602           val (good,bad) = List.partition ok ths
   602           val (good,bad) = List.partition ok ths
   603       in  if !Output.show_debug_msgs then
   603       in
   604              (Output.debug("blacklist filter gets " ^ Int.toString (length ths) ^ " theorems");
   604         Output.debug (fn () => "blacklist filter gets " ^ Int.toString (length ths) ^ " theorems");
   605               Output.debug("filtered: " ^ space_implode ", " (map #1 bad));
   605         Output.debug (fn () => "filtered: " ^ space_implode ", " (map #1 bad));
   606               Output.debug("...and returns " ^ Int.toString (length good)))
   606         Output.debug (fn () => "...and returns " ^ Int.toString (length good));
   607           else ();
   607         good 
   608           good 
       
   609       end
   608       end
   610   else ths;
   609   else ths;
   611 
   610 
   612 (***************************************************************)
   611 (***************************************************************)
   613 (* Type Classes Present in the Axiom or Conjecture Clauses     *)
   612 (* Type Classes Present in the Axiom or Conjecture Clauses     *)
   749         val writer = if dfg then dfg_writer else tptp_writer
   748         val writer = if dfg then dfg_writer else tptp_writer
   750         and file = atp_input_file()
   749         and file = atp_input_file()
   751         and user_lemmas_names = map #1 user_rules
   750         and user_lemmas_names = map #1 user_rules
   752     in
   751     in
   753         writer logic goal_cls file (axclauses,classrel_clauses,arity_clauses) user_lemmas_names;
   752         writer logic goal_cls file (axclauses,classrel_clauses,arity_clauses) user_lemmas_names;
   754         Output.debug ("Writing to " ^ file);
   753         Output.debug (fn () => "Writing to " ^ file);
   755         file
   754         file
   756     end;
   755     end;
   757 
   756 
   758 
   757 
   759 (**** remove tmp files ****)
   758 (**** remove tmp files ****)
   760 fun cond_rm_tmp file =
   759 fun cond_rm_tmp file =
   761     if !Output.show_debug_msgs orelse !destdir <> "" then Output.debug "ATP input kept..."
   760     if !Output.debugging orelse !destdir <> ""
       
   761     then Output.debug (fn () => "ATP input kept...")
   762     else OS.FileSys.remove file;
   762     else OS.FileSys.remove file;
   763 
   763 
   764 
   764 
   765 (****** setup ATPs as Isabelle methods ******)
   765 (****** setup ATPs as Isabelle methods ******)
   766 
   766 
   783       | make_atp_list (sg_term::xs) n =
   783       | make_atp_list (sg_term::xs) n =
   784           let
   784           let
   785             val probfile = prob_pathname n
   785             val probfile = prob_pathname n
   786             val time = Int.toString (!time_limit)
   786             val time = Int.toString (!time_limit)
   787           in
   787           in
   788             Output.debug ("problem file in watcher_call_provers is " ^ probfile);
   788             Output.debug (fn () => "problem file in watcher_call_provers is " ^ probfile);
   789             (*options are separated by Watcher.setting_sep, currently #"%"*)
   789             (*options are separated by Watcher.setting_sep, currently #"%"*)
   790             if !prover = "spass"
   790             if !prover = "spass"
   791             then
   791             then
   792               let val spass = helper_path "SPASS_HOME" "SPASS"
   792               let val spass = helper_path "SPASS_HOME" "SPASS"
   793                   val sopts =
   793                   val sopts =
   814           end
   814           end
   815 
   815 
   816     val atp_list = make_atp_list sg_terms 1
   816     val atp_list = make_atp_list sg_terms 1
   817   in
   817   in
   818     Watcher.callResProvers(childout,atp_list);
   818     Watcher.callResProvers(childout,atp_list);
   819     Output.debug "Sent commands to watcher!"
   819     Output.debug (fn () => "Sent commands to watcher!")
   820   end
   820   end
   821 
   821 
   822 fun trace_vector fname =
   822 fun trace_vector fname =
   823   let val path = File.explode_platform_path fname
   823   let val path = File.explode_platform_path fname
   824   in  Vector.app (File.append path o (fn s => s ^ "\n"))  end;
   824   in  Vector.app (File.append path o (fn s => s ^ "\n"))  end;
   827   and allows the suppression of the suffix "_1" in problem-generation mode.
   827   and allows the suppression of the suffix "_1" in problem-generation mode.
   828   FIXME: does not cope with &&, and it isn't easy because one could have multiple
   828   FIXME: does not cope with &&, and it isn't easy because one could have multiple
   829   subgoals, each involving &&.*)
   829   subgoals, each involving &&.*)
   830 fun write_problem_files probfile (ctxt,th)  =
   830 fun write_problem_files probfile (ctxt,th)  =
   831   let val goals = Thm.prems_of th
   831   let val goals = Thm.prems_of th
   832       val _ = Output.debug ("number of subgoals = " ^ Int.toString (length goals))
   832       val _ = Output.debug (fn () => "number of subgoals = " ^ Int.toString (length goals))
   833       val thy = ProofContext.theory_of ctxt
   833       val thy = ProofContext.theory_of ctxt
   834       fun get_neg_subgoals [] _ = []
   834       fun get_neg_subgoals [] _ = []
   835         | get_neg_subgoals (gl::gls) n = #1 (ResAxioms.neg_conjecture_clauses th n) :: 
   835         | get_neg_subgoals (gl::gls) n = #1 (ResAxioms.neg_conjecture_clauses th n) :: 
   836                                          get_neg_subgoals gls (n+1)
   836                                          get_neg_subgoals gls (n+1)
   837       val goal_cls = get_neg_subgoals goals 1
   837       val goal_cls = get_neg_subgoals goals 1
   842       val (included_thms,white_thms) = get_clasimp_atp_lemmas ctxt []
   842       val (included_thms,white_thms) = get_clasimp_atp_lemmas ctxt []
   843       val included_cls = included_thms |> blacklist_filter
   843       val included_cls = included_thms |> blacklist_filter
   844                                        |> ResAxioms.cnf_rules_pairs |> make_unique
   844                                        |> ResAxioms.cnf_rules_pairs |> make_unique
   845                                        |> restrict_to_logic logic
   845                                        |> restrict_to_logic logic
   846                                        |> remove_unwanted_clauses
   846                                        |> remove_unwanted_clauses
   847       val _ = Output.debug ("included clauses = " ^ Int.toString(length included_cls))
   847       val _ = Output.debug (fn () => "included clauses = " ^ Int.toString(length included_cls))
   848       val white_cls = ResAxioms.cnf_rules_pairs white_thms
   848       val white_cls = ResAxioms.cnf_rules_pairs white_thms
   849       (*clauses relevant to goal gl*)
   849       (*clauses relevant to goal gl*)
   850       val axcls_list = map (fn ngcls => get_relevant_clauses thy included_cls white_cls (map prop_of ngcls)) goal_cls
   850       val axcls_list = map (fn ngcls => get_relevant_clauses thy included_cls white_cls (map prop_of ngcls)) goal_cls
   851       val _ = app (fn axcls => Output.debug ("filtered clauses = " ^ Int.toString(length axcls)))
   851       val _ = app (fn axcls => Output.debug (fn () => "filtered clauses = " ^ Int.toString(length axcls)))
   852                   axcls_list
   852                   axcls_list
   853       val writer = if !prover = "spass" then dfg_writer else tptp_writer
   853       val writer = if !prover = "spass" then dfg_writer else tptp_writer
   854       fun write_all [] [] _ = []
   854       fun write_all [] [] _ = []
   855         | write_all (ccls::ccls_list) (axcls::axcls_list) k =
   855         | write_all (ccls::ccls_list) (axcls::axcls_list) k =
   856             let val fname = probfile k
   856             let val fname = probfile k
   861                 val subs = tfree_classes_of_terms ccltms
   861                 val subs = tfree_classes_of_terms ccltms
   862                 and supers = tvar_classes_of_terms axtms
   862                 and supers = tvar_classes_of_terms axtms
   863                 and tycons = type_consts_of_terms thy (ccltms@axtms)
   863                 and tycons = type_consts_of_terms thy (ccltms@axtms)
   864                 (*TFrees in conjecture clauses; TVars in axiom clauses*)
   864                 (*TFrees in conjecture clauses; TVars in axiom clauses*)
   865                 val classrel_clauses = ResClause.make_classrel_clauses thy subs supers
   865                 val classrel_clauses = ResClause.make_classrel_clauses thy subs supers
   866                 val _ = Output.debug ("classrel clauses = " ^ Int.toString (length classrel_clauses))
   866                 val _ = Output.debug (fn () => "classrel clauses = " ^ Int.toString (length classrel_clauses))
   867                 val arity_clauses = ResClause.arity_clause_thy thy tycons supers
   867                 val arity_clauses = ResClause.arity_clause_thy thy tycons supers
   868                 val _ = Output.debug ("arity clauses = " ^ Int.toString (length arity_clauses))
   868                 val _ = Output.debug (fn () => "arity clauses = " ^ Int.toString (length arity_clauses))
   869                 val clnames = writer logic ccls fname (axcls,classrel_clauses,arity_clauses) []
   869                 val clnames = writer logic ccls fname (axcls,classrel_clauses,arity_clauses) []
   870                 val thm_names = Vector.fromList clnames
   870                 val thm_names = Vector.fromList clnames
   871                 val _ = if !Output.show_debug_msgs
   871                 val _ = if !Output.debugging
   872                         then trace_vector (fname ^ "_thm_names") thm_names else ()
   872                         then trace_vector (fname ^ "_thm_names") thm_names else ()
   873             in  (thm_names,fname) :: write_all ccls_list axcls_list (k+1)  end
   873             in  (thm_names,fname) :: write_all ccls_list axcls_list (k+1)  end
   874       val (thm_names_list, filenames) = ListPair.unzip (write_all goal_cls axcls_list 1)
   874       val (thm_names_list, filenames) = ListPair.unzip (write_all goal_cls axcls_list 1)
   875   in
   875   in
   876       (filenames, thm_names_list)
   876       (filenames, thm_names_list)
   881 
   881 
   882 fun kill_last_watcher () =
   882 fun kill_last_watcher () =
   883     (case !last_watcher_pid of
   883     (case !last_watcher_pid of
   884          NONE => ()
   884          NONE => ()
   885        | SOME (_, _, pid, files) =>
   885        | SOME (_, _, pid, files) =>
   886           (Output.debug ("Killing old watcher, pid = " ^ string_of_pid pid);
   886           (Output.debug (fn () => "Killing old watcher, pid = " ^ string_of_pid pid);
   887            Watcher.killWatcher pid;
   887            Watcher.killWatcher pid;
   888            ignore (map (try cond_rm_tmp) files)))
   888            ignore (map (try cond_rm_tmp) files)))
   889      handle OS.SysErr _ => Output.debug "Attempt to kill watcher failed";
   889      handle OS.SysErr _ => Output.debug (fn () => "Attempt to kill watcher failed");
   890 
   890 
   891 (*writes out the current problems and calls ATPs*)
   891 (*writes out the current problems and calls ATPs*)
   892 fun isar_atp (ctxt, th) =
   892 fun isar_atp (ctxt, th) =
   893   if Thm.no_prems th then ()
   893   if Thm.no_prems th then ()
   894   else
   894   else
   896       val _ = kill_last_watcher()
   896       val _ = kill_last_watcher()
   897       val (files,thm_names_list) = write_problem_files prob_pathname (ctxt,th)
   897       val (files,thm_names_list) = write_problem_files prob_pathname (ctxt,th)
   898       val (childin, childout, pid) = Watcher.createWatcher (ctxt, th, thm_names_list)
   898       val (childin, childout, pid) = Watcher.createWatcher (ctxt, th, thm_names_list)
   899     in
   899     in
   900       last_watcher_pid := SOME (childin, childout, pid, files);
   900       last_watcher_pid := SOME (childin, childout, pid, files);
   901       Output.debug ("problem files: " ^ space_implode ", " files);
   901       Output.debug (fn () => "problem files: " ^ space_implode ", " files);
   902       Output.debug ("pid: " ^ string_of_pid pid);
   902       Output.debug (fn () => "pid: " ^ string_of_pid pid);
   903       watcher_call_provers (sign_of_thm th) (Thm.prems_of th) (childin, childout, pid)
   903       watcher_call_provers (sign_of_thm th) (Thm.prems_of th) (childin, childout, pid)
   904     end;
   904     end;
   905 
   905 
   906 (*For ML scripts, and primarily, for debugging*)
   906 (*For ML scripts, and primarily, for debugging*)
   907 fun callatp () =
   907 fun callatp () =
   921 (** the Isar toplevel hook **)
   921 (** the Isar toplevel hook **)
   922 
   922 
   923 fun invoke_atp_ml (ctxt, goal) =
   923 fun invoke_atp_ml (ctxt, goal) =
   924   let val thy = ProofContext.theory_of ctxt;
   924   let val thy = ProofContext.theory_of ctxt;
   925   in
   925   in
   926     Output.debug ("subgoals in isar_atp:\n" ^
   926     Output.debug (fn () => "subgoals in isar_atp:\n" ^
   927                   Pretty.string_of (ProofContext.pretty_term ctxt
   927                   Pretty.string_of (ProofContext.pretty_term ctxt
   928                     (Logic.mk_conjunction_list (Thm.prems_of goal))));
   928                     (Logic.mk_conjunction_list (Thm.prems_of goal))));
   929     Output.debug ("current theory: " ^ Context.theory_name thy);
   929     Output.debug (fn () => "current theory: " ^ Context.theory_name thy);
   930     inc hook_count;
   930     inc hook_count;
   931     Output.debug ("in hook for time: " ^ Int.toString (!hook_count));
   931     Output.debug (fn () => "in hook for time: " ^ Int.toString (!hook_count));
   932     ResClause.init thy;
   932     ResClause.init thy;
   933     ResHolClause.init thy;
   933     ResHolClause.init thy;
   934     if !time_limit > 0 then isar_atp (ctxt, goal)
   934     if !time_limit > 0 then isar_atp (ctxt, goal)
   935     else (warning "Writing problem file only"; isar_atp_writeonly (ctxt, goal))
   935     else (warning "Writing problem file only"; isar_atp_writeonly (ctxt, goal))
   936   end;
   936   end;