src/HOL/Tools/Quickcheck/narrowing_generators.ML
changeset 43308 fd6cc1378fec
parent 43240 da47097bd589
child 43314 a9090cabca14
equal deleted inserted replaced
43307:1a32a953cef1 43308:fd6cc1378fec
   192       thy
   192       thy
   193   end;
   193   end;
   194 
   194 
   195 (* testing framework *)
   195 (* testing framework *)
   196 
   196 
   197 val target = "Haskell"
   197 val target = "Haskell_Quickcheck"
   198 
   198 
   199 (** invocation of Haskell interpreter **)
   199 (** invocation of Haskell interpreter **)
   200 
   200 
   201 val narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs")
   201 val narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs")
   202 val pnf_narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/PNF_Narrowing_Engine.hs")
   202 val pnf_narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/PNF_Narrowing_Engine.hs")
   208   let
   208   let
   209     val path = Path.append (Path.explode "~/.isabelle") (Path.basic (name ^ serial_string ()))
   209     val path = Path.append (Path.explode "~/.isabelle") (Path.basic (name ^ serial_string ()))
   210     val _ = Isabelle_System.mkdirs path;
   210     val _ = Isabelle_System.mkdirs path;
   211   in Exn.release (Exn.capture f path) end;
   211   in Exn.release (Exn.capture f path) end;
   212   
   212   
   213 fun value contains_existentials ctxt (get, put, put_ml) (code, value_name) =
   213 fun value (contains_existentials, (quiet, size)) ctxt (get, put, put_ml) (code, value_name) =
   214   let
   214   let
   215     fun message s = if Config.get ctxt Quickcheck.quiet then () else Output.urgent_message s
   215     fun message s = if quiet then () else Output.urgent_message s
   216     val tmp_prefix = "Quickcheck_Narrowing"
   216     val tmp_prefix = "Quickcheck_Narrowing"
   217     val with_tmp_dir =
   217     val with_tmp_dir =
   218       if Config.get ctxt overlord then with_overlord_dir else Isabelle_System.with_tmp_dir 
   218       if Config.get ctxt overlord then with_overlord_dir else Isabelle_System.with_tmp_dir 
   219     fun run in_path = 
   219     fun run in_path = 
   220       let
   220       let
   237         val cmd = "exec \"$ISABELLE_GHC\" -fglasgow-exts " ^
   237         val cmd = "exec \"$ISABELLE_GHC\" -fglasgow-exts " ^
   238           (space_implode " " (map File.shell_path [code_file, narrowing_engine_file, main_file])) ^
   238           (space_implode " " (map File.shell_path [code_file, narrowing_engine_file, main_file])) ^
   239           " -o " ^ executable ^ ";"
   239           " -o " ^ executable ^ ";"
   240         val _ = if bash cmd <> 0 then error "Compilation with GHC failed" else ()
   240         val _ = if bash cmd <> 0 then error "Compilation with GHC failed" else ()
   241         fun with_size k =
   241         fun with_size k =
   242           if k > Config.get ctxt Quickcheck.size then
   242           if k > size then
   243             NONE
   243             NONE
   244           else
   244           else
   245             let
   245             let
   246               val _ = message ("Test data size: " ^ string_of_int k)
   246               val _ = message ("Test data size: " ^ string_of_int k)
   247               val (response, _) = bash_output (executable ^ " " ^ string_of_int k)
   247               val (response, _) = bash_output (executable ^ " " ^ string_of_int k)
   262                |> Context.proof_map (exec false ml_code);
   262                |> Context.proof_map (exec false ml_code);
   263            in get ctxt' () end     
   263            in get ctxt' () end     
   264       end
   264       end
   265   in with_tmp_dir tmp_prefix run end;
   265   in with_tmp_dir tmp_prefix run end;
   266 
   266 
   267 fun dynamic_value_strict contains_existentials cookie thy postproc t =
   267 fun dynamic_value_strict opts cookie thy postproc t =
   268   let
   268   let
   269     val ctxt = Proof_Context.init_global thy
   269     val ctxt = Proof_Context.init_global thy
   270     fun evaluator naming program ((_, vs_ty), t) deps = Exn.interruptible_capture (value contains_existentials ctxt cookie)
   270     fun evaluator naming program ((_, vs_ty), t) deps = Exn.interruptible_capture (value opts ctxt cookie)
   271       (Code_Target.evaluator thy target naming program deps (vs_ty, t));    
   271       (Code_Target.evaluator thy target naming program deps (vs_ty, t));    
   272   in Exn.release (Code_Thingol.dynamic_value thy (Exn.map_result o postproc) evaluator t) end;
   272   in Exn.release (Code_Thingol.dynamic_value thy (Exn.map_result o postproc) evaluator t) end;
   273 
   273 
   274 (** counterexample generator **)
   274 (** counterexample generator **)
   275   
   275   
   371       map (fn (p, (_, (x, T))) => (x, mk_case_term ctxt p qs result)) ps
   371       map (fn (p, (_, (x, T))) => (x, mk_case_term ctxt p qs result)) ps
   372     end
   372     end
   373   
   373   
   374 fun test_term ctxt (limit_time, is_interactive) (t, eval_terms) =
   374 fun test_term ctxt (limit_time, is_interactive) (t, eval_terms) =
   375   let
   375   let
       
   376     val opts = (Config.get ctxt Quickcheck.quiet, Config.get ctxt Quickcheck.size)
   376     val thy = Proof_Context.theory_of ctxt
   377     val thy = Proof_Context.theory_of ctxt
   377     val t' = fold_rev (fn (x, T) => fn t => HOLogic.mk_all (x, T, t)) (Term.add_frees t []) t
   378     val t' = fold_rev (fn (x, T) => fn t => HOLogic.mk_all (x, T, t)) (Term.add_frees t []) t
   378     val pnf_t = make_pnf_term thy t'
   379     val pnf_t = make_pnf_term thy t'
   379   in
   380   in
   380     if Config.get ctxt allow_existentials andalso contains_existentials pnf_t then
   381     if Config.get ctxt allow_existentials andalso contains_existentials pnf_t then
   386         val (qs, prop_t) = finitize (strip_quantifiers pnf_t)
   387         val (qs, prop_t) = finitize (strip_quantifiers pnf_t)
   387         val prop_term = fold_rev (fn (_, (x, T)) => fn t => Abs (x, T, t)) qs prop_t
   388         val prop_term = fold_rev (fn (_, (x, T)) => fn t => Abs (x, T, t)) qs prop_t
   388         val ((prop_def, _), ctxt') = Local_Theory.define ((Binding.conceal (Binding.name "test_property"), NoSyn),
   389         val ((prop_def, _), ctxt') = Local_Theory.define ((Binding.conceal (Binding.name "test_property"), NoSyn),
   389           ((Binding.conceal Binding.empty, [Code.add_default_eqn_attrib]), prop_term)) ctxt
   390           ((Binding.conceal Binding.empty, [Code.add_default_eqn_attrib]), prop_term)) ctxt
   390         val (prop_def', thy') = Local_Theory.exit_result_global Morphism.term (prop_def, ctxt') 
   391         val (prop_def', thy') = Local_Theory.exit_result_global Morphism.term (prop_def, ctxt') 
   391         val result = dynamic_value_strict true
   392         val result = dynamic_value_strict (true, opts)
   392           (Existential_Counterexample.get, Existential_Counterexample.put,
   393           (Existential_Counterexample.get, Existential_Counterexample.put,
   393             "Narrowing_Generators.put_existential_counterexample")
   394             "Narrowing_Generators.put_existential_counterexample")
   394           thy' (Option.map o map_counterexample) (mk_property qs prop_def')
   395           thy' (Option.map o map_counterexample) (mk_property qs prop_def')
   395         val result' = Option.map (mk_terms ctxt' (fst (strip_quantifiers pnf_t))) result
   396         val result' = Option.map (mk_terms ctxt' (fst (strip_quantifiers pnf_t))) result
   396       in
   397       in
   402         val t' = Term.list_abs_free (Term.add_frees t [], t)
   403         val t' = Term.list_abs_free (Term.add_frees t [], t)
   403         fun wrap f t = list_abs (f (strip_abs t))
   404         fun wrap f t = list_abs (f (strip_abs t))
   404         val finitize = if Config.get ctxt finite_functions then wrap finitize_functions else I
   405         val finitize = if Config.get ctxt finite_functions then wrap finitize_functions else I
   405         fun ensure_testable t =
   406         fun ensure_testable t =
   406           Const (@{const_name Quickcheck_Narrowing.ensure_testable}, fastype_of t --> fastype_of t) $ t
   407           Const (@{const_name Quickcheck_Narrowing.ensure_testable}, fastype_of t --> fastype_of t) $ t
   407         val result = dynamic_value_strict false
   408         val result = dynamic_value_strict (false, opts)
   408           (Counterexample.get, Counterexample.put, "Narrowing_Generators.put_counterexample")
   409           (Counterexample.get, Counterexample.put, "Narrowing_Generators.put_counterexample")
   409           thy (Option.map o map) (ensure_testable (finitize t'))
   410           thy (Option.map o map) (ensure_testable (finitize t'))
   410       in
   411       in
   411         Quickcheck.Result {counterexample = Option.map ((curry (op ~~)) (Term.add_free_names t [])) result,
   412         Quickcheck.Result {counterexample = Option.map ((curry (op ~~)) (Term.add_free_names t [])) result,
   412           evaluation_terms = Option.map (K []) result, timings = [], reports = []}
   413           evaluation_terms = Option.map (K []) result, timings = [], reports = []}