src/HOL/Tools/Quickcheck/find_unused_assms.ML
author wenzelm
Sun, 20 May 2012 11:34:33 +0200
changeset 47884 21c42b095c84
parent 46961 5c6955f487e5
child 50286 e8b29ddbb61f
permissions -rw-r--r--
try to avoid races again (cf. 8c37cb84065f and fd3a36e48b09);
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     1
(*  Title:      HOL/Tools/Quickcheck/find_unused_assms.ML
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     2
    Author:     Lukas Bulwahn, TU Muenchen
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     3
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     4
Finding unused assumptions in lemmas (using Quickcheck)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     5
*)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     6
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     7
signature FIND_UNUSED_ASSMS =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     8
sig
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
     9
  val find_unused_assms : Proof.context -> string -> (string * int list list option) list
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    10
  val print_unused_assms : Proof.context -> string option -> unit
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    11
end;
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    12
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    13
structure Find_Unused_Assms : FIND_UNUSED_ASSMS =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    14
struct
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    15
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    16
fun all_unconcealed_thms_of thy =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    17
  let
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    18
    val facts = Global_Theory.facts_of thy
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    19
  in
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    20
    Facts.fold_static
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    21
      (fn (s, ths) =>
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    22
        if Facts.is_concealed facts s then I else append (map (`(Thm.get_name_hint)) ths))
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    23
      facts []
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    24
  end;
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    25
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    26
fun thms_of thy thy_name = all_unconcealed_thms_of thy
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    27
  |> filter (fn (_, th) => Context.theory_name (theory_of_thm th) = thy_name);
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    28
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    29
fun do_while P f s = if P s then (let val s' = f s in (do_while P f s') o (cons s') end) else I
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    30
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    31
fun drop_indexes is xs = fold_index (fn (i, x) => if member (op =) is i then I else cons x) xs []
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    32
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    33
fun find_max_subsets [] = []
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    34
  | find_max_subsets (ss :: sss) = ss ::
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    35
      (find_max_subsets (map (filter_out (fn s => exists (fn s' => subset (op =) (s, s')) ss)) sss))
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    36
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    37
(* main functionality *)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    38
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    39
fun find_unused_assms ctxt thy_name =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    40
  let
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    41
    val ctxt' = ctxt
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    42
       |> Config.put Quickcheck.abort_potential true
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    43
       |> Config.put Quickcheck.quiet true
46711
f745bcc4a1e5 more explicit Long_Name operations (NB: analyzing qualifiers is inherently fragile);
wenzelm
parents: 46589
diff changeset
    44
    val all_thms = filter (fn (s, _) => length (Long_Name.explode s) = 2)  (* FIXME !? *)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    45
      (thms_of (Proof_Context.theory_of ctxt) thy_name)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    46
    fun check_single conjecture =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    47
      case try (Quickcheck.test_terms ctxt' (true, true) []) [(conjecture, [])] of
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    48
         SOME (SOME _) => false
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    49
       | SOME NONE => true
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    50
       | NONE => false
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    51
    fun build X Ss =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    52
      fold (fn S => fold
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    53
        (fn x => if member (op =) S x then I
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    54
          else insert (eq_set (op =)) (insert (op =) x S)) X) Ss []
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    55
    fun check (s, th) =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    56
      case Logic.strip_horn (prop_of (Thm.unvarify_global th)) of
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    57
        ([], _) => cons (s, NONE)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    58
      | (ts, t) =>
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    59
        let
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    60
          fun mk_conjecture is = (Logic.list_implies (drop_indexes is ts, t))
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    61
          val singles = filter (check_single o mk_conjecture o single) (map_index fst ts) 
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    62
          val multiples = do_while (not o null)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    63
            (fn I => filter (check_single o mk_conjecture) (build singles I))
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    64
            (map single singles) [(map single singles)]
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    65
          val maximals = flat (find_max_subsets multiples)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    66
        in
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    67
          cons (s, SOME maximals)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    68
        end
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    69
  in
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    70
    fold check all_thms []
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    71
  end
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    72
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    73
(* printing results *)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    74
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    75
fun pretty_indexes is =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    76
  Pretty.block (separate (Pretty.str " and ")
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    77
      (map (fn x => Pretty.str (string_of_int (x + 1))) (sort int_ord is))
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    78
     @ [Pretty.brk 1])
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    79
  
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    80
fun pretty_thm (s, SOME set_of_indexes) =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    81
  Pretty.block (Pretty.str s :: Pretty.str ":" :: Pretty.brk 1 ::
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    82
    Pretty.str "unnecessary assumption(s) " ::
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    83
    separate (Pretty.str ", or ") (map pretty_indexes set_of_indexes))
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    84
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    85
fun print_unused_assms ctxt opt_thy_name =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    86
  let
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    87
    val thy_name = the_default (Context.theory_name (Proof_Context.theory_of ctxt)) opt_thy_name
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    88
    val results = find_unused_assms ctxt thy_name
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    89
    val total = length results
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    90
    val with_assumptions = length (filter (is_some o snd) results)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    91
    val with_superfluous_assumptions = filter_out (fn (_, r) => r = SOME [])
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    92
      (filter (is_some o snd) results)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    93
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    94
    val msg = "Found " ^ string_of_int (length with_superfluous_assumptions)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    95
      ^ " theorem(s) with (potentially) superfluous assumptions"      
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    96
    val end_msg = "Checked " ^ string_of_int with_assumptions ^ " theorem(s) with assumptions"
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    97
      ^ " in the theory " ^ quote thy_name
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    98
      ^ " with a total of " ^ string_of_int total ^ " theorem(s)"  
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    99
  in
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   100
    ([Pretty.str (msg ^ ":"), Pretty.str ""] @
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   101
        map pretty_thm with_superfluous_assumptions
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   102
    @ [Pretty.str "", Pretty.str end_msg])
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   103
  end |> Pretty.chunks |> Pretty.writeln;
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   104
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   105
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   106
val _ =
46961
5c6955f487e5 outer syntax command definitions based on formal command_spec derived from theory header declarations;
wenzelm
parents: 46716
diff changeset
   107
  Outer_Syntax.improper_command @{command_spec "find_unused_assms"}
5c6955f487e5 outer syntax command definitions based on formal command_spec derived from theory header declarations;
wenzelm
parents: 46716
diff changeset
   108
    "find theorems with superfluous assumptions"
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   109
    (Scan.option Parse.name
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   110
      >> (fn opt_thy_name =>
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   111
        Toplevel.no_timing o Toplevel.keep (fn state =>
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   112
          print_unused_assms (Toplevel.context_of state) opt_thy_name)));
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   113
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   114
end;