src/HOL/Tools/Sledgehammer/sledgehammer_mash.ML
changeset 55286 7bbbd9393ce0
parent 55202 824c48a539c9
child 55642 63beb38e9258
equal deleted inserted replaced
55285:e88ad20035f4 55286:7bbbd9393ce0
   176       " >& " ^ err_file ^
   176       " >& " ^ err_file ^
   177       (if background then " &" else "")
   177       (if background then " &" else "")
   178     fun run_on () =
   178     fun run_on () =
   179       (Isabelle_System.bash command
   179       (Isabelle_System.bash command
   180        |> tap (fn _ =>
   180        |> tap (fn _ =>
   181             case try File.read (Path.explode err_file) |> the_default "" of
   181             (case try File.read (Path.explode err_file) |> the_default "" of
   182               "" => trace_msg ctxt (K "Done")
   182               "" => trace_msg ctxt (K "Done")
   183             | s => warning ("MaSh error: " ^ elide_string 1000 s));
   183             | s => warning ("MaSh error: " ^ elide_string 1000 s)));
   184        read_suggs (fn () => try File.read_lines sugg_path |> these))
   184        read_suggs (fn () => try File.read_lines sugg_path |> these))
   185     fun clean_up () =
   185     fun clean_up () =
   186       if overlord then ()
   186       if overlord then ()
   187       else List.app wipe_out_file [err_file, sugg_file, cmd_file]
   187       else List.app wipe_out_file [err_file, sugg_file, cmd_file]
   188   in
   188   in
   241   encode_features feats ^
   241   encode_features feats ^
   242   (if null hints then "" else "; " ^ encode_strs hints) ^ "\n"
   242   (if null hints then "" else "; " ^ encode_strs hints) ^ "\n"
   243 
   243 
   244 (* The suggested weights don't make much sense. *)
   244 (* The suggested weights don't make much sense. *)
   245 fun extract_suggestion sugg =
   245 fun extract_suggestion sugg =
   246   case space_explode "=" sugg of
   246   (case space_explode "=" sugg of
   247     [name, _ (* weight *)] =>
   247     [name, _ (* weight *)] =>
   248     SOME (unencode_str name (* , Real.fromString weight |> the_default 1.0 *))
   248     SOME (unencode_str name (* , Real.fromString weight |> the_default 1.0 *))
   249   | [name] => SOME (unencode_str name (* , 1.0 *))
   249   | [name] => SOME (unencode_str name (* , 1.0 *))
   250   | _ => NONE
   250   | _ => NONE)
   251 
   251 
   252 fun extract_suggestions line =
   252 fun extract_suggestions line =
   253   case space_explode ":" line of
   253   (case space_explode ":" line of
   254     [goal, suggs] =>
   254     [goal, suggs] => (unencode_str goal, map_filter extract_suggestion (space_explode " " suggs))
   255     (unencode_str goal, map_filter extract_suggestion (space_explode " " suggs))
   255   | _ => ("", []))
   256   | _ => ("", [])
       
   257 
   256 
   258 structure MaSh =
   257 structure MaSh =
   259 struct
   258 struct
   260 
   259 
   261 fun shutdown ctxt overlord =
   260 fun shutdown ctxt overlord =
   292      run_mash_tool ctxt overlord ([] |> save ? cons save_models_arg) false
   291      run_mash_tool ctxt overlord ([] |> save ? cons save_models_arg) false
   293                    (relearns, str_of_relearn) (K ()))
   292                    (relearns, str_of_relearn) (K ()))
   294 
   293 
   295 fun query ctxt overlord max_suggs (query as (_, _, _, feats)) =
   294 fun query ctxt overlord max_suggs (query as (_, _, _, feats)) =
   296   (trace_msg ctxt (fn () => "MaSh query " ^ encode_features feats);
   295   (trace_msg ctxt (fn () => "MaSh query " ^ encode_features feats);
   297    run_mash_tool ctxt overlord [] false ([query], str_of_query max_suggs)
   296    run_mash_tool ctxt overlord [] false ([query], str_of_query max_suggs) (fn suggs =>
   298        (fn suggs =>
   297      (case suggs () of
   299            case suggs () of
   298        [] => []
   300              [] => []
   299      | suggs => snd (extract_suggestions (List.last suggs))))
   301            | suggs => snd (extract_suggestions (List.last suggs)))
       
   302    handle List.Empty => [])
   300    handle List.Empty => [])
   303 
   301 
   304 end;
   302 end;
   305 
   303 
   306 
   304 
   360 val version = "*** MaSh version 20131206 ***"
   358 val version = "*** MaSh version 20131206 ***"
   361 
   359 
   362 exception FILE_VERSION_TOO_NEW of unit
   360 exception FILE_VERSION_TOO_NEW of unit
   363 
   361 
   364 fun extract_node line =
   362 fun extract_node line =
   365   case space_explode ":" line of
   363   (case space_explode ":" line of
   366     [head, parents] =>
   364     [head, parents] =>
   367     (case space_explode " " head of
   365     (case space_explode " " head of
   368        [kind, name] =>
   366       [kind, name] =>
   369        SOME (unencode_str name, unencode_strs parents,
   367       SOME (unencode_str name, unencode_strs parents,
   370              try proof_kind_of_str kind |> the_default Isar_Proof)
   368         try proof_kind_of_str kind |> the_default Isar_Proof)
   371      | _ => NONE)
   369     | _ => NONE)
   372   | _ => NONE
   370   | _ => NONE)
   373 
   371 
   374 fun load_state _ _ (state as (true, _)) = state
   372 fun load_state _ _ (state as (true, _)) = state
   375   | load_state ctxt overlord _ =
   373   | load_state ctxt overlord _ =
   376     let val path = mash_state_file () in
   374     let val path = mash_state_file () in
   377       (true,
   375       (true,
   378        case try File.read_lines path of
   376        (case try File.read_lines path of
   379          SOME (version' :: node_lines) =>
   377          SOME (version' :: node_lines) =>
   380          let
   378          let
   381            fun add_edge_to name parent =
   379            fun add_edge_to name parent =
   382              Graph.default_node (parent, Isar_Proof)
   380              Graph.default_node (parent, Isar_Proof)
   383              #> Graph.add_edge (parent, name)
   381              #> Graph.add_edge (parent, name)
   384            fun add_node line =
   382            fun add_node line =
   385              case extract_node line of
   383              (case extract_node line of
   386                NONE => I (* shouldn't happen *)
   384                NONE => I (* shouldn't happen *)
   387              | SOME (name, parents, kind) =>
   385              | SOME (name, parents, kind) =>
   388                update_access_graph_node (name, kind)
   386                update_access_graph_node (name, kind) #> fold (add_edge_to name) parents)
   389                #> fold (add_edge_to name) parents
       
   390            val (access_G, num_known_facts) =
   387            val (access_G, num_known_facts) =
   391              case string_ord (version', version) of
   388              (case string_ord (version', version) of
   392                EQUAL =>
   389                EQUAL =>
   393                (try_graph ctxt "loading state" Graph.empty (fn () =>
   390                (try_graph ctxt "loading state" Graph.empty (fn () =>
   394                     fold add_node node_lines Graph.empty),
   391                   fold add_node node_lines Graph.empty),
   395                 length node_lines)
   392                 length node_lines)
   396              | LESS =>
   393              | LESS =>
   397                (* can't parse old file *)
   394                (* can't parse old file *)
   398                (MaSh.unlearn ctxt overlord; (Graph.empty, 0))
   395                (MaSh.unlearn ctxt overlord; (Graph.empty, 0))
   399              | GREATER => raise FILE_VERSION_TOO_NEW ()
   396              | GREATER => raise FILE_VERSION_TOO_NEW ())
   400          in
   397          in
   401            trace_msg ctxt (fn () =>
   398            trace_msg ctxt (fn () =>
   402                "Loaded fact graph (" ^ graph_info access_G ^ ")");
   399                "Loaded fact graph (" ^ graph_info access_G ^ ")");
   403            {access_G = access_G, num_known_facts = num_known_facts,
   400            {access_G = access_G, num_known_facts = num_known_facts,
   404             dirty = SOME []}
   401             dirty = SOME []}
   405          end
   402          end
   406        | _ => empty_state)
   403        | _ => empty_state))
   407     end
   404     end
   408 
   405 
   409 fun save_state _ (state as {dirty = SOME [], ...}) = state
   406 fun save_state _ (state as {dirty = SOME [], ...}) = state
   410   | save_state ctxt {access_G, num_known_facts, dirty} =
   407   | save_state ctxt {access_G, num_known_facts, dirty} =
   411     let
   408     let
   413         str_of_proof_kind kind ^ " " ^ encode_str name ^ ": " ^
   410         str_of_proof_kind kind ^ " " ^ encode_str name ^ ": " ^
   414         encode_strs parents ^ "\n"
   411         encode_strs parents ^ "\n"
   415       fun append_entry (name, (kind, (parents, _))) =
   412       fun append_entry (name, (kind, (parents, _))) =
   416         cons (name, Graph.Keys.dest parents, kind)
   413         cons (name, Graph.Keys.dest parents, kind)
   417       val (banner, entries) =
   414       val (banner, entries) =
   418         case dirty of
   415         (case dirty of
   419           SOME names =>
   416           SOME names => (NONE, fold (append_entry o Graph.get_entry access_G) names [])
   420           (NONE, fold (append_entry o Graph.get_entry access_G) names [])
   417         | NONE => (SOME (version ^ "\n"), Graph.fold append_entry access_G []))
   421         | NONE => (SOME (version ^ "\n"), Graph.fold append_entry access_G [])
       
   422     in
   418     in
   423       write_file banner (entries, str_of_entry) (mash_state_file ());
   419       write_file banner (entries, str_of_entry) (mash_state_file ());
   424       trace_msg ctxt (fn () =>
   420       trace_msg ctxt (fn () =>
   425           "Saved fact graph (" ^ graph_info access_G ^
   421           "Saved fact graph (" ^ graph_info access_G ^
   426           (case dirty of
   422           (case dirty of
   469 
   465 
   470 fun nickname_of_thm th =
   466 fun nickname_of_thm th =
   471   if Thm.has_name_hint th then
   467   if Thm.has_name_hint th then
   472     let val hint = Thm.get_name_hint th in
   468     let val hint = Thm.get_name_hint th in
   473       (* There must be a better way to detect local facts. *)
   469       (* There must be a better way to detect local facts. *)
   474       case try (unprefix local_prefix) hint of
   470       (case try (unprefix local_prefix) hint of
   475         SOME suf =>
   471         SOME suf =>
   476         thy_name_of_thm th ^ Long_Name.separator ^ suf ^
   472         thy_name_of_thm th ^ Long_Name.separator ^ suf ^ Long_Name.separator ^
   477         Long_Name.separator ^ elided_backquote_thm 50 th
   473         elided_backquote_thm 50 th
   478       | NONE => hint
   474       | NONE => hint)
   479     end
   475     end
   480   else
   476   else
   481     elided_backquote_thm 200 th
   477     elided_backquote_thm 200 th
   482 
   478 
   483 fun find_suggested_facts ctxt facts =
   479 fun find_suggested_facts ctxt facts =
   510       val mess = mess |> map (apsnd (apfst (normalize_scores max_facts)))
   506       val mess = mess |> map (apsnd (apfst (normalize_scores max_facts)))
   511       fun score_in fact (global_weight, (sels, unks)) =
   507       fun score_in fact (global_weight, (sels, unks)) =
   512         let
   508         let
   513           val score_at = try (nth sels) #> Option.map (fn (_, score) => global_weight * score)
   509           val score_at = try (nth sels) #> Option.map (fn (_, score) => global_weight * score)
   514         in
   510         in
   515           case find_index (curry fact_eq fact o fst) sels of
   511           (case find_index (curry fact_eq fact o fst) sels of
   516             ~1 => if member fact_eq unks fact then NONE else SOME 0.0
   512             ~1 => if member fact_eq unks fact then NONE else SOME 0.0
   517           | rank => score_at rank
   513           | rank => score_at rank)
   518         end
   514         end
   519       fun weight_of fact = mess |> map_filter (score_in fact) |> scaled_avg
   515       fun weight_of fact = mess |> map_filter (score_in fact) |> scaled_avg
   520       val facts = fold (union fact_eq o map fst o take max_facts o fst o snd) mess []
   516       val facts = fold (union fact_eq o map fst o take max_facts o fst o snd) mess []
   521     in
   517     in
   522       facts |> map (`weight_of) |> sort (int_ord o swap o pairself fst)
   518       facts |> map (`weight_of) |> sort (int_ord o swap o pairself fst)
   534 fun crude_theory_ord p =
   530 fun crude_theory_ord p =
   535   if Theory.subthy p then
   531   if Theory.subthy p then
   536     if Theory.eq_thy p then EQUAL else LESS
   532     if Theory.eq_thy p then EQUAL else LESS
   537   else if Theory.subthy (swap p) then
   533   else if Theory.subthy (swap p) then
   538     GREATER
   534     GREATER
   539   else case int_ord (pairself (length o Theory.ancestors_of) p) of
   535   else
   540     EQUAL => string_ord (pairself Context.theory_name p)
   536     (case int_ord (pairself (length o Theory.ancestors_of) p) of
   541   | order => order
   537       EQUAL => string_ord (pairself Context.theory_name p)
       
   538     | order => order)
   542 
   539 
   543 fun crude_thm_ord p =
   540 fun crude_thm_ord p =
   544   case crude_theory_ord (pairself theory_of_thm p) of
   541   (case crude_theory_ord (pairself theory_of_thm p) of
   545     EQUAL =>
   542     EQUAL =>
   546     let val q = pairself nickname_of_thm p in
   543     let val q = pairself nickname_of_thm p in
   547       (* Hack to put "xxx_def" before "xxxI" and "xxxE" *)
   544       (* Hack to put "xxx_def" before "xxxI" and "xxxE" *)
   548       case bool_ord (pairself (String.isSuffix "_def") (swap q)) of
   545       (case bool_ord (pairself (String.isSuffix "_def") (swap q)) of
   549         EQUAL => string_ord q
   546         EQUAL => string_ord q
   550       | ord => ord
   547       | ord => ord)
   551     end
   548     end
   552   | ord => ord
   549   | ord => ord)
   553 
   550 
   554 val thm_less_eq = Theory.subthy o pairself theory_of_thm
   551 val thm_less_eq = Theory.subthy o pairself theory_of_thm
   555 fun thm_less p = thm_less_eq p andalso not (thm_less_eq (swap p))
   552 fun thm_less p = thm_less_eq p andalso not (thm_less_eq (swap p))
   556 
   553 
   557 val freezeT = Type.legacy_freeze_type
   554 val freezeT = Type.legacy_freeze_type
   722     fun add_term_pats _ 0 _ = I
   719     fun add_term_pats _ 0 _ = I
   723       | add_term_pats Ts depth t =
   720       | add_term_pats Ts depth t =
   724         add_term_pat Ts depth t #> add_term_pats Ts (depth - 1) t
   721         add_term_pat Ts depth t #> add_term_pats Ts (depth - 1) t
   725     fun add_term Ts = add_term_pats Ts term_max_depth
   722     fun add_term Ts = add_term_pats Ts term_max_depth
   726     fun add_subterms Ts t =
   723     fun add_subterms Ts t =
   727       case strip_comb t of
   724       (case strip_comb t of
   728         (Const (s, T), args) =>
   725         (Const (s, T), args) =>
   729         (not (is_widely_irrelevant_const s) ? add_term Ts t)
   726         (not (is_widely_irrelevant_const s) ? add_term Ts t)
   730         #> add_subtypes T
   727         #> add_subtypes T
   731         #> fold (add_subterms Ts) args
   728         #> fold (add_subterms Ts) args
   732       | (head, args) =>
   729       | (head, args) =>
   733         (case head of
   730         (case head of
   734            Free (_, T) => add_term Ts t #> add_subtypes T
   731            Free (_, T) => add_term Ts t #> add_subtypes T
   735          | Var (_, T) => add_subtypes T
   732          | Var (_, T) => add_subtypes T
   736          | Abs (_, T, body) => add_subtypes T #> add_subterms (T :: Ts) body
   733          | Abs (_, T, body) => add_subtypes T #> add_subterms (T :: Ts) body
   737          | _ => I)
   734          | _ => I)
   738         #> fold (add_subterms Ts) args
   735         #> fold (add_subterms Ts) args)
   739   in [] |> fold (add_subterms []) ts end
   736   in [] |> fold (add_subterms []) ts end
   740 
   737 
   741 val term_max_depth = 2
   738 val term_max_depth = 2
   742 val type_max_depth = 1
   739 val type_max_depth = 1
   743 
   740 
   803       deps
   800       deps
   804   end
   801   end
   805 
   802 
   806 fun prover_dependencies_of ctxt (params as {verbose, max_facts, ...}) prover
   803 fun prover_dependencies_of ctxt (params as {verbose, max_facts, ...}) prover
   807                            auto_level facts name_tabs th =
   804                            auto_level facts name_tabs th =
   808   case isar_dependencies_of name_tabs th of
   805   (case isar_dependencies_of name_tabs th of
   809     [] => (false, [])
   806     [] => (false, [])
   810   | isar_deps =>
   807   | isar_deps =>
   811     let
   808     let
   812       val thy = Proof_Context.theory_of ctxt
   809       val thy = Proof_Context.theory_of ctxt
   813       val goal = goal_of_thm thy th
   810       val goal = goal_of_thm thy th
   817       fun nickify ((_, stature), th) = ((nickname_of_thm th, stature), th)
   814       fun nickify ((_, stature), th) = ((nickname_of_thm th, stature), th)
   818       fun is_dep dep (_, th) = nickname_of_thm th = dep
   815       fun is_dep dep (_, th) = nickname_of_thm th = dep
   819       fun add_isar_dep facts dep accum =
   816       fun add_isar_dep facts dep accum =
   820         if exists (is_dep dep) accum then
   817         if exists (is_dep dep) accum then
   821           accum
   818           accum
   822         else case find_first (is_dep dep) facts of
   819         else
   823           SOME ((_, status), th) => accum @ [(("", status), th)]
   820           (case find_first (is_dep dep) facts of
   824         | NONE => accum (* shouldn't happen *)
   821             SOME ((_, status), th) => accum @ [(("", status), th)]
       
   822           | NONE => accum (* shouldn't happen *))
   825       val mepo_facts =
   823       val mepo_facts =
   826         facts
   824         facts
   827         |> mepo_suggested_facts ctxt params (max_facts |> the_default prover_default_max_facts) NONE
   825         |> mepo_suggested_facts ctxt params (max_facts |> the_default prover_default_max_facts) NONE
   828              hyp_ts concl_t
   826              hyp_ts concl_t
   829       val facts =
   827       val facts =
   836         "MaSh: " ^ quote prover ^ " on " ^ quote name ^ " with " ^ string_of_int num_isar_deps ^
   834         "MaSh: " ^ quote prover ^ " on " ^ quote name ^ " with " ^ string_of_int num_isar_deps ^
   837         " + " ^ string_of_int (length facts - num_isar_deps) ^ " facts."
   835         " + " ^ string_of_int (length facts - num_isar_deps) ^ " facts."
   838         |> Output.urgent_message
   836         |> Output.urgent_message
   839       else
   837       else
   840         ();
   838         ();
   841       case run_prover_for_mash ctxt params prover name facts goal of
   839       (case run_prover_for_mash ctxt params prover name facts goal of
   842         {outcome = NONE, used_facts, ...} =>
   840         {outcome = NONE, used_facts, ...} =>
   843         (if verbose andalso auto_level = 0 then
   841         (if verbose andalso auto_level = 0 then
   844            let val num_facts = length used_facts in
   842            let val num_facts = length used_facts in
   845              "Found proof with " ^ string_of_int num_facts ^ " fact" ^
   843              "Found proof with " ^ string_of_int num_facts ^ " fact" ^
   846              plural_s num_facts ^ "."
   844              plural_s num_facts ^ "."
   847              |> Output.urgent_message
   845              |> Output.urgent_message
   848            end
   846            end
   849          else
   847          else
   850            ();
   848            ();
   851          (true, map fst used_facts))
   849          (true, map fst used_facts))
   852       | _ => (false, isar_deps)
   850       | _ => (false, isar_deps))
   853     end
   851     end)
   854 
   852 
   855 
   853 
   856 (*** High-level communication with MaSh ***)
   854 (*** High-level communication with MaSh ***)
   857 
   855 
   858 (* In the following functions, chunks are risers w.r.t. "thm_less_eq". *)
   856 (* In the following functions, chunks are risers w.r.t. "thm_less_eq". *)
  1138               val (relearns, access_G) =
  1136               val (relearns, access_G) =
  1139                 ([], access_G) |> fold (relearn_wrt_access_graph ctxt) relearns
  1137                 ([], access_G) |> fold (relearn_wrt_access_graph ctxt) relearns
  1140               val access_G = access_G |> fold flop_wrt_access_graph flops
  1138               val access_G = access_G |> fold flop_wrt_access_graph flops
  1141               val num_known_facts = num_known_facts + length learns
  1139               val num_known_facts = num_known_facts + length learns
  1142               val dirty =
  1140               val dirty =
  1143                 case (was_empty, dirty, relearns) of
  1141                 (case (was_empty, dirty, relearns) of
  1144                   (false, SOME names, []) => SOME (map #1 learns @ names)
  1142                   (false, SOME names, []) => SOME (map #1 learns @ names)
  1145                 | _ => NONE
  1143                 | _ => NONE)
  1146             in
  1144             in
  1147               MaSh.learn ctxt overlord (save andalso null relearns) (rev learns);
  1145               MaSh.learn ctxt overlord (save andalso null relearns) (rev learns);
  1148               MaSh.relearn ctxt overlord save relearns;
  1146               MaSh.relearn ctxt overlord save relearns;
  1149               {access_G = access_G, num_known_facts = num_known_facts,
  1147               {access_G = access_G, num_known_facts = num_known_facts,
  1150                dirty = dirty}
  1148                dirty = dirty}
  1200           | relearn_old_fact ((_, (_, status)), th)
  1198           | relearn_old_fact ((_, (_, status)), th)
  1201                              ((relearns, flops), (n, next_commit, _)) =
  1199                              ((relearns, flops), (n, next_commit, _)) =
  1202             let
  1200             let
  1203               val name = nickname_of_thm th
  1201               val name = nickname_of_thm th
  1204               val (n, relearns, flops) =
  1202               val (n, relearns, flops) =
  1205                 case deps_of status th of
  1203                 (case deps_of status th of
  1206                   SOME deps => (n + 1, (name, deps) :: relearns, flops)
  1204                   SOME deps => (n + 1, (name, deps) :: relearns, flops)
  1207                 | NONE => (n, relearns, name :: flops)
  1205                 | NONE => (n, relearns, name :: flops))
  1208               val (relearns, flops, next_commit) =
  1206               val (relearns, flops, next_commit) =
  1209                 if Time.> (Timer.checkRealTimer timer, next_commit) then
  1207                 if Time.> (Timer.checkRealTimer timer, next_commit) then
  1210                   (commit false [] relearns flops;
  1208                   (commit false [] relearns flops;
  1211                    ([], [], next_commit_time ()))
  1209                    ([], [], next_commit_time ()))
  1212                 else
  1210                 else
  1323             val {access_G, num_known_facts, ...} = peek_state ctxt overlord I
  1321             val {access_G, num_known_facts, ...} = peek_state ctxt overlord I
  1324             val is_in_access_G = is_fact_in_graph access_G o snd
  1322             val is_in_access_G = is_fact_in_graph access_G o snd
  1325           in
  1323           in
  1326             if length facts - num_known_facts
  1324             if length facts - num_known_facts
  1327                <= max_facts_to_learn_before_query then
  1325                <= max_facts_to_learn_before_query then
  1328               case length (filter_out is_in_access_G facts) of
  1326               (case length (filter_out is_in_access_G facts) of
  1329                 0 => false
  1327                 0 => false
  1330               | num_facts_to_learn =>
  1328               | num_facts_to_learn =>
  1331                 if num_facts_to_learn <= max_facts_to_learn_before_query then
  1329                 if num_facts_to_learn <= max_facts_to_learn_before_query then
  1332                   (mash_learn_facts ctxt params prover false 2 false timeout facts
  1330                   (mash_learn_facts ctxt params prover false 2 false timeout facts
  1333                    |> (fn "" => () | s => Output.urgent_message (MaShN ^ ": " ^ s));
  1331                    |> (fn "" => () | s => Output.urgent_message (MaShN ^ ": " ^ s));
  1334                    true)
  1332                    true)
  1335                 else
  1333                 else
  1336                   (maybe_launch_thread (); false)
  1334                   (maybe_launch_thread (); false))
  1337             else
  1335             else
  1338               (maybe_launch_thread (); false)
  1336               (maybe_launch_thread (); false)
  1339           end
  1337           end
  1340         else
  1338         else
  1341           false
  1339           false
  1342       val (save, effective_fact_filter) =
  1340       val (save, effective_fact_filter) =
  1343         case fact_filter of
  1341         (case fact_filter of
  1344           SOME ff => (ff <> mepoN andalso maybe_learn (), ff)
  1342           SOME ff => (ff <> mepoN andalso maybe_learn (), ff)
  1345         | NONE =>
  1343         | NONE =>
  1346           if is_mash_enabled () then
  1344           if is_mash_enabled () then
  1347             (maybe_learn (),
  1345             (maybe_learn (),
  1348              if mash_can_suggest_facts ctxt overlord then meshN else mepoN)
  1346              if mash_can_suggest_facts ctxt overlord then meshN else mepoN)
  1349           else
  1347           else
  1350             (false, mepoN)
  1348             (false, mepoN))
  1351 
  1349 
  1352       val unique_facts = drop_duplicate_facts facts
  1350       val unique_facts = drop_duplicate_facts facts
  1353       val add_ths = Attrib.eval_thms ctxt add
  1351       val add_ths = Attrib.eval_thms ctxt add
  1354 
  1352 
  1355       fun in_add (_, th) = member Thm.eq_thm_prop add_ths th
  1353       fun in_add (_, th) = member Thm.eq_thm_prop add_ths th
  1371            |> effective_fact_filter <> mashN ? cons (mepo_weight, mepo)
  1369            |> effective_fact_filter <> mashN ? cons (mepo_weight, mepo)
  1372            |> Par_List.map (apsnd (fn f => f ()))
  1370            |> Par_List.map (apsnd (fn f => f ()))
  1373       val mesh = mesh_facts (eq_snd Thm.eq_thm_prop) max_facts mess |> add_and_take
  1371       val mesh = mesh_facts (eq_snd Thm.eq_thm_prop) max_facts mess |> add_and_take
  1374     in
  1372     in
  1375       if save then MaSh.save ctxt overlord else ();
  1373       if save then MaSh.save ctxt overlord else ();
  1376       case (fact_filter, mess) of
  1374       (case (fact_filter, mess) of
  1377         (NONE, [(_, (mepo, _)), (_, (mash, _))]) =>
  1375         (NONE, [(_, (mepo, _)), (_, (mash, _))]) =>
  1378         [(meshN, mesh), (mepoN, mepo |> map fst |> add_and_take),
  1376         [(meshN, mesh), (mepoN, mepo |> map fst |> add_and_take),
  1379          (mashN, mash |> map fst |> add_and_take)]
  1377          (mashN, mash |> map fst |> add_and_take)]
  1380       | _ => [(effective_fact_filter, mesh)]
  1378       | _ => [(effective_fact_filter, mesh)])
  1381     end
  1379     end
  1382 
  1380 
  1383 fun kill_learners ctxt ({overlord, ...} : params) =
  1381 fun kill_learners ctxt ({overlord, ...} : params) =
  1384   (Async_Manager.kill_threads MaShN "learner"; MaSh.shutdown ctxt overlord)
  1382   (Async_Manager.kill_threads MaShN "learner"; MaSh.shutdown ctxt overlord)
  1385 fun running_learners () = Async_Manager.running_threads MaShN "learner"
  1383 fun running_learners () = Async_Manager.running_threads MaShN "learner"