haftmann@29132
|
1 |
(* Author: Florian Haftmann, TU Muenchen *)
|
haftmann@26265
|
2 |
|
haftmann@26265
|
3 |
header {* A simple counterexample generator *}
|
haftmann@26265
|
4 |
|
haftmann@26265
|
5 |
theory Quickcheck
|
haftmann@32657
|
6 |
imports Random Code_Evaluation
|
haftmann@31260
|
7 |
uses ("Tools/quickcheck_generators.ML")
|
haftmann@26265
|
8 |
begin
|
haftmann@26265
|
9 |
|
haftmann@31179
|
10 |
notation fcomp (infixl "o>" 60)
|
haftmann@31179
|
11 |
notation scomp (infixl "o\<rightarrow>" 60)
|
haftmann@31179
|
12 |
|
haftmann@31179
|
13 |
|
haftmann@26265
|
14 |
subsection {* The @{text random} class *}
|
haftmann@26265
|
15 |
|
haftmann@28335
|
16 |
class random = typerep +
|
haftmann@31205
|
17 |
fixes random :: "code_numeral \<Rightarrow> Random.seed \<Rightarrow> ('a \<times> (unit \<Rightarrow> term)) \<times> Random.seed"
|
haftmann@26265
|
18 |
|
haftmann@26267
|
19 |
|
haftmann@31260
|
20 |
subsection {* Fundamental and numeric types*}
|
haftmann@31179
|
21 |
|
haftmann@31179
|
22 |
instantiation bool :: random
|
haftmann@31179
|
23 |
begin
|
haftmann@31179
|
24 |
|
haftmann@31179
|
25 |
definition
|
haftmann@31985
|
26 |
"random i = Random.range 2 o\<rightarrow>
|
haftmann@32657
|
27 |
(\<lambda>k. Pair (if k = 0 then Code_Evaluation.valtermify False else Code_Evaluation.valtermify True))"
|
haftmann@31179
|
28 |
|
haftmann@31179
|
29 |
instance ..
|
haftmann@31179
|
30 |
|
haftmann@31179
|
31 |
end
|
haftmann@31179
|
32 |
|
haftmann@31179
|
33 |
instantiation itself :: (typerep) random
|
haftmann@31179
|
34 |
begin
|
haftmann@31179
|
35 |
|
haftmann@31205
|
36 |
definition random_itself :: "code_numeral \<Rightarrow> Random.seed \<Rightarrow> ('a itself \<times> (unit \<Rightarrow> term)) \<times> Random.seed" where
|
haftmann@32657
|
37 |
"random_itself _ = Pair (Code_Evaluation.valtermify TYPE('a))"
|
haftmann@31179
|
38 |
|
haftmann@31179
|
39 |
instance ..
|
haftmann@31179
|
40 |
|
haftmann@31179
|
41 |
end
|
haftmann@31179
|
42 |
|
haftmann@31483
|
43 |
instantiation char :: random
|
haftmann@31483
|
44 |
begin
|
haftmann@31483
|
45 |
|
haftmann@31483
|
46 |
definition
|
haftmann@32657
|
47 |
"random _ = Random.select chars o\<rightarrow> (\<lambda>c. Pair (c, \<lambda>u. Code_Evaluation.term_of c))"
|
haftmann@31483
|
48 |
|
haftmann@31483
|
49 |
instance ..
|
haftmann@31483
|
50 |
|
haftmann@31483
|
51 |
end
|
haftmann@31483
|
52 |
|
haftmann@31483
|
53 |
instantiation String.literal :: random
|
haftmann@31483
|
54 |
begin
|
haftmann@31483
|
55 |
|
haftmann@31483
|
56 |
definition
|
haftmann@32657
|
57 |
"random _ = Pair (STR '''', \<lambda>u. Code_Evaluation.term_of (STR ''''))"
|
haftmann@31483
|
58 |
|
haftmann@31483
|
59 |
instance ..
|
haftmann@31483
|
60 |
|
haftmann@31483
|
61 |
end
|
haftmann@31483
|
62 |
|
haftmann@31179
|
63 |
instantiation nat :: random
|
haftmann@31179
|
64 |
begin
|
haftmann@31179
|
65 |
|
haftmann@32657
|
66 |
definition random_nat :: "code_numeral \<Rightarrow> Random.seed \<Rightarrow> (nat \<times> (unit \<Rightarrow> Code_Evaluation.term)) \<times> Random.seed" where
|
haftmann@31194
|
67 |
"random_nat i = Random.range (i + 1) o\<rightarrow> (\<lambda>k. Pair (
|
haftmann@31205
|
68 |
let n = Code_Numeral.nat_of k
|
haftmann@32657
|
69 |
in (n, \<lambda>_. Code_Evaluation.term_of n)))"
|
haftmann@31194
|
70 |
|
haftmann@31194
|
71 |
instance ..
|
haftmann@31194
|
72 |
|
haftmann@31194
|
73 |
end
|
haftmann@31194
|
74 |
|
haftmann@31194
|
75 |
instantiation int :: random
|
haftmann@31194
|
76 |
begin
|
haftmann@31194
|
77 |
|
haftmann@31194
|
78 |
definition
|
haftmann@31194
|
79 |
"random i = Random.range (2 * i + 1) o\<rightarrow> (\<lambda>k. Pair (
|
haftmann@31205
|
80 |
let j = (if k \<ge> i then Code_Numeral.int_of (k - i) else - Code_Numeral.int_of (i - k))
|
haftmann@32657
|
81 |
in (j, \<lambda>_. Code_Evaluation.term_of j)))"
|
haftmann@31179
|
82 |
|
haftmann@31179
|
83 |
instance ..
|
haftmann@31179
|
84 |
|
haftmann@30945
|
85 |
end
|
haftmann@31179
|
86 |
|
haftmann@31260
|
87 |
|
haftmann@31260
|
88 |
subsection {* Complex generators *}
|
haftmann@31260
|
89 |
|
haftmann@31603
|
90 |
text {* Towards @{typ "'a \<Rightarrow> 'b"} *}
|
haftmann@31603
|
91 |
|
haftmann@31603
|
92 |
axiomatization random_fun_aux :: "typerep \<Rightarrow> typerep \<Rightarrow> ('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> term)
|
haftmann@31603
|
93 |
\<Rightarrow> (Random.seed \<Rightarrow> ('b \<times> (unit \<Rightarrow> term)) \<times> Random.seed) \<Rightarrow> (Random.seed \<Rightarrow> Random.seed \<times> Random.seed)
|
haftmann@31603
|
94 |
\<Rightarrow> Random.seed \<Rightarrow> (('a \<Rightarrow> 'b) \<times> (unit \<Rightarrow> term)) \<times> Random.seed"
|
haftmann@31603
|
95 |
|
haftmann@31622
|
96 |
definition random_fun_lift :: "(Random.seed \<Rightarrow> ('b \<times> (unit \<Rightarrow> term)) \<times> Random.seed)
|
haftmann@31622
|
97 |
\<Rightarrow> Random.seed \<Rightarrow> (('a\<Colon>term_of \<Rightarrow> 'b\<Colon>typerep) \<times> (unit \<Rightarrow> term)) \<times> Random.seed" where
|
haftmann@32657
|
98 |
"random_fun_lift f = random_fun_aux TYPEREP('a) TYPEREP('b) (op =) Code_Evaluation.term_of f Random.split_seed"
|
haftmann@31603
|
99 |
|
haftmann@31985
|
100 |
instantiation "fun" :: ("{eq, term_of}", random) random
|
haftmann@31603
|
101 |
begin
|
haftmann@31603
|
102 |
|
haftmann@31603
|
103 |
definition random_fun :: "code_numeral \<Rightarrow> Random.seed \<Rightarrow> (('a \<Rightarrow> 'b) \<times> (unit \<Rightarrow> term)) \<times> Random.seed" where
|
haftmann@31622
|
104 |
"random i = random_fun_lift (random i)"
|
haftmann@31603
|
105 |
|
haftmann@31603
|
106 |
instance ..
|
haftmann@31603
|
107 |
|
haftmann@31603
|
108 |
end
|
haftmann@31603
|
109 |
|
haftmann@31603
|
110 |
text {* Towards type copies and datatypes *}
|
haftmann@31603
|
111 |
|
haftmann@31260
|
112 |
definition collapse :: "('a \<Rightarrow> ('a \<Rightarrow> 'b \<times> 'a) \<times> 'a) \<Rightarrow> 'a \<Rightarrow> 'b \<times> 'a" where
|
haftmann@31260
|
113 |
"collapse f = (f o\<rightarrow> id)"
|
haftmann@31223
|
114 |
|
haftmann@31260
|
115 |
definition beyond :: "code_numeral \<Rightarrow> code_numeral \<Rightarrow> code_numeral" where
|
haftmann@31260
|
116 |
"beyond k l = (if l > k then l else 0)"
|
haftmann@31260
|
117 |
|
haftmann@31267
|
118 |
lemma beyond_zero:
|
haftmann@31267
|
119 |
"beyond k 0 = 0"
|
haftmann@31267
|
120 |
by (simp add: beyond_def)
|
haftmann@31267
|
121 |
|
haftmann@31483
|
122 |
lemma random_aux_rec:
|
haftmann@31483
|
123 |
fixes random_aux :: "code_numeral \<Rightarrow> 'a"
|
haftmann@31483
|
124 |
assumes "random_aux 0 = rhs 0"
|
haftmann@31483
|
125 |
and "\<And>k. random_aux (Suc_code_numeral k) = rhs (Suc_code_numeral k)"
|
haftmann@31483
|
126 |
shows "random_aux k = rhs k"
|
haftmann@31483
|
127 |
using assms by (rule code_numeral.induct)
|
haftmann@31483
|
128 |
|
blanchet@33561
|
129 |
setup {* Quickcheck.setup *}
|
blanchet@33561
|
130 |
|
bulwahn@33250
|
131 |
subsection {* the Random-Predicate Monad *}
|
bulwahn@33250
|
132 |
|
bulwahn@33250
|
133 |
types 'a randompred = "Random.seed \<Rightarrow> ('a Predicate.pred \<times> Random.seed)"
|
bulwahn@33250
|
134 |
|
bulwahn@33250
|
135 |
definition empty :: "'a randompred"
|
bulwahn@33250
|
136 |
where "empty = Pair (bot_class.bot)"
|
bulwahn@33250
|
137 |
|
bulwahn@33250
|
138 |
definition single :: "'a => 'a randompred"
|
bulwahn@33250
|
139 |
where "single x = Pair (Predicate.single x)"
|
bulwahn@33250
|
140 |
|
bulwahn@33250
|
141 |
definition bind :: "'a randompred \<Rightarrow> ('a \<Rightarrow> 'b randompred) \<Rightarrow> 'b randompred"
|
bulwahn@33250
|
142 |
where
|
bulwahn@33250
|
143 |
"bind R f = (\<lambda>s. let
|
bulwahn@33250
|
144 |
(P, s') = R s;
|
bulwahn@33250
|
145 |
(s1, s2) = Random.split_seed s'
|
bulwahn@33250
|
146 |
in (Predicate.bind P (%a. fst (f a s1)), s2))"
|
bulwahn@33250
|
147 |
|
bulwahn@33250
|
148 |
definition union :: "'a randompred \<Rightarrow> 'a randompred \<Rightarrow> 'a randompred"
|
bulwahn@33250
|
149 |
where
|
bulwahn@33250
|
150 |
"union R1 R2 = (\<lambda>s. let
|
bulwahn@33250
|
151 |
(P1, s') = R1 s; (P2, s'') = R2 s'
|
bulwahn@33250
|
152 |
in (upper_semilattice_class.sup P1 P2, s''))"
|
bulwahn@33250
|
153 |
|
bulwahn@33250
|
154 |
definition if_randompred :: "bool \<Rightarrow> unit randompred"
|
bulwahn@33250
|
155 |
where
|
bulwahn@33250
|
156 |
"if_randompred b = (if b then single () else empty)"
|
bulwahn@33250
|
157 |
|
bulwahn@33250
|
158 |
definition not_randompred :: "unit randompred \<Rightarrow> unit randompred"
|
bulwahn@33250
|
159 |
where
|
bulwahn@33250
|
160 |
"not_randompred P = (\<lambda>s. let
|
bulwahn@33250
|
161 |
(P', s') = P s
|
bulwahn@33250
|
162 |
in if Predicate.eval P' () then (Orderings.bot, s') else (Predicate.single (), s'))"
|
bulwahn@33250
|
163 |
|
bulwahn@33250
|
164 |
definition Random :: "(Random.seed \<Rightarrow> ('a \<times> (unit \<Rightarrow> term)) \<times> Random.seed) \<Rightarrow> 'a randompred"
|
bulwahn@33250
|
165 |
where "Random g = scomp g (Pair o (Predicate.single o fst))"
|
bulwahn@33250
|
166 |
|
bulwahn@33250
|
167 |
definition map :: "('a \<Rightarrow> 'b) \<Rightarrow> ('a randompred \<Rightarrow> 'b randompred)"
|
bulwahn@33250
|
168 |
where "map f P = bind P (single o f)"
|
bulwahn@33250
|
169 |
|
bulwahn@33250
|
170 |
subsection {* Code setup *}
|
bulwahn@33250
|
171 |
|
haftmann@31260
|
172 |
use "Tools/quickcheck_generators.ML"
|
haftmann@31260
|
173 |
setup {* Quickcheck_Generators.setup *}
|
haftmann@31260
|
174 |
|
haftmann@31260
|
175 |
code_const random_fun_aux (Quickcheck "Quickcheck'_Generators.random'_fun")
|
haftmann@31260
|
176 |
-- {* With enough criminal energy this can be abused to derive @{prop False};
|
haftmann@31260
|
177 |
for this reason we use a distinguished target @{text Quickcheck}
|
haftmann@31260
|
178 |
not spoiling the regular trusted code generation *}
|
haftmann@31223
|
179 |
|
haftmann@31607
|
180 |
code_reserved Quickcheck Quickcheck_Generators
|
haftmann@31607
|
181 |
|
bulwahn@33254
|
182 |
hide (open) fact empty_def single_def bind_def union_def if_randompred_def not_randompred_def Random_def map_def
|
bulwahn@33250
|
183 |
hide (open) type randompred
|
haftmann@31641
|
184 |
hide (open) const random collapse beyond random_fun_aux random_fun_lift
|
bulwahn@33250
|
185 |
empty single bind union if_randompred not_randompred Random map
|
haftmann@31267
|
186 |
|
haftmann@31179
|
187 |
no_notation fcomp (infixl "o>" 60)
|
haftmann@31179
|
188 |
no_notation scomp (infixl "o\<rightarrow>" 60)
|
haftmann@31179
|
189 |
|
haftmann@31179
|
190 |
end
|