removing unneccessary manual instantiations and dead definitions; hiding more constants and facts
1 (* Author: Lukas Bulwahn, TU Muenchen *)
3 header {* Counterexample generator preforming narrowing-based testing *}
5 theory Quickcheck_Narrowing
6 imports Quickcheck_Exhaustive
8 ("~~/src/HOL/Tools/Quickcheck/PNF_Narrowing_Engine.hs")
9 ("~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs")
10 ("~~/src/HOL/Tools/Quickcheck/narrowing_generators.ML")
13 subsection {* Counterexample generator *}
15 text {* We create a new target for the necessary code generation setup. *}
17 setup {* Code_Target.extend_target ("Haskell_Quickcheck", (Code_Haskell.target, K I)) *}
19 subsubsection {* Code generation setup *}
22 (Haskell_Quickcheck "Typerep")
24 code_const Typerep.Typerep
25 (Haskell_Quickcheck "Typerep")
27 code_reserved Haskell_Quickcheck Typerep
30 (Haskell_Quickcheck "Char")
33 fold String_Code.add_literal_char ["Haskell_Quickcheck"]
34 #> String_Code.add_literal_list_string "Haskell_Quickcheck"
37 code_instance char :: equal
38 (Haskell_Quickcheck -)
40 code_const "HOL.equal \<Colon> char \<Rightarrow> char \<Rightarrow> bool"
41 (Haskell_Quickcheck infix 4 "==")
43 subsubsection {* Type @{text "code_int"} for Haskell_Quickcheck's Int type *}
45 typedef (open) code_int = "UNIV \<Colon> int set"
46 morphisms int_of of_int by rule
48 lemma of_int_int_of [simp]:
49 "of_int (int_of k) = k"
50 by (rule int_of_inverse)
52 lemma int_of_of_int [simp]:
53 "int_of (of_int n) = n"
54 by (rule of_int_inverse) (rule UNIV_I)
57 "(\<And>n\<Colon>code_int. PROP P n) \<equiv> (\<And>n\<Colon>int. PROP P (of_int n))"
60 assume "\<And>n\<Colon>code_int. PROP P n"
61 then show "PROP P (of_int n)" .
64 assume "\<And>n\<Colon>int. PROP P (of_int n)"
65 then have "PROP P (of_int (int_of n))" .
66 then show "PROP P n" by simp
70 lemma int_of_inject [simp]:
71 "int_of k = int_of l \<longleftrightarrow> k = l"
72 by (rule int_of_inject)
74 lemma of_int_inject [simp]:
75 "of_int n = of_int m \<longleftrightarrow> n = m"
76 by (rule of_int_inject) (rule UNIV_I)+
78 instantiation code_int :: equal
82 "HOL.equal k l \<longleftrightarrow> HOL.equal (int_of k) (int_of l)"
85 qed (auto simp add: equal_code_int_def equal_int_def eq_int_refl)
89 instantiation code_int :: number
99 lemma int_of_number [simp]:
100 "int_of (number_of k) = number_of k"
101 by (simp add: number_of_code_int_def number_of_is_id)
104 definition nat_of :: "code_int => nat"
106 "nat_of i = nat (int_of i)"
109 code_datatype "number_of \<Colon> int \<Rightarrow> code_int"
112 instantiation code_int :: "{minus, linordered_semidom, semiring_div, linorder}"
115 definition [simp, code del]:
118 definition [simp, code del]:
121 definition [simp, code del]:
122 "n + m = of_int (int_of n + int_of m)"
124 definition [simp, code del]:
125 "n - m = of_int (int_of n - int_of m)"
127 definition [simp, code del]:
128 "n * m = of_int (int_of n * int_of m)"
130 definition [simp, code del]:
131 "n div m = of_int (int_of n div int_of m)"
133 definition [simp, code del]:
134 "n mod m = of_int (int_of n mod int_of m)"
136 definition [simp, code del]:
137 "n \<le> m \<longleftrightarrow> int_of n \<le> int_of m"
139 definition [simp, code del]:
140 "n < m \<longleftrightarrow> int_of n < int_of m"
144 qed (auto simp add: code_int left_distrib zmult_zless_mono2)
148 lemma zero_code_int_code [code, code_unfold]:
149 "(0\<Colon>code_int) = Numeral0"
150 by (simp add: number_of_code_int_def Pls_def)
151 lemma [code_post]: "Numeral0 = (0\<Colon>code_int)"
152 using zero_code_int_code ..
154 lemma one_code_int_code [code, code_unfold]:
155 "(1\<Colon>code_int) = Numeral1"
156 by (simp add: number_of_code_int_def Pls_def Bit1_def)
157 lemma [code_post]: "Numeral1 = (1\<Colon>code_int)"
158 using one_code_int_code ..
161 definition div_mod_code_int :: "code_int \<Rightarrow> code_int \<Rightarrow> code_int \<times> code_int" where
162 [code del]: "div_mod_code_int n m = (n div m, n mod m)"
165 "div_mod_code_int n m = (if m = 0 then (0, n) else (n div m, n mod m))"
166 unfolding div_mod_code_int_def by auto
169 "n div m = fst (div_mod_code_int n m)"
170 unfolding div_mod_code_int_def by simp
173 "n mod m = snd (div_mod_code_int n m)"
174 unfolding div_mod_code_int_def by simp
176 lemma int_of_code [code]:
177 "int_of k = (if k = 0 then 0
178 else (if k mod 2 = 0 then 2 * int_of (k div 2) else 2 * int_of (k div 2) + 1))"
180 have 1: "(int_of k div 2) * 2 + int_of k mod 2 = int_of k"
181 by (rule mod_div_equality)
182 have "int_of k mod 2 = 0 \<or> int_of k mod 2 = 1" by auto
183 from this show ?thesis
185 apply (insert 1) by (auto simp add: mult_ac)
189 code_instance code_numeral :: equal
190 (Haskell_Quickcheck -)
192 setup {* fold (Numeral.add_code @{const_name number_code_int_inst.number_of_code_int}
193 false Code_Printer.literal_numeral) ["Haskell_Quickcheck"] *}
195 code_const "0 \<Colon> code_int"
196 (Haskell_Quickcheck "0")
198 code_const "1 \<Colon> code_int"
199 (Haskell_Quickcheck "1")
201 code_const "minus \<Colon> code_int \<Rightarrow> code_int \<Rightarrow> code_int"
202 (Haskell_Quickcheck "(_/ -/ _)")
204 code_const div_mod_code_int
205 (Haskell_Quickcheck "divMod")
207 code_const "HOL.equal \<Colon> code_int \<Rightarrow> code_int \<Rightarrow> bool"
208 (Haskell_Quickcheck infix 4 "==")
210 code_const "op \<le> \<Colon> code_int \<Rightarrow> code_int \<Rightarrow> bool"
211 (Haskell_Quickcheck infix 4 "<=")
213 code_const "op < \<Colon> code_int \<Rightarrow> code_int \<Rightarrow> bool"
214 (Haskell_Quickcheck infix 4 "<")
217 (Haskell_Quickcheck "Int")
221 subsubsection {* Narrowing's deep representation of types and terms *}
223 datatype narrowing_type = SumOfProd "narrowing_type list list"
225 datatype narrowing_term = Var "code_int list" narrowing_type | Ctr code_int "narrowing_term list"
226 datatype 'a cons = C narrowing_type "(narrowing_term list => 'a) list"
228 subsubsection {* From narrowing's deep representation of terms to Code_Evaluation's terms *}
230 class partial_term_of = typerep +
231 fixes partial_term_of :: "'a itself => narrowing_term => Code_Evaluation.term"
233 lemma partial_term_of_anything: "partial_term_of x nt \<equiv> t"
234 by (rule eq_reflection) (cases "partial_term_of x nt", cases t, simp)
237 subsubsection {* Auxilary functions for Narrowing *}
239 consts nth :: "'a list => code_int => 'a"
241 code_const nth (Haskell_Quickcheck infixl 9 "!!")
243 consts error :: "char list => 'a"
245 code_const error (Haskell_Quickcheck "error")
247 consts toEnum :: "code_int => char"
249 code_const toEnum (Haskell_Quickcheck "toEnum")
251 consts map_index :: "(code_int * 'a => 'b) => 'a list => 'b list"
253 consts split_At :: "code_int => 'a list => 'a list * 'a list"
255 subsubsection {* Narrowing's basic operations *}
257 type_synonym 'a narrowing = "code_int => 'a cons"
259 definition empty :: "'a narrowing"
261 "empty d = C (SumOfProd []) []"
263 definition cons :: "'a => 'a narrowing"
265 "cons a d = (C (SumOfProd [[]]) [(%_. a)])"
267 fun conv :: "(narrowing_term list => 'a) list => narrowing_term => 'a"
269 "conv cs (Var p _) = error (Char Nibble0 Nibble0 # map toEnum p)"
270 | "conv cs (Ctr i xs) = (nth cs i) xs"
272 fun nonEmpty :: "narrowing_type => bool"
274 "nonEmpty (SumOfProd ps) = (\<not> (List.null ps))"
276 definition "apply" :: "('a => 'b) narrowing => 'a narrowing => 'b narrowing"
279 (case f d of C (SumOfProd ps) cfs =>
280 case a (d - 1) of C ta cas =>
282 shallow = (d > 0 \<and> nonEmpty ta);
283 cs = [(%xs'. (case xs' of [] => undefined | x # xs => cf xs (conv cas x))). shallow, cf <- cfs]
284 in C (SumOfProd [ta # p. shallow, p <- ps]) cs)"
286 definition sum :: "'a narrowing => 'a narrowing => 'a narrowing"
289 (case a d of C (SumOfProd ssa) ca =>
290 case b d of C (SumOfProd ssb) cb =>
291 C (SumOfProd (ssa @ ssb)) (ca @ cb))"
294 assumes "a d = a' d" "b d = b' d" "d = d'"
295 shows "sum a b d = sum a' b' d'"
296 using assms unfolding sum_def by (auto split: cons.split narrowing_type.split)
299 assumes "f d = f' d" "(\<And>d'. 0 <= d' & d' < d ==> a d' = a' d')"
301 shows "apply f a d = apply f' a' d'"
304 have "int_of (of_int 0) < int_of d' ==> int_of (of_int 0) <= int_of (of_int (int_of d' - int_of (of_int 1)))"
305 by (simp add: of_int_inverse)
307 have "int_of (of_int (int_of d' - int_of (of_int 1))) < int_of d'"
308 by (simp add: of_int_inverse)
309 ultimately show ?thesis
310 unfolding apply_def by (auto split: cons.split narrowing_type.split simp add: Let_def)
313 subsubsection {* Narrowing generator type class *}
316 fixes narrowing :: "code_int => 'a cons"
318 definition drawn_from :: "'a list => 'a cons"
319 where "drawn_from xs = C (SumOfProd (map (%_. []) xs)) (map (%x y. x) xs)"
321 instantiation int :: narrowing
325 "narrowing_int d = (let i = Quickcheck_Narrowing.int_of d in drawn_from [-i .. i])"
331 datatype property = Universal narrowing_type "(narrowing_term => property)" "narrowing_term => Code_Evaluation.term" | Existential narrowing_type "(narrowing_term => property)" "narrowing_term => Code_Evaluation.term" | Property bool
333 (* FIXME: hard-wired maximal depth of 100 here *)
334 definition exists :: "('a :: {narrowing, partial_term_of} => property) => property"
336 "exists f = (case narrowing (100 :: code_int) of C ty cs => Existential ty (\<lambda> t. f (conv cs t)) (partial_term_of (TYPE('a))))"
338 definition "all" :: "('a :: {narrowing, partial_term_of} => property) => property"
340 "all f = (case narrowing (100 :: code_int) of C ty cs => Universal ty (\<lambda>t. f (conv cs t)) (partial_term_of (TYPE('a))))"
342 subsubsection {* class @{text is_testable} *}
344 text {* The class @{text is_testable} ensures that all necessary type instances are generated. *}
348 instance bool :: is_testable ..
350 instance "fun" :: ("{term_of, narrowing, partial_term_of}", is_testable) is_testable ..
352 definition ensure_testable :: "'a :: is_testable => 'a :: is_testable"
354 "ensure_testable f = f"
357 subsubsection {* Defining a simple datatype to represent functions in an incomplete and redundant way *}
359 datatype ('a, 'b) ffun = Constant 'b | Update 'a 'b "('a, 'b) ffun"
361 primrec eval_ffun :: "('a, 'b) ffun => 'a => 'b"
363 "eval_ffun (Constant c) x = c"
364 | "eval_ffun (Update x' y f) x = (if x = x' then y else eval_ffun f x)"
366 hide_type (open) ffun
367 hide_const (open) Constant Update eval_ffun
369 datatype 'b cfun = Constant 'b
371 primrec eval_cfun :: "'b cfun => 'a => 'b"
373 "eval_cfun (Constant c) y = c"
375 hide_type (open) cfun
376 hide_const (open) Constant eval_cfun
378 subsubsection {* Setting up the counterexample generator *}
380 setup {* Thy_Load.provide_file (Path.explode ("~~/src/HOL/Tools/Quickcheck/PNF_Narrowing_Engine.hs")) *}
381 setup {* Thy_Load.provide_file (Path.explode ("~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs")) *}
382 use "~~/src/HOL/Tools/Quickcheck/narrowing_generators.ML"
384 setup {* Narrowing_Generators.setup *}
386 hide_type code_int narrowing_type narrowing_term cons property
387 hide_const int_of of_int nth error toEnum map_index split_At empty
388 C cons conv nonEmpty "apply" sum ensure_testable all exists
389 hide_fact empty_def cons_def conv.simps nonEmpty.simps apply_def sum_def ensure_testable_def all_def exists_def