src/HOL/Tools/Sledgehammer/sledgehammer_mepo.ML
author blanchet
Fri Mar 14 11:15:46 2014 +0100 (2014-03-14 ago)
changeset 56128 c106ac2ff76d
parent 55286 7bbbd9393ce0
child 56245 84fc7dfa3cd4
permissions -rw-r--r--
undo rewrite rules (e.g. for 'fun_app') in Isar
     1 (*  Title:      HOL/Tools/Sledgehammer/sledgehammer_mepo.ML
     2     Author:     Jia Meng, Cambridge University Computer Laboratory and NICTA
     3     Author:     Jasmin Blanchette, TU Muenchen
     4 
     5 Sledgehammer's iterative relevance filter (MePo = Meng-Paulson).
     6 *)
     7 
     8 signature SLEDGEHAMMER_MEPO =
     9 sig
    10   type stature = ATP_Problem_Generate.stature
    11   type raw_fact = Sledgehammer_Fact.raw_fact
    12   type fact = Sledgehammer_Fact.fact
    13   type params = Sledgehammer_Prover.params
    14 
    15   type relevance_fudge =
    16     {local_const_multiplier : real,
    17      worse_irrel_freq : real,
    18      higher_order_irrel_weight : real,
    19      abs_rel_weight : real,
    20      abs_irrel_weight : real,
    21      theory_const_rel_weight : real,
    22      theory_const_irrel_weight : real,
    23      chained_const_irrel_weight : real,
    24      intro_bonus : real,
    25      elim_bonus : real,
    26      simp_bonus : real,
    27      local_bonus : real,
    28      assum_bonus : real,
    29      chained_bonus : real,
    30      max_imperfect : real,
    31      max_imperfect_exp : real,
    32      threshold_divisor : real,
    33      ridiculous_threshold : real}
    34 
    35   val trace : bool Config.T
    36   val pseudo_abs_name : string
    37   val default_relevance_fudge : relevance_fudge
    38   val mepo_suggested_facts :
    39     Proof.context -> params -> int -> relevance_fudge option -> term list -> term ->
    40     raw_fact list -> fact list
    41 end;
    42 
    43 structure Sledgehammer_MePo : SLEDGEHAMMER_MEPO =
    44 struct
    45 
    46 open ATP_Problem_Generate
    47 open Sledgehammer_Util
    48 open Sledgehammer_Fact
    49 open Sledgehammer_Prover
    50 
    51 val trace =
    52   Attrib.setup_config_bool @{binding sledgehammer_mepo_trace} (K false)
    53 fun trace_msg ctxt msg = if Config.get ctxt trace then tracing (msg ()) else ()
    54 
    55 val sledgehammer_prefix = "Sledgehammer" ^ Long_Name.separator
    56 val pseudo_abs_name = sledgehammer_prefix ^ "abs"
    57 val theory_const_suffix = Long_Name.separator ^ " 1"
    58 
    59 type relevance_fudge =
    60   {local_const_multiplier : real,
    61    worse_irrel_freq : real,
    62    higher_order_irrel_weight : real,
    63    abs_rel_weight : real,
    64    abs_irrel_weight : real,
    65    theory_const_rel_weight : real,
    66    theory_const_irrel_weight : real,
    67    chained_const_irrel_weight : real,
    68    intro_bonus : real,
    69    elim_bonus : real,
    70    simp_bonus : real,
    71    local_bonus : real,
    72    assum_bonus : real,
    73    chained_bonus : real,
    74    max_imperfect : real,
    75    max_imperfect_exp : real,
    76    threshold_divisor : real,
    77    ridiculous_threshold : real}
    78 
    79 (* FUDGE *)
    80 val default_relevance_fudge =
    81   {local_const_multiplier = 1.5,
    82    worse_irrel_freq = 100.0,
    83    higher_order_irrel_weight = 1.05,
    84    abs_rel_weight = 0.5,
    85    abs_irrel_weight = 2.0,
    86    theory_const_rel_weight = 0.5,
    87    theory_const_irrel_weight = 0.25,
    88    chained_const_irrel_weight = 0.25,
    89    intro_bonus = 0.15,
    90    elim_bonus = 0.15,
    91    simp_bonus = 0.15,
    92    local_bonus = 0.55,
    93    assum_bonus = 1.05,
    94    chained_bonus = 1.5,
    95    max_imperfect = 11.5,
    96    max_imperfect_exp = 1.0,
    97    threshold_divisor = 2.0,
    98    ridiculous_threshold = 0.1}
    99 
   100 fun order_of_type (Type (@{type_name fun}, [T1, T2])) =
   101     Int.max (order_of_type T1 + 1, order_of_type T2)
   102   | order_of_type (Type (_, Ts)) = fold (Integer.max o order_of_type) Ts 0
   103   | order_of_type _ = 0
   104 
   105 (* An abstraction of Isabelle types and first-order terms *)
   106 datatype pattern = PVar | PApp of string * pattern list
   107 datatype ptype = PType of int * typ list
   108 
   109 fun string_of_patternT (TVar _) = "_"
   110   | string_of_patternT (Type (s, ps)) =
   111     if null ps then s else s ^ string_of_patternsT ps
   112   | string_of_patternT (TFree (s, _)) = s
   113 and string_of_patternsT ps = "(" ^ commas (map string_of_patternT ps) ^ ")"
   114 fun string_of_ptype (PType (_, ps)) = string_of_patternsT ps
   115 
   116 (*Is the second type an instance of the first one?*)
   117 fun match_patternT (TVar _, _) = true
   118   | match_patternT (Type (s, ps), Type (t, qs)) =
   119     s = t andalso match_patternsT (ps, qs)
   120   | match_patternT (TFree (s, _), TFree (t, _)) = s = t
   121   | match_patternT (_, _) = false
   122 and match_patternsT (_, []) = true
   123   | match_patternsT ([], _) = false
   124   | match_patternsT (p :: ps, q :: qs) =
   125     match_patternT (p, q) andalso match_patternsT (ps, qs)
   126 fun match_ptype (PType (_, ps), PType (_, qs)) = match_patternsT (ps, qs)
   127 
   128 (* Is there a unifiable constant? *)
   129 fun pconst_mem f consts (s, ps) =
   130   exists (curry (match_ptype o f) ps)
   131          (map snd (filter (curry (op =) s o fst) consts))
   132 fun pconst_hyper_mem f const_tab (s, ps) =
   133   exists (curry (match_ptype o f) ps) (these (Symtab.lookup const_tab s))
   134 
   135 (* Pairs a constant with the list of its type instantiations. *)
   136 fun ptype thy const x =
   137   (if const then these (try (Sign.const_typargs thy) x) else [])
   138 fun rich_ptype thy const (s, T) =
   139   PType (order_of_type T, ptype thy const (s, T))
   140 fun rich_pconst thy const (s, T) = (s, rich_ptype thy const (s, T))
   141 
   142 fun string_of_hyper_pconst (s, ps) =
   143   s ^ "{" ^ commas (map string_of_ptype ps) ^ "}"
   144 
   145 fun patternT_eq (TVar _, TVar _) = true
   146   | patternT_eq (Type (s, Ts), Type (t, Us)) = s = t andalso patternsT_eq (Ts, Us)
   147   | patternT_eq (TFree (s, _), TFree (t, _)) = (s = t)
   148   | patternT_eq _ = false
   149 and patternsT_eq ([], []) = true
   150   | patternsT_eq ([], _) = false
   151   | patternsT_eq (_, []) = false
   152   | patternsT_eq (T :: Ts, U :: Us) = patternT_eq (T, U) andalso patternsT_eq (Ts, Us)
   153 fun ptype_eq (PType (m, Ts), PType (n, Us)) = m = n andalso patternsT_eq (Ts, Us)
   154 
   155  (* Add a pconstant to the table, but a [] entry means a standard connective,
   156     which we ignore. *)
   157 fun add_pconst_to_table (s, p) = Symtab.map_default (s, [p]) (insert ptype_eq p)
   158 
   159 (* Set constants tend to pull in too many irrelevant facts. We limit the damage
   160    by treating them more or less as if they were built-in but add their
   161    axiomatization at the end. *)
   162 val set_consts = [@{const_name Collect}, @{const_name Set.member}]
   163 val set_thms = @{thms Collect_mem_eq mem_Collect_eq Collect_cong}
   164 
   165 fun add_pconsts_in_term thy =
   166   let
   167     fun do_const const (x as (s, _)) ts =
   168       if member (op =) set_consts s then
   169         fold (do_term false) ts
   170       else
   171         (not (is_irrelevant_const s) ? add_pconst_to_table (rich_pconst thy const x))
   172         #> fold (do_term false) ts
   173     and do_term ext_arg t =
   174       (case strip_comb t of
   175         (Const x, ts) => do_const true x ts
   176       | (Free x, ts) => do_const false x ts
   177       | (Abs (_, T, t'), ts) =>
   178         ((null ts andalso not ext_arg)
   179          (* Since lambdas on the right-hand side of equalities are usually
   180             extensionalized later by "abs_extensionalize_term", we don't
   181             penalize them here. *)
   182          ? add_pconst_to_table (pseudo_abs_name,
   183                                 PType (order_of_type T + 1, [])))
   184         #> fold (do_term false) (t' :: ts)
   185       | (_, ts) => fold (do_term false) ts)
   186     and do_term_or_formula ext_arg T =
   187       if T = HOLogic.boolT then do_formula else do_term ext_arg
   188     and do_formula t =
   189       (case t of
   190         Const (@{const_name all}, _) $ Abs (_, _, t') => do_formula t'
   191       | @{const "==>"} $ t1 $ t2 => do_formula t1 #> do_formula t2
   192       | Const (@{const_name "=="}, Type (_, [T, _])) $ t1 $ t2 =>
   193         do_term_or_formula false T t1 #> do_term_or_formula true T t2
   194       | @{const Trueprop} $ t1 => do_formula t1
   195       | @{const False} => I
   196       | @{const True} => I
   197       | @{const Not} $ t1 => do_formula t1
   198       | Const (@{const_name All}, _) $ Abs (_, _, t') => do_formula t'
   199       | Const (@{const_name Ex}, _) $ Abs (_, _, t') => do_formula t'
   200       | @{const HOL.conj} $ t1 $ t2 => do_formula t1 #> do_formula t2
   201       | @{const HOL.disj} $ t1 $ t2 => do_formula t1 #> do_formula t2
   202       | @{const HOL.implies} $ t1 $ t2 => do_formula t1 #> do_formula t2
   203       | Const (@{const_name HOL.eq}, Type (_, [T, _])) $ t1 $ t2 =>
   204         do_term_or_formula false T t1 #> do_term_or_formula true T t2
   205       | Const (@{const_name If}, Type (_, [_, Type (_, [T, _])]))
   206         $ t1 $ t2 $ t3 =>
   207         do_formula t1 #> fold (do_term_or_formula false T) [t2, t3]
   208       | Const (@{const_name Ex1}, _) $ Abs (_, _, t') => do_formula t'
   209       | Const (@{const_name Ball}, _) $ t1 $ Abs (_, _, t') =>
   210         do_formula (t1 $ Bound ~1) #> do_formula t'
   211       | Const (@{const_name Bex}, _) $ t1 $ Abs (_, _, t') =>
   212         do_formula (t1 $ Bound ~1) #> do_formula t'
   213       | (t0 as Const (_, @{typ bool})) $ t1 =>
   214         do_term false t0 #> do_formula t1  (* theory constant *)
   215       | _ => do_term false t)
   216   in do_formula end
   217 
   218 fun pconsts_in_fact thy t =
   219   Symtab.fold (fn (s, pss) => fold (cons o pair s) pss)
   220               (Symtab.empty |> add_pconsts_in_term thy t) []
   221 
   222 (* Inserts a dummy "constant" referring to the theory name, so that relevance
   223    takes the given theory into account. *)
   224 fun theory_constify ({theory_const_rel_weight, theory_const_irrel_weight, ...}
   225                      : relevance_fudge) thy_name t =
   226   if exists (curry (op <) 0.0) [theory_const_rel_weight,
   227                                 theory_const_irrel_weight] then
   228     Const (thy_name ^ theory_const_suffix, @{typ bool}) $ t
   229   else
   230     t
   231 
   232 fun theory_const_prop_of fudge th =
   233   theory_constify fudge (Context.theory_name (theory_of_thm th)) (prop_of th)
   234 
   235 fun pair_consts_fact thy fudge fact =
   236   (case fact |> snd |> theory_const_prop_of fudge |> pconsts_in_fact thy of
   237     [] => NONE
   238   | consts => SOME ((fact, consts), NONE))
   239 
   240 (* A two-dimensional symbol table counts frequencies of constants. It's keyed
   241    first by constant name and second by its list of type instantiations. For the
   242    latter, we need a linear ordering on "pattern list". *)
   243 
   244 fun patternT_ord p =
   245   (case p of
   246     (Type (s, ps), Type (t, qs)) =>
   247     (case fast_string_ord (s, t) of
   248       EQUAL => dict_ord patternT_ord (ps, qs)
   249     | ord => ord)
   250   | (TVar _, TVar _) => EQUAL
   251   | (TVar _, _) => LESS
   252   | (Type _, TVar _) => GREATER
   253   | (Type _, TFree _) => LESS
   254   | (TFree (s, _), TFree (t, _)) => fast_string_ord (s, t)
   255   | (TFree _, _) => GREATER)
   256 fun ptype_ord (PType (m, ps), PType (n, qs)) =
   257   (case dict_ord patternT_ord (ps, qs) of
   258     EQUAL => int_ord (m, n)
   259   | ord => ord)
   260 
   261 structure PType_Tab = Table(type key = ptype val ord = ptype_ord)
   262 
   263 fun count_fact_consts thy fudge =
   264   let
   265     fun do_const const (s, T) ts =
   266       (* Two-dimensional table update. Constant maps to types maps to count. *)
   267       PType_Tab.map_default (rich_ptype thy const (s, T), 0) (Integer.add 1)
   268       |> Symtab.map_default (s, PType_Tab.empty)
   269       #> fold do_term ts
   270     and do_term t =
   271       (case strip_comb t of
   272         (Const x, ts) => do_const true x ts
   273       | (Free x, ts) => do_const false x ts
   274       | (Abs (_, _, t'), ts) => fold do_term (t' :: ts)
   275       | (_, ts) => fold do_term ts)
   276   in do_term o theory_const_prop_of fudge o snd end
   277 
   278 fun pow_int _ 0 = 1.0
   279   | pow_int x 1 = x
   280   | pow_int x n = if n > 0 then x * pow_int x (n - 1) else pow_int x (n + 1) / x
   281 
   282 (*The frequency of a constant is the sum of those of all instances of its type.*)
   283 fun pconst_freq match const_tab (c, ps) =
   284   PType_Tab.fold (fn (qs, m) => match (ps, qs) ? Integer.add m)
   285                  (the (Symtab.lookup const_tab c)) 0
   286 
   287 
   288 (* A surprising number of theorems contain only a few significant constants.
   289    These include all induction rules, and other general theorems. *)
   290 
   291 (* "log" seems best in practice. A constant function of one ignores the constant
   292    frequencies. Rare constants give more points if they are relevant than less
   293    rare ones. *)
   294 fun rel_weight_for _ freq = 1.0 + 2.0 / Math.ln (Real.fromInt freq + 1.0)
   295 
   296 (* Irrelevant constants are treated differently. We associate lower penalties to
   297    very rare constants and very common ones -- the former because they can't
   298    lead to the inclusion of too many new facts, and the latter because they are
   299    so common as to be of little interest. *)
   300 fun irrel_weight_for ({worse_irrel_freq, higher_order_irrel_weight, ...}
   301                       : relevance_fudge) order freq =
   302   let val (k, x) = worse_irrel_freq |> `Real.ceil in
   303     (if freq < k then Math.ln (Real.fromInt (freq + 1)) / Math.ln x
   304      else rel_weight_for order freq / rel_weight_for order k)
   305     * pow_int higher_order_irrel_weight (order - 1)
   306   end
   307 
   308 fun multiplier_of_const_name local_const_multiplier s =
   309   if String.isSubstring "." s then 1.0 else local_const_multiplier
   310 
   311 (* Computes a constant's weight, as determined by its frequency. *)
   312 fun generic_pconst_weight local_const_multiplier abs_weight theory_const_weight
   313         chained_const_weight weight_for f const_tab chained_const_tab
   314         (c as (s, PType (m, _))) =
   315   if s = pseudo_abs_name then
   316     abs_weight
   317   else if String.isSuffix theory_const_suffix s then
   318     theory_const_weight
   319   else
   320     multiplier_of_const_name local_const_multiplier s
   321     * weight_for m (pconst_freq (match_ptype o f) const_tab c)
   322     |> (if chained_const_weight < 1.0 andalso
   323            pconst_hyper_mem I chained_const_tab c then
   324           curry (op *) chained_const_weight
   325         else
   326           I)
   327 
   328 fun rel_pconst_weight ({local_const_multiplier, abs_rel_weight,
   329                         theory_const_rel_weight, ...} : relevance_fudge)
   330                       const_tab =
   331   generic_pconst_weight local_const_multiplier abs_rel_weight
   332                         theory_const_rel_weight 0.0 rel_weight_for I const_tab
   333                         Symtab.empty
   334 
   335 fun irrel_pconst_weight (fudge as {local_const_multiplier, abs_irrel_weight,
   336                                    theory_const_irrel_weight,
   337                                    chained_const_irrel_weight, ...})
   338                         const_tab chained_const_tab =
   339   generic_pconst_weight local_const_multiplier abs_irrel_weight
   340                         theory_const_irrel_weight chained_const_irrel_weight
   341                         (irrel_weight_for fudge) swap const_tab
   342                         chained_const_tab
   343 
   344 fun stature_bonus ({intro_bonus, ...} : relevance_fudge) (_, Intro) =
   345     intro_bonus
   346   | stature_bonus {elim_bonus, ...} (_, Elim) = elim_bonus
   347   | stature_bonus {simp_bonus, ...} (_, Simp) = simp_bonus
   348   | stature_bonus {local_bonus, ...} (Local, _) = local_bonus
   349   | stature_bonus {assum_bonus, ...} (Assum, _) = assum_bonus
   350   | stature_bonus {chained_bonus, ...} (Chained, _) = chained_bonus
   351   | stature_bonus _ _ = 0.0
   352 
   353 fun is_odd_const_name s =
   354   s = pseudo_abs_name orelse String.isSuffix theory_const_suffix s
   355 
   356 fun fact_weight fudge stature const_tab rel_const_tab chained_const_tab
   357                 fact_consts =
   358   (case fact_consts |> List.partition (pconst_hyper_mem I rel_const_tab)
   359                    ||> filter_out (pconst_hyper_mem swap rel_const_tab) of
   360     ([], _) => 0.0
   361   | (rel, irrel) =>
   362     if forall (forall (is_odd_const_name o fst)) [rel, irrel] then
   363       0.0
   364     else
   365       let
   366         val irrel = irrel |> filter_out (pconst_mem swap rel)
   367         val rel_weight =
   368           0.0 |> fold (curry (op +) o rel_pconst_weight fudge const_tab) rel
   369         val irrel_weight =
   370           ~ (stature_bonus fudge stature)
   371           |> fold (curry (op +)
   372                    o irrel_pconst_weight fudge const_tab chained_const_tab)
   373                   irrel
   374         val res = rel_weight / (rel_weight + irrel_weight)
   375       in if Real.isFinite res then res else 0.0 end)
   376 
   377 fun take_most_relevant ctxt max_facts remaining_max
   378         ({max_imperfect, max_imperfect_exp, ...} : relevance_fudge)
   379         (candidates : ((raw_fact * (string * ptype) list) * real) list) =
   380   let
   381     val max_imperfect =
   382       Real.ceil (Math.pow (max_imperfect,
   383                     Math.pow (Real.fromInt remaining_max
   384                               / Real.fromInt max_facts, max_imperfect_exp)))
   385     val (perfect, imperfect) =
   386       candidates |> sort (Real.compare o swap o pairself snd)
   387                  |> take_prefix (fn (_, w) => w > 0.99999)
   388     val ((accepts, more_rejects), rejects) =
   389       chop max_imperfect imperfect |>> append perfect |>> chop remaining_max
   390   in
   391     trace_msg ctxt (fn () =>
   392         "Actually passed (" ^ string_of_int (length accepts) ^ " of " ^
   393         string_of_int (length candidates) ^ "): " ^
   394         (accepts |> map (fn ((((name, _), _), _), weight) =>
   395                             name () ^ " [" ^ Real.toString weight ^ "]")
   396                  |> commas));
   397     (accepts, more_rejects @ rejects)
   398   end
   399 
   400 fun if_empty_replace_with_scope thy facts sc tab =
   401   if Symtab.is_empty tab then
   402     Symtab.empty
   403     |> fold (add_pconsts_in_term thy)
   404             (map_filter (fn ((_, (sc', _)), th) =>
   405                             if sc' = sc then SOME (prop_of th) else NONE) facts)
   406   else
   407     tab
   408 
   409 fun consider_arities th =
   410   let
   411     fun aux _ _ NONE = NONE
   412       | aux t args (SOME tab) =
   413         (case t of
   414           t1 $ t2 => SOME tab |> aux t1 (t2 :: args) |> aux t2 []
   415         | Const (s, _) =>
   416           (if is_widely_irrelevant_const s then
   417              SOME tab
   418            else
   419              (case Symtab.lookup tab s of
   420                NONE => SOME (Symtab.update (s, length args) tab)
   421              | SOME n => if n = length args then SOME tab else NONE))
   422         | _ => SOME tab)
   423   in aux (prop_of th) [] end
   424 
   425 (* FIXME: This is currently only useful for polymorphic type encodings. *)
   426 fun could_benefit_from_ext facts =
   427   fold (consider_arities o snd) facts (SOME Symtab.empty) |> is_none
   428 
   429 (* High enough so that it isn't wrongly considered as very relevant (e.g., for E
   430    weights), but low enough so that it is unlikely to be truncated away if few
   431    facts are included. *)
   432 val special_fact_index = 45 (* FUDGE *)
   433 
   434 fun eq_prod eqx eqy ((x1, y1), (x2, y2)) = eqx (x1, x2) andalso eqy (y1, y2)
   435 
   436 val really_hopeless_get_kicked_out_iter = 5 (* FUDGE *)
   437 
   438 fun relevance_filter ctxt thres0 decay max_facts
   439         (fudge as {threshold_divisor, ridiculous_threshold, ...}) facts hyp_ts concl_t =
   440   let
   441     val thy = Proof_Context.theory_of ctxt
   442     val const_tab = fold (count_fact_consts thy fudge) facts Symtab.empty
   443     val add_pconsts = add_pconsts_in_term thy
   444     val chained_ts =
   445       facts |> map_filter (fn ((_, (Chained, _)), th) => SOME (prop_of th)
   446                             | _ => NONE)
   447     val chained_const_tab = Symtab.empty |> fold add_pconsts chained_ts
   448     val goal_const_tab =
   449       Symtab.empty
   450       |> fold add_pconsts hyp_ts
   451       |> add_pconsts concl_t
   452       |> (fn tab => if Symtab.is_empty tab then chained_const_tab else tab)
   453       |> fold (if_empty_replace_with_scope thy facts) [Chained, Assum, Local]
   454     fun iter j remaining_max thres rel_const_tab hopeless hopeful =
   455       let
   456         val hopeless =
   457           hopeless |> j = really_hopeless_get_kicked_out_iter
   458                       ? filter_out (fn (_, w) => w < 0.001)
   459         fun relevant [] _ [] =
   460             (* Nothing has been added this iteration. *)
   461             if j = 0 andalso thres >= ridiculous_threshold then
   462               (* First iteration? Try again. *)
   463               iter 0 max_facts (thres / threshold_divisor) rel_const_tab
   464                    hopeless hopeful
   465             else
   466               []
   467           | relevant candidates rejects [] =
   468             let
   469               val (accepts, more_rejects) =
   470                 take_most_relevant ctxt max_facts remaining_max fudge candidates
   471               val sps = maps (snd o fst) accepts
   472               val rel_const_tab' =
   473                 rel_const_tab |> fold add_pconst_to_table sps
   474               fun is_dirty (s, _) =
   475                 Symtab.lookup rel_const_tab' s <> Symtab.lookup rel_const_tab s
   476               val (hopeful_rejects, hopeless_rejects) =
   477                  (rejects @ hopeless, ([], []))
   478                  |-> fold (fn (ax as (_, consts), old_weight) =>
   479                               if exists is_dirty consts then
   480                                 apfst (cons (ax, NONE))
   481                               else
   482                                 apsnd (cons (ax, old_weight)))
   483                  |>> append (more_rejects
   484                              |> map (fn (ax as (_, consts), old_weight) =>
   485                                         (ax, if exists is_dirty consts then NONE
   486                                              else SOME old_weight)))
   487               val thres =
   488                 1.0 - (1.0 - thres)
   489                       * Math.pow (decay, Real.fromInt (length accepts))
   490               val remaining_max = remaining_max - length accepts
   491             in
   492               trace_msg ctxt (fn () => "New or updated constants: " ^
   493                   commas (rel_const_tab'
   494                           |> Symtab.dest
   495                           |> subtract (eq_prod (op =) (eq_list ptype_eq))
   496                                       (rel_const_tab |> Symtab.dest)
   497                           |> map string_of_hyper_pconst));
   498               map (fst o fst) accepts @
   499               (if remaining_max = 0 then
   500                  []
   501                else
   502                  iter (j + 1) remaining_max thres rel_const_tab'
   503                       hopeless_rejects hopeful_rejects)
   504             end
   505           | relevant candidates rejects
   506                      (((ax as (((_, stature), _), fact_consts)), cached_weight)
   507                       :: hopeful) =
   508             let
   509               val weight =
   510                 (case cached_weight of
   511                   SOME w => w
   512                 | NONE =>
   513                   fact_weight fudge stature const_tab rel_const_tab chained_const_tab fact_consts)
   514             in
   515               if weight >= thres then
   516                 relevant ((ax, weight) :: candidates) rejects hopeful
   517               else
   518                 relevant candidates ((ax, weight) :: rejects) hopeful
   519             end
   520         in
   521           trace_msg ctxt (fn () =>
   522               "ITERATION " ^ string_of_int j ^ ": current threshold: " ^
   523               Real.toString thres ^ ", constants: " ^
   524               commas (rel_const_tab
   525                       |> Symtab.dest
   526                       |> filter (curry (op <>) [] o snd)
   527                       |> map string_of_hyper_pconst));
   528           relevant [] [] hopeful
   529         end
   530     fun uses_const s t =
   531       fold_aterms (curry (fn (Const (s', _), false) => s' = s | (_, b) => b)) t
   532                   false
   533     fun uses_const_anywhere accepts s =
   534       exists (uses_const s o prop_of o snd) accepts orelse
   535       exists (uses_const s) (concl_t :: hyp_ts)
   536     fun add_set_const_thms accepts =
   537       exists (uses_const_anywhere accepts) set_consts ? append set_thms
   538     fun insert_into_facts accepts [] = accepts
   539       | insert_into_facts accepts ths =
   540         let
   541           val add = facts |> filter (member Thm.eq_thm_prop ths o snd)
   542           val (bef, after) =
   543             accepts |> filter_out (member Thm.eq_thm_prop ths o snd)
   544                     |> take (max_facts - length add)
   545                     |> chop special_fact_index
   546         in bef @ add @ after end
   547     fun insert_special_facts accepts =
   548       (* FIXME: get rid of "ext" here once it is treated as a helper *)
   549       [] |> could_benefit_from_ext accepts ? cons @{thm ext}
   550          |> add_set_const_thms accepts
   551          |> insert_into_facts accepts
   552   in
   553     facts |> map_filter (pair_consts_fact thy fudge)
   554           |> iter 0 max_facts thres0 goal_const_tab []
   555           |> insert_special_facts
   556           |> tap (fn accepts => trace_msg ctxt (fn () =>
   557                       "Total relevant: " ^ string_of_int (length accepts)))
   558   end
   559 
   560 fun mepo_suggested_facts ctxt ({fact_thresholds = (thres0, thres1), ...} : params) max_facts fudge
   561       hyp_ts concl_t facts =
   562   let
   563     val thy = Proof_Context.theory_of ctxt
   564     val fudge = fudge |> the_default default_relevance_fudge
   565     val decay = Math.pow ((1.0 - thres1) / (1.0 - thres0),
   566                           1.0 / Real.fromInt (max_facts + 1))
   567   in
   568     trace_msg ctxt (fn () => "Considering " ^ string_of_int (length facts) ^ " facts");
   569     (if thres1 < 0.0 then
   570        facts
   571      else if thres0 > 1.0 orelse thres0 > thres1 orelse max_facts <= 0 then
   572        []
   573      else
   574        relevance_filter ctxt thres0 decay max_facts fudge facts hyp_ts
   575          (concl_t |> theory_constify fudge (Context.theory_name thy)))
   576     |> map fact_of_raw_fact
   577   end
   578 
   579 end;