27 datatype report = Report of |
27 datatype report = Report of |
28 { iterations : int, raised_match_errors : int, |
28 { iterations : int, raised_match_errors : int, |
29 satisfied_assms : int list, positive_concl_tests : int } |
29 satisfied_assms : int list, positive_concl_tests : int } |
30 (* registering generators *) |
30 (* registering generators *) |
31 val add_generator: |
31 val add_generator: |
32 string * (Proof.context -> term * term list -> int -> term list option * report option) |
32 string * (Proof.context -> (term * term list) list -> int list -> term list option * report option) |
33 -> Context.generic -> Context.generic |
33 -> Context.generic -> Context.generic |
34 val add_batch_generator: |
34 val add_batch_generator: |
35 string * (Proof.context -> term list -> (int -> term list option) list) |
35 string * (Proof.context -> term list -> (int -> term list option) list) |
36 -> Context.generic -> Context.generic |
36 -> Context.generic -> Context.generic |
37 (* quickcheck's result *) |
37 (* quickcheck's result *) |
159 (merge (op =) (default_type1, default_type2), merge_expectation (expect1, expect2)); |
159 (merge (op =) (default_type1, default_type2), merge_expectation (expect1, expect2)); |
160 |
160 |
161 structure Data = Generic_Data |
161 structure Data = Generic_Data |
162 ( |
162 ( |
163 type T = |
163 type T = |
164 ((string * (Proof.context -> term * term list -> int -> term list option * report option)) list |
164 ((string * (Proof.context -> (term * term list) list -> int list -> term list option * report option)) list |
165 * (string * (Proof.context -> term list -> (int -> term list option) list)) list) |
165 * (string * (Proof.context -> term list -> (int -> term list option) list)) list) |
166 * test_params; |
166 * test_params; |
167 val empty = (([], []), Test_Params {default_type = [], expect = No_Expectation}); |
167 val empty = (([], []), Test_Params {default_type = [], expect = No_Expectation}); |
168 val extend = I; |
168 val extend = I; |
169 fun merge (((generators1, batch_generators1), params1), ((generators2, batch_generators2), params2)) : T = |
169 fun merge (((generators1, batch_generators1), params1), ((generators2, batch_generators2), params2)) : T = |
238 val current_size = Unsynchronized.ref 0 |
238 val current_size = Unsynchronized.ref 0 |
239 val current_result = Unsynchronized.ref empty_result |
239 val current_result = Unsynchronized.ref empty_result |
240 fun excipit () = |
240 fun excipit () = |
241 "Quickcheck ran out of time while testing at size " ^ string_of_int (!current_size) |
241 "Quickcheck ran out of time while testing at size " ^ string_of_int (!current_size) |
242 val (test_fun, comp_time) = cpu_time "quickcheck compilation" |
242 val (test_fun, comp_time) = cpu_time "quickcheck compilation" |
243 (fn () => mk_tester ctxt (t, eval_terms)); |
243 (fn () => mk_tester ctxt [(t, eval_terms)]); |
244 val _ = add_timing comp_time current_result |
244 val _ = add_timing comp_time current_result |
245 fun with_size test_fun k = |
245 fun with_size test_fun k = |
246 if k > Config.get ctxt size then |
246 if k > Config.get ctxt size then |
247 NONE |
247 NONE |
248 else |
248 else |
249 let |
249 let |
250 val _ = message ("Test data size: " ^ string_of_int k) |
250 val _ = message ("Test data size: " ^ string_of_int k) |
251 val _ = current_size := k |
251 val _ = current_size := k |
252 val ((result, report), timing) = |
252 val ((result, report), timing) = |
253 cpu_time ("size " ^ string_of_int k) (fn () => test_fun (k - 1)) |
253 cpu_time ("size " ^ string_of_int k) (fn () => test_fun [1, k - 1]) |
254 val _ = add_timing timing current_result |
254 val _ = add_timing timing current_result |
255 val _ = add_report k report current_result |
255 val _ = add_report k report current_result |
256 in |
256 in |
257 case result of NONE => with_size test_fun (k + 1) | SOME q => SOME q |
257 case result of NONE => with_size test_fun (k + 1) | SOME q => SOME q |
258 end; |
258 end; |
291 |
291 |
292 fun test_term_with_increasing_cardinality ctxt (limit_time, is_interactive) ts = |
292 fun test_term_with_increasing_cardinality ctxt (limit_time, is_interactive) ts = |
293 let |
293 let |
294 val thy = ProofContext.theory_of ctxt |
294 val thy = ProofContext.theory_of ctxt |
295 fun message s = if Config.get ctxt quiet then () else Output.urgent_message s |
295 fun message s = if Config.get ctxt quiet then () else Output.urgent_message s |
296 val (ts, eval_terms) = split_list ts |
296 val (ts', eval_terms) = split_list ts |
297 val _ = map check_test_term ts |
297 val _ = map check_test_term ts' |
298 val names = Term.add_free_names (hd ts) [] |
298 val names = Term.add_free_names (hd ts') [] |
299 val Ts = map snd (Term.add_frees (hd ts) []) |
299 val Ts = map snd (Term.add_frees (hd ts') []) |
300 val current_result = Unsynchronized.ref empty_result |
300 val current_result = Unsynchronized.ref empty_result |
301 val (test_funs, comp_time) = cpu_time "quickcheck compilation" |
301 val (test_fun, comp_time) = cpu_time "quickcheck compilation" (fn () => mk_tester ctxt ts) |
302 (fn () => map (mk_tester ctxt) (ts ~~ eval_terms)) |
|
303 val _ = add_timing comp_time current_result |
302 val _ = add_timing comp_time current_result |
304 fun test_card_size (card, size) = |
303 fun test_card_size (card, size) = |
305 (* FIXME: why decrement size by one? *) |
304 (* FIXME: why decrement size by one? *) |
306 let |
305 let |
307 val (ts, timing) = cpu_time ("size " ^ string_of_int size ^ " and card " ^ string_of_int card) |
306 val (ts, timing) = cpu_time ("size " ^ string_of_int size ^ " and card " ^ string_of_int card) |
308 (fn () => fst (the (nth test_funs (card - 1)) (size - 1))) |
307 (fn () => fst ((the test_fun) [card - 1, size - 1])) |
309 val _ = add_timing timing current_result |
308 val _ = add_timing timing current_result |
310 in |
309 in |
311 Option.map (pair card) ts |
310 Option.map (pair card) ts |
312 end |
311 end |
313 val enumeration_card_size = |
312 val enumeration_card_size = |
317 else |
316 else |
318 (* size does matter *) |
317 (* size does matter *) |
319 map_product pair (1 upto (length ts)) (1 upto (Config.get ctxt size)) |
318 map_product pair (1 upto (length ts)) (1 upto (Config.get ctxt size)) |
320 |> sort (fn ((c1, s1), (c2, s2)) => int_ord ((c1 + s1), (c2 + s2))) |
319 |> sort (fn ((c1, s1), (c2, s2)) => int_ord ((c1 + s1), (c2 + s2))) |
321 in |
320 in |
322 if (forall is_none test_funs) then !current_result |
321 case test_fun of |
323 else if (forall is_some test_funs) then |
322 NONE => !current_result |
|
323 | SOME test_fun => |
324 limit ctxt (limit_time, is_interactive) (fn () => |
324 limit ctxt (limit_time, is_interactive) (fn () => |
325 let |
325 let |
326 val _ = case get_first test_card_size enumeration_card_size of |
326 val _ = case get_first test_card_size enumeration_card_size of |
327 SOME (card, ts) => add_response names (nth eval_terms (card - 1)) (SOME ts) current_result |
327 SOME (card, ts) => add_response names (nth eval_terms (card - 1)) (SOME ts) current_result |
328 | NONE => () |
328 | NONE => () |
329 in !current_result end) |
329 in !current_result end) |
330 (fn () => (message "Quickcheck ran out of time"; !current_result)) () |
330 (fn () => (message "Quickcheck ran out of time"; !current_result)) () |
331 else |
|
332 error "Unexpectedly, testers of some cardinalities are executable but others are not" |
|
333 end |
331 end |
334 |
332 |
335 fun get_finite_types ctxt = |
333 fun get_finite_types ctxt = |
336 fst (chop (Config.get ctxt finite_type_size) |
334 fst (chop (Config.get ctxt finite_type_size) |
337 (map (Type o rpair []) ["Enum.finite_1", "Enum.finite_2", "Enum.finite_3", |
335 (map (Type o rpair []) ["Enum.finite_1", "Enum.finite_2", "Enum.finite_3", |