automatic derivation of partial_term_of functions; renaming type and term to longer names narrowing_type and narrowing_term; hiding constant C; adding overlord option
authorbulwahn
Mon, 30 May 2011 13:57:59 +0200
changeset 43047 26774ccb1c74
parent 43046 2a1b01680505
child 43048 c62bed03fbce
automatic derivation of partial_term_of functions; renaming type and term to longer names narrowing_type and narrowing_term; hiding constant C; adding overlord option
src/HOL/Library/Quickcheck_Narrowing.thy
src/HOL/Tools/Quickcheck/Narrowing_Engine.hs
src/HOL/Tools/Quickcheck/narrowing_generators.ML
--- a/src/HOL/Library/Quickcheck_Narrowing.thy	Mon May 30 12:20:04 2011 +0100
+++ b/src/HOL/Library/Quickcheck_Narrowing.thy	Mon May 30 13:57:59 2011 +0200
@@ -86,7 +86,7 @@
   "nat_of i = nat (int_of i)"
 
 
-code_datatype "number_of \<Colon> int \<Rightarrow> code_numeral"
+code_datatype "number_of \<Colon> int \<Rightarrow> code_int"
   
   
 instantiation code_int :: "{minus, linordered_semidom, semiring_div, linorder}"
@@ -200,16 +200,19 @@
 
 subsubsection {* Narrowing's deep representation of types and terms *}
 
-datatype type = SumOfProd "type list list"
+datatype narrowing_type = SumOfProd "narrowing_type list list"
 
-datatype "term" = Var "code_int list" type | Ctr code_int "term list"
-
-datatype 'a cons = C type "(term list => 'a) list"
+datatype narrowing_term = Var "code_int list" narrowing_type | Ctr code_int "narrowing_term list"
+datatype 'a cons = C narrowing_type "(narrowing_term list => 'a) list"
 
 subsubsection {* From narrowing's deep representation of terms to Code_Evaluation's terms *}
 
 class partial_term_of = typerep +
-  fixes partial_term_of :: "'a itself => term => Code_Evaluation.term"
+  fixes partial_term_of :: "'a itself => narrowing_term => Code_Evaluation.term"
+
+lemma partial_term_of_anything: "partial_term_of x nt \<equiv> t"
+  by (rule eq_reflection) (cases "partial_term_of x nt", cases t, simp)
+
 
 subsubsection {* Auxilary functions for Narrowing *}
 
@@ -241,12 +244,12 @@
 where
   "cons a d = (C (SumOfProd [[]]) [(%_. a)])"
 
-fun conv :: "(term list => 'a) list => term => 'a"
+fun conv :: "(narrowing_term list => 'a) list => narrowing_term => 'a"
 where
   "conv cs (Var p _) = error (Char Nibble0 Nibble0 # map toEnum p)"
 | "conv cs (Ctr i xs) = (nth cs i) xs"
 
-fun nonEmpty :: "type => bool"
+fun nonEmpty :: "narrowing_type => bool"
 where
   "nonEmpty (SumOfProd ps) = (\<not> (List.null ps))"
 
@@ -270,7 +273,7 @@
 lemma [fundef_cong]:
   assumes "a d = a' d" "b d = b' d" "d = d'"
   shows "sum a b d = sum a' b' d'"
-using assms unfolding sum_def by (auto split: cons.split type.split)
+using assms unfolding sum_def by (auto split: cons.split narrowing_type.split)
 
 lemma [fundef_cong]:
   assumes "f d = f' d" "(\<And>d'. 0 <= d' & d' < d ==> a d' = a' d')"
@@ -284,7 +287,7 @@
   have "int_of (of_int (int_of d' - int_of (of_int 1))) < int_of d'"
     by (simp add: of_int_inverse)
   ultimately show ?thesis
-    unfolding apply_def by (auto split: cons.split type.split simp add: Let_def)
+    unfolding apply_def by (auto split: cons.split narrowing_type.split simp add: Let_def)
 qed
 
 type_synonym pos = "code_int list"
