src/HOL/Tools/Quickcheck/find_unused_assms.ML
author wenzelm
Tue, 09 Apr 2013 15:29:25 +0200
changeset 51658 21c10672633b
parent 50578 9efc99c990d5
child 56161 300f613060b0
permissions -rw-r--r--
discontinued Toplevel.no_timing complication -- also recovers timing of diagnostic commands, e.g. 'find_theorems'; print timing as tracing, to keep it out of the way in Proof General; no timing of control commands, especially relevant for Proof General;
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
50286
wenzelm
parents: 46961
diff changeset
     4
Finding unused assumptions in lemmas (using Quickcheck).
46589
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
50286
wenzelm
parents: 46961
diff changeset
    11
end
46589
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 []
50286
wenzelm
parents: 46961
diff changeset
    24
  end
46589
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
50286
wenzelm
parents: 46961
diff changeset
    27
  |> filter (fn (_, th) => Context.theory_name (theory_of_thm th) = thy_name)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    28
50286
wenzelm
parents: 46961
diff changeset
    29
fun do_while P f s list =
wenzelm
parents: 46961
diff changeset
    30
  if P s then
wenzelm
parents: 46961
diff changeset
    31
    let val s' = f s
wenzelm
parents: 46961
diff changeset
    32
    in do_while P f s' (cons s' list) end
wenzelm
parents: 46961
diff changeset
    33
  else list
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    34
50286
wenzelm
parents: 46961
diff changeset
    35
fun drop_indexes is xs =
wenzelm
parents: 46961
diff changeset
    36
  fold_index (fn (i, x) => if member (op =) is i then I else cons x) xs []
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    37
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    38
fun find_max_subsets [] = []
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    39
  | find_max_subsets (ss :: sss) = ss ::
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    40
      (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
    41
50286
wenzelm
parents: 46961
diff changeset
    42
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    43
(* main functionality *)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    44
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    45
fun find_unused_assms ctxt thy_name =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    46
  let
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    47
    val ctxt' = ctxt
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    48
       |> Config.put Quickcheck.abort_potential true
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    49
       |> Config.put Quickcheck.quiet true
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    50
    val all_thms =
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    51
      filter (fn (s, _) => length (Long_Name.explode s) = 2)  (* FIXME !? *)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    52
        (thms_of (Proof_Context.theory_of ctxt) thy_name)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    53
    fun check_single conjecture =
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    54
      (case try (Quickcheck.test_terms ctxt' (true, true) []) [(conjecture, [])] of
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    55
        SOME (SOME _) => false
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    56
      | SOME NONE => true
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    57
      | NONE => false)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    58
    fun build X Ss =
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    59
      fold
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    60
        (fn S => fold
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    61
          (fn x =>
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    62
            if member (op =) S x then I
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    63
            else insert (eq_set (op =)) (insert (op =) x S)) X) Ss []
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    64
    fun check (s, th) =
50286
wenzelm
parents: 46961
diff changeset
    65
      (case Logic.strip_horn (prop_of (Thm.unvarify_global th)) of
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    66
        ([], _) => (s, NONE)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    67
      | (ts, t) =>
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    68
          let
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    69
            fun mk_conjecture is = Logic.list_implies (drop_indexes is ts, t)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    70
            val singles = filter (check_single o mk_conjecture o single) (0 upto (length ts - 1))
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    71
            val multiples =
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    72
              do_while (not o null)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    73
                (fn I => filter (check_single o mk_conjecture) (build singles I))
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    74
                (map single singles) [(map single singles)]
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    75
            val maximals = flat (find_max_subsets multiples)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    76
          in
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    77
            (s, SOME maximals)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    78
          end)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    79
  in
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    80
    rev (Par_List.map check all_thms)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    81
  end
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    82
50286
wenzelm
parents: 46961
diff changeset
    83
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    84
(* printing results *)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    85
50286
wenzelm
parents: 46961
diff changeset
    86
local
wenzelm
parents: 46961
diff changeset
    87
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    88
fun pretty_indexes is =
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    89
  Pretty.block
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    90
    (flat (separate [Pretty.str " and", Pretty.brk 1]
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    91
      (map (fn i => [Pretty.str (string_of_int (i + 1))]) (sort int_ord is))))
50286
wenzelm
parents: 46961
diff changeset
    92
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    93
fun pretty_thm (s, set_of_indexes) =
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    94
  Pretty.block (Pretty.str s :: Pretty.str ":" :: Pretty.brk 1 ::
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    95
    Pretty.str "unnecessary assumption(s) " ::
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    96
    separate (Pretty.str " or ") (map pretty_indexes set_of_indexes))
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    97
50286
wenzelm
parents: 46961
diff changeset
    98
in
wenzelm
parents: 46961
diff changeset
    99
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   100
fun print_unused_assms ctxt opt_thy_name =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   101
  let
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   102
    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
   103
    val results = find_unused_assms ctxt thy_name
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   104
    val total = length results
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   105
    val with_assumptions = length (filter (is_some o snd) results)
50286
wenzelm
parents: 46961
diff changeset
   106
    val with_superfluous_assumptions =
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
   107
      map_filter (fn (_, NONE) => NONE | (_, SOME []) => NONE | (s, SOME r) => SOME (s, r)) results
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   108
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   109
    val msg =
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   110
      "Found " ^ string_of_int (length with_superfluous_assumptions) ^
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   111
      " theorems with (potentially) superfluous assumptions"
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   112
    val end_msg =
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   113
      "Checked " ^ string_of_int with_assumptions ^ " theorems with assumptions (" ^
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   114
      string_of_int total ^ " total) in the theory " ^ quote thy_name
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   115
  in
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
   116
    [Pretty.str (msg ^ ":"), Pretty.str ""] @
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
   117
    map pretty_thm with_superfluous_assumptions @
50286
wenzelm
parents: 46961
diff changeset
   118
    [Pretty.str "", Pretty.str end_msg]
wenzelm
parents: 46961
diff changeset
   119
  end |> Pretty.chunks |> Pretty.writeln
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   120
50286
wenzelm
parents: 46961
diff changeset
   121
end
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   122
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   123
val _ =
46961
5c6955f487e5 outer syntax command definitions based on formal command_spec derived from theory header declarations;
wenzelm
parents: 46716
diff changeset
   124
  Outer_Syntax.improper_command @{command_spec "find_unused_assms"}
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   125
    "find theorems with (potentially) superfluous assumptions"
51658
21c10672633b discontinued Toplevel.no_timing complication -- also recovers timing of diagnostic commands, e.g. 'find_theorems';
wenzelm
parents: 50578
diff changeset
   126
    (Scan.option Parse.name >> (fn name =>
21c10672633b discontinued Toplevel.no_timing complication -- also recovers timing of diagnostic commands, e.g. 'find_theorems';
wenzelm
parents: 50578
diff changeset
   127
      Toplevel.keep (fn state => print_unused_assms (Toplevel.context_of state) name)))
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   128
50286
wenzelm
parents: 46961
diff changeset
   129
end