src/HOL/Tools/Quickcheck/find_unused_assms.ML
author wenzelm
Tue, 28 Jul 2015 21:47:03 +0200
changeset 60825 bacfb7c45d81
parent 60638 16d80e5ef2dc
child 65458 cf504b7a7aa7
permissions -rw-r--r--
more explicit context; tuned signature;
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
60638
16d80e5ef2dc tuned signature;
wenzelm
parents: 59936
diff changeset
    16
fun thms_of thy thy_name =
16d80e5ef2dc tuned signature;
wenzelm
parents: 59936
diff changeset
    17
  Global_Theory.all_thms_of thy false
16d80e5ef2dc tuned signature;
wenzelm
parents: 59936
diff changeset
    18
  |> filter (fn (_, th) => Thm.theory_name_of_thm th = thy_name)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    19
50286
wenzelm
parents: 46961
diff changeset
    20
fun do_while P f s list =
wenzelm
parents: 46961
diff changeset
    21
  if P s then
wenzelm
parents: 46961
diff changeset
    22
    let val s' = f s
wenzelm
parents: 46961
diff changeset
    23
    in do_while P f s' (cons s' list) end
wenzelm
parents: 46961
diff changeset
    24
  else list
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    25
50286
wenzelm
parents: 46961
diff changeset
    26
fun drop_indexes is xs =
wenzelm
parents: 46961
diff changeset
    27
  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
    28
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    29
fun find_max_subsets [] = []
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    30
  | find_max_subsets (ss :: sss) = ss ::
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    31
      (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
    32
50286
wenzelm
parents: 46961
diff changeset
    33
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    34
(* main functionality *)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    35
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    36
fun find_unused_assms ctxt thy_name =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    37
  let
60825
bacfb7c45d81 more explicit context;
wenzelm
parents: 60638
diff changeset
    38
    val thy = Proof_Context.theory_of ctxt
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    39
    val ctxt' = ctxt
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    40
       |> Config.put Quickcheck.abort_potential true
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    41
       |> Config.put Quickcheck.quiet true
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    42
    val all_thms =
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    43
      filter (fn (s, _) => length (Long_Name.explode s) = 2)  (* FIXME !? *)
60825
bacfb7c45d81 more explicit context;
wenzelm
parents: 60638
diff changeset
    44
        (thms_of thy thy_name)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    45
    fun check_single conjecture =
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    46
      (case try (Quickcheck.test_terms ctxt' (true, true) []) [(conjecture, [])] of
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    47
        SOME (SOME _) => false
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    48
      | SOME NONE => true
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    49
      | NONE => false)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    50
    fun build X Ss =
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    51
      fold
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    52
        (fn S => fold
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    53
          (fn x =>
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    54
            if member (op =) S x then I
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    55
            else insert (eq_set (op =)) (insert (op =) x S)) X) Ss []
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    56
    fun check (s, th) =
60825
bacfb7c45d81 more explicit context;
wenzelm
parents: 60638
diff changeset
    57
      (case Logic.strip_horn (Thm.prop_of (Thm.unvarify_global thy th)) of
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    58
        ([], _) => (s, NONE)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    59
      | (ts, t) =>
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    60
          let
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    61
            fun mk_conjecture is = Logic.list_implies (drop_indexes is ts, t)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    62
            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
    63
            val multiples =
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    64
              do_while (not o null)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    65
                (fn I => filter (check_single o mk_conjecture) (build singles I))
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    66
                (map single singles) [(map single singles)]
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    67
            val maximals = flat (find_max_subsets multiples)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    68
          in
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    69
            (s, SOME maximals)
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    70
          end)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    71
  in
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    72
    rev (Par_List.map check all_thms)
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    73
  end
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    74
50286
wenzelm
parents: 46961
diff changeset
    75
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    76
(* printing results *)
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    77
50286
wenzelm
parents: 46961
diff changeset
    78
local
wenzelm
parents: 46961
diff changeset
    79
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    80
fun pretty_indexes is =
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    81
  Pretty.block
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    82
    (flat (separate [Pretty.str " and", Pretty.brk 1]
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    83
      (map (fn i => [Pretty.str (string_of_int (i + 1))]) (sort int_ord is))))
50286
wenzelm
parents: 46961
diff changeset
    84
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    85
fun pretty_thm (s, set_of_indexes) =
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    86
  Pretty.block (Pretty.str s :: Pretty.str ":" :: Pretty.brk 1 ::
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    87
    Pretty.str "unnecessary assumption(s) " ::
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
    88
    separate (Pretty.str " or ") (map pretty_indexes set_of_indexes))
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    89
50286
wenzelm
parents: 46961
diff changeset
    90
in
wenzelm
parents: 46961
diff changeset
    91
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    92
fun print_unused_assms ctxt opt_thy_name =
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    93
  let
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    94
    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
    95
    val results = find_unused_assms ctxt thy_name
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    96
    val total = length results
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
    97
    val with_assumptions = length (filter (is_some o snd) results)
50286
wenzelm
parents: 46961
diff changeset
    98
    val with_superfluous_assumptions =
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
    99
      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
   100
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   101
    val msg =
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   102
      "Found " ^ string_of_int (length with_superfluous_assumptions) ^
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   103
      " theorems with (potentially) superfluous assumptions"
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   104
    val end_msg =
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   105
      "Checked " ^ string_of_int with_assumptions ^ " theorems with assumptions (" ^
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   106
      string_of_int total ^ " total) in the theory " ^ quote thy_name
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   107
  in
50287
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
   108
    [Pretty.str (msg ^ ":"), Pretty.str ""] @
6cb7a7b97eac simplified use of fold/map;
wenzelm
parents: 50286
diff changeset
   109
    map pretty_thm with_superfluous_assumptions @
50286
wenzelm
parents: 46961
diff changeset
   110
    [Pretty.str "", Pretty.str end_msg]
56334
6b3739fee456 some shortcuts for chunks, which sometimes avoid bulky string output;
wenzelm
parents: 56161
diff changeset
   111
  end |> Pretty.writeln_chunks
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   112
50286
wenzelm
parents: 46961
diff changeset
   113
end
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   114
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   115
val _ =
59936
b8ffc3dc9e24 @{command_spec} is superseded by @{command_keyword};
wenzelm
parents: 59582
diff changeset
   116
  Outer_Syntax.command @{command_keyword find_unused_assms}
50578
9efc99c990d5 more parallel find_unused_assms;
wenzelm
parents: 50287
diff changeset
   117
    "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
   118
    (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
   119
      Toplevel.keep (fn state => print_unused_assms (Toplevel.context_of state) name)))
46589
689311986778 adding new command "find_unused_assms"
bulwahn
parents:
diff changeset
   120
50286
wenzelm
parents: 46961
diff changeset
   121
end