src/Tools/try.ML
author wenzelm
Sat, 13 Jul 2013 14:11:48 +0200
changeset 52645 e8c1c5612677
parent 52644 cea207576f81
child 52647 45ce95b8bf69
permissions -rw-r--r--
clarified some default options;

(*  Title:      Tools/try.ML
    Author:     Jasmin Blanchette, TU Muenchen

Manager for tools that should be tried on conjectures.
*)

signature TRY =
sig
  type tool =
    string * (int * string * (bool -> Proof.state -> bool * (string * Proof.state)))

  val tryN : string

  val serial_commas : string -> string list -> string list
  val subgoal_count : Proof.state -> int
  val get_tools : theory -> tool list
  val try_tools : Proof.state -> (string * string) option
  val tool_setup : tool -> unit
end;

structure Try : TRY =
struct

type tool =
  string * (int * string * (bool -> Proof.state -> bool * (string * Proof.state)))

val tryN = "try"


(* preferences *)

val _ =
  ProofGeneral.preference_option ProofGeneral.category_tracing
    (SOME "4.0")
    @{option auto_time_limit}
    "auto-try-time-limit"
    "Time limit for automatically tried tools (in seconds)"


(* helpers *)

fun serial_commas _ [] = ["??"]
  | serial_commas _ [s] = [s]
  | serial_commas conj [s1, s2] = [s1, conj, s2]
  | serial_commas conj [s1, s2, s3] = [s1 ^ ",", s2 ^ ",", conj, s3]
  | serial_commas conj (s :: ss) = s ^ "," :: serial_commas conj ss

val subgoal_count = Logic.count_prems o prop_of o #goal o Proof.goal


(* configuration *)

fun tool_ord ((name1, (weight1, _, _)), (name2, (weight2, _, _))) =
  prod_ord int_ord string_ord ((weight1, name1), (weight2, name2))

structure Data = Theory_Data
(
  type T = tool list
  val empty = []
  val extend = I
  fun merge data : T = Ord_List.merge tool_ord data
)

val get_tools = Data.get

val register_tool = Data.map o Ord_List.insert tool_ord


(* try command *)

fun try_tools state =
  if subgoal_count state = 0 then
    (Output.urgent_message "No subgoal!"; NONE)
  else
    get_tools (Proof.theory_of state)
    |> tap (fn tools =>
               "Trying " ^ space_implode " "
                    (serial_commas "and" (map (quote o fst) tools)) ^ "..."
               |> Output.urgent_message)
    |> Par_List.get_some
           (fn (name, (_, _, tool)) =>
               case try (tool false) state of
                 SOME (true, (outcome_code, _)) => SOME (name, outcome_code)
               | _ => NONE)
    |> tap (fn NONE => Output.urgent_message "Tried in vain." | _ => ())

val _ =
  Outer_Syntax.improper_command @{command_spec "try"}
    "try a combination of automatic proving and disproving tools"
    (Scan.succeed (Toplevel.unknown_proof o Toplevel.keep (ignore o try_tools o Toplevel.proof_of)))


(* automatic try (TTY) *)

fun auto_try state =
  get_tools (Proof.theory_of state)
  |> map_filter (fn (_, (_, auto, tool)) => if Options.default_bool auto then SOME tool else NONE)
  |> Par_List.get_some (fn tool =>
                           case try (tool true) state of
                             SOME (true, (_, state)) => SOME state
                           | _ => NONE)
  |> the_default state

val _ = Context.>> (Specification.add_theorem_hook (fn interact => fn state =>
  let
    val auto_time_limit = Options.default_real @{option auto_time_limit}
  in
    if interact andalso not (!Toplevel.quiet) andalso auto_time_limit > 0.0 then
      TimeLimit.timeLimit (seconds auto_time_limit) auto_try state
      handle TimeLimit.TimeOut => state
    else
      state
  end))


(* asynchronous print function (PIDE) *)

fun print_function ((name, (weight, auto, tool)): tool) =
  Command.print_function {name = name, pri = ~ weight, persistent = true}
    (fn {command_name} =>
      if Keyword.is_theory_goal command_name andalso Options.default_bool auto then
        SOME (fn _ => fn st =>
          let
            val auto_time_limit = Options.default_real @{option auto_time_limit}
          in
            if auto_time_limit > 0.0 then
              (case try Toplevel.proof_of st of
                SOME state =>
                  (case
                    (try o TimeLimit.timeLimit (seconds auto_time_limit))
                      (fn () => tool true state) () of
                    SOME (true, (_, state')) =>
                      List.app Pretty.writeln (Proof.pretty_goal_messages state')
                  | _ => ())
              | NONE => ())
            else ()
          end)
      else NONE);


(* hybrid tool setup *)

fun tool_setup tool =
  (Context.>> (Context.map_theory (register_tool tool)); print_function tool);

end;