added 'atp_messages' command, which displays recent messages synchronously;
authorwenzelm
Mon, 15 Dec 2008 21:41:00 +0100
changeset 29112 f2b45eea6dac
parent 29111 d2b60c49a713
child 29113 fb31b7a6c858
added 'atp_messages' command, which displays recent messages synchronously;
doc-src/IsarRef/Thy/HOL_Specific.thy
src/HOL/Tools/atp_manager.ML
--- a/doc-src/IsarRef/Thy/HOL_Specific.thy	Mon Dec 15 10:19:02 2008 +0100
+++ b/doc-src/IsarRef/Thy/HOL_Specific.thy	Mon Dec 15 21:41:00 2008 +0100
@@ -804,12 +804,14 @@
     @{command_def (HOL) "print_atps"}@{text "\<^sup>*"} & : & @{text "context \<rightarrow>"} \\
     @{command_def (HOL) "atp_info"}@{text "\<^sup>*"} & : & @{text "any \<rightarrow>"} \\
     @{command_def (HOL) "atp_kill"}@{text "\<^sup>*"} & : & @{text "any \<rightarrow>"} \\
+    @{command_def (HOL) "atp_messages"}@{text "\<^sup>*"} & : & @{text "any \<rightarrow>"} \\
     @{method_def (HOL) metis} & : & @{text method} \\
   \end{matharray}
 
   \begin{rail}
   'sledgehammer' (nameref *)
   ;
+  'atp\_messages' ('(' nat ')')?
 
   'metis' thmrefs
   ;
@@ -842,6 +844,12 @@
   \item @{command (HOL) atp_kill} terminates all presently running
   provers.
 
+  \item @{command (HOL) atp_messages} displays recent messages issued
+  by automated theorem provers.  This allows to examine results that
+  might have got lost due to the asynchronous nature of default
+  @{command (HOL) sledgehammer} output.  An optional message limit may
+  be specified (default 5).
+
   \item @{method (HOL) metis}~@{text "facts"} invokes the Metis prover
   with the given facts.  Metis is an automated proof tool of medium
   strength, but is fully integrated into Isabelle/HOL, with explicit
--- a/src/HOL/Tools/atp_manager.ML	Mon Dec 15 10:19:02 2008 +0100
+++ b/src/HOL/Tools/atp_manager.ML	Mon Dec 15 21:41:00 2008 +0100
@@ -1,5 +1,4 @@
 (*  Title:      HOL/Tools/atp_manager.ML
-    ID:         $Id$
     Author:     Fabian Immler, TU Muenchen
 
 ATP threads are registered here.
@@ -19,6 +18,7 @@
   val set_timeout: int -> unit
   val kill: unit -> unit
   val info: unit -> unit
+  val messages: int option -> unit
   type prover = int -> Proof.state -> bool * string
   val add_prover: string -> prover -> theory -> theory
   val print_provers: theory -> unit
@@ -30,6 +30,9 @@
 
 (** preferences **)
 
+val message_store_limit = 20;
+val message_display_limit = 5;
+
 local
 
 val atps = ref "e";
@@ -85,13 +88,14 @@
  {timeout_heap: ThreadHeap.T,
   oldest_heap: ThreadHeap.T,
   active: (Thread.thread * (Time.time * Time.time * string)) list,
-  cancelling: (Thread.thread * (Time.time * Time.time * string)) list};
+  cancelling: (Thread.thread * (Time.time * Time.time * string)) list,
+  messages: string list};
 
-fun make_state timeout_heap oldest_heap active cancelling =
+fun make_state timeout_heap oldest_heap active cancelling messages =
   State {timeout_heap = timeout_heap, oldest_heap = oldest_heap,
-    active = active, cancelling = cancelling};
+    active = active, cancelling = cancelling, messages = messages};
 
-val state = Synchronized.var "atp_manager" (make_state ThreadHeap.empty ThreadHeap.empty [] []);
+val state = Synchronized.var "atp_manager" (make_state ThreadHeap.empty ThreadHeap.empty [] [] []);
 
 
 (* the managing thread *)
@@ -103,7 +107,7 @@
 (* unregister thread from thread manager -- move to cancelling *)
 
 fun unregister (success, message) thread = Synchronized.change_result state
