src/HOL/Tools/ATP_Manager/atp_wrapper.ML
changeset 35969 c9565298df9e
parent 35869 cac366550624
child 36001 992839c4be90
equal deleted inserted replaced
35968:b7f98ff9c7d9 35969:c9565298df9e
    18 end;
    18 end;
    19 
    19 
    20 structure ATP_Wrapper : ATP_WRAPPER =
    20 structure ATP_Wrapper : ATP_WRAPPER =
    21 struct
    21 struct
    22 
    22 
       
    23 open Sledgehammer_Fact_Preprocessor
    23 open Sledgehammer_HOL_Clause
    24 open Sledgehammer_HOL_Clause
    24 open Sledgehammer_Fact_Filter
    25 open Sledgehammer_Fact_Filter
    25 open Sledgehammer_Proof_Reconstruct
    26 open Sledgehammer_Proof_Reconstruct
    26 open ATP_Manager
    27 open ATP_Manager
    27 
    28 
    41 
    42 
    42 (* prover configuration *)
    43 (* prover configuration *)
    43 
    44 
    44 type prover_config =
    45 type prover_config =
    45  {command: Path.T,
    46  {command: Path.T,
    46   arguments: int -> string,
    47   arguments: Time.time -> string,
    47   failure_strs: string list,
    48   failure_strs: string list,
    48   max_new_clauses: int,
    49   max_new_clauses: int,
    49   insert_theory_const: bool,
    50   add_theory_const: bool,
    50   emit_structured_proof: bool};
    51   supports_isar_proofs: bool};
    51 
    52 
    52 
    53 
    53 (* basic template *)
    54 (* basic template *)
    54 
    55 
    55 fun with_path cleanup after f path =
    56 fun with_path cleanup after f path =
    62   case filter (fn s => String.isSubstring s proof) strs of
    63   case filter (fn s => String.isSubstring s proof) strs of
    63     [] => if is_proof_well_formed proof then NONE
    64     [] => if is_proof_well_formed proof then NONE
    64           else SOME "Ill-formed ATP output"
    65           else SOME "Ill-formed ATP output"
    65   | (failure :: _) => SOME failure
    66   | (failure :: _) => SOME failure
    66 
    67 
    67 fun external_prover relevance_filter prepare write cmd args failure_strs
    68 fun generic_prover get_facts prepare write cmd args failure_strs produce_answer
    68         produce_answer name ({with_full_types, subgoal, goal, axiom_clauses,
    69         name ({full_types, ...} : params)
    69                               filtered_clauses}: problem) =
    70         ({subgoal, goal, relevance_override, axiom_clauses, filtered_clauses}
       
    71          : problem) =
    70   let
    72   let
    71     (* get clauses and prepare them for writing *)
    73     (* get clauses and prepare them for writing *)
    72     val (ctxt, (chain_ths, th)) = goal;
    74     val (ctxt, (chain_ths, th)) = goal;
    73     val thy = ProofContext.theory_of ctxt;
    75     val thy = ProofContext.theory_of ctxt;
    74     val chain_ths = map (Thm.put_name_hint chained_hint) chain_ths;
    76     val chain_ths = map (Thm.put_name_hint chained_hint) chain_ths;
    75     val goal_cls = #1 (Sledgehammer_Fact_Preprocessor.neg_conjecture_clauses ctxt th subgoal);
    77     val goal_cls = #1 (neg_conjecture_clauses ctxt th subgoal);
    76     val the_filtered_clauses =
    78     val the_filtered_clauses =
    77       (case filtered_clauses of
    79       (case filtered_clauses of
    78         NONE => relevance_filter goal goal_cls
    80         NONE => get_facts relevance_override goal goal_cls
    79       | SOME fcls => fcls);
    81       | SOME fcls => fcls);
    80     val the_axiom_clauses =
    82     val the_axiom_clauses =
    81       (case axiom_clauses of
    83       (case axiom_clauses of
    82         NONE => the_filtered_clauses
    84         NONE => the_filtered_clauses
    83       | SOME axcls => axcls);
    85       | SOME axcls => axcls);
    84     val (thm_names, clauses) =
    86     val (internal_thm_names, clauses) =
    85       prepare goal_cls chain_ths the_axiom_clauses the_filtered_clauses thy;
    87       prepare goal_cls chain_ths the_axiom_clauses the_filtered_clauses thy;
    86 
    88 
    87     (* path to unique problem file *)
    89     (* path to unique problem file *)
    88     val destdir' = Config.get ctxt destdir;
    90     val destdir' = Config.get ctxt destdir;
    89     val problem_prefix' = Config.get ctxt problem_prefix;
    91     val problem_prefix' = Config.get ctxt problem_prefix;
   119       in (proof, as_time t) end;
   121       in (proof, as_time t) end;
   120     fun split_time' s =
   122     fun split_time' s =
   121       if Config.get ctxt measure_runtime then split_time s else (s, 0)
   123       if Config.get ctxt measure_runtime then split_time s else (s, 0)
   122     fun run_on probfile =
   124     fun run_on probfile =
   123       if File.exists cmd then
   125       if File.exists cmd then
   124         write with_full_types probfile clauses
   126         write full_types probfile clauses
   125         |> pair (apfst split_time' (bash_output (cmd_line probfile)))
   127         |> pair (apfst split_time' (bash_output (cmd_line probfile)))
   126       else error ("Bad executable: " ^ Path.implode cmd);
   128       else error ("Bad executable: " ^ Path.implode cmd);
   127 
   129 
   128     (* if problemfile has not been exported, delete problemfile; otherwise export proof, too *)
   130     (* if problemfile has not been exported, delete problemfile; otherwise export proof, too *)
   129     fun cleanup probfile = if destdir' = "" then try File.rm probfile else NONE;
   131     fun cleanup probfile = if destdir' = "" then try File.rm probfile else NONE;
   130     fun export probfile (((proof, _), _), _) =
   132     fun export probfile (((proof, _), _), _) =
   131       if destdir' = "" then ()
   133       if destdir' = "" then ()
   132       else File.write (Path.explode (Path.implode probfile ^ "_proof")) proof;
   134       else File.write (Path.explode (Path.implode probfile ^ "_proof")) proof;
   133 
   135 
   134     val (((proof, time), rc), conj_pos) =
   136     val (((proof, atp_run_time_in_msecs), rc), conj_pos) =
   135       with_path cleanup export run_on (prob_pathname subgoal);
   137       with_path cleanup export run_on (prob_pathname subgoal);
   136 
   138 
   137     (* check for success and print out some information on failure *)
   139     (* check for success and print out some information on failure *)
   138     val failure = find_failure failure_strs proof;
   140     val failure = find_failure failure_strs proof;
   139     val success = rc = 0 andalso is_none failure;
   141     val success = rc = 0 andalso is_none failure;
   140     val (message, real_thm_names) =
   142     val (message, relevant_thm_names) =
   141       if is_some failure then ("External prover failed.", [])
   143       if is_some failure then ("External prover failed.", [])
   142       else if rc <> 0 then ("External prover failed: " ^ proof, [])
   144       else if rc <> 0 then ("External prover failed: " ^ proof, [])
   143       else apfst (fn s => "Try this command: " ^ s)
   145       else
   144         (produce_answer name (proof, thm_names, conj_pos, ctxt, th, subgoal));
   146         (produce_answer name (proof, internal_thm_names, conj_pos, ctxt, th,
       
   147                               subgoal));
   145   in
   148   in
   146     {success = success, message = message,
   149     {success = success, message = message,
   147       theorem_names = real_thm_names, runtime = time, proof = proof,
   150      relevant_thm_names = relevant_thm_names,
   148       internal_thm_names = thm_names, filtered_clauses = the_filtered_clauses}
   151      atp_run_time_in_msecs = atp_run_time_in_msecs, proof = proof,
       
   152      internal_thm_names = internal_thm_names,
       
   153      filtered_clauses = the_filtered_clauses}
   149   end;
   154   end;
   150 
   155 
   151 
   156 
   152 (* generic TPTP-based provers *)
   157 (* generic TPTP-based provers *)
   153 
   158 
   154 fun generic_tptp_prover
   159 fun generic_tptp_prover
   155         (name, {command, arguments, failure_strs, max_new_clauses,
   160         (name, {command, arguments, failure_strs, max_new_clauses,
   156                 insert_theory_const, emit_structured_proof}) timeout =
   161                 add_theory_const, supports_isar_proofs})
   157   external_prover (get_relevant_facts max_new_clauses insert_theory_const)
   162         (params as {relevance_threshold, higher_order, follow_defs, isar_proof,
   158       (prepare_clauses false) write_tptp_file command (arguments timeout)
   163                     ...}) timeout =
   159       failure_strs
   164   generic_prover
   160       (if emit_structured_proof then structured_isar_proof
   165       (get_relevant_facts relevance_threshold higher_order follow_defs
   161        else metis_lemma_list false) name;
   166                           max_new_clauses add_theory_const)
   162 
   167       (prepare_clauses higher_order false) write_tptp_file command
   163 fun tptp_prover (name, p) = (name, generic_tptp_prover (name, p));
   168       (arguments timeout) failure_strs
       
   169       (if supports_isar_proofs andalso isar_proof then structured_isar_proof
       
   170        else metis_lemma_list false) name params;
       
   171 
       
   172 fun tptp_prover name p = (name, generic_tptp_prover (name, p));
   164 
   173 
   165 
   174 
   166 (** common provers **)
   175 (** common provers **)
   167 
   176 
   168 (* Vampire *)
   177 (* Vampire *)
   169 
   178 
   170 (*NB: Vampire does not work without explicit timelimit*)
   179 (* NB: Vampire does not work without explicit time limit. *)
   171 
   180 
   172 val vampire_failure_strs =
   181 val vampire_config : prover_config =
   173   ["Satisfiability detected", "Refutation not found", "CANNOT PROVE"];
   182   {command = Path.explode "$VAMPIRE_HOME/vampire",
   174 val vampire_max_new_clauses = 60;
   183    arguments = (fn timeout => "--output_syntax tptp --mode casc -t " ^
   175 val vampire_insert_theory_const = false;
   184                               string_of_int (Time.toSeconds timeout)),
   176 
   185    failure_strs =
   177 fun vampire_prover_config isar : prover_config =
   186      ["Satisfiability detected", "Refutation not found", "CANNOT PROVE"],
   178  {command = Path.explode "$VAMPIRE_HOME/vampire",
   187    max_new_clauses = 60,
   179   arguments = (fn timeout => "--output_syntax tptp --mode casc" ^
   188    add_theory_const = false,
   180     " -t " ^ string_of_int timeout),
   189    supports_isar_proofs = true}
   181   failure_strs = vampire_failure_strs,
   190 val vampire = tptp_prover "vampire" vampire_config
   182   max_new_clauses = vampire_max_new_clauses,
       
   183   insert_theory_const = vampire_insert_theory_const,
       
   184   emit_structured_proof = isar};
       
   185 
       
   186 val vampire = tptp_prover ("vampire", vampire_prover_config false);
       
   187 val vampire_isar = tptp_prover ("vampire_isar", vampire_prover_config true);
       
   188 
   191 
   189 
   192 
   190 (* E prover *)
   193 (* E prover *)
   191 
   194 
   192 val eprover_failure_strs =
   195 val e_config : prover_config =
   193   ["SZS status: Satisfiable", "SZS status Satisfiable",
   196   {command = Path.explode "$E_HOME/eproof",
   194    "SZS status: ResourceOut", "SZS status ResourceOut",
   197    arguments = (fn timeout => "--tstp-in --tstp-out -l5 -xAutoDev \
   195    "# Cannot determine problem status"];
   198                               \-tAutoDev --silent --cpu-limit=" ^
   196 val eprover_max_new_clauses = 100;
   199                               string_of_int (Time.toSeconds timeout)),
   197 val eprover_insert_theory_const = false;
   200    failure_strs =
   198 
   201        ["SZS status: Satisfiable", "SZS status Satisfiable",
   199 fun eprover_config isar : prover_config =
   202         "SZS status: ResourceOut", "SZS status ResourceOut",
   200  {command = Path.explode "$E_HOME/eproof",
   203         "# Cannot determine problem status"],
   201   arguments = (fn timeout => "--tstp-in --tstp-out -l5 -xAutoDev -tAutoDev" ^
   204    max_new_clauses = 100,
   202     " --silent --cpu-limit=" ^ string_of_int timeout),
   205    add_theory_const = false,
   203   failure_strs = eprover_failure_strs,
   206    supports_isar_proofs = true}
   204   max_new_clauses = eprover_max_new_clauses,
   207 val e = tptp_prover "e" e_config
   205   insert_theory_const = eprover_insert_theory_const,
       
   206   emit_structured_proof = isar};
       
   207 
       
   208 val eprover = tptp_prover ("e", eprover_config false);
       
   209 val eprover_isar = tptp_prover ("e_isar", eprover_config true);
       
   210 
   208 
   211 
   209 
   212 (* SPASS *)
   210 (* SPASS *)
   213 
   211 
   214 val spass_failure_strs =
   212 fun generic_dfg_prover
   215   ["SPASS beiseite: Completion found.", "SPASS beiseite: Ran out of time.",
   213         (name, ({command, arguments, failure_strs, max_new_clauses,
   216    "SPASS beiseite: Maximal number of loops exceeded."];
   214                  add_theory_const, ...} : prover_config))
   217 val spass_max_new_clauses = 40;
   215         (params as {relevance_threshold, higher_order, follow_defs, ...})
   218 val spass_insert_theory_const = true;
   216         timeout =
   219 
   217   generic_prover
   220 fun spass_config insert_theory_const: prover_config =
   218       (get_relevant_facts relevance_threshold higher_order follow_defs
       
   219                           max_new_clauses add_theory_const)
       
   220       (prepare_clauses higher_order true) write_dfg_file command
       
   221       (arguments timeout) failure_strs (metis_lemma_list true) name params;
       
   222 
       
   223 fun dfg_prover (name, p) = (name, generic_dfg_prover (name, p));
       
   224 
       
   225 fun spass_config_for add_theory_const : prover_config =
   221  {command = Path.explode "$SPASS_HOME/SPASS",
   226  {command = Path.explode "$SPASS_HOME/SPASS",
   222   arguments = (fn timeout => "-Auto -SOS=1 -PGiven=0 -PProblem=0 -Splits=0" ^
   227   arguments = (fn timeout => "-Auto -SOS=1 -PGiven=0 -PProblem=0 -Splits=0" ^
   223     " -FullRed=0 -DocProof -TimeLimit=" ^ string_of_int timeout),
   228     " -FullRed=0 -DocProof -TimeLimit=" ^
   224   failure_strs = spass_failure_strs,
   229     string_of_int (Time.toSeconds timeout)),
   225   max_new_clauses = spass_max_new_clauses,
   230   failure_strs =
   226   insert_theory_const = insert_theory_const,
   231     ["SPASS beiseite: Completion found.", "SPASS beiseite: Ran out of time.",
   227   emit_structured_proof = false};
   232      "SPASS beiseite: Maximal number of loops exceeded."],
   228 
   233   max_new_clauses = 40,
   229 fun generic_dfg_prover
   234   add_theory_const = add_theory_const,
   230         (name, ({command, arguments, failure_strs, max_new_clauses,
   235   supports_isar_proofs = false};
   231                  insert_theory_const, ...} : prover_config)) timeout =
   236 
   232   external_prover
   237 val spass_config = spass_config_for true
   233     (get_relevant_facts max_new_clauses insert_theory_const)
   238 val spass = dfg_prover ("spass", spass_config)
   234     (prepare_clauses true)
   239 
   235     write_dfg_file
   240 val spass_no_tc_config = spass_config_for false
   236     command
   241 val spass_no_tc = dfg_prover ("spass_no_tc", spass_no_tc_config)
   237     (arguments timeout)
       
   238     failure_strs
       
   239     (metis_lemma_list true)
       
   240     name;
       
   241 
       
   242 fun dfg_prover (name, p) = (name, generic_dfg_prover (name, p));
       
   243 
       
   244 val spass = dfg_prover ("spass", spass_config spass_insert_theory_const);
       
   245 val spass_no_tc = dfg_prover ("spass_no_tc", spass_config false);
       
   246 
   242 
   247 
   243 
   248 (* remote prover invocation via SystemOnTPTP *)
   244 (* remote prover invocation via SystemOnTPTP *)
   249 
   245 
   250 val systems = Synchronized.var "atp_wrapper_systems" ([]: string list);
   246 val systems = Synchronized.var "atp_wrapper_systems" ([]: string list);
   251 
   247 
   252 fun get_systems () =
   248 fun get_systems () =
   253   let
   249   let
   254     val (answer, rc) = bash_output ("\"$ISABELLE_ATP_MANAGER/SystemOnTPTP\" -w")
   250     val (answer, rc) = bash_output "\"$ISABELLE_ATP_MANAGER/SystemOnTPTP\" -w"
   255   in
   251   in
   256     if rc <> 0 then error ("Failed to get available systems at SystemOnTPTP:\n" ^ answer)
   252     if rc <> 0 then
   257     else split_lines answer
   253       error ("Failed to get available systems at SystemOnTPTP:\n" ^ answer)
       
   254     else
       
   255       split_lines answer
   258   end;
   256   end;
   259 
   257 
   260 fun refresh_systems_on_tptp () =
   258 fun refresh_systems_on_tptp () =
   261   Synchronized.change systems (fn _ => get_systems ());
   259   Synchronized.change systems (fn _ => get_systems ());
   262 
   260 
   269     NONE => error ("System " ^ quote prefix ^ " not available at SystemOnTPTP")
   267     NONE => error ("System " ^ quote prefix ^ " not available at SystemOnTPTP")
   270   | SOME sys => sys);
   268   | SOME sys => sys);
   271 
   269 
   272 val remote_failure_strs = ["Remote-script could not extract proof"];
   270 val remote_failure_strs = ["Remote-script could not extract proof"];
   273 
   271 
   274 fun remote_prover_config prover_prefix args max_new insert_tc: prover_config =
   272 fun remote_prover_config prover_prefix args max_new_clauses add_theory_const
   275  {command = Path.explode "$ISABELLE_ATP_MANAGER/SystemOnTPTP",
   273                          : prover_config =
   276   arguments = (fn timeout =>
   274   {command = Path.explode "$ISABELLE_ATP_MANAGER/SystemOnTPTP",
   277     args ^ " -t " ^ string_of_int timeout ^ " -s " ^ the_system prover_prefix),
   275    arguments = (fn timeout =>
   278   failure_strs = remote_failure_strs,
   276      args ^ " -t " ^ string_of_int (Time.toSeconds timeout) ^ " -s " ^
   279   max_new_clauses = max_new,
   277      the_system prover_prefix),
   280   insert_theory_const = insert_tc,
   278    failure_strs = remote_failure_strs,
   281   emit_structured_proof = false};
   279    max_new_clauses = max_new_clauses,
   282 
   280    add_theory_const = add_theory_const,
   283 val remote_vampire = tptp_prover ("remote_vampire", remote_prover_config
   281    supports_isar_proofs = false}
   284   "Vampire---9" "" vampire_max_new_clauses vampire_insert_theory_const);
   282 
   285 
   283 val remote_vampire =
   286 val remote_eprover = tptp_prover ("remote_e", remote_prover_config
   284   tptp_prover "remote_vampire"
   287   "EP---" "" eprover_max_new_clauses eprover_insert_theory_const);
   285       (remote_prover_config "Vampire---9" ""
   288 
   286            (#max_new_clauses vampire_config) (#add_theory_const vampire_config))
   289 val remote_spass = tptp_prover ("remote_spass", remote_prover_config
   287 
   290   "SPASS---" "-x" spass_max_new_clauses spass_insert_theory_const);
   288 val remote_e =
       
   289   tptp_prover "remote_e"
       
   290       (remote_prover_config "EP---" ""
       
   291            (#max_new_clauses e_config) (#add_theory_const e_config))
       
   292 
       
   293 val remote_spass =
       
   294   tptp_prover "remote_spass"
       
   295       (remote_prover_config "SPASS---" "-x"
       
   296            (#max_new_clauses spass_config) (#add_theory_const spass_config))
   291 
   297 
   292 val provers =
   298 val provers =
   293   [spass, vampire, eprover, vampire_isar, eprover_isar, spass_no_tc,
   299   [spass, vampire, e, spass_no_tc, remote_vampire, remote_spass, remote_e]
   294    remote_vampire, remote_spass, remote_eprover]
       
   295 val prover_setup = fold add_prover provers
   300 val prover_setup = fold add_prover provers
   296 
   301 
   297 val setup =
   302 val setup =
   298   destdir_setup
   303   destdir_setup
   299   #> problem_prefix_setup
   304   #> problem_prefix_setup