src/HOL/Tools/Sledgehammer/sledgehammer.ML
changeset 40062 cfaebaa8588f
parent 40061 71cc5aac8b76
child 40063 d086e3699e78
equal deleted inserted replaced
40061:71cc5aac8b76 40062:cfaebaa8588f
    40      axioms: axiom list,
    40      axioms: axiom list,
    41      only: bool}
    41      only: bool}
    42 
    42 
    43   type prover_result =
    43   type prover_result =
    44     {outcome: failure option,
    44     {outcome: failure option,
    45      message: string,
       
    46      used_axioms: (string * locality) list,
    45      used_axioms: (string * locality) list,
    47      run_time_in_msecs: int}
    46      run_time_in_msecs: int option,
       
    47      message: string}
    48 
    48 
    49   type prover = params -> minimize_command -> prover_problem -> prover_result
    49   type prover = params -> minimize_command -> prover_problem -> prover_result
    50 
    50 
    51   val smtN : string
    51   val smtN : string
       
    52   val smt_prover_names : string list
       
    53   val smt_default_max_relevant : int
    52   val dest_dir : string Config.T
    54   val dest_dir : string Config.T
    53   val problem_prefix : string Config.T
    55   val problem_prefix : string Config.T
    54   val measure_run_time : bool Config.T
    56   val measure_run_time : bool Config.T
    55   val available_provers : theory -> unit
    57   val available_provers : theory -> unit
    56   val kill_provers : unit -> unit
    58   val kill_provers : unit -> unit
    57   val running_provers : unit -> unit
    59   val running_provers : unit -> unit
    58   val messages : int option -> unit
    60   val messages : int option -> unit
    59   val run_atp : theory -> string -> prover
    61   val get_prover : theory -> string -> prover
    60   val is_smt_solver_installed : unit -> bool
       
    61   val run_smt_solver :
       
    62     bool -> params -> minimize_command -> prover_problem
       
    63     -> string * (string * locality) list
       
    64   val run_sledgehammer :
    62   val run_sledgehammer :
    65     params -> bool -> int -> relevance_override -> (string -> minimize_command)
    63     params -> bool -> int -> relevance_override -> (string -> minimize_command)
    66     -> Proof.state -> bool * Proof.state
    64     -> Proof.state -> bool * Proof.state
    67   val setup : theory -> theory
    65   val setup : theory -> theory
    68 end;
    66 end;
    85 (* Identifier to distinguish Sledgehammer from other tools using
    83 (* Identifier to distinguish Sledgehammer from other tools using
    86    "Async_Manager". *)
    84    "Async_Manager". *)
    87 val das_Tool = "Sledgehammer"
    85 val das_Tool = "Sledgehammer"
    88 
    86 
    89 val smtN = "smt"
    87 val smtN = "smt"
    90 val smt_names = [smtN, remote_prefix ^ smtN]
    88 val smt_prover_names = [smtN, remote_prefix ^ smtN]
       
    89 
       
    90 val smt_default_max_relevant = 300 (* FUDGE *)
       
    91 val auto_max_relevant_divisor = 2 (* FUDGE *)
    91 
    92 
    92 fun available_provers thy =
    93 fun available_provers thy =
    93   let
    94   let
    94     val (remote_provers, local_provers) =
    95     val (remote_provers, local_provers) =
    95       sort_strings (available_atps thy) @ smt_names
    96       sort_strings (available_atps thy) @ smt_prover_names
    96       |> List.partition (String.isPrefix remote_prefix)
    97       |> List.partition (String.isPrefix remote_prefix)
    97   in
    98   in
    98     priority ("Available provers: " ^ commas (local_provers @ remote_provers) ^
    99     priority ("Available provers: " ^ commas (local_provers @ remote_provers) ^
    99               ".")
   100               ".")
   100   end
   101   end
   133 
   134 
   134 type prover_result =
   135 type prover_result =
   135   {outcome: failure option,
   136   {outcome: failure option,
   136    message: string,
   137    message: string,
   137    used_axioms: (string * locality) list,
   138    used_axioms: (string * locality) list,
   138    run_time_in_msecs: int}
   139    run_time_in_msecs: int option}
   139 
   140 
   140 type prover = params -> minimize_command -> prover_problem -> prover_result
   141 type prover = params -> minimize_command -> prover_problem -> prover_result
   141 
   142 
   142 (* configuration attributes *)
   143 (* configuration attributes *)
   143 
   144 
   177 
   178 
   178 fun dest_Unprepared (Unprepared p) = p
   179 fun dest_Unprepared (Unprepared p) = p
   179   | dest_Unprepared (Prepared _) = raise Fail "dest_Unprepared"
   180   | dest_Unprepared (Prepared _) = raise Fail "dest_Unprepared"
   180 fun prepared_axiom ctxt (Unprepared p) = prepare_axiom ctxt p
   181 fun prepared_axiom ctxt (Unprepared p) = prepare_axiom ctxt p
   181   | prepared_axiom _ (Prepared p) = p
   182   | prepared_axiom _ (Prepared p) = p
       
   183 
       
   184 fun int_option_add (SOME m) (SOME n) = SOME (m + n)
       
   185   | int_option_add _ _ = NONE
   182 
   186 
   183 (* Important messages are important but not so important that users want to see
   187 (* Important messages are important but not so important that users want to see
   184    them each time. *)
   188    them each time. *)
   185 val important_message_keep_factor = 0.1
   189 val important_message_keep_factor = 0.1
   186 
   190 
   230         fun as_num f = f >> (fst o read_int);
   234         fun as_num f = f >> (fst o read_int);
   231         val num = as_num (Scan.many1 Symbol.is_ascii_digit);
   235         val num = as_num (Scan.many1 Symbol.is_ascii_digit);
   232         val digit = Scan.one Symbol.is_ascii_digit;
   236         val digit = Scan.one Symbol.is_ascii_digit;
   233         val num3 = as_num (digit ::: digit ::: (digit >> single));
   237         val num3 = as_num (digit ::: digit ::: (digit >> single));
   234         val time = num --| Scan.$$ "." -- num3 >> (fn (a, b) => a * 1000 + b);
   238         val time = num --| Scan.$$ "." -- num3 >> (fn (a, b) => a * 1000 + b);
   235         val as_time = the_default 0 o Scan.read Symbol.stopper time o explode;
   239         val as_time = Scan.read Symbol.stopper time o explode
   236       in (output, as_time t) end;
   240       in (output, as_time t) end;
   237     fun run_on probfile =
   241     fun run_on probfile =
   238       case filter (curry (op =) "" o getenv o fst) (exec :: required_execs) of
   242       case filter (curry (op =) "" o getenv o fst) (exec :: required_execs) of
   239         (home_var, _) :: _ =>
   243         (home_var, _) :: _ =>
   240         error ("The environment variable " ^ quote home_var ^ " is not set.")
   244         error ("The environment variable " ^ quote home_var ^ " is not set.")
   248                   bash_output command
   252                   bash_output command
   249                   |>> (if overlord then
   253                   |>> (if overlord then
   250                          prefix ("% " ^ command ^ "\n% " ^ timestamp () ^ "\n")
   254                          prefix ("% " ^ command ^ "\n% " ^ timestamp () ^ "\n")
   251                        else
   255                        else
   252                          I)
   256                          I)
   253                   |>> (if measure_run_time then split_time else rpair 0)
   257                   |>> (if measure_run_time then split_time else rpair NONE)
   254                 val (tstplike_proof, outcome) =
   258                 val (tstplike_proof, outcome) =
   255                   extract_tstplike_proof_and_outcome complete res_code
   259                   extract_tstplike_proof_and_outcome complete res_code
   256                       proof_delims known_failures output
   260                       proof_delims known_failures output
   257               in (output, msecs, tstplike_proof, outcome) end
   261               in (output, msecs, tstplike_proof, outcome) end
   258             val readable_names = debug andalso overlord
   262             val readable_names = debug andalso overlord
   275                            timeout)
   279                            timeout)
   276               |> run_twice
   280               |> run_twice
   277                  ? (fn (_, msecs0, _, SOME _) =>
   281                  ? (fn (_, msecs0, _, SOME _) =>
   278                        run true (Time.- (timeout, Timer.checkRealTimer timer))
   282                        run true (Time.- (timeout, Timer.checkRealTimer timer))
   279                        |> (fn (output, msecs, tstplike_proof, outcome) =>
   283                        |> (fn (output, msecs, tstplike_proof, outcome) =>
   280                               (output, msecs0 + msecs, tstplike_proof, outcome))
   284                               (output, int_option_add msecs0 msecs,
       
   285                                tstplike_proof, outcome))
   281                      | result => result)
   286                      | result => result)
   282           in ((pool, conjecture_shape, axiom_names), result) end
   287           in ((pool, conjecture_shape, axiom_names), result) end
   283         else
   288         else
   284           error ("Bad executable: " ^ Path.implode command ^ ".")
   289           error ("Bad executable: " ^ Path.implode command ^ ".")
   285 
   290 
   310             (pool, debug, isar_shrink_factor, ctxt, conjecture_shape)
   315             (pool, debug, isar_shrink_factor, ctxt, conjecture_shape)
   311             (proof_banner auto, full_types, minimize_command, tstplike_proof,
   316             (proof_banner auto, full_types, minimize_command, tstplike_proof,
   312              axiom_names, goal, subgoal)
   317              axiom_names, goal, subgoal)
   313         |>> (fn message =>
   318         |>> (fn message =>
   314                 message ^ (if verbose then
   319                 message ^ (if verbose then
   315                              "\nATP real CPU time: " ^ string_of_int msecs ^
   320                              "\nATP real CPU time: " ^
   316                              " ms."
   321                              string_of_int (the msecs) ^ " ms."
   317                            else
   322                            else
   318                              "") ^
   323                              "") ^
   319                 (if important_message <> "" then
   324                 (if important_message <> "" then
   320                    "\n\nImportant message from Dr. Geoff Sutcliffe:\n" ^
   325                    "\n\nImportant message from Dr. Geoff Sutcliffe:\n" ^
   321                    important_message
   326                    important_message
   325   in
   330   in
   326     {outcome = outcome, message = message, used_axioms = used_axioms,
   331     {outcome = outcome, message = message, used_axioms = used_axioms,
   327      run_time_in_msecs = msecs}
   332      run_time_in_msecs = msecs}
   328   end
   333   end
   329 
   334 
   330 fun run_atp thy name = atp_fun false name (get_atp thy name)
   335 fun get_atp_as_prover thy name = atp_fun false name (get_atp thy name)
   331 
   336 
   332 fun run_atp_somehow (params as {blocking, debug, max_relevant, timeout,
   337 fun run_atp_somehow (params as {blocking, debug, max_relevant, timeout,
   333                                 expect, ...})
   338                                 expect, ...})
   334                     auto i n minimize_command
   339                     auto i n minimize_command
   335                     (prover_problem as {state, goal, axioms, ...})
   340                     (problem as {state, goal, axioms, ...})
   336                     (prover as {default_max_relevant, ...}, atp_name) =
   341                     (prover as {default_max_relevant, ...}, atp_name) =
   337   let
   342   let
   338     val ctxt = Proof.context_of state
   343     val ctxt = Proof.context_of state
   339     val birth_time = Time.now ()
   344     val birth_time = Time.now ()
   340     val death_time = Time.+ (birth_time, timeout)
   345     val death_time = Time.+ (birth_time, timeout)
   343     val desc = prover_description ctxt params atp_name num_axioms i n goal
   348     val desc = prover_description ctxt params atp_name num_axioms i n goal
   344     fun go () =
   349     fun go () =
   345       let
   350       let
   346         fun really_go () =
   351         fun really_go () =
   347           atp_fun auto atp_name prover params (minimize_command atp_name)
   352           atp_fun auto atp_name prover params (minimize_command atp_name)
   348                   prover_problem
   353                   problem
   349           |> (fn {outcome, message, ...} =>
   354           |> (fn {outcome, message, ...} =>
   350                  (if is_some outcome then "none" else "some", message))
   355                  (if is_some outcome then "none" else "some", message))
   351         val (outcome_code, message) =
   356         val (outcome_code, message) =
   352           if debug then
   357           if debug then
   353             really_go ()
   358             really_go ()
   381       (Async_Manager.launch das_Tool birth_time death_time desc (snd o go);
   386       (Async_Manager.launch das_Tool birth_time death_time desc (snd o go);
   382        (false, state))
   387        (false, state))
   383   end
   388   end
   384 
   389 
   385 (* FIXME: dummy *)
   390 (* FIXME: dummy *)
   386 fun is_smt_solver_installed () = true
   391 fun run_smt_solver remote timeout state axioms i =
   387 
   392   {outcome = NONE, used_axioms = axioms |> take 5 |> map fst,
   388 (* FIXME: dummy *)
   393    run_time_in_msecs = NONE}
   389 fun raw_run_smt_solver remote timeout state axioms i =
   394 
   390   ("", axioms |> take 5 |> map fst)
   395 fun get_smt_solver_as_prover remote ({timeout, ...} : params) minimize_command
   391 
   396                              ({state, subgoal, axioms, ...} : prover_problem) =
   392 fun run_smt_solver remote ({timeout, ...} : params) minimize_command
   397   let
   393                    ({state, subgoal, axioms, ...} : prover_problem) =
   398     val {outcome, used_axioms, run_time_in_msecs} =
   394   raw_run_smt_solver remote timeout state
   399       run_smt_solver remote timeout state
   395                      (map_filter (try dest_Unprepared) axioms) subgoal
   400                      (map_filter (try dest_Unprepared) axioms) subgoal
   396 
   401     val message =
   397 fun run_smt_solver_somehow state (params as {timeout, ...}) i n goal axioms
   402       if outcome = NONE then
       
   403         sendback_line (proof_banner false)
       
   404                       (apply_on_subgoal subgoal (subgoal_count state) ^
       
   405                        command_call smtN (map fst used_axioms))
       
   406       else
       
   407         ""
       
   408   in
       
   409     {outcome = outcome, used_axioms = used_axioms,
       
   410      run_time_in_msecs = run_time_in_msecs, message = message}
       
   411   end
       
   412 
       
   413 fun get_prover thy name =
       
   414   if member (op =) smt_prover_names name then
       
   415     get_smt_solver_as_prover (String.isPrefix remote_prefix)
       
   416   else
       
   417     get_atp_as_prover thy name
       
   418 
       
   419 fun run_smt_solver_somehow state params minimize_command i n goal axioms
   398                            (remote, name) =
   420                            (remote, name) =
   399   let
   421   let
   400     val ctxt = Proof.context_of state
   422     val ctxt = Proof.context_of state
   401     val desc = prover_description ctxt params name (length axioms) i n goal
   423     val desc = prover_description ctxt params name (length axioms) i n goal
   402     val (failure, used_axioms) =
   424     val problem =
   403       raw_run_smt_solver remote timeout state axioms i
   425       {state = state, goal = goal, subgoal = i,
   404     val success = (failure = "")
   426        axioms = axioms |> map Unprepared, only = true}
   405     val message =
   427     val {outcome, used_axioms, message, ...} =
   406       das_Tool ^ ": " ^ desc ^ "\n" ^
   428       get_smt_solver_as_prover remote params minimize_command problem
   407       (if success then
   429     val _ =
   408          sendback_line (proof_banner false)
   430       priority (das_Tool ^ ": " ^ desc ^ "\n" ^
   409                        (apply_on_subgoal i n ^
   431                 (if outcome = NONE then message
   410                         command_call "smt" (map fst used_axioms))
   432                  else "An unknown error occurred."))
   411        else
   433   in outcome = NONE end
   412          "Error: " ^ failure)
       
   413   in priority message; success end
       
   414 
       
   415 val smt_default_max_relevant = 300 (* FUDGE *)
       
   416 val auto_max_relevant_divisor = 2 (* FUDGE *)
       
   417 
   434 
   418 fun run_sledgehammer (params as {blocking, provers, full_types,
   435 fun run_sledgehammer (params as {blocking, provers, full_types,
   419                                  relevance_thresholds, max_relevant, timeout,
   436                                  relevance_thresholds, max_relevant, timeout,
   420                                  ...})
   437                                  ...})
   421                      auto i (relevance_override as {only, ...}) minimize_command
   438                      auto i (relevance_override as {only, ...}) minimize_command
   431       val {context = ctxt, facts = chained_ths, goal} = Proof.goal state
   448       val {context = ctxt, facts = chained_ths, goal} = Proof.goal state
   432       val (_, hyp_ts, concl_t) = strip_subgoal goal i
   449       val (_, hyp_ts, concl_t) = strip_subgoal goal i
   433       val _ = () |> not blocking ? kill_provers
   450       val _ = () |> not blocking ? kill_provers
   434       val _ = if auto then () else priority "Sledgehammering..."
   451       val _ = if auto then () else priority "Sledgehammering..."
   435       val (smts, atps) =
   452       val (smts, atps) =
   436         provers |> List.partition (member (op =) smt_names)
   453         provers |> List.partition (member (op =) smt_prover_names)
   437                 |>> (take 1 #> map (`(String.isPrefix remote_prefix)))
   454                 |>> (take 1 #> map (`(String.isPrefix remote_prefix)))
   438                 ||> map (`(get_atp thy))
   455                 ||> map (`(get_atp thy))
   439       fun run_atps (res as (success, state)) =
   456       fun run_atps (res as (success, state)) =
   440         if success orelse null atps then
   457         if success orelse null atps then
   441           res
   458           res
   449                   |> auto ? (fn n => n div auto_max_relevant_divisor)
   466                   |> auto ? (fn n => n div auto_max_relevant_divisor)
   450             val axioms =
   467             val axioms =
   451               relevant_facts ctxt full_types relevance_thresholds
   468               relevant_facts ctxt full_types relevance_thresholds
   452                              max_max_relevant relevance_override chained_ths
   469                              max_max_relevant relevance_override chained_ths
   453                              hyp_ts concl_t
   470                              hyp_ts concl_t
   454             val prover_problem =
   471             val problem =
   455               {state = state, goal = goal, subgoal = i,
   472               {state = state, goal = goal, subgoal = i,
   456                axioms = axioms |> map (Prepared o prepare_axiom ctxt),
   473                axioms = axioms |> map (Prepared o prepare_axiom ctxt),
   457                only = only}
   474                only = only}
   458             val run_atp_somehow =
   475             val run_atp_somehow =
   459               run_atp_somehow params auto i n minimize_command prover_problem
   476               run_atp_somehow params auto i n minimize_command problem
   460           in
   477           in
   461             if auto then
   478             if auto then
   462               fold (fn prover => fn (true, state) => (true, state)
   479               fold (fn prover => fn (true, state) => (true, state)
   463                                   | (false, _) => run_atp_somehow prover)
   480                                   | (false, _) => run_atp_somehow prover)
   464                    atps (false, state)
   481                    atps (false, state)
   476             val axioms =
   493             val axioms =
   477               relevant_facts ctxt full_types relevance_thresholds
   494               relevant_facts ctxt full_types relevance_thresholds
   478                              max_relevant relevance_override chained_ths
   495                              max_relevant relevance_override chained_ths
   479                              hyp_ts concl_t
   496                              hyp_ts concl_t
   480           in
   497           in
   481             smts |> map (run_smt_solver_somehow state params i n goal axioms)
   498             smts |> map (run_smt_solver_somehow state params minimize_command i
       
   499                                                 n goal axioms)
   482                  |> exists I |> rpair state
   500                  |> exists I |> rpair state
   483           end
   501           end
   484       fun run_atps_and_smt_solvers () =
   502       fun run_atps_and_smt_solvers () =
   485         [run_atps, run_smt_solvers]
   503         [run_atps, run_smt_solvers]
   486         |> Par_List.map (fn f => f (false, state) |> K ())
   504         |> Par_List.map (fn f => f (false, state) |> K ())