src/HOL/Tools/Sledgehammer/sledgehammer.ML
changeset 40061 71cc5aac8b76
parent 40060 5ef6747aa619
child 40062 cfaebaa8588f
equal deleted inserted replaced
40060:5ef6747aa619 40061:71cc5aac8b76
    27      isar_proof: bool,
    27      isar_proof: bool,
    28      isar_shrink_factor: int,
    28      isar_shrink_factor: int,
    29      timeout: Time.time,
    29      timeout: Time.time,
    30      expect: string}
    30      expect: string}
    31 
    31 
    32   type atp_problem =
    32   datatype axiom =
       
    33     Unprepared of (string * locality) * thm |
       
    34     Prepared of term * ((string * locality) * fol_formula) option
       
    35 
       
    36   type prover_problem =
    33     {state: Proof.state,
    37     {state: Proof.state,
    34      goal: thm,
    38      goal: thm,
    35      subgoal: int,
    39      subgoal: int,
    36      axioms: (term * ((string * locality) * fol_formula) option) list,
    40      axioms: axiom list,
    37      only: bool}
    41      only: bool}
    38 
    42 
    39   type atp_result =
    43   type prover_result =
    40     {outcome: failure option,
    44     {outcome: failure option,
    41      message: string,
    45      message: string,
    42      pool: string Symtab.table,
    46      used_axioms: (string * locality) list,
    43      used_thm_names: (string * locality) list,
    47      run_time_in_msecs: int}
    44      atp_run_time_in_msecs: int,
    48 
    45      output: string,
    49   type prover = params -> minimize_command -> prover_problem -> prover_result
    46      tstplike_proof: string,
       
    47      axiom_names: (string * locality) list vector,
       
    48      conjecture_shape: int list list}
       
    49 
       
    50   type atp = params -> minimize_command -> atp_problem -> atp_result
       
    51 
    50 
    52   val smtN : string
    51   val smtN : string
    53   val dest_dir : string Config.T
    52   val dest_dir : string Config.T
    54   val problem_prefix : string Config.T
    53   val problem_prefix : string Config.T
    55   val measure_run_time : bool Config.T
    54   val measure_run_time : bool Config.T
    56   val available_provers : theory -> unit
    55   val available_provers : theory -> unit
    57   val kill_provers : unit -> unit
    56   val kill_provers : unit -> unit
    58   val running_provers : unit -> unit
    57   val running_provers : unit -> unit
    59   val messages : int option -> unit
    58   val messages : int option -> unit
    60   val run_atp : theory -> string -> atp
    59   val run_atp : theory -> string -> prover
       
    60   val is_smt_solver_installed : unit -> bool
    61   val run_smt_solver :
    61   val run_smt_solver :
    62     Proof.context -> bool -> Time.time -> ('a * thm) list -> string * 'a list
    62     bool -> params -> minimize_command -> prover_problem
    63   val is_smt_solver_installed : unit -> bool
    63     -> string * (string * locality) list
    64   val run_sledgehammer :
    64   val run_sledgehammer :
    65     params -> bool -> int -> relevance_override -> (string -> minimize_command)
    65     params -> bool -> int -> relevance_override -> (string -> minimize_command)
    66     -> Proof.state -> bool * Proof.state
    66     -> Proof.state -> bool * Proof.state
    67   val setup : theory -> theory
    67   val setup : theory -> theory
    68 end;
    68 end;
   118    isar_proof: bool,
   118    isar_proof: bool,
   119    isar_shrink_factor: int,
   119    isar_shrink_factor: int,
   120    timeout: Time.time,
   120    timeout: Time.time,
   121    expect: string}
   121    expect: string}
   122 
   122 
   123 type atp_problem =
   123 datatype axiom =
       
   124   Unprepared of (string * locality) * thm |
       
   125   Prepared of term * ((string * locality) * fol_formula) option
       
   126 
       
   127 type prover_problem =
   124   {state: Proof.state,
   128   {state: Proof.state,
   125    goal: thm,
   129    goal: thm,
   126    subgoal: int,
   130    subgoal: int,
   127    axioms: (term * ((string * locality) * fol_formula) option) list,
   131    axioms: axiom list,
   128    only: bool}
   132    only: bool}
   129 
   133 
   130 type atp_result =
   134 type prover_result =
   131   {outcome: failure option,
   135   {outcome: failure option,
   132    message: string,
   136    message: string,
   133    pool: string Symtab.table,
   137    used_axioms: (string * locality) list,
   134    used_thm_names: (string * locality) list,
   138    run_time_in_msecs: int}
   135    atp_run_time_in_msecs: int,
   139 
   136    output: string,
   140 type prover = params -> minimize_command -> prover_problem -> prover_result
   137    tstplike_proof: string,
       
   138    axiom_names: (string * locality) list vector,
       
   139    conjecture_shape: int list list}
       
   140 
       
   141 type atp = params -> minimize_command -> atp_problem -> atp_result
       
   142 
   141 
   143 (* configuration attributes *)
   142 (* configuration attributes *)
   144 
   143 
   145 val (dest_dir, dest_dir_setup) =
   144 val (dest_dir, dest_dir_setup) =
   146   Attrib.config_string "sledgehammer_dest_dir" (K "")
   145   Attrib.config_string "sledgehammer_dest_dir" (K "")
   174 fun proof_banner auto =
   173 fun proof_banner auto =
   175   if auto then "Sledgehammer found a proof" else "Try this command"
   174   if auto then "Sledgehammer found a proof" else "Try this command"
   176 
   175 
   177 (* generic TPTP-based ATPs *)
   176 (* generic TPTP-based ATPs *)
   178 
   177 
       
   178 fun dest_Unprepared (Unprepared p) = p
       
   179   | dest_Unprepared (Prepared _) = raise Fail "dest_Unprepared"
       
   180 fun prepared_axiom ctxt (Unprepared p) = prepare_axiom ctxt p
       
   181   | prepared_axiom _ (Prepared p) = p
       
   182 
   179 (* Important messages are important but not so important that users want to see
   183 (* Important messages are important but not so important that users want to see
   180    them each time. *)
   184    them each time. *)
   181 val important_message_keep_factor = 0.1
   185 val important_message_keep_factor = 0.1
   182 
   186 
   183 fun atp_fun auto atp_name
   187 fun atp_fun auto atp_name
   184         {exec, required_execs, arguments, has_incomplete_mode, proof_delims,
   188         {exec, required_execs, arguments, has_incomplete_mode, proof_delims,
   185          known_failures, default_max_relevant, explicit_forall,
   189          known_failures, default_max_relevant, explicit_forall,
   186          use_conjecture_for_hypotheses}
   190          use_conjecture_for_hypotheses}
   187         ({debug, verbose, overlord, full_types, explicit_apply,
   191         ({debug, verbose, overlord, full_types, explicit_apply,
   188           max_relevant, isar_proof, isar_shrink_factor, timeout, ...} : params)
   192           max_relevant, isar_proof, isar_shrink_factor, timeout, ...} : params)
   189         minimize_command ({state, goal, subgoal, axioms, only} : atp_problem) =
   193         minimize_command
       
   194         ({state, goal, subgoal, axioms, only} : prover_problem) =
   190   let
   195   let
   191     val ctxt = Proof.context_of state
   196     val ctxt = Proof.context_of state
   192     val (_, hyp_ts, concl_t) = strip_subgoal goal subgoal
   197     val (_, hyp_ts, concl_t) = strip_subgoal goal subgoal
   193     val axioms = axioms |> not only
   198     val axioms =
   194                           ? take (the_default default_max_relevant max_relevant)
   199       axioms |> not only ? take (the_default default_max_relevant max_relevant)
       
   200              |> map (prepared_axiom ctxt)
   195     val dest_dir = if overlord then getenv "ISABELLE_HOME_USER"
   201     val dest_dir = if overlord then getenv "ISABELLE_HOME_USER"
   196                    else Config.get ctxt dest_dir
   202                    else Config.get ctxt dest_dir
   197     val problem_prefix = Config.get ctxt problem_prefix
   203     val problem_prefix = Config.get ctxt problem_prefix
   198     val atp_problem_file_name =
   204     val problem_file_name =
   199       Path.basic ((if overlord then "prob_" ^ atp_name
   205       Path.basic ((if overlord then "prob_" ^ atp_name
   200                    else problem_prefix ^ serial_string ())
   206                    else problem_prefix ^ serial_string ())
   201                   ^ "_" ^ string_of_int subgoal)
   207                   ^ "_" ^ string_of_int subgoal)
   202     val atp_problem_path_name =
   208     val problem_path_name =
   203       if dest_dir = "" then
   209       if dest_dir = "" then
   204         File.tmp_path atp_problem_file_name
   210         File.tmp_path problem_file_name
   205       else if File.exists (Path.explode dest_dir) then
   211       else if File.exists (Path.explode dest_dir) then
   206         Path.append (Path.explode dest_dir) atp_problem_file_name
   212         Path.append (Path.explode dest_dir) problem_file_name
   207       else
   213       else
   208         error ("No such directory: " ^ quote dest_dir ^ ".")
   214         error ("No such directory: " ^ quote dest_dir ^ ".")
   209     val measure_run_time = verbose orelse Config.get ctxt measure_run_time
   215     val measure_run_time = verbose orelse Config.get ctxt measure_run_time
   210     val command = Path.explode (getenv (fst exec) ^ "/" ^ snd exec)
   216     val command = Path.explode (getenv (fst exec) ^ "/" ^ snd exec)
   211     (* write out problem file and call ATP *)
   217     (* write out problem file and call ATP *)
   286         ()
   292         ()
   287       else
   293       else
   288         File.write (Path.explode (Path.implode probfile ^ "_proof")) output
   294         File.write (Path.explode (Path.implode probfile ^ "_proof")) output
   289     val ((pool, conjecture_shape, axiom_names),
   295     val ((pool, conjecture_shape, axiom_names),
   290          (output, msecs, tstplike_proof, outcome)) =
   296          (output, msecs, tstplike_proof, outcome)) =
   291       with_path cleanup export run_on atp_problem_path_name
   297       with_path cleanup export run_on problem_path_name
   292     val (conjecture_shape, axiom_names) =
   298     val (conjecture_shape, axiom_names) =
   293       repair_conjecture_shape_and_axiom_names output conjecture_shape
   299       repair_conjecture_shape_and_axiom_names output conjecture_shape
   294                                               axiom_names
   300                                               axiom_names
   295     val important_message =
   301     val important_message =
   296       if random () <= important_message_keep_factor then
   302       if random () <= important_message_keep_factor then
   297         extract_important_message output
   303         extract_important_message output
   298       else
   304       else
   299         ""
   305         ""
   300     val (message, used_thm_names) =
   306     val (message, used_axioms) =
   301       case outcome of
   307       case outcome of
   302         NONE =>
   308         NONE =>
   303         proof_text isar_proof
   309         proof_text isar_proof
   304             (pool, debug, isar_shrink_factor, ctxt, conjecture_shape)
   310             (pool, debug, isar_shrink_factor, ctxt, conjecture_shape)
   305             (proof_banner auto, full_types, minimize_command, tstplike_proof,
   311             (proof_banner auto, full_types, minimize_command, tstplike_proof,
   315                    important_message
   321                    important_message
   316                  else
   322                  else
   317                    ""))
   323                    ""))
   318       | SOME failure => (string_for_failure failure, [])
   324       | SOME failure => (string_for_failure failure, [])
   319   in
   325   in
   320     {outcome = outcome, message = message, pool = pool,
   326     {outcome = outcome, message = message, used_axioms = used_axioms,
   321      used_thm_names = used_thm_names, atp_run_time_in_msecs = msecs,
   327      run_time_in_msecs = msecs}
   322      output = output, tstplike_proof = tstplike_proof,
       
   323      axiom_names = axiom_names, conjecture_shape = conjecture_shape}
       
   324   end
   328   end
   325 
   329 
   326 fun run_atp thy name = atp_fun false name (get_atp thy name)
   330 fun run_atp thy name = atp_fun false name (get_atp thy name)
   327 
   331 
   328 fun run_atp_somehow (params as {blocking, debug, max_relevant, timeout,
   332 fun run_atp_somehow (params as {blocking, debug, max_relevant, timeout,
   329                                 expect, ...})
   333                                 expect, ...})
   330                     auto i n minimize_command
   334                     auto i n minimize_command
   331                     (atp_problem as {state, goal, axioms, ...})
   335                     (prover_problem as {state, goal, axioms, ...})
   332                     (atp as {default_max_relevant, ...}, atp_name) =
   336                     (prover as {default_max_relevant, ...}, atp_name) =
   333   let
   337   let
   334     val ctxt = Proof.context_of state
   338     val ctxt = Proof.context_of state
   335     val birth_time = Time.now ()
   339     val birth_time = Time.now ()
   336     val death_time = Time.+ (birth_time, timeout)
   340     val death_time = Time.+ (birth_time, timeout)
   337     val max_relevant = the_default default_max_relevant max_relevant
   341     val max_relevant = the_default default_max_relevant max_relevant
   338     val num_axioms = Int.min (length axioms, max_relevant)
   342     val num_axioms = Int.min (length axioms, max_relevant)
   339     val desc = prover_description ctxt params atp_name num_axioms i n goal
   343     val desc = prover_description ctxt params atp_name num_axioms i n goal
   340     fun go () =
   344     fun go () =
   341       let
   345       let
   342         fun really_go () =
   346         fun really_go () =
   343           atp_fun auto atp_name atp params (minimize_command atp_name)
   347           atp_fun auto atp_name prover params (minimize_command atp_name)
   344                   atp_problem
   348                   prover_problem
   345           |> (fn {outcome, message, ...} =>
   349           |> (fn {outcome, message, ...} =>
   346                  (if is_some outcome then "none" else "some", message))
   350                  (if is_some outcome then "none" else "some", message))
   347         val (outcome_code, message) =
   351         val (outcome_code, message) =
   348           if debug then
   352           if debug then
   349             really_go ()
   353             really_go ()
   377       (Async_Manager.launch das_Tool birth_time death_time desc (snd o go);
   381       (Async_Manager.launch das_Tool birth_time death_time desc (snd o go);
   378        (false, state))
   382        (false, state))
   379   end
   383   end
   380 
   384 
   381 (* FIXME: dummy *)
   385 (* FIXME: dummy *)
   382 fun run_smt_solver ctxt remote timeout axioms =
   386 fun is_smt_solver_installed () = true
       
   387 
       
   388 (* FIXME: dummy *)
       
   389 fun raw_run_smt_solver remote timeout state axioms i =
   383   ("", axioms |> take 5 |> map fst)
   390   ("", axioms |> take 5 |> map fst)
   384 
   391 
   385 (* FIXME: dummy *)
   392 fun run_smt_solver remote ({timeout, ...} : params) minimize_command
   386 fun is_smt_solver_installed () = true
   393                    ({state, subgoal, axioms, ...} : prover_problem) =
   387 
   394   raw_run_smt_solver remote timeout state
   388 fun run_smt_solver_somehow ctxt (params as {timeout, ...}) i n goal axioms
   395                      (map_filter (try dest_Unprepared) axioms) subgoal
       
   396 
       
   397 fun run_smt_solver_somehow state (params as {timeout, ...}) i n goal axioms
   389                            (remote, name) =
   398                            (remote, name) =
   390   let
   399   let
   391     val desc =
   400     val ctxt = Proof.context_of state
   392       prover_description ctxt params name (length axioms) i n goal
   401     val desc = prover_description ctxt params name (length axioms) i n goal
   393     val (failure, used_thm_names) = run_smt_solver ctxt remote timeout axioms
   402     val (failure, used_axioms) =
       
   403       raw_run_smt_solver remote timeout state axioms i
   394     val success = (failure = "")
   404     val success = (failure = "")
   395     val message =
   405     val message =
   396       das_Tool ^ ": " ^ desc ^ "\n" ^
   406       das_Tool ^ ": " ^ desc ^ "\n" ^
   397       (if success then
   407       (if success then
   398          sendback_line (proof_banner false)
   408          sendback_line (proof_banner false)
   399                        (apply_on_subgoal i n ^
   409                        (apply_on_subgoal i n ^
   400                         command_call "smt" (map fst used_thm_names))
   410                         command_call "smt" (map fst used_axioms))
   401        else
   411        else
   402          "Error: " ^ failure)
   412          "Error: " ^ failure)
   403   in priority message; success end
   413   in priority message; success end
   404 
   414 
   405 val smt_default_max_relevant = 300 (* FUDGE *)
   415 val smt_default_max_relevant = 300 (* FUDGE *)
   439                   |> auto ? (fn n => n div auto_max_relevant_divisor)
   449                   |> auto ? (fn n => n div auto_max_relevant_divisor)
   440             val axioms =
   450             val axioms =
   441               relevant_facts ctxt full_types relevance_thresholds
   451               relevant_facts ctxt full_types relevance_thresholds
   442                              max_max_relevant relevance_override chained_ths
   452                              max_max_relevant relevance_override chained_ths
   443                              hyp_ts concl_t
   453                              hyp_ts concl_t
   444             val atp_problem =
   454             val prover_problem =
   445               {state = state, goal = goal, subgoal = i,
   455               {state = state, goal = goal, subgoal = i,
   446                axioms = map (prepare_axiom ctxt) axioms, only = only}
   456                axioms = axioms |> map (Prepared o prepare_axiom ctxt),
       
   457                only = only}
   447             val run_atp_somehow =
   458             val run_atp_somehow =
   448               run_atp_somehow params auto i n minimize_command atp_problem
   459               run_atp_somehow params auto i n minimize_command prover_problem
   449           in
   460           in
   450             if auto then
   461             if auto then
   451               fold (fn atp => fn (true, state) => (true, state)
   462               fold (fn prover => fn (true, state) => (true, state)
   452                                | (false, _) => run_atp_somehow atp)
   463                                   | (false, _) => run_atp_somehow prover)
   453                    atps (false, state)
   464                    atps (false, state)
   454             else
   465             else
   455               atps |> (if blocking then Par_List.map else map) run_atp_somehow
   466               atps |> (if blocking then Par_List.map else map) run_atp_somehow
   456                    |> exists fst |> rpair state
   467                    |> exists fst |> rpair state
   457           end
   468           end
   465             val axioms =
   476             val axioms =
   466               relevant_facts ctxt full_types relevance_thresholds
   477               relevant_facts ctxt full_types relevance_thresholds
   467                              max_relevant relevance_override chained_ths
   478                              max_relevant relevance_override chained_ths
   468                              hyp_ts concl_t
   479                              hyp_ts concl_t
   469           in
   480           in
   470             smts |> map (run_smt_solver_somehow ctxt params i n goal axioms)
   481             smts |> map (run_smt_solver_somehow state params i n goal axioms)
   471                  |> exists I |> rpair state
   482                  |> exists I |> rpair state
   472           end
   483           end
   473       fun run_atps_and_smt_solvers () =
   484       fun run_atps_and_smt_solvers () =
   474         [run_atps, run_smt_solvers]
   485         [run_atps, run_smt_solvers]
   475         |> Par_List.map (fn f => f (false, state) |> K ())
   486         |> Par_List.map (fn f => f (false, state) |> K ())