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