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