-  (fn State {timeout_heap, oldest_heap, active, cancelling} =>
+  (fn State {timeout_heap, oldest_heap, active, cancelling, messages} =>
     let
       val info = lookup_thread active thread
 
@@ -127,7 +131,11 @@
         | SOME (_, _, desc) => "Sledgehammer: " ^ desc ^ "\n" ^ message ^
           (if null group_threads then ""
            else "\nInterrupted " ^ string_of_int (length group_threads - 1) ^ " other group members")
-    in (message', make_state timeout_heap oldest_heap active'' cancelling'') end);
+
+      val messages' = message ::
+       (if length messages < message_store_limit then messages
+        else #1 (chop message_store_limit messages));
+    in (message', make_state timeout_heap oldest_heap active'' cancelling'' messages') end);
 
 
 (* kill excessive atp threads *)
@@ -140,12 +148,13 @@
 
 fun kill_oldest () =
   let exception Unchanged in
-    Synchronized.change_result state (fn State {timeout_heap, oldest_heap, active, cancelling} =>
+    Synchronized.change_result state
+      (fn State {timeout_heap, oldest_heap, active, cancelling, messages} =>
         if ThreadHeap.is_empty oldest_heap orelse not (excessive_atps active)
         then raise Unchanged
         else
           let val ((_, oldest_thread), oldest_heap') = ThreadHeap.min_elem oldest_heap
-          in (oldest_thread, make_state timeout_heap oldest_heap' active cancelling) end)
+          in (oldest_thread, make_state timeout_heap oldest_heap' active cancelling messages) end)
       |> (priority o unregister (false, "Interrupted (maximum number of ATPs exceeded)"))
     handle Unchanged => ()
   end;
@@ -175,7 +184,7 @@
         | SOME (time, _) => SOME time)
 
       (* action: cancel find threads whose timeout is reached, and interrupt cancelling threads *)
-      fun action (State {timeout_heap, oldest_heap, active, cancelling}) =
+      fun action (State {timeout_heap, oldest_heap, active, cancelling, messages}) =
         let val (timeout_threads, timeout_heap') =
           ThreadHeap.upto (Time.now (), Thread.self ()) timeout_heap
         in
@@ -185,7 +194,7 @@
             let
               val _ = List.app (SimpleThread.interrupt o #1) cancelling
               val cancelling' = filter (Thread.isActive o #1) cancelling
-              val state' = make_state timeout_heap' oldest_heap active cancelling'
+              val state' = make_state timeout_heap' oldest_heap active cancelling' messages
             in SOME (map #2 timeout_threads, state') end
         end
     in
@@ -203,12 +212,13 @@
 
 fun register birthtime deadtime (thread, desc) =
  (check_thread_manager ();
-  Synchronized.change state (fn State {timeout_heap, oldest_heap, active, cancelling} =>
-    let
-      val timeout_heap' = ThreadHeap.insert (deadtime, thread) timeout_heap
-      val oldest_heap' = ThreadHeap.insert (birthtime, thread) oldest_heap
-      val active' = update_thread (thread, (birthtime, deadtime, desc)) active
-    in make_state timeout_heap' oldest_heap' active' cancelling end));
+  Synchronized.change state
+    (fn State {timeout_heap, oldest_heap, active, cancelling, messages} =>
+      let
+        val timeout_heap' = ThreadHeap.insert (deadtime, thread) timeout_heap
+        val oldest_heap' = ThreadHeap.insert (birthtime, thread) oldest_heap
+        val active' = update_thread (thread, (birthtime, deadtime, desc)) active
+      in make_state timeout_heap' oldest_heap' active' cancelling messages end));
 
 
 
@@ -217,16 +227,17 @@
 (* kill: move all threads to cancelling *)
 
 fun kill () = Synchronized.change state
-  (fn State {timeout_heap, oldest_heap, active, cancelling} =>
+  (fn State {timeout_heap, oldest_heap, active, cancelling, messages} =>
     let val formerly_active = map (fn (th, (tb, _, desc)) => (th, (tb, Time.now (), desc))) active
-    in make_state timeout_heap oldest_heap [] (formerly_active @ cancelling) end);
+    in make_state timeout_heap oldest_heap [] (formerly_active @ cancelling) messages end);
 
 
-(* info: information on running threads *)
+(* ATP info *)
 
 fun info () =
   let
-    val State {timeout_heap, oldest_heap, active, cancelling} = Synchronized.value state
+    val State {active, cancelling, ...} = Synchronized.value state
+
     fun running_info (_, (birth_time, dead_time, desc)) = "Running: "
         ^ (string_of_int o Time.toSeconds) (Time.- (Time.now (), birth_time))
         ^ " s  --  "
@@ -235,6 +246,7 @@
     fun cancelling_info (_, (_, dead_time, desc)) = "Trying to interrupt thread since "
         ^ (string_of_int o Time.toSeconds) (Time.- (Time.now (), dead_time))
         ^ " s:\n" ^ desc
+
     val running =
       if null active then "No ATPs running."
       else space_implode "\n\n" ("Running ATPs:" :: map running_info active)
@@ -242,8 +254,17 @@
       if null cancelling then ""
       else space_implode "\n\n"
         ("Trying to interrupt the following ATPs:" :: map cancelling_info cancelling)
+
   in writeln (running ^ "\n" ^ interrupting) end;
 
+fun messages opt_limit =
+  let
+    val limit = the_default message_display_limit opt_limit;
+    val State {messages = msgs, ...} = Synchronized.value state
+    val header = "Recent ATP messages" ^
+      (if length msgs <= limit then ":" else " (" ^ string_of_int limit ^ " displayed):");
+  in writeln (cat_lines (header :: "" :: #1 (chop limit msgs))) end;
+
 
 
 (** The Sledgehammer **)
@@ -322,6 +343,11 @@
     (Scan.succeed (Toplevel.no_timing o Toplevel.imperative info));
 
 val _ =
+  OuterSyntax.improper_command "atp_messages" "print recent messages issued by managed provers" K.diag
+    (Scan.option (P.$$$ "(" |-- P.nat --| P.$$$ ")") >>
+      (fn limit => Toplevel.no_timing o Toplevel.imperative (fn () => messages limit)));
+
+val _ =
   OuterSyntax.improper_command "print_atps" "print external provers" K.diag
     (Scan.succeed (Toplevel.no_timing o Toplevel.unknown_theory o
       Toplevel.keep (print_provers o Toplevel.theory_of)));
@@ -329,7 +355,7 @@
 val _ =
   OuterSyntax.command "sledgehammer" "call all automatic theorem provers" K.diag
     (Scan.repeat P.xname >> (fn names => Toplevel.no_timing o Toplevel.unknown_proof o
-    Toplevel.keep ((sledgehammer names) o Toplevel.proof_of)));
+      Toplevel.keep ((sledgehammer names) o Toplevel.proof_of)));
 
 end;