src/HOL/Tools/atp_minimal.ML
author immler@in.tum.de
Mon, 04 May 2009 23:37:39 +0200
changeset 31037 ac8669134e7a
child 31236 2a1f5c87ac28
permissions -rw-r--r--
added Philipp Meyer's implementation of AtpMinimal
together with related changes in the sledgehammer-interface:
adapted type of prover, optional relevance filtering,
public get_prover for registered atps in AtpManager,
included atp_minimize in s/h response;
     1 (*  Title:      HOL/Tools/atp_minimal.ML
     2     Author:     Philipp Meyer, TU Muenchen
     3 
     4 Minimalization of theorem list for metis by using an external automated theorem prover
     5 *)
     6 
     7 structure AtpMinimal =
     8 struct
     9 
    10   (* output control *)
    11   fun debug str = Output.debug (fn () => str)
    12   fun debug_fn f = if !Output.debugging then f() else ()
    13   fun answer str = Output.writeln str
    14   fun println str = Output.priority str
    15 
    16   fun order_unique name_list = OrdList.make (String.collate Char.compare) name_list
    17   fun length_string namelist = Int.toString (length namelist)
    18 
    19   fun print_names name_thms_pairs =
    20     let
    21       val names = (map fst name_thms_pairs)
    22       val ordered = order_unique names
    23     in
    24       app (fn name => (debug ("  " ^ name))) ordered
    25     end
    26 
    27   (* minimalization algorithm *)
    28   local
    29     fun isplit (l,r) [] = (l,r)
    30       | isplit (l,r) (h::[]) = (h::l, r)
    31       | isplit (l,r) (h1::h2::t) = isplit (h1::l, h2::r) t
    32   in
    33     fun split lst = isplit ([],[]) lst
    34   end
    35 
    36   local
    37     fun min p sup [] = raise Empty
    38       | min p sup [s0] = [s0]
    39       | min p sup s =
    40         let
    41           val (l0, r0) = split s
    42         in
    43           if p(sup @ l0)
    44           then min p sup l0
    45           else
    46             if p(sup @ r0)
    47             then min p sup r0
    48             else
    49               let
    50                 val l = min p (sup @ r0) l0
    51                 val r = min p (sup @ l) r0
    52               in
    53                 l @ r
    54               end
    55         end
    56   in
    57     (* return a minimal subset v of s that satisfies p
    58      @pre p(s) & ~p([]) & monotone(p)
    59      @post v subset s & p(v) &
    60            forall e in v. ~p(v \ e)
    61      *)
    62     fun minimal p s = min p [] s
    63   end
    64 
    65  (* failure check and producing answer*)
    66   datatype 'a prove_result = Success of 'a | Failure | Timeout | Error
    67 
    68   val string_of_result = fn
    69     Success _ => "Success"
    70   | Failure => "Failure"
    71   | Timeout => "Timeout"
    72   | Error => "Error"
    73 
    74   val failure_strings =
    75      [("SPASS beiseite: Ran out of time.", Timeout),
    76      ("Timeout", Timeout),
    77      ("time limit exceeded", Timeout),
    78      ("# Cannot determine problem status within resource limit", Timeout),
    79      ("Error", Error)]
    80 
    81   fun produce_answer (success, message, result_string, thm_name_vec) =
    82     if success then
    83       (Success (Vector.foldr op:: [] thm_name_vec), result_string)
    84     else
    85       let
    86         val failure = get_first (fn (s, t) => if String.isSubstring s result_string then SOME (t, result_string) else NONE) failure_strings
    87       in
    88         if is_some failure then
    89           the failure
    90         else
    91           (Failure, result_string)
    92       end
    93 
    94   (* wrapper for calling external prover *)
    95   fun sh_test_thms prover prover_name time_limit subgoalno state name_thms_pairs =
    96     let
    97       val _ = println ("Testing " ^ (length_string name_thms_pairs) ^ " theorems... ")
    98       val name_thm_pairs = flat (map (fn (n, ths) => map_index (fn (i, th) => (n, th)) ths) name_thms_pairs)
    99       val _ = debug_fn (fn () => print_names name_thm_pairs)
   100       val axclauses = ResAxioms.cnf_rules_pairs (Proof.theory_of state) name_thm_pairs
   101       val (result, proof) =
   102         (produce_answer (prover time_limit (SOME axclauses) prover_name subgoalno (Proof.get_goal state)))
   103       val _ = println (string_of_result result)
   104       val _ = debug proof
   105     in
   106       (result, proof)
   107     end
   108 
   109   (* minimalization of thms *)
   110   fun minimalize prover prover_name time_limit state name_thms_pairs =
   111     let
   112       val _ = println ("Minimize called with " ^ (length_string name_thms_pairs) ^ " theorems, prover: "
   113                        ^ prover_name ^ ", time limit: " ^ (Int.toString time_limit) ^ " seconds")
   114       val _ = debug_fn (fn () => app (fn (n, tl) => (debug n; app (fn t => debug ("  " ^ Display.string_of_thm t)) tl)) name_thms_pairs)
   115       val test_thms_fun = sh_test_thms prover prover_name time_limit 1 state
   116       fun test_thms thms = case test_thms_fun thms of (Success _, _) => true | _ => false
   117     in
   118       (* try proove first to check result and get used theorems *)
   119       (case test_thms_fun name_thms_pairs of
   120         (Success used, _) =>
   121           let
   122             val ordered_used = order_unique used
   123             val to_use =
   124               if length ordered_used < length name_thms_pairs then
   125                 filter (fn (name1, _) => List.exists (equal name1) ordered_used) name_thms_pairs
   126               else
   127                 name_thms_pairs
   128             val min_thms = (minimal test_thms to_use)
   129             val min_names = order_unique (map fst min_thms)
   130             val _ = println ("Minimal " ^ (length_string min_thms) ^ " theorems")
   131             val _ = debug_fn (fn () => print_names min_thms)
   132           in
   133             answer ("Try this command: " ^ Markup.markup Markup.sendback ("apply (metis " ^ (space_implode " " min_names) ^ ")"))
   134           end
   135       | (Timeout, _) =>
   136           answer ("Timeout: You may need to increase the time limit of " ^ (Int.toString time_limit) ^ " seconds. Call atp_minimize [time=...] ")
   137       | (Error, msg) =>
   138           answer ("Error in prover: " ^ msg)
   139       | (Failure, _) =>
   140           answer "Failure: No proof with the theorems supplied")
   141       handle ResHolClause.TOO_TRIVIAL =>
   142           answer ("Trivial: Try this command: " ^ Markup.markup Markup.sendback "apply metis")
   143       | ERROR msg =>
   144           answer ("Error: " ^ msg)
   145     end
   146 
   147   (* isar command and parsing input *)
   148 
   149   local structure K = OuterKeyword and P = OuterParse and T = OuterLex in
   150 
   151   fun get_thms context =
   152     map (fn (name, interval) =>
   153       let
   154         val thmref = Facts.Named ((name, Position.none), interval)
   155         val ths = ProofContext.get_fact context thmref
   156         val name' = Facts.string_of_ref thmref
   157       in
   158         (name', ths)
   159       end)
   160 
   161   val default_prover = "remote_vampire"
   162   val default_time_limit = 5
   163 
   164   fun get_time_limit_arg time_string =
   165     (case Int.fromString time_string of
   166       SOME t => t
   167     | NONE => error ("Invalid time limit: " ^ quote time_string))
   168 
   169   val get_options =
   170     let
   171       val def = (default_prover, default_time_limit)
   172     in
   173       foldl (fn ((name, a), (p, t)) => (case name of
   174         "time" => (p, (get_time_limit_arg a))
   175       | "atp" => (a, t)
   176       | n => error ("Invalid argument: " ^ n))) def
   177     end
   178 
   179   fun sh_min_command args thm_names state =
   180     let
   181       val (prover_name, time_limit) = get_options args
   182       val prover =
   183         case AtpManager.get_prover prover_name (Proof.theory_of state) of
   184           SOME prover => prover
   185         | NONE => error ("Unknown prover: " ^ quote prover_name)
   186       val name_thms_pairs = get_thms (Proof.context_of state) thm_names
   187     in
   188       minimalize prover prover_name time_limit state name_thms_pairs
   189     end
   190 
   191   val parse_args = Scan.optional (Args.bracks (P.list (P.xname --| P.$$$ "=" -- P.xname) )) []
   192   val parse_thm_names = Scan.repeat (P.xname -- Scan.option Attrib.thm_sel)
   193 
   194   val _ =
   195     OuterSyntax.command "atp_minimize" "minimize theorem list with external prover" K.diag
   196       (parse_args -- parse_thm_names >> (fn (args, thm_names) =>
   197         Toplevel.no_timing o Toplevel.unknown_proof o Toplevel.keep ((sh_min_command args thm_names) o Toplevel.proof_of)))
   198 
   199   end
   200 end
   201