src/Pure/Tools/find_theorems.ML
changeset 52941 28407b5f1c72
parent 52940 6fce81e92e7c
child 52942 07093b66fc9d
equal deleted inserted replaced
52940:6fce81e92e7c 52941:28407b5f1c72
     7 
     7 
     8 signature FIND_THEOREMS =
     8 signature FIND_THEOREMS =
     9 sig
     9 sig
    10   datatype 'term criterion =
    10   datatype 'term criterion =
    11     Name of string | Intro | Elim | Dest | Solves | Simp of 'term | Pattern of 'term
    11     Name of string | Intro | Elim | Dest | Solves | Simp of 'term | Pattern of 'term
    12 
       
    13   datatype theorem =
       
    14     Internal of Facts.ref * thm | External of Facts.ref * term
       
    15 
       
    16   type 'term query = {
    12   type 'term query = {
    17     goal: thm option,
    13     goal: thm option,
    18     limit: int option,
    14     limit: int option,
    19     rem_dups: bool,
    15     rem_dups: bool,
    20     criteria: (bool * 'term criterion) list
    16     criteria: (bool * 'term criterion) list
    21   }
    17   }
    22 
       
    23   val read_criterion: Proof.context -> string criterion -> term criterion
       
    24   val read_query: Position.T -> string -> (bool * string criterion) list
    18   val read_query: Position.T -> string -> (bool * string criterion) list
    25 
       
    26   val find_theorems: Proof.context -> thm option -> int option -> bool ->
    19   val find_theorems: Proof.context -> thm option -> int option -> bool ->
    27     (bool * term criterion) list -> int option * (Facts.ref * thm) list
    20     (bool * term criterion) list -> int option * (Facts.ref * thm) list
    28   val find_theorems_cmd: Proof.context -> thm option -> int option -> bool ->
    21   val find_theorems_cmd: Proof.context -> thm option -> int option -> bool ->
    29     (bool * string criterion) list -> int option * (Facts.ref * thm) list
    22     (bool * string criterion) list -> int option * (Facts.ref * thm) list
    30 
       
    31   val filter_theorems: Proof.context -> theorem list -> term query ->
       
    32     int option * theorem list
       
    33   val filter_theorems_cmd: Proof.context -> theorem list -> string query ->
       
    34     int option * theorem list
       
    35 
       
    36   val pretty_theorem: Proof.context -> theorem -> Pretty.T
       
    37   val pretty_thm: Proof.context -> Facts.ref * thm -> Pretty.T
    23   val pretty_thm: Proof.context -> Facts.ref * thm -> Pretty.T
    38 end;
    24 end;
    39 
    25 
    40 structure Find_Theorems: FIND_THEOREMS =
    26 structure Find_Theorems: FIND_THEOREMS =
    41 struct
    27 struct
   167     fun subst_size pat =
   153     fun subst_size pat =
   168       let val (_, subst) =
   154       let val (_, subst) =
   169         Pattern.match thy (if po then (pat, obj) else (obj, pat)) (Vartab.empty, Vartab.empty)
   155         Pattern.match thy (if po then (pat, obj) else (obj, pat)) (Vartab.empty, Vartab.empty)
   170       in Vartab.fold (fn (_, (_, t)) => fn n => size_of_term t + n) subst 0 end;
   156       in Vartab.fold (fn (_, (_, t)) => fn n => size_of_term t + n) subst 0 end;
   171 
   157 
   172     fun bestmatch [] = NONE
   158     fun best_match [] = NONE
   173       | bestmatch xs = SOME (foldl1 Int.min xs);
   159       | best_match xs = SOME (foldl1 Int.min xs);
   174 
   160 
   175     val match_thm = matches o refine_term;
   161     val match_thm = matches o refine_term;
   176   in
   162   in
   177     map (subst_size o refine_term) (filter match_thm (extract_terms term_src))
   163     map (subst_size o refine_term) (filter match_thm (extract_terms term_src))
   178     |> bestmatch
   164     |> best_match
   179   end;
   165   end;
   180 
   166 
   181 
   167 
   182 (* filter_name *)
   168 (* filter_name *)
   183 
   169 
   220       val rule = prop_of theorem;
   206       val rule = prop_of theorem;
   221       val prems = Logic.prems_of_goal goal 1;
   207       val prems = Logic.prems_of_goal goal 1;
   222       val goal_concl = Logic.concl_of_goal goal 1;
   208       val goal_concl = Logic.concl_of_goal goal 1;
   223       val rule_mp = hd (Logic.strip_imp_prems rule);
   209       val rule_mp = hd (Logic.strip_imp_prems rule);
   224       val rule_concl = Logic.strip_imp_concl rule;
   210       val rule_concl = Logic.strip_imp_concl rule;
   225       fun combine t1 t2 = Const ("*combine*", dummyT --> dummyT) $ (t1 $ t2);
   211       fun combine t1 t2 = Const ("*combine*", dummyT --> dummyT) $ (t1 $ t2);  (* FIXME ?? *)
   226       val rule_tree = combine rule_mp rule_concl;
   212       val rule_tree = combine rule_mp rule_concl;
   227       fun goal_tree prem = combine prem goal_concl;
   213       fun goal_tree prem = combine prem goal_concl;
   228       fun try_subst prem = is_matching_thm (single, I) ctxt true (goal_tree prem) rule_tree;
   214       fun try_subst prem = is_matching_thm (single, I) ctxt true (goal_tree prem) rule_tree;
   229       val successful = prems |> map_filter try_subst;
   215       val successful = prems |> map_filter try_subst;
   230     in
   216     in
   242       Proof_Context.theory_of ctxt
   228       Proof_Context.theory_of ctxt
   243       |> Context_Position.set_visible_global (Context_Position.is_visible ctxt);
   229       |> Context_Position.set_visible_global (Context_Position.is_visible ctxt);
   244     val ctxt' = Proof_Context.transfer thy' ctxt;
   230     val ctxt' = Proof_Context.transfer thy' ctxt;
   245     val goal' = Thm.transfer thy' goal;
   231     val goal' = Thm.transfer thy' goal;
   246 
   232 
   247     fun etacn thm i =
   233     fun limited_etac thm i =
   248       Seq.take (Options.default_int @{option find_theorems_tac_limit}) o etac thm i;
   234       Seq.take (Options.default_int @{option find_theorems_tac_limit}) o etac thm i;
   249     fun try_thm thm =
   235     fun try_thm thm =
   250       if Thm.no_prems thm then rtac thm 1 goal'
   236       if Thm.no_prems thm then rtac thm 1 goal'
   251       else (etacn thm THEN_ALL_NEW (Goal.norm_hhf_tac THEN' Method.assm_tac ctxt')) 1 goal';
   237       else (limited_etac thm THEN_ALL_NEW (Goal.norm_hhf_tac THEN' Method.assm_tac ctxt')) 1 goal';
   252   in
   238   in
   253     fn Internal (_, thm) =>
   239     fn Internal (_, thm) =>
   254         if is_some (Seq.pull (try_thm thm))
   240         if is_some (Seq.pull (try_thm thm))
   255         then SOME (Thm.nprems_of thm, 0) else NONE
   241         then SOME (Thm.nprems_of thm, 0) else NONE
   256      | External _ => NONE
   242      | External _ => NONE
   414   |> map #1;
   400   |> map #1;
   415 
   401 
   416 end;
   402 end;
   417 
   403 
   418 
   404 
   419 (* pretty_theorems *)
   405 
       
   406 (** main operations **)
       
   407 
       
   408 (* filter_theorems *)
   420 
   409 
   421 fun all_facts_of ctxt =
   410 fun all_facts_of ctxt =
   422   let
   411   let
   423     fun visible_facts facts =
   412     fun visible_facts facts =
   424       Facts.dest_static [] facts
   413       Facts.dest_static [] facts
   453       else pair NONE o Seq.list_of o Seq.take (the opt_limit) o lazy_filter filters;
   442       else pair NONE o Seq.list_of o Seq.take (the opt_limit) o lazy_filter filters;
   454 
   443 
   455   in find theorems end;
   444   in find theorems end;
   456 
   445 
   457 fun filter_theorems_cmd ctxt theorems raw_query =
   446 fun filter_theorems_cmd ctxt theorems raw_query =
   458   filter_theorems ctxt theorems (map_criteria
   447   filter_theorems ctxt theorems (map_criteria (map (apsnd (read_criterion ctxt))) raw_query);
   459     (map (apsnd (read_criterion ctxt))) raw_query);
   448 
       
   449 
       
   450 (* find_theorems *)
       
   451 
       
   452 local
   460 
   453 
   461 fun gen_find_theorems filter ctxt opt_goal opt_limit rem_dups raw_criteria =
   454 fun gen_find_theorems filter ctxt opt_goal opt_limit rem_dups raw_criteria =
   462   let
   455   let
   463     val assms =
   456     val assms =
   464       Proof_Context.get_fact ctxt (Facts.named "local.assms")
   457       Proof_Context.get_fact ctxt (Facts.named "local.assms")
   469     filter ctxt (map Internal (all_facts_of ctxt))
   462     filter ctxt (map Internal (all_facts_of ctxt))
   470       {goal = opt_goal', limit = opt_limit, rem_dups = rem_dups, criteria = raw_criteria}
   463       {goal = opt_goal', limit = opt_limit, rem_dups = rem_dups, criteria = raw_criteria}
   471     |> apsnd (map (fn Internal f => f))
   464     |> apsnd (map (fn Internal f => f))
   472   end;
   465   end;
   473 
   466 
       
   467 in
       
   468 
   474 val find_theorems = gen_find_theorems filter_theorems;
   469 val find_theorems = gen_find_theorems filter_theorems;
   475 val find_theorems_cmd = gen_find_theorems filter_theorems_cmd;
   470 val find_theorems_cmd = gen_find_theorems filter_theorems_cmd;
       
   471 
       
   472 end;
       
   473 
       
   474 
       
   475 (* pretty_theorems *)
       
   476 
       
   477 local
   476 
   478 
   477 fun pretty_ref ctxt thmref =
   479 fun pretty_ref ctxt thmref =
   478   let
   480   let
   479     val (name, sel) =
   481     val (name, sel) =
   480       (case thmref of
   482       (case thmref of
   488 fun pretty_theorem ctxt (Internal (thmref, thm)) =
   490 fun pretty_theorem ctxt (Internal (thmref, thm)) =
   489       Pretty.block (pretty_ref ctxt thmref @ [Display.pretty_thm ctxt thm])
   491       Pretty.block (pretty_ref ctxt thmref @ [Display.pretty_thm ctxt thm])
   490   | pretty_theorem ctxt (External (thmref, prop)) =
   492   | pretty_theorem ctxt (External (thmref, prop)) =
   491       Pretty.block (pretty_ref ctxt thmref @ [Syntax.unparse_term ctxt prop]);
   493       Pretty.block (pretty_ref ctxt thmref @ [Syntax.unparse_term ctxt prop]);
   492 
   494 
       
   495 in
       
   496 
   493 fun pretty_thm ctxt (thmref, thm) = pretty_theorem ctxt (Internal (thmref, thm));
   497 fun pretty_thm ctxt (thmref, thm) = pretty_theorem ctxt (Internal (thmref, thm));
   494 
   498 
   495 fun pretty_theorems ctxt opt_goal opt_limit rem_dups raw_criteria =
   499 fun pretty_theorems state opt_limit rem_dups raw_criteria =
   496   let
   500   let
       
   501     val ctxt = Proof.context_of state;
       
   502     val opt_goal = try Proof.simple_goal state |> Option.map #goal;
   497     val criteria = map (apsnd (read_criterion ctxt)) raw_criteria;
   503     val criteria = map (apsnd (read_criterion ctxt)) raw_criteria;
       
   504 
   498     val (opt_found, theorems) =
   505     val (opt_found, theorems) =
   499       filter_theorems ctxt (map Internal (all_facts_of ctxt))
   506       filter_theorems ctxt (map Internal (all_facts_of ctxt))
   500         {goal = opt_goal, limit = opt_limit, rem_dups = rem_dups, criteria = criteria};
   507         {goal = opt_goal, limit = opt_limit, rem_dups = rem_dups, criteria = criteria};
   501     val returned = length theorems;
   508     val returned = length theorems;
   502 
   509 
   515      else
   522      else
   516       [Pretty.str (tally_msg ^ ":"), Pretty.str ""] @
   523       [Pretty.str (tally_msg ^ ":"), Pretty.str ""] @
   517         grouped 10 Par_List.map (Pretty.item o single o pretty_theorem ctxt) theorems)
   524         grouped 10 Par_List.map (Pretty.item o single o pretty_theorem ctxt) theorems)
   518   end |> Pretty.fbreaks |> curry Pretty.blk 0;
   525   end |> Pretty.fbreaks |> curry Pretty.blk 0;
   519 
   526 
   520 fun pretty_theorems_cmd state opt_lim rem_dups spec =
   527 end;
   521   let
       
   522     val ctxt = Toplevel.context_of state;
       
   523     val opt_goal = try (Proof.simple_goal o Toplevel.proof_of) state |> Option.map #goal;
       
   524   in pretty_theorems ctxt opt_goal opt_lim rem_dups spec end;
       
   525 
   528 
   526 
   529 
   527 
   530 
   528 (** Isar command syntax **)
   531 (** Isar command syntax **)
       
   532 
       
   533 fun proof_state st =
       
   534   (case try Toplevel.proof_of st of
       
   535     SOME state => state
       
   536   | NONE => Proof.init (Toplevel.context_of st));
   529 
   537 
   530 local
   538 local
   531 
   539 
   532 val criterion =
   540 val criterion =
   533   Parse.reserved "name" |-- Parse.!!! (Parse.$$$ ":" |-- Parse.xname) >> Name ||
   541   Parse.reserved "name" |-- Parse.!!! (Parse.$$$ ":" |-- Parse.xname) >> Name ||
   556 
   564 
   557 val _ =
   565 val _ =
   558   Outer_Syntax.improper_command @{command_spec "find_theorems"}
   566   Outer_Syntax.improper_command @{command_spec "find_theorems"}
   559     "find theorems meeting specified criteria"
   567     "find theorems meeting specified criteria"
   560     (options -- query >> (fn ((opt_lim, rem_dups), spec) =>
   568     (options -- query >> (fn ((opt_lim, rem_dups), spec) =>
   561       Toplevel.keep (fn state =>
   569       Toplevel.keep (fn st =>
   562         Pretty.writeln (pretty_theorems_cmd state opt_lim rem_dups spec))));
   570         Pretty.writeln (pretty_theorems (proof_state st) opt_lim rem_dups spec))));
   563 
   571 
   564 end;
   572 end;
   565 
   573 
   566 
   574 
   567 
   575 
   568 (** PIDE query operation **)
   576 (** PIDE query operation **)
   569 
   577 
   570 val _ =
   578 val _ =
   571   Query_Operation.register "find_theorems" (fn st => fn args =>
   579   Query_Operation.register "find_theorems" (fn st => fn args =>
   572     if can Toplevel.theory_of st then
   580     if can Toplevel.context_of st then
   573       Pretty.string_of (pretty_theorems_cmd st NONE false (maps (read_query Position.none) args))
   581       Pretty.string_of
   574     else error "Unknown theory context");
   582         (pretty_theorems (proof_state st) NONE false (maps (read_query Position.none) args))
   575 
   583     else error "Unknown context");
   576 end;
   584 
       
   585 end;