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