@@ -459,7 +462,7 @@
 
 instance bool :: is_testable ..
 
-instance "fun" :: ("{term_of, narrowing}", is_testable) is_testable ..
+instance "fun" :: ("{term_of, narrowing, partial_term_of}", is_testable) is_testable ..
 
 definition ensure_testable :: "'a :: is_testable => 'a :: is_testable"
 where
@@ -494,8 +497,8 @@
 
 setup {* Narrowing_Generators.setup *}
 
-hide_type (open) code_int type "term" cons
+hide_type (open) code_int narrowing_type narrowing_term cons
 hide_const (open) int_of of_int nth error toEnum map_index split_At empty
-  cons conv nonEmpty "apply" sum cons1 cons2 ensure_testable
+  C cons conv nonEmpty "apply" sum cons1 cons2 ensure_testable
 
 end
\ No newline at end of file
--- a/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs	Mon May 30 12:20:04 2011 +0100
+++ b/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs	Mon May 30 13:57:59 2011 +0200
@@ -10,20 +10,20 @@
 
 -- Term refinement
 
-new :: Pos -> [[Type]] -> [Terma];
+new :: Pos -> [[Narrowing_type]] -> [Narrowing_term];
 new p ps = [ Ctr c (zipWith (\i t -> Var (p++[i]) t) [0..] ts)
            | (c, ts) <- zip [0..] ps ];
 
-refine :: Terma -> Pos -> [Terma];
+refine :: Narrowing_term -> Pos -> [Narrowing_term];
 refine (Var p (SumOfProd ss)) [] = new p ss;
 refine (Ctr c xs) p = map (Ctr c) (refineList xs p);
 
-refineList :: [Terma] -> Pos -> [[Terma]];
+refineList :: [Narrowing_term] -> Pos -> [[Narrowing_term]];
 refineList xs (i:is) = let (ls, x:rs) = splitAt i xs in [ls ++ y:rs | y <- refine x is];
 
 -- Find total instantiations of a partial value
 
-total :: Terma -> [Terma];
+total :: Narrowing_term -> [Narrowing_term];
 total (Ctr c xs) = [Ctr c ys | ys <- mapM total xs];
 total (Var p (SumOfProd ss)) = [y | x <- new p ss, y <- total x];
 
@@ -42,13 +42,13 @@
 str_of_list [] = "[]";
 str_of_list (x:xs) = "(" ++ x ++ " :: " ++ str_of_list xs ++ ")";
 
-report :: Result -> [Terma] -> IO Int;
+report :: Result -> [Narrowing_term] -> IO Int;
 report r xs = putStrLn ("SOME (" ++ (str_of_list $ zipWith ($) (showArgs r) $ head [ys | ys <- mapM total xs]) ++ ")") >> hFlush stdout >> exitWith ExitSuccess;
 
 eval :: Bool -> (Bool -> IO a) -> (Pos -> IO a) -> IO a;
 eval p k u = answer p (\p -> answer p k u) u;
 
-ref :: Result -> [Terma] -> IO Int;
+ref :: Result -> [Narrowing_term] -> IO Int;
 ref r xs = eval (apply_fun r xs) (\res -> if res then return 1 else report r xs) (\p -> sumMapM (ref r) 1 (refineList xs p));
           
 refute :: Result -> IO Int;
@@ -71,18 +71,18 @@
 };
 
 data Result =
-  Result { args     :: [Terma]
-         , showArgs :: [Terma -> String]
-         , apply_fun    :: [Terma] -> Bool
+  Result { args     :: [Narrowing_term]
+         , showArgs :: [Narrowing_term -> String]
+         , apply_fun    :: [Narrowing_term] -> Bool
          };
 
 data P = P (Int -> Int -> Result);
 
-run :: Testable a => ([Terma] -> a) -> Int -> Int -> Result;
+run :: Testable a => ([Narrowing_term] -> a) -> Int -> Int -> Result;
 run a = let P f = property a in f;
 
 class Testable a where {
-  property :: ([Terma] -> a) -> P;
+  property :: ([Narrowing_term] -> a) -> P;
 };
 
 instance Testable Bool where {
--- a/src/HOL/Tools/Quickcheck/narrowing_generators.ML	Mon May 30 12:20:04 2011 +0100
+++ b/src/HOL/Tools/Quickcheck/narrowing_generators.ML	Mon May 30 13:57:59 2011 +0200
@@ -19,8 +19,89 @@
 (* configurations *)
 
 val finite_functions = Attrib.setup_config_bool @{binding quickcheck_finite_functions} (K true)
+val overlord = Attrib.setup_config_bool @{binding quickcheck_narrowing_overlord} (K false)
 
-(* narrowing specific names and types *)
+(* partial_term_of instances *)
+
+fun mk_partial_term_of (x, T) =
+  Const (@{const_name Quickcheck_Narrowing.partial_term_of_class.partial_term_of},
+    Term.itselfT T --> @{typ narrowing_term} --> @{typ Code_Evaluation.term})
+      $ Const ("TYPE", Term.itselfT T) $ x
+
+(** formal definition **)
+
+fun add_partial_term_of tyco raw_vs thy =
+  let
+    val vs = map (fn (v, _) => (v, @{sort typerep})) raw_vs;
+    val ty = Type (tyco, map TFree vs);
+    val lhs = Const (@{const_name partial_term_of},
+        Term.itselfT ty --> @{typ narrowing_term} --> @{typ Code_Evaluation.term})
+      $ Free ("x", Term.itselfT ty) $ Free ("t", @{typ narrowing_term});
+    val rhs = @{term "undefined :: Code_Evaluation.term"};
+    val eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs));
+    fun triv_name_of t = (fst o dest_Free o fst o strip_comb o fst
+      o HOLogic.dest_eq o HOLogic.dest_Trueprop) t ^ "_triv";
+  in
+    thy
+    |> Class.instantiation ([tyco], vs, @{sort partial_term_of})
+    |> `(fn lthy => Syntax.check_term lthy eq)
+    |-> (fn eq => Specification.definition (NONE, ((Binding.name (triv_name_of eq), []), eq)))
+    |> snd
+    |> Class.prove_instantiation_exit (K (Class.intro_classes_tac []))
+  end;
+
+fun ensure_partial_term_of (tyco, (raw_vs, _)) thy =
+  let
+    val need_inst = not (can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort partial_term_of})
+      andalso can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort typerep};
+  in if need_inst then add_partial_term_of tyco raw_vs thy else thy end;
+
+
+(** code equations for datatypes **)
+
+fun mk_partial_term_of_eq thy ty (i, (c, (_, tys))) =
+  let
+    val frees = map Free (Name.names Name.context "a" (map (K @{typ narrowing_term}) tys))
+    val narrowing_term = @{term "Quickcheck_Narrowing.Ctr"} $ HOLogic.mk_number @{typ code_int} i
+      $ (HOLogic.mk_list @{typ narrowing_term} frees)
+    val rhs = fold (fn u => fn t => @{term "Code_Evaluation.App"} $ t $ u)
+        (map mk_partial_term_of (frees ~~ tys))
+        (@{term "Code_Evaluation.Const"} $ HOLogic.mk_literal c $ HOLogic.mk_typerep (tys ---> ty))
+    val insts =
+      map (SOME o Thm.cterm_of thy o map_types Logic.unvarifyT_global o Logic.varify_global)
+        [Free ("ty", Term.itselfT ty), narrowing_term, rhs]
+    val cty = Thm.ctyp_of thy ty;
+  in
+    @{thm partial_term_of_anything}
+    |> Drule.instantiate' [SOME cty] insts
+    |> Thm.varifyT_global
+  end
+
+fun add_partial_term_of_code tyco raw_vs raw_cs thy =
+  let
+    val algebra = Sign.classes_of thy;
+    val vs = map (fn (v, sort) =>
+      (v, curry (Sorts.inter_sort algebra) @{sort typerep} sort)) raw_vs;
+    val ty = Type (tyco, map TFree vs);
+    val cs = (map o apsnd o apsnd o map o map_atyps)
+      (fn TFree (v, _) => TFree (v, (the o AList.lookup (op =) vs) v)) raw_cs;
+    val const = AxClass.param_of_inst thy (@{const_name partial_term_of}, tyco);
+    val eqs = map_index (mk_partial_term_of_eq thy ty) cs;
+ in
+    thy
+    |> Code.del_eqns const
+    |> fold Code.add_eqn eqs
+  end;
+
+fun ensure_partial_term_of_code (tyco, (raw_vs, cs)) thy =
+  let
+    val has_inst = can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort partial_term_of};
+  in if has_inst then add_partial_term_of_code tyco raw_vs cs thy else thy end;
+
+
+(* narrowing generators *)
+
+(** narrowing specific names and types **)
 
 exception FUNCTION_TYPE;
 
@@ -48,7 +129,7 @@
     Const (@{const_name Quickcheck_Narrowing.sum}, T --> T --> T) $ t $ u
   end
 
-(* creating narrowing instances *)
+(** deriving narrowing instances **)
 
 fun mk_equations descr vs tycos narrowings (Ts, Us) =
   let
@@ -95,16 +176,24 @@
 
 val target = "Haskell"
 
-(* invocation of Haskell interpreter *)
+(** invocation of Haskell interpreter **)
 
 val narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs")
 
 fun exec verbose code =
   ML_Context.exec (fn () => Secure.use_text ML_Env.local_context (0, "generated code") verbose code)
 
+fun with_tmp_dir name f =
+  let
+    val path = Path.append (Path.explode "~/.isabelle") (Path.basic (name ^ serial_string ()))
+    val _ = Isabelle_System.mkdirs path;
+  in Exn.release (Exn.capture f path) end;
+  
 fun value ctxt (get, put, put_ml) (code, value) size =
   let
     val tmp_prefix = "Quickcheck_Narrowing"
+    val with_tmp_dir = if Config.get ctxt overlord 
+      then Isabelle_System.with_tmp_dir else Quickcheck_Narrowing.with_tmp_dir 
     fun run in_path = 
       let
         val code_file = Path.append in_path (Path.basic "Code.hs")
@@ -127,7 +216,7 @@
       in
         bash_output cmd
       end
-    val result = Isabelle_System.with_tmp_dir tmp_prefix run
+    val result = with_tmp_dir tmp_prefix run
     val output_value = the_default "NONE"
       (try (snd o split_last o filter_out (fn s => s = "") o split_lines o fst) result)
       |> translate_string (fn s => if s = "\\" then "\\\\" else s)
@@ -152,7 +241,7 @@
       evaluation cookie thy (Code_Target.evaluator thy target naming program deps) (vs_ty, t) args size;
   in Exn.release (Code_Thingol.dynamic_value thy (Exn.map_result o postproc) evaluator t) end;
 
-(* counterexample generator *)
+(** counterexample generator **)
   
 structure Counterexample = Proof_Data
 (
@@ -203,9 +292,12 @@
     (result, NONE)
   end;
 
+(* setup *)
 
 val setup =
-  Datatype.interpretation (Quickcheck_Common.ensure_sort_datatype
+  Code.datatype_interpretation ensure_partial_term_of
+  #> Code.datatype_interpretation ensure_partial_term_of_code
+  #> Datatype.interpretation (Quickcheck_Common.ensure_sort_datatype
     (((@{sort typerep}, @{sort term_of}), @{sort narrowing}), instantiate_narrowing_datatype))
   #> Context.theory_map
     (Quickcheck.add_generator ("narrowing", compile_generator_expr))