src/HOL/Tools/ATP_Manager/atp_manager.ML
changeset 37583 9ce2451647d5
parent 37581 03edc498db6f
child 37584 2e289dc13615
equal deleted inserted replaced
37582:f329e1b99ce6 37583:9ce2451647d5
    65 struct
    65 struct
    66 
    66 
    67 open Metis_Clauses
    67 open Metis_Clauses
    68 open Sledgehammer_Fact_Filter
    68 open Sledgehammer_Fact_Filter
    69 open Sledgehammer_Proof_Reconstruct
    69 open Sledgehammer_Proof_Reconstruct
       
    70 open Async_Manager
       
    71 
       
    72 (** The Sledgehammer **)
       
    73 
       
    74 fun kill_atps () = kill_threads "ATPs"
       
    75 fun running_atps () = running_threads "ATPs"
       
    76 val messages = thread_messages "ATP"
    70 
    77 
    71 (** problems, results, provers, etc. **)
    78 (** problems, results, provers, etc. **)
    72 
    79 
    73 type params =
    80 type params =
    74   {debug: bool,
    81   {debug: bool,
   110    filtered_clauses: cnf_thm list}
   117    filtered_clauses: cnf_thm list}
   111 
   118 
   112 type prover =
   119 type prover =
   113   params -> minimize_command -> Time.time -> problem -> prover_result
   120   params -> minimize_command -> Time.time -> problem -> prover_result
   114 
   121 
   115 
       
   116 (** preferences **)
       
   117 
       
   118 val message_store_limit = 20;
       
   119 val message_display_limit = 5;
       
   120 
       
   121 
       
   122 (** thread management **)
       
   123 
       
   124 (* data structures over threads *)
       
   125 
       
   126 structure Thread_Heap = Heap
       
   127 (
       
   128   type elem = Time.time * Thread.thread;
       
   129   fun ord ((a, _), (b, _)) = Time.compare (a, b);
       
   130 );
       
   131 
       
   132 fun lookup_thread xs = AList.lookup Thread.equal xs;
       
   133 fun delete_thread xs = AList.delete Thread.equal xs;
       
   134 fun update_thread xs = AList.update Thread.equal xs;
       
   135 
       
   136 
       
   137 (* state of thread manager *)
       
   138 
       
   139 type state =
       
   140  {manager: Thread.thread option,
       
   141   timeout_heap: Thread_Heap.T,
       
   142   active: (Thread.thread * (Time.time * Time.time * string)) list,
       
   143   canceling: (Thread.thread * (Time.time * string)) list,
       
   144   messages: string list,
       
   145   store: string list};
       
   146 
       
   147 fun make_state manager timeout_heap active canceling messages store : state =
       
   148   {manager = manager, timeout_heap = timeout_heap, active = active,
       
   149    canceling = canceling, messages = messages, store = store}
       
   150 
       
   151 val global_state = Synchronized.var "atp_manager"
       
   152   (make_state NONE Thread_Heap.empty [] [] [] []);
       
   153 
       
   154 
       
   155 (* unregister ATP thread *)
       
   156 
       
   157 fun unregister verbose message thread =
       
   158   Synchronized.change global_state
       
   159   (fn state as {manager, timeout_heap, active, canceling, messages, store} =>
       
   160     (case lookup_thread active thread of
       
   161       SOME (birth_time, _, desc) =>
       
   162         let
       
   163           val active' = delete_thread thread active;
       
   164           val now = Time.now ()
       
   165           val canceling' = (thread, (now, desc)) :: canceling
       
   166           val message' =
       
   167             desc ^ "\n" ^ message ^
       
   168             (if verbose then
       
   169                "Total time: " ^ Int.toString (Time.toMilliseconds
       
   170                                           (Time.- (now, birth_time))) ^ " ms.\n"
       
   171              else
       
   172                "")
       
   173           val messages' = message' :: messages;
       
   174           val store' = message' ::
       
   175             (if length store <= message_store_limit then store
       
   176              else #1 (chop message_store_limit store));
       
   177         in make_state manager timeout_heap active' canceling' messages' store' end
       
   178     | NONE => state));
       
   179 
       
   180 
       
   181 (* main manager thread -- only one may exist *)
       
   182 
       
   183 val min_wait_time = Time.fromMilliseconds 300;
       
   184 val max_wait_time = Time.fromSeconds 10;
       
   185 
       
   186 fun replace_all bef aft =
       
   187   let
       
   188     fun aux seen "" = String.implode (rev seen)
       
   189       | aux seen s =
       
   190         if String.isPrefix bef s then
       
   191           aux seen "" ^ aft ^ aux [] (unprefix bef s)
       
   192         else
       
   193           aux (String.sub (s, 0) :: seen) (String.extract (s, 1, NONE))
       
   194   in aux [] end
       
   195 
       
   196 (* This is a workaround for Proof General's off-by-a-few sendback display bug,
       
   197    whereby "pr" in "proof" is not highlighted. *)
       
   198 val break_into_chunks =
       
   199   map (replace_all "\n\n" "\000") #> maps (space_explode "\000")
       
   200 
       
   201 fun print_new_messages () =
       
   202   case Synchronized.change_result global_state
       
   203          (fn {manager, timeout_heap, active, canceling, messages, store} =>
       
   204              (messages, make_state manager timeout_heap active canceling []
       
   205                                    store)) of
       
   206     [] => ()
       
   207   | msgs =>
       
   208     msgs |> break_into_chunks
       
   209          |> (fn msg :: msgs => "Sledgehammer: " ^ msg :: msgs)
       
   210          |> List.app priority
       
   211 
       
   212 fun check_thread_manager verbose = Synchronized.change global_state
       
   213   (fn state as {manager, timeout_heap, active, canceling, messages, store} =>
       
   214     if (case manager of SOME thread => Thread.isActive thread | NONE => false) then state
       
   215     else let val manager = SOME (Toplevel.thread false (fn () =>
       
   216       let
       
   217         fun time_limit timeout_heap =
       
   218           (case try Thread_Heap.min timeout_heap of
       
   219             NONE => Time.+ (Time.now (), max_wait_time)
       
   220           | SOME (time, _) => time);
       
   221 
       
   222         (*action: find threads whose timeout is reached, and interrupt canceling threads*)
       
   223         fun action {manager, timeout_heap, active, canceling, messages, store} =
       
   224           let val (timeout_threads, timeout_heap') =
       
   225             Thread_Heap.upto (Time.now (), Thread.self ()) timeout_heap;
       
   226           in
       
   227             if null timeout_threads andalso null canceling
       
   228             then NONE
       
   229             else
       
   230               let
       
   231                 val _ = List.app (Simple_Thread.interrupt o #1) canceling
       
   232                 val canceling' = filter (Thread.isActive o #1) canceling
       
   233                 val state' = make_state manager timeout_heap' active canceling' messages store;
       
   234               in SOME (map #2 timeout_threads, state') end
       
   235           end;
       
   236       in
       
   237         while Synchronized.change_result global_state
       
   238           (fn state as {timeout_heap, active, canceling, messages, store, ...} =>
       
   239             if null active andalso null canceling andalso null messages
       
   240             then (false, make_state NONE timeout_heap active canceling messages store)
       
   241             else (true, state))
       
   242         do
       
   243           (Synchronized.timed_access global_state (SOME o time_limit o #timeout_heap) action
       
   244             |> these
       
   245             |> List.app (unregister verbose "Timed out.\n");
       
   246             print_new_messages ();
       
   247             (*give threads some time to respond to interrupt*)
       
   248             OS.Process.sleep min_wait_time)
       
   249       end))
       
   250     in make_state manager timeout_heap active canceling messages store end)
       
   251 
       
   252 
       
   253 (* register ATP thread *)
       
   254 
       
   255 fun register verbose birth_time death_time (thread, desc) =
       
   256  (Synchronized.change global_state
       
   257     (fn {manager, timeout_heap, active, canceling, messages, store} =>
       
   258       let
       
   259         val timeout_heap' = Thread_Heap.insert (death_time, thread) timeout_heap;
       
   260         val active' = update_thread (thread, (birth_time, death_time, desc)) active;
       
   261         val state' = make_state manager timeout_heap' active' canceling messages store;
       
   262       in state' end);
       
   263   check_thread_manager verbose);
       
   264 
       
   265 
       
   266 
       
   267 (** user commands **)
       
   268 
       
   269 (* kill ATPs *)
       
   270 
       
   271 fun kill_atps () = Synchronized.change global_state
       
   272   (fn {manager, timeout_heap, active, canceling, messages, store} =>
       
   273     let
       
   274       val killing = map (fn (th, (_, _, desc)) => (th, (Time.now (), desc))) active;
       
   275       val state' = make_state manager timeout_heap [] (killing @ canceling) messages store;
       
   276       val _ = if null active then ()
       
   277               else priority "Killed active Sledgehammer threads."
       
   278     in state' end);
       
   279 
       
   280 
       
   281 (* running_atps *)
       
   282 
       
   283 fun seconds time = string_of_int (Time.toSeconds time) ^ "s";
       
   284 
       
   285 fun running_atps () =
       
   286   let
       
   287     val {active, canceling, ...} = Synchronized.value global_state;
       
   288 
       
   289     val now = Time.now ();
       
   290     fun running_info (_, (birth_time, death_time, desc)) =
       
   291       "Running: " ^ seconds (Time.- (now, birth_time)) ^ " -- " ^
       
   292         seconds (Time.- (death_time, now)) ^ " to live:\n" ^ desc;
       
   293     fun canceling_info (_, (deadth_time, desc)) =
       
   294       "Trying to interrupt thread since " ^ seconds (Time.- (now, deadth_time)) ^ ":\n" ^ desc;
       
   295 
       
   296     val running =
       
   297       if null active then "No ATPs running."
       
   298       else space_implode "\n\n" ("Running ATPs:" :: map running_info active);
       
   299     val interrupting =
       
   300       if null canceling then
       
   301         ""
       
   302       else
       
   303         space_implode "\n\n" ("Trying to interrupt the following ATPs:" ::
       
   304                               map canceling_info canceling)
       
   305   in priority (running ^ "\n" ^ interrupting) end;
       
   306 
       
   307 fun messages opt_limit =
       
   308   let
       
   309     val limit = the_default message_display_limit opt_limit;
       
   310     val {store, ...} = Synchronized.value global_state;
       
   311     val header =
       
   312       "Recent ATP messages" ^
       
   313         (if length store <= limit then ":" else " (" ^ string_of_int limit ^ " displayed):");
       
   314   in List.app priority (header :: break_into_chunks (#1 (chop limit store))) end
       
   315 
       
   316 
       
   317 (** The Sledgehammer **)
       
   318 
       
   319 (* named provers *)
   122 (* named provers *)
   320 
   123 
   321 structure Data = Theory_Data
   124 structure Data = Theory_Data
   322 (
   125 (
   323   type T = (prover * stamp) Symtab.table;
   126   type T = (prover * stamp) Symtab.table;
   351     val desc =
   154     val desc =
   352       "ATP " ^ quote name ^ " for subgoal " ^ string_of_int i ^ ":\n" ^
   155       "ATP " ^ quote name ^ " for subgoal " ^ string_of_int i ^ ":\n" ^
   353       Syntax.string_of_term ctxt (Thm.term_of (Thm.cprem_of goal i));
   156       Syntax.string_of_term ctxt (Thm.term_of (Thm.cprem_of goal i));
   354     val _ = Toplevel.thread true (fn () =>
   157     val _ = Toplevel.thread true (fn () =>
   355       let
   158       let
   356         val _ = register verbose birth_time death_time (Thread.self (), desc)
   159         val _ = register "Sledgehammer" verbose birth_time death_time
       
   160                          (Thread.self (), desc)
   357         val problem =
   161         val problem =
   358           {subgoal = i, goal = (ctxt, (facts, goal)),
   162           {subgoal = i, goal = (ctxt, (facts, goal)),
   359            relevance_override = relevance_override, axiom_clauses = NONE,
   163            relevance_override = relevance_override, axiom_clauses = NONE,
   360            filtered_clauses = NONE}
   164            filtered_clauses = NONE}
   361         val message =
   165         val message =