src/Pure/Tools/find_theorems.ML
changeset 55671 aeca05e62fef
parent 55670 95454b2980ee
child 55672 5e25cc741ab9
equal deleted inserted replaced
55670:95454b2980ee 55671:aeca05e62fef
    87 
    87 
    88 fun map_criteria f {goal, limit, rem_dups, criteria} =
    88 fun map_criteria f {goal, limit, rem_dups, criteria} =
    89   {goal = goal, limit = limit, rem_dups = rem_dups, criteria = f criteria};
    89   {goal = goal, limit = limit, rem_dups = rem_dups, criteria = f criteria};
    90 
    90 
    91 
    91 
    92 
       
    93 (** theorems, either internal or external (without proof) **)
       
    94 
       
    95 datatype theorem =
       
    96   Internal of Facts.ref * thm |
       
    97   External of Facts.ref * term; (* FIXME: Facts.ref not appropriate *)
       
    98 
       
    99 fun prop_of (Internal (_, thm)) = Thm.full_prop_of thm
       
   100   | prop_of (External (_, prop)) = prop;
       
   101 
       
   102 fun nprems_of (Internal (_, thm)) = Thm.nprems_of thm
       
   103   | nprems_of (External (_, prop)) = Logic.count_prems prop;
       
   104 
       
   105 fun size_of (Internal (_, thm)) = size_of_term (Thm.prop_of thm)
       
   106   | size_of (External (_, prop)) = size_of_term prop;
       
   107 
       
   108 fun major_prem_of (Internal (_, thm)) = Thm.major_prem_of thm
       
   109   | major_prem_of (External (_, prop)) =
       
   110       Logic.strip_assums_concl (hd (Logic.strip_imp_prems prop));
       
   111 
       
   112 fun fact_ref_of (Internal (fact_ref, _)) = fact_ref
       
   113   | fact_ref_of (External (fact_ref, _)) = fact_ref;
       
   114 
       
   115 
       
   116 
       
   117 (** search criterion filters **)
    92 (** search criterion filters **)
   118 
    93 
   119 (*generated filters are to be of the form
    94 (*generated filters are to be of the form
   120   input: theorem
    95   input: (Facts.ref * thm)
   121   output: (p:int, s:int, t:int) option, where
    96   output: (p:int, s:int, t:int) option, where
   122     NONE indicates no match
    97     NONE indicates no match
   123     p is the primary sorting criterion
    98     p is the primary sorting criterion
   124       (eg. size of term)
    99       (eg. size of term)
   125     s is the secondary sorting criterion
   100     s is the secondary sorting criterion
   162   end;
   137   end;
   163 
   138 
   164 
   139 
   165 (* filter_name *)
   140 (* filter_name *)
   166 
   141 
   167 fun filter_name str_pat theorem =
   142 fun filter_name str_pat (thmref, _) =
   168   if match_string str_pat (Facts.name_of_ref (fact_ref_of theorem))
   143   if match_string str_pat (Facts.name_of_ref thmref)
   169   then SOME (0, 0, 0) else NONE;
   144   then SOME (0, 0, 0) else NONE;
   170 
   145 
   171 
   146 
   172 (* filter intro/elim/dest/solves rules *)
   147 (* filter intro/elim/dest/solves rules *)
   173 
   148 
   174 fun filter_dest ctxt goal theorem =
   149 fun filter_dest ctxt goal (_, thm) =
   175   let
   150   let
   176     val extract_dest =
   151     val extract_dest =
   177      (fn theorem => if nprems_of theorem = 0 then [] else [prop_of theorem],
   152      (fn thm => if Thm.no_prems thm then [] else [Thm.full_prop_of thm],
   178       hd o Logic.strip_imp_prems);
   153       hd o Logic.strip_imp_prems);
   179     val prems = Logic.prems_of_goal goal 1;
   154     val prems = Logic.prems_of_goal goal 1;
   180 
   155 
   181     fun try_subst prem = is_matching_thm extract_dest ctxt true prem theorem;
   156     fun try_subst prem = is_matching_thm extract_dest ctxt true prem thm;
   182     val successful = prems |> map_filter try_subst;
   157     val successful = prems |> map_filter try_subst;
   183   in
   158   in
   184     (*if possible, keep best substitution (one with smallest size)*)
   159     (*if possible, keep best substitution (one with smallest size)*)
   185     (*dest rules always have assumptions, so a dest with one
   160     (*dest rules always have assumptions, so a dest with one
   186       assumption is as good as an intro rule with none*)
   161       assumption is as good as an intro rule with none*)
   187     if not (null successful)
   162     if not (null successful) then
   188     then SOME (size_of theorem, nprems_of theorem - 1, foldl1 Int.min successful) else NONE
   163       SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm - 1, foldl1 Int.min successful)
   189   end;
   164     else NONE
   190 
   165   end;
   191 fun filter_intro ctxt goal theorem =
   166 
   192   let
   167 fun filter_intro ctxt goal (_, thm) =
   193     val extract_intro = (single o prop_of, Logic.strip_imp_concl);
   168   let
       
   169     val extract_intro = (single o Thm.full_prop_of, Logic.strip_imp_concl);
   194     val concl = Logic.concl_of_goal goal 1;
   170     val concl = Logic.concl_of_goal goal 1;
   195     val ss = is_matching_thm extract_intro ctxt true concl theorem;
   171   in
   196   in
   172     (case is_matching_thm extract_intro ctxt true concl thm of
   197     if is_some ss then SOME (size_of theorem, nprems_of theorem, the ss) else NONE
   173       SOME ss => SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, ss)
   198   end;
   174     | NONE => NONE)
   199 
   175   end;
   200 fun filter_elim ctxt goal theorem =
   176 
   201   if nprems_of theorem > 0 then
   177 fun filter_elim ctxt goal (_, thm) =
       
   178   if Thm.nprems_of thm > 0 then
   202     let
   179     let
   203       val rule = prop_of theorem;
   180       val rule = Thm.full_prop_of thm;
   204       val prems = Logic.prems_of_goal goal 1;
   181       val prems = Logic.prems_of_goal goal 1;
   205       val goal_concl = Logic.concl_of_goal goal 1;
   182       val goal_concl = Logic.concl_of_goal goal 1;
   206       val rule_mp = hd (Logic.strip_imp_prems rule);
   183       val rule_mp = hd (Logic.strip_imp_prems rule);
   207       val rule_concl = Logic.strip_imp_concl rule;
   184       val rule_concl = Logic.strip_imp_concl rule;
   208       fun combine t1 t2 = Const ("*combine*", dummyT --> dummyT) $ (t1 $ t2);  (* FIXME ?? *)
   185       fun combine t1 t2 = Const ("*combine*", dummyT --> dummyT) $ (t1 $ t2);  (* FIXME ?? *)
   211       fun try_subst prem = is_matching_thm (single, I) ctxt true (goal_tree prem) rule_tree;
   188       fun try_subst prem = is_matching_thm (single, I) ctxt true (goal_tree prem) rule_tree;
   212       val successful = prems |> map_filter try_subst;
   189       val successful = prems |> map_filter try_subst;
   213     in
   190     in
   214       (*elim rules always have assumptions, so an elim with one
   191       (*elim rules always have assumptions, so an elim with one
   215         assumption is as good as an intro rule with none*)
   192         assumption is as good as an intro rule with none*)
   216       if is_nontrivial (Proof_Context.theory_of ctxt) (major_prem_of theorem)
   193       if is_nontrivial (Proof_Context.theory_of ctxt) (Thm.major_prem_of thm)
   217         andalso not (null successful)
   194           andalso not (null successful) then
   218       then SOME (size_of theorem, nprems_of theorem - 1, foldl1 Int.min successful) else NONE
   195         SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm - 1, foldl1 Int.min successful)
       
   196       else NONE
   219     end
   197     end
   220   else NONE;
   198   else NONE;
   221 
   199 
   222 fun filter_solves ctxt goal =
   200 fun filter_solves ctxt goal =
   223   let
   201   let
   233       if Thm.no_prems thm then rtac thm 1 goal'
   211       if Thm.no_prems thm then rtac thm 1 goal'
   234       else
   212       else
   235         (limited_etac thm THEN_ALL_NEW (Goal.norm_hhf_tac ctxt' THEN' Method.assm_tac ctxt'))
   213         (limited_etac thm THEN_ALL_NEW (Goal.norm_hhf_tac ctxt' THEN' Method.assm_tac ctxt'))
   236           1 goal';
   214           1 goal';
   237   in
   215   in
   238     fn Internal (_, thm) =>
   216     fn (_, thm) =>
   239         if is_some (Seq.pull (try_thm thm))
   217       if is_some (Seq.pull (try_thm thm))
   240         then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, 0) else NONE
   218       then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, 0)
   241      | External _ => NONE
   219       else NONE
   242   end;
   220   end;
   243 
   221 
   244 
   222 
   245 (* filter_simp *)
   223 (* filter_simp *)
   246 
   224 
   247 fun filter_simp ctxt t (Internal (_, thm)) =
   225 fun filter_simp ctxt t (_, thm) =
   248       let
   226   let
   249         val mksimps = Simplifier.mksimps ctxt;
   227     val mksimps = Simplifier.mksimps ctxt;
   250         val extract_simp =
   228     val extract_simp =
   251           (map Thm.full_prop_of o mksimps, #1 o Logic.dest_equals o Logic.strip_imp_concl);
   229       (map Thm.full_prop_of o mksimps, #1 o Logic.dest_equals o Logic.strip_imp_concl);
   252         val ss = is_matching_thm extract_simp ctxt false t thm;
   230   in
   253       in
   231     (case is_matching_thm extract_simp ctxt false t thm of
   254         if is_some ss
   232       SOME ss => SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, ss)
   255         then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, the ss)
   233     | NONE => NONE)
   256         else NONE
   234   end;
   257       end
       
   258   | filter_simp _ _ (External _) = NONE;
       
   259 
   235 
   260 
   236 
   261 (* filter_pattern *)
   237 (* filter_pattern *)
   262 
   238 
   263 fun get_names t = Term.add_const_names t (Term.add_free_names t []);
   239 fun get_names t = Term.add_const_names t (Term.add_free_names t []);
   272 
   248 
   273 fun filter_pattern ctxt pat =
   249 fun filter_pattern ctxt pat =
   274   let
   250   let
   275     val pat_consts = get_names pat;
   251     val pat_consts = get_names pat;
   276 
   252 
   277     fun check (theorem, NONE) = check (theorem, SOME (get_names (prop_of theorem)))
   253     fun check ((x, thm), NONE) = check ((x, thm), SOME (get_names (Thm.full_prop_of thm)))
   278       | check (theorem, c as SOME thm_consts) =
   254       | check ((_, thm), c as SOME thm_consts) =
   279          (if subset (op =) (pat_consts, thm_consts) andalso
   255          (if subset (op =) (pat_consts, thm_consts) andalso
   280             Pattern.matches_subterm (Proof_Context.theory_of ctxt) (pat, prop_of theorem)
   256             Pattern.matches_subterm (Proof_Context.theory_of ctxt) (pat, Thm.full_prop_of thm)
   281           then SOME (size_of theorem, nprems_of theorem, 0) else NONE, c);
   257           then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, 0) else NONE, c);
   282   in check end;
   258   in check end;
   283 
   259 
   284 
   260 
   285 (* interpret criteria as filters *)
   261 (* interpret criteria as filters *)
   286 
   262 
   318 in
   294 in
   319 
   295 
   320 fun filter_criterion ctxt opt_goal (b, c) =
   296 fun filter_criterion ctxt opt_goal (b, c) =
   321   (if b then I else (apfst opt_not)) o filter_crit ctxt opt_goal c;
   297   (if b then I else (apfst opt_not)) o filter_crit ctxt opt_goal c;
   322 
   298 
   323 fun sorted_filter filters theorems =
   299 fun sorted_filter filters thms =
   324   let
   300   let
   325     fun eval_filters theorem = app_filters theorem (SOME (0, 0, 0), NONE, filters);
   301     fun eval_filters thm = app_filters thm (SOME (0, 0, 0), NONE, filters);
   326 
   302 
   327     (*filters return: (thm size, number of assumptions, substitution size) option, so
   303     (*filters return: (thm size, number of assumptions, substitution size) option, so
   328       sort according to size of thm first, then number of assumptions,
   304       sort according to size of thm first, then number of assumptions,
   329       then by the substitution size, then by term order *)
   305       then by the substitution size, then by term order *)
   330     fun result_ord (((p0, s0, t0), thm0), ((p1, s1, t1), thm1)) =
   306     fun result_ord (((p0, s0, t0), (_, thm0)), ((p1, s1, t1), (_, thm1))) =
   331       prod_ord int_ord (prod_ord int_ord (prod_ord int_ord Term_Ord.term_ord)) 
   307       prod_ord int_ord (prod_ord int_ord (prod_ord int_ord Term_Ord.term_ord))
   332          ((p1, (s1, (t1, prop_of thm1))), (p0, (s0, (t0, prop_of thm0))));
   308          ((p1, (s1, (t1, Thm.full_prop_of thm1))), (p0, (s0, (t0, Thm.full_prop_of thm0))));
   333   in
   309   in
   334     grouped 100 Par_List.map eval_filters theorems
   310     grouped 100 Par_List.map eval_filters thms
   335     |> map_filter I |> sort result_ord |> map #2
   311     |> map_filter I |> sort result_ord |> map #2
   336   end;
   312   end;
   337 
   313 
   338 fun lazy_filter filters =
   314 fun lazy_filter filters =
   339   let
   315   let
   366 
   342 
   367 fun rem_cdups nicer xs =
   343 fun rem_cdups nicer xs =
   368   let
   344   let
   369     fun rem_c rev_seen [] = rev rev_seen
   345     fun rem_c rev_seen [] = rev rev_seen
   370       | rem_c rev_seen [x] = rem_c (x :: rev_seen) []
   346       | rem_c rev_seen [x] = rem_c (x :: rev_seen) []
   371       | rem_c rev_seen ((x as (t, _)) :: (y as (t', _)) :: xs) =
   347       | rem_c rev_seen ((x as ((n, thm), _)) :: (y as ((n', thm'), _)) :: rest) =
   372           if prop_of t aconv prop_of t'
   348           if Thm.eq_thm_prop (thm, thm')
   373           then rem_c rev_seen ((if nicer (fact_ref_of t) (fact_ref_of t') then x else y) :: xs)
   349           then rem_c rev_seen ((if nicer n n' then x else y) :: rest)
   374           else rem_c (x :: rev_seen) (y :: xs);
   350           else rem_c (x :: rev_seen) (y :: rest);
   375   in rem_c [] xs end;
   351   in rem_c [] xs end;
   376 
   352 
   377 in
   353 in
   378 
   354 
   379 fun nicer_shortest ctxt =
   355 fun nicer_shortest ctxt =
   394       | nicer (Facts.Fact _) (Facts.Fact _) = true;
   370       | nicer (Facts.Fact _) (Facts.Fact _) = true;
   395   in nicer end;
   371   in nicer end;
   396 
   372 
   397 fun rem_thm_dups nicer xs =
   373 fun rem_thm_dups nicer xs =
   398   (xs ~~ (1 upto length xs))
   374   (xs ~~ (1 upto length xs))
   399   |> sort (Term_Ord.fast_term_ord o pairself (prop_of o #1))
   375   |> sort (Term_Ord.fast_term_ord o pairself (Thm.full_prop_of o #2 o #1))
   400   |> rem_cdups nicer
   376   |> rem_cdups nicer
   401   |> sort (int_ord o pairself #2)
   377   |> sort (int_ord o pairself #2)
   402   |> map #1;
   378   |> map #1;
   403 
   379 
   404 end;
   380 end;
   459       Proof_Context.get_fact ctxt (Facts.named "local.assms")
   435       Proof_Context.get_fact ctxt (Facts.named "local.assms")
   460         handle ERROR _ => [];
   436         handle ERROR _ => [];
   461     val add_prems = Seq.hd o TRY (Method.insert_tac assms 1);
   437     val add_prems = Seq.hd o TRY (Method.insert_tac assms 1);
   462     val opt_goal' = Option.map add_prems opt_goal;
   438     val opt_goal' = Option.map add_prems opt_goal;
   463   in
   439   in
   464     filter ctxt (map Internal (all_facts_of ctxt))
   440     filter ctxt (all_facts_of ctxt)
   465       {goal = opt_goal', limit = opt_limit, rem_dups = rem_dups, criteria = raw_criteria}
   441       {goal = opt_goal', limit = opt_limit, rem_dups = rem_dups, criteria = raw_criteria}
   466     |> apsnd (map (fn Internal f => f))
       
   467   end;
   442   end;
   468 
   443 
   469 in
   444 in
   470 
   445 
   471 val find_theorems = gen_find_theorems filter_theorems;
   446 val find_theorems = gen_find_theorems filter_theorems;
   487   in
   462   in
   488     [Pretty.mark (Proof_Context.markup_fact ctxt name) (Pretty.str name),
   463     [Pretty.mark (Proof_Context.markup_fact ctxt name) (Pretty.str name),
   489       Pretty.str (Facts.string_of_selection sel), Pretty.str ":", Pretty.brk 1]
   464       Pretty.str (Facts.string_of_selection sel), Pretty.str ":", Pretty.brk 1]
   490   end;
   465   end;
   491 
   466 
   492 fun pretty_theorem ctxt (Internal (thmref, thm)) =
       
   493       Pretty.block (pretty_ref ctxt thmref @ [Display.pretty_thm ctxt thm])
       
   494   | pretty_theorem ctxt (External (thmref, prop)) =
       
   495       Pretty.block (pretty_ref ctxt thmref @ [Syntax.unparse_term ctxt prop]);
       
   496 
       
   497 in
   467 in
   498 
   468 
   499 fun pretty_thm ctxt (thmref, thm) = pretty_theorem ctxt (Internal (thmref, thm));
   469 fun pretty_thm ctxt (thmref, thm) =
       
   470   Pretty.block (pretty_ref ctxt thmref @ [Display.pretty_thm ctxt thm]);
   500 
   471 
   501 fun pretty_theorems state opt_limit rem_dups raw_criteria =
   472 fun pretty_theorems state opt_limit rem_dups raw_criteria =
   502   let
   473   let
   503     val ctxt = Proof.context_of state;
   474     val ctxt = Proof.context_of state;
   504     val opt_goal = try Proof.simple_goal state |> Option.map #goal;
   475     val opt_goal = try Proof.simple_goal state |> Option.map #goal;
   505     val criteria = map (apsnd (read_criterion ctxt)) raw_criteria;
   476     val criteria = map (apsnd (read_criterion ctxt)) raw_criteria;
   506 
   477 
   507     val (opt_found, theorems) =
   478     val (opt_found, theorems) =
   508       filter_theorems ctxt (map Internal (all_facts_of ctxt))
   479       filter_theorems ctxt (all_facts_of ctxt)
   509         {goal = opt_goal, limit = opt_limit, rem_dups = rem_dups, criteria = criteria};
   480         {goal = opt_goal, limit = opt_limit, rem_dups = rem_dups, criteria = criteria};
   510     val returned = length theorems;
   481     val returned = length theorems;
   511 
   482 
   512     val tally_msg =
   483     val tally_msg =
   513       (case opt_found of
   484       (case opt_found of
   521     Pretty.big_list "searched for:" (map (pretty_criterion ctxt) criteria) ::
   492     Pretty.big_list "searched for:" (map (pretty_criterion ctxt) criteria) ::
   522     Pretty.str "" ::
   493     Pretty.str "" ::
   523     (if null theorems then [Pretty.str "nothing found"]
   494     (if null theorems then [Pretty.str "nothing found"]
   524      else
   495      else
   525       [Pretty.str (tally_msg ^ ":"), Pretty.str ""] @
   496       [Pretty.str (tally_msg ^ ":"), Pretty.str ""] @
   526         grouped 10 Par_List.map (Pretty.item o single o pretty_theorem ctxt) (rev theorems))
   497         grouped 10 Par_List.map (Pretty.item o single o pretty_thm ctxt) (rev theorems))
   527   end |> Pretty.fbreaks |> curry Pretty.blk 0;
   498   end |> Pretty.fbreaks |> curry Pretty.blk 0;
   528 
   499 
   529 end;
   500 end;
   530 
   501 
   531 
   502