src/Tools/quickcheck.ML
changeset 42159 234ec7011e5d
parent 42089 904897d0c5bd
child 42162 00899500c6ca
equal deleted inserted replaced
42158:9bcecd429f77 42159:234ec7011e5d
    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",