src/HOL/Tools/Sledgehammer/sledgehammer_filter_mash.ML
changeset 48251 6cdcfbddc077
parent 48249 2bd242c56c90
child 48288 255c6e1fd505
equal deleted inserted replaced
48250:1065c307fafe 48251:6cdcfbddc077
     4 Sledgehammer's machine-learning-based relevance filter (MaSh).
     4 Sledgehammer's machine-learning-based relevance filter (MaSh).
     5 *)
     5 *)
     6 
     6 
     7 signature SLEDGEHAMMER_FILTER_MASH =
     7 signature SLEDGEHAMMER_FILTER_MASH =
     8 sig
     8 sig
       
     9   type status = ATP_Problem_Generate.status
       
    10   type stature = ATP_Problem_Generate.stature
       
    11   type params = Sledgehammer_Provers.params
       
    12   type prover_result = Sledgehammer_Provers.prover_result
       
    13 
       
    14   val fact_name_of : string -> string
       
    15   val all_non_tautological_facts_of :
       
    16     theory -> (((unit -> string) * stature) * thm) list
       
    17   val theory_ord : theory * theory -> order
       
    18   val thm_ord : thm * thm -> order
       
    19   val thms_by_thy : ('a * thm) list -> (string * thm list) list
       
    20   val has_thy : theory -> thm -> bool
       
    21   val parent_thms : (string * thm list) list -> theory -> string list
       
    22   val features_of : theory -> status * thm -> string list
       
    23   val isabelle_dependencies_of : string list -> thm -> string list
       
    24   val goal_of_thm : theory -> thm -> thm
       
    25   val iter_facts :
       
    26     Proof.context -> params -> int -> thm
       
    27     -> (((unit -> string) * stature) * thm) list
       
    28     -> ((string * stature) * thm) list
       
    29   val run_prover :
       
    30     Proof.context -> params -> ((string * stature) * thm) list -> thm
       
    31     -> prover_result
       
    32   val generate_accessibility : theory -> bool -> string -> unit
       
    33   val generate_features : theory -> bool -> string -> unit
       
    34   val generate_isa_dependencies : theory -> bool -> string -> unit
       
    35   val generate_atp_dependencies :
       
    36     Proof.context -> params -> theory -> bool -> string -> unit
       
    37 
     9   val reset : unit -> unit
    38   val reset : unit -> unit
    10   val can_suggest : unit -> bool
    39   val can_suggest : unit -> bool
    11   val can_learn_thy : theory -> bool
    40   val can_learn_thy : theory -> bool
    12   val learn_thy : theory -> real -> unit
    41   val learn_thy : theory -> real -> unit
    13   val learn_proof : theory -> term -> thm list -> unit
    42   val learn_proof : theory -> term -> thm list -> unit
    14 end;
    43 end;
    15 
    44 
    16 structure Sledgehammer_Filter_MaSh : SLEDGEHAMMER_FILTER_MASH =
    45 structure Sledgehammer_Filter_MaSh : SLEDGEHAMMER_FILTER_MASH =
    17 struct
    46 struct
    18 
    47 
       
    48 open ATP_Util
       
    49 open ATP_Problem_Generate
       
    50 open Sledgehammer_Util
       
    51 open Sledgehammer_Fact
       
    52 open Sledgehammer_Filter_Iter
       
    53 open Sledgehammer_Provers
       
    54 
       
    55 
       
    56 (*** Low-level communication with MaSh ***)
       
    57 
    19 fun mash_reset () =
    58 fun mash_reset () =
    20   tracing "MaSh RESET"
    59   tracing "MaSh RESET"
    21 
    60 
    22 fun mash_add fact (access, feats, deps) =
    61 fun mash_add fact (access, feats, deps) =
    23   tracing ("MaSh ADD " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^
    62   tracing ("MaSh ADD " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^
    28 
    67 
    29 fun mash_suggest fact (access, feats) =
    68 fun mash_suggest fact (access, feats) =
    30   tracing ("MaSh SUGGEST " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^
    69   tracing ("MaSh SUGGEST " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^
    31            space_implode " " feats)
    70            space_implode " " feats)
    32 
    71 
       
    72 
       
    73 (*** Isabelle helpers ***)
       
    74 
       
    75 val fact_name_of = prefix fact_prefix o ascii_of
       
    76 
       
    77 fun escape_meta_char c =
       
    78   if Char.isAlphaNum c orelse c = #"_" orelse c = #"." orelse c = #"(" orelse
       
    79      c = #")" orelse c = #"," then
       
    80     String.str c
       
    81   else
       
    82     (* fixed width, in case more digits follow *)
       
    83     "\\" ^ stringN_of_int 3 (Char.ord c)
       
    84 
       
    85 val escape_meta = String.translate escape_meta_char
       
    86 
       
    87 val thy_prefix = "y_"
       
    88 
       
    89 val fact_name_of = escape_meta
       
    90 val thy_name_of = prefix thy_prefix o escape_meta
       
    91 val const_name_of = prefix const_prefix o escape_meta
       
    92 val type_name_of = prefix type_const_prefix o escape_meta
       
    93 val class_name_of = prefix class_prefix o escape_meta
       
    94 
       
    95 val thy_name_of_thm = theory_of_thm #> Context.theory_name
       
    96 
       
    97 local
       
    98 
       
    99 fun has_bool @{typ bool} = true
       
   100   | has_bool (Type (_, Ts)) = exists has_bool Ts
       
   101   | has_bool _ = false
       
   102 
       
   103 fun has_fun (Type (@{type_name fun}, _)) = true
       
   104   | has_fun (Type (_, Ts)) = exists has_fun Ts
       
   105   | has_fun _ = false
       
   106 
       
   107 val is_conn = member (op =)
       
   108   [@{const_name Trueprop}, @{const_name HOL.conj}, @{const_name HOL.disj},
       
   109    @{const_name HOL.implies}, @{const_name Not},
       
   110    @{const_name All}, @{const_name Ex}, @{const_name Ball}, @{const_name Bex},
       
   111    @{const_name HOL.eq}]
       
   112 
       
   113 val has_bool_arg_const =
       
   114   exists_Const (fn (c, T) =>
       
   115                    not (is_conn c) andalso exists has_bool (binder_types T))
       
   116 
       
   117 fun higher_inst_const thy (c, T) =
       
   118   case binder_types T of
       
   119     [] => false
       
   120   | Ts => length (binder_types (Sign.the_const_type thy c)) <> length Ts
       
   121 
       
   122 val binders = [@{const_name All}, @{const_name Ex}]
       
   123 
       
   124 in
       
   125 
       
   126 fun is_fo_term thy t =
       
   127   let
       
   128     val t =
       
   129       t |> Envir.beta_eta_contract
       
   130         |> transform_elim_prop
       
   131         |> Object_Logic.atomize_term thy
       
   132   in
       
   133     Term.is_first_order binders t andalso
       
   134     not (exists_subterm (fn Var (_, T) => has_bool T orelse has_fun T
       
   135                           | _ => false) t orelse
       
   136          has_bool_arg_const t orelse exists_Const (higher_inst_const thy) t)
       
   137   end
       
   138 
       
   139 end
       
   140 
       
   141 fun interesting_terms_types_and_classes term_max_depth type_max_depth t =
       
   142   let
       
   143     val bad_types = [@{type_name prop}, @{type_name bool}, @{type_name fun}]
       
   144     val bad_consts = atp_widely_irrelevant_consts
       
   145     fun do_add_type (Type (s, Ts)) =
       
   146         (not (member (op =) bad_types s) ? insert (op =) (type_name_of s))
       
   147         #> fold do_add_type Ts
       
   148       | do_add_type (TFree (_, S)) = union (op =) (map class_name_of S)
       
   149       | do_add_type (TVar (_, S)) = union (op =) (map class_name_of S)
       
   150     fun add_type T = type_max_depth >= 0 ? do_add_type T
       
   151     fun mk_app s args =
       
   152       if member (op <>) args "" then s ^ "(" ^ space_implode "," args ^ ")"
       
   153       else s
       
   154     fun patternify ~1 _ = ""
       
   155       | patternify depth t =
       
   156         case strip_comb t of
       
   157           (Const (s, _), args) =>
       
   158           mk_app (const_name_of s) (map (patternify (depth - 1)) args)
       
   159         | _ => ""
       
   160     fun add_term_patterns ~1 _ = I
       
   161       | add_term_patterns depth t =
       
   162         insert (op =) (patternify depth t)
       
   163         #> add_term_patterns (depth - 1) t
       
   164     val add_term = add_term_patterns term_max_depth
       
   165     fun add_patterns t =
       
   166       let val (head, args) = strip_comb t in
       
   167         (case head of
       
   168            Const (s, T) =>
       
   169            not (member (op =) bad_consts s) ? (add_term t #> add_type T)
       
   170          | Free (_, T) => add_type T
       
   171          | Var (_, T) => add_type T
       
   172          | Abs (_, T, body) => add_type T #> add_patterns body
       
   173          | _ => I)
       
   174         #> fold add_patterns args
       
   175       end
       
   176   in [] |> add_patterns t |> sort string_ord end
       
   177 
       
   178 fun is_likely_tautology th =
       
   179   null (interesting_terms_types_and_classes 0 ~1 (prop_of th)) andalso
       
   180   not (Thm.eq_thm_prop (@{thm ext}, th))
       
   181 
       
   182 fun is_too_meta thy th =
       
   183   fastype_of (Object_Logic.atomize_term thy (prop_of th)) <> @{typ bool}
       
   184 
       
   185 fun all_non_tautological_facts_of thy =
       
   186   all_facts_of thy
       
   187   |> filter_out ((is_likely_tautology orf is_too_meta thy) o snd)
       
   188 
       
   189 fun theory_ord p =
       
   190   if Theory.eq_thy p then EQUAL
       
   191   else if Theory.subthy p then LESS
       
   192   else if Theory.subthy (swap p) then GREATER
       
   193   else EQUAL
       
   194 
       
   195 val thm_ord = theory_ord o pairself theory_of_thm
       
   196 
       
   197 fun thms_by_thy ths =
       
   198   ths |> map (snd #> `thy_name_of_thm)
       
   199       |> AList.group (op =)
       
   200       |> sort (int_ord o pairself (length o Theory.ancestors_of o theory_of_thm
       
   201                                    o hd o snd))
       
   202       |> map (apsnd (sort thm_ord))
       
   203 
       
   204 fun has_thy thy th = (Context.theory_name thy = thy_name_of_thm th)
       
   205 
       
   206 fun parent_thms thy_ths thy =
       
   207   Theory.parents_of thy
       
   208   |> map Context.theory_name
       
   209   |> map_filter (AList.lookup (op =) thy_ths)
       
   210   |> map List.last
       
   211   |> map (fact_name_of o Thm.get_name_hint)
       
   212 
       
   213 fun is_exists (s, _) = (s = @{const_name Ex} orelse s = @{const_name Ex1})
       
   214 
       
   215 val max_depth = 1
       
   216 
       
   217 (* TODO: Generate type classes for types? *)
       
   218 fun features_of thy (status, th) =
       
   219   let val t = Thm.prop_of th in
       
   220     thy_name_of (thy_name_of_thm th) ::
       
   221     interesting_terms_types_and_classes max_depth max_depth t
       
   222     |> not (has_no_lambdas t) ? cons "lambdas"
       
   223     |> exists_Const is_exists t ? cons "skolems"
       
   224     |> not (is_fo_term thy t) ? cons "ho"
       
   225     |> (case status of
       
   226           General => I
       
   227         | Induction => cons "induction"
       
   228         | Intro => cons "intro"
       
   229         | Inductive => cons "inductive"
       
   230         | Elim => cons "elim"
       
   231         | Simp => cons "simp"
       
   232         | Def => cons "def")
       
   233   end
       
   234 
       
   235 fun isabelle_dependencies_of all_facts =
       
   236   thms_in_proof (SOME all_facts)
       
   237   #> map fact_name_of #> sort string_ord
       
   238 
       
   239 val freezeT = Type.legacy_freeze_type
       
   240 
       
   241 fun freeze (t $ u) = freeze t $ freeze u
       
   242   | freeze (Abs (s, T, t)) = Abs (s, freezeT T, freeze t)
       
   243   | freeze (Var ((s, _), T)) = Free (s, freezeT T)
       
   244   | freeze (Const (s, T)) = Const (s, freezeT T)
       
   245   | freeze (Free (s, T)) = Free (s, freezeT T)
       
   246   | freeze t = t
       
   247 
       
   248 fun goal_of_thm thy = prop_of #> freeze #> cterm_of thy #> Goal.init
       
   249 
       
   250 fun iter_facts ctxt ({provers, relevance_thresholds, ...} : params) max_relevant
       
   251                goal =
       
   252   let
       
   253     val prover_name = hd provers
       
   254     val (_, hyp_ts, concl_t) = ATP_Util.strip_subgoal ctxt goal 1
       
   255     val is_built_in_const =
       
   256       Sledgehammer_Provers.is_built_in_const_for_prover ctxt prover_name
       
   257     val relevance_fudge =
       
   258       Sledgehammer_Provers.relevance_fudge_for_prover ctxt prover_name
       
   259     val relevance_override = {add = [], del = [], only = false}
       
   260   in
       
   261     iterative_relevant_facts ctxt relevance_thresholds max_relevant
       
   262                              is_built_in_const relevance_fudge
       
   263                              relevance_override [] hyp_ts concl_t
       
   264   end
       
   265 
       
   266 fun run_prover ctxt (params as {provers, ...}) facts goal =
       
   267   let
       
   268     val problem =
       
   269       {state = Proof.init ctxt, goal = goal, subgoal = 1, subgoal_count = 1,
       
   270        facts = facts |> map Sledgehammer_Provers.Untranslated_Fact}
       
   271     val prover =
       
   272       Sledgehammer_Minimize.get_minimizing_prover ctxt
       
   273           Sledgehammer_Provers.Normal (hd provers)
       
   274   in prover params (K (K (K ""))) problem end
       
   275 
       
   276 fun generate_accessibility thy include_thy file_name =
       
   277   let
       
   278     val path = file_name |> Path.explode
       
   279     val _ = File.write path ""
       
   280     fun do_thm th prevs =
       
   281       let
       
   282         val s = th ^ ": " ^ space_implode " " prevs ^ "\n"
       
   283         val _ = File.append path s
       
   284       in [th] end
       
   285     val thy_ths =
       
   286       all_non_tautological_facts_of thy
       
   287       |> not include_thy ? filter_out (has_thy thy o snd)
       
   288       |> thms_by_thy
       
   289     fun do_thy ths =
       
   290       let
       
   291         val thy = theory_of_thm (hd ths)
       
   292         val parents = parent_thms thy_ths thy
       
   293         val ths = ths |> map (fact_name_of o Thm.get_name_hint)
       
   294       in fold do_thm ths parents; () end
       
   295   in List.app (do_thy o snd) thy_ths end
       
   296 
       
   297 fun generate_features thy include_thy file_name =
       
   298   let
       
   299     val path = file_name |> Path.explode
       
   300     val _ = File.write path ""
       
   301     val facts =
       
   302       all_non_tautological_facts_of thy
       
   303       |> not include_thy ? filter_out (has_thy thy o snd)
       
   304     fun do_fact ((_, (_, status)), th) =
       
   305       let
       
   306         val name = Thm.get_name_hint th
       
   307         val feats = features_of thy (status, th)
       
   308         val s = fact_name_of name ^ ": " ^ space_implode " " feats ^ "\n"
       
   309       in File.append path s end
       
   310   in List.app do_fact facts end
       
   311 
       
   312 fun generate_isa_dependencies thy include_thy file_name =
       
   313   let
       
   314     val path = file_name |> Path.explode
       
   315     val _ = File.write path ""
       
   316     val ths =
       
   317       all_non_tautological_facts_of thy
       
   318       |> not include_thy ? filter_out (has_thy thy o snd)
       
   319       |> map snd
       
   320     val all_names = ths |> map Thm.get_name_hint
       
   321     fun do_thm th =
       
   322       let
       
   323         val name = Thm.get_name_hint th
       
   324         val deps = isabelle_dependencies_of all_names th
       
   325         val s = fact_name_of name ^ ": " ^ space_implode " " deps ^ "\n"
       
   326       in File.append path s end
       
   327   in List.app do_thm ths end
       
   328 
       
   329 fun generate_atp_dependencies ctxt (params as {max_relevant, ...}) thy
       
   330                               include_thy file_name =
       
   331   let
       
   332     val path = file_name |> Path.explode
       
   333     val _ = File.write path ""
       
   334     val facts =
       
   335       all_non_tautological_facts_of thy
       
   336       |> not include_thy ? filter_out (has_thy thy o snd)
       
   337     val ths = facts |> map snd
       
   338     val all_names = ths |> map Thm.get_name_hint
       
   339     fun is_dep dep (_, th) = fact_name_of (Thm.get_name_hint th) = dep
       
   340     fun add_isa_dep facts dep accum =
       
   341       if exists (is_dep dep) accum then
       
   342         accum
       
   343       else case find_first (is_dep dep) facts of
       
   344         SOME ((name, status), th) => accum @ [((name (), status), th)]
       
   345       | NONE => accum (* shouldn't happen *)
       
   346     fun fix_name ((_, stature), th) =
       
   347       ((th |> Thm.get_name_hint |> fact_name_of, stature), th)
       
   348     fun do_thm th =
       
   349       let
       
   350         val name = Thm.get_name_hint th
       
   351         val goal = goal_of_thm thy th
       
   352         val deps =
       
   353           case isabelle_dependencies_of all_names th of
       
   354             [] => []
       
   355           | isa_dep as [_] => isa_dep (* can hardly beat that *)
       
   356           | isa_deps =>
       
   357             let
       
   358               val facts =
       
   359                 facts |> filter (fn (_, th') => thm_ord (th', th) = LESS)
       
   360               val facts =
       
   361                 facts |> iter_facts ctxt params (the max_relevant) goal
       
   362                       |> fold (add_isa_dep facts) isa_deps
       
   363                       |> map fix_name
       
   364             in
       
   365               case run_prover ctxt params facts goal of
       
   366                 {outcome = NONE, used_facts, ...} =>
       
   367                 used_facts |> map fst |> sort string_ord
       
   368               | _ => isa_deps
       
   369             end
       
   370         val s = fact_name_of name ^ ": " ^ space_implode " " deps ^ "\n"
       
   371       in File.append path s end
       
   372   in List.app do_thm ths end
       
   373 
       
   374 
       
   375 (*** High-level communication with MaSh ***)
       
   376 
    33 fun reset () =
   377 fun reset () =
    34   ()
   378   ()
    35 
   379 
    36 fun can_suggest () =
   380 fun can_suggest () =
    37   true
   381   true