1 (* Title: HOL/Nitpick_Examples/Mono_Nits.thy
2 Author: Jasmin Blanchette, TU Muenchen
5 Examples featuring Nitpick's monotonicity check.
8 section {* Examples Featuring Nitpick's Monotonicity Check *}
12 (* "~/afp/thys/DPT-SAT-Solver/DPT_SAT_Solver" *)
13 (* "~/afp/thys/AVL-Trees/AVL2" "~/afp/thys/Huffman/Huffman" *)
26 val tac_timeout = seconds 1.0
27 val case_names = case_const_names ctxt
28 val defs = all_defs_of thy subst
29 val nondefs = all_nondefs_of ctxt subst
30 val def_tables = const_def_tables ctxt subst defs
31 val nondef_table = const_nondef_table nondefs
32 val simp_table = Unsynchronized.ref (const_simp_table ctxt subst)
33 val psimp_table = const_psimp_table ctxt subst
34 val choice_spec_table = const_choice_spec_table ctxt subst
35 val intro_table = inductive_intro_table ctxt subst def_tables
36 val ground_thm_table = ground_theorem_table thy
37 val ersatz_table = ersatz_table ctxt
38 val hol_ctxt as {thy, ...} : hol_context =
39 {thy = thy, ctxt = ctxt, max_bisim_depth = ~1, boxes = [], wfs = [],
40 user_axioms = NONE, debug = false, whacks = [], binary_ints = SOME false,
41 destroy_constrs = true, specialize = false, star_linear_preds = false,
42 total_consts = NONE, needs = NONE, tac_timeout = tac_timeout, evals = [],
43 case_names = case_names, def_tables = def_tables,
44 nondef_table = nondef_table, nondefs = nondefs, simp_table = simp_table,
45 psimp_table = psimp_table, choice_spec_table = choice_spec_table,
46 intro_table = intro_table, ground_thm_table = ground_thm_table,
47 ersatz_table = ersatz_table, skolems = Unsynchronized.ref [],
48 special_funs = Unsynchronized.ref [], unrolled_preds = Unsynchronized.ref [],
49 wf_cache = Unsynchronized.ref [], constr_cache = Unsynchronized.ref []}
53 Nitpick_Mono.formulas_monotonic hol_ctxt binarize @{typ 'a} ([t], [])
56 let val T = fastype_of t in
57 Logic.mk_implies (Logic.mk_equals (Free ("dummyP", T), t), @{const False})
61 fun mono t = is_mono t orelse raise BUG
62 fun nonmono t = not (is_mono t) orelse raise BUG
63 fun const t = is_const t orelse raise BUG
64 fun nonconst t = not (is_const t) orelse raise BUG
67 ML {* Nitpick_Mono.trace := false *}
69 ML_val {* const @{term "A\<Colon>('a\<Rightarrow>'b)"} *}
70 ML_val {* const @{term "(A\<Colon>'a set) = A"} *}
71 ML_val {* const @{term "(A\<Colon>'a set set) = A"} *}
72 ML_val {* const @{term "(\<lambda>x\<Colon>'a set. a \<in> x)"} *}
73 ML_val {* const @{term "{{a\<Colon>'a}} = C"} *}
74 ML_val {* const @{term "{f\<Colon>'a\<Rightarrow>nat} = {g\<Colon>'a\<Rightarrow>nat}"} *}
75 ML_val {* const @{term "A \<union> (B\<Colon>'a set)"} *}
76 ML_val {* const @{term "\<lambda>A B x\<Colon>'a. A x \<or> B x"} *}
77 ML_val {* const @{term "P (a\<Colon>'a)"} *}
78 ML_val {* const @{term "\<lambda>a\<Colon>'a. b (c (d\<Colon>'a)) (e\<Colon>'a) (f\<Colon>'a)"} *}
79 ML_val {* const @{term "\<forall>A\<Colon>'a set. a \<in> A"} *}
80 ML_val {* const @{term "\<forall>A\<Colon>'a set. P A"} *}
81 ML_val {* const @{term "P \<or> Q"} *}
82 ML_val {* const @{term "A \<union> B = (C\<Colon>'a set)"} *}
83 ML_val {* const @{term "(\<lambda>A B x\<Colon>'a. A x \<or> B x) A B = C"} *}
84 ML_val {* const @{term "(if P then (A\<Colon>'a set) else B) = C"} *}
85 ML_val {* const @{term "let A = (C\<Colon>'a set) in A \<union> B"} *}
86 ML_val {* const @{term "THE x\<Colon>'b. P x"} *}
87 ML_val {* const @{term "(\<lambda>x\<Colon>'a. False)"} *}
88 ML_val {* const @{term "(\<lambda>x\<Colon>'a. True)"} *}
89 ML_val {* const @{term "(\<lambda>x\<Colon>'a. False) = (\<lambda>x\<Colon>'a. False)"} *}
90 ML_val {* const @{term "(\<lambda>x\<Colon>'a. True) = (\<lambda>x\<Colon>'a. True)"} *}
91 ML_val {* const @{term "Let (a\<Colon>'a) A"} *}
92 ML_val {* const @{term "A (a\<Colon>'a)"} *}
93 ML_val {* const @{term "insert (a\<Colon>'a) A = B"} *}
94 ML_val {* const @{term "- (A\<Colon>'a set)"} *}
95 ML_val {* const @{term "finite (A\<Colon>'a set)"} *}
96 ML_val {* const @{term "\<not> finite (A\<Colon>'a set)"} *}
97 ML_val {* const @{term "finite (A\<Colon>'a set set)"} *}
98 ML_val {* const @{term "\<lambda>a\<Colon>'a. A a \<and> \<not> B a"} *}
99 ML_val {* const @{term "A < (B\<Colon>'a set)"} *}
100 ML_val {* const @{term "A \<le> (B\<Colon>'a set)"} *}
101 ML_val {* const @{term "[a\<Colon>'a]"} *}
102 ML_val {* const @{term "[a\<Colon>'a set]"} *}
103 ML_val {* const @{term "[A \<union> (B\<Colon>'a set)]"} *}
104 ML_val {* const @{term "[A \<union> (B\<Colon>'a set)] = [C]"} *}
105 ML_val {* const @{term "{(\<lambda>x\<Colon>'a. x = a)} = C"} *}
106 ML_val {* const @{term "(\<lambda>a\<Colon>'a. \<not> A a) = B"} *}
107 ML_val {* const @{prop "\<forall>F f g (h\<Colon>'a set). F f \<and> F g \<and> \<not> f a \<and> g a \<longrightarrow> \<not> f a"} *}
108 ML_val {* const @{term "\<lambda>A B x\<Colon>'a. A x \<and> B x \<and> A = B"} *}
109 ML_val {* const @{term "p = (\<lambda>(x\<Colon>'a) (y\<Colon>'a). P x \<or> \<not> Q y)"} *}
110 ML_val {* const @{term "p = (\<lambda>(x\<Colon>'a) (y\<Colon>'a). p x y \<Colon> bool)"} *}
111 ML_val {* const @{term "p = (\<lambda>A B x. A x \<and> \<not> B x) (\<lambda>x. True) (\<lambda>y. x \<noteq> y)"} *}
112 ML_val {* const @{term "p = (\<lambda>y. x \<noteq> y)"} *}
113 ML_val {* const @{term "(\<lambda>x. (p\<Colon>'a\<Rightarrow>bool\<Rightarrow>bool) x False)"} *}
114 ML_val {* const @{term "(\<lambda>x y. (p\<Colon>'a\<Rightarrow>'a\<Rightarrow>bool\<Rightarrow>bool) x y False)"} *}
115 ML_val {* const @{term "f = (\<lambda>x\<Colon>'a. P x \<longrightarrow> Q x)"} *}
116 ML_val {* const @{term "\<forall>a\<Colon>'a. P a"} *}
118 ML_val {* nonconst @{term "\<forall>P (a\<Colon>'a). P a"} *}
119 ML_val {* nonconst @{term "THE x\<Colon>'a. P x"} *}
120 ML_val {* nonconst @{term "SOME x\<Colon>'a. P x"} *}
121 ML_val {* nonconst @{term "(\<lambda>A B x\<Colon>'a. A x \<or> B x) = myunion"} *}
122 ML_val {* nonconst @{term "(\<lambda>x\<Colon>'a. False) = (\<lambda>x\<Colon>'a. True)"} *}
123 ML_val {* nonconst @{prop "\<forall>F f g (h\<Colon>'a set). F f \<and> F g \<and> \<not> a \<in> f \<and> a \<in> g \<longrightarrow> F h"} *}
125 ML_val {* mono @{prop "Q (\<forall>x\<Colon>'a set. P x)"} *}
126 ML_val {* mono @{prop "P (a\<Colon>'a)"} *}
127 ML_val {* mono @{prop "{a} = {b\<Colon>'a}"} *}
128 ML_val {* mono @{prop "(\<lambda>x. x = a) = (\<lambda>y. y = (b\<Colon>'a))"} *}
129 ML_val {* mono @{prop "(a\<Colon>'a) \<in> P \<and> P \<union> P = P"} *}
130 ML_val {* mono @{prop "\<forall>F\<Colon>'a set set. P"} *}
131 ML_val {* mono @{prop "\<not> (\<forall>F f g (h\<Colon>'a set). F f \<and> F g \<and> \<not> a \<in> f \<and> a \<in> g \<longrightarrow> F h)"} *}
132 ML_val {* mono @{prop "\<not> Q (\<forall>x\<Colon>'a set. P x)"} *}
133 ML_val {* mono @{prop "\<not> (\<forall>x\<Colon>'a. P x)"} *}
134 ML_val {* mono @{prop "myall P = (P = (\<lambda>x\<Colon>'a. True))"} *}
135 ML_val {* mono @{prop "myall P = (P = (\<lambda>x\<Colon>'a. False))"} *}
136 ML_val {* mono @{prop "\<forall>x\<Colon>'a. P x"} *}
137 ML_val {* mono @{term "(\<lambda>A B x\<Colon>'a. A x \<or> B x) \<noteq> myunion"} *}
139 ML_val {* nonmono @{prop "A = (\<lambda>x::'a. True) \<and> A = (\<lambda>x. False)"} *}
140 ML_val {* nonmono @{prop "\<forall>F f g (h\<Colon>'a set). F f \<and> F g \<and> \<not> a \<in> f \<and> a \<in> g \<longrightarrow> F h"} *}
143 val preproc_timeout = seconds 5.0
144 val mono_timeout = seconds 1.0
146 fun is_forbidden_theorem name =
147 length (Long_Name.explode name) <> 2 orelse
148 String.isPrefix "type_definition" (List.last (Long_Name.explode name)) orelse
149 String.isPrefix "arity_" (List.last (Long_Name.explode name)) orelse
150 String.isSuffix "_def" name orelse
151 String.isSuffix "_raw" name
153 fun theorems_of thy =
154 filter (fn (name, th) =>
155 not (is_forbidden_theorem name) andalso
156 (theory_of_thm th, thy) |> pairself Context.theory_name |> op =)
157 (Global_Theory.all_thms_of thy true)
159 fun check_formulas tsp =
161 fun is_type_actually_monotonic T =
162 Nitpick_Mono.formulas_monotonic hol_ctxt binarize T tsp
163 val free_Ts = fold Term.add_tfrees (op @ tsp) [] |> map TFree
164 val (mono_free_Ts, nonmono_free_Ts) =
165 TimeLimit.timeLimit mono_timeout
166 (List.partition is_type_actually_monotonic) free_Ts
168 if not (null mono_free_Ts) then "MONO"
169 else if not (null nonmono_free_Ts) then "NONMONO"
172 handle TimeLimit.TimeOut => "TIMEOUT"
173 | NOT_SUPPORTED _ => "UNSUP"
174 | exn => if Exn.is_interrupt exn then reraise exn else "UNKNOWN"
176 fun check_theory thy =
178 val path = File.tmp_path (Context.theory_name thy ^ ".out" |> Path.explode)
179 val _ = File.write path ""
180 fun check_theorem (name, th) =
182 val t = th |> prop_of |> Type.legacy_freeze |> close_form
183 val neg_t = Logic.mk_implies (t, @{prop False})
184 val (nondef_ts, def_ts, _, _, _, _) =
185 TimeLimit.timeLimit preproc_timeout (preprocess_formulas hol_ctxt [])
187 val res = name ^ ": " ^ check_formulas (nondef_ts, def_ts)
188 in File.append path (res ^ "\n"); writeln res end
189 handle TimeLimit.TimeOut => ()
190 in thy |> theorems_of |> List.app check_theorem end
194 ML_val {* check_theory @{theory AVL2} *}
195 ML_val {* check_theory @{theory Fun} *}
196 ML_val {* check_theory @{theory Huffman} *}
197 ML_val {* check_theory @{theory List} *}
198 ML_val {* check_theory @{theory Map} *}
199 ML_val {* check_theory @{theory Relation} *}
202 ML {* getenv "ISABELLE_TMP" *}