src/HOL/Tools/Quickcheck/quickcheck_common.ML
author wenzelm
Fri, 13 May 2011 22:55:00 +0200
changeset 43665 88bee9f6eec7
parent 43232 23f352990944
child 45112 7943b69f0188
permissions -rw-r--r--
proper Proof.context for classical tactics;
reduced claset to snapshot of classical context;
discontinued clasimpset;
     1 (*  Title:      HOL/Tools/Quickcheck/quickcheck_common.ML
     2     Author:     Florian Haftmann, Lukas Bulwahn, TU Muenchen
     3 
     4 Common functions for quickcheck's generators.
     5 *)
     6 
     7 signature QUICKCHECK_COMMON =
     8 sig
     9   val strip_imp : term -> (term list * term)
    10   val define_functions : ((term list -> term list) * (Proof.context -> tactic) option)
    11     -> string -> string list -> string list -> typ list -> Proof.context -> Proof.context 
    12   val perhaps_constrain: theory -> (typ * sort) list -> (string * sort) list
    13     -> (string * sort -> string * sort) option
    14   val ensure_sort_datatype:
    15     ((sort * sort) * sort) * (Datatype.config -> Datatype.descr -> (string * sort) list
    16       -> string list -> string -> string list * string list -> typ list * typ list -> theory -> theory)
    17     -> Datatype.config -> string list -> theory -> theory
    18   val gen_mk_parametric_generator_expr :
    19    (((Proof.context -> term * term list -> term) * term) * typ)
    20      -> Proof.context -> (term * term list) list -> term
    21   val post_process_term : term -> term
    22 end;
    23 
    24 structure Quickcheck_Common : QUICKCHECK_COMMON =
    25 struct
    26 
    27 (* static options *)
    28 
    29 val define_foundationally = false
    30 
    31 (* HOLogic's term functions *)
    32 
    33 fun strip_imp (Const(@{const_name HOL.implies},_) $ A $ B) = apfst (cons A) (strip_imp B)
    34   | strip_imp A = ([], A)
    35 
    36 fun mk_undefined T = Const(@{const_name undefined}, T)
    37   
    38 (* defining functions *)
    39 
    40 fun pat_completeness_auto ctxt =
    41   Pat_Completeness.pat_completeness_tac ctxt 1 THEN auto_tac ctxt
    42 
    43 fun define_functions (mk_equations, termination_tac) prfx argnames names Ts =
    44   if define_foundationally andalso is_some termination_tac then
    45     let
    46       val eqs_t = mk_equations (map2 (fn name => fn T => Free (name, T)) names Ts)
    47     in
    48       Function.add_function
    49         (map (fn (name, T) => (Binding.conceal (Binding.name name), SOME T, NoSyn))
    50           (names ~~ Ts))
    51         (map (pair (apfst Binding.conceal Attrib.empty_binding)) eqs_t)
    52         Function_Common.default_config pat_completeness_auto
    53       #> snd
    54       #> Local_Theory.restore
    55       #> (fn lthy => Function.prove_termination NONE (the termination_tac lthy) lthy)
    56       #> snd
    57     end
    58   else
    59     fold_map (fn (name, T) => Local_Theory.define
    60         ((Binding.conceal (Binding.name name), NoSyn),
    61           (apfst Binding.conceal Attrib.empty_binding, mk_undefined T))
    62       #> apfst fst) (names ~~ Ts)
    63     #> (fn (consts, lthy) =>
    64       let
    65         val eqs_t = mk_equations consts
    66         val eqs = map (fn eq => Goal.prove lthy argnames [] eq
    67           (fn _ => Skip_Proof.cheat_tac (Proof_Context.theory_of lthy))) eqs_t
    68       in
    69         fold (fn (name, eq) => Local_Theory.note
    70         ((Binding.conceal (Binding.qualify true prfx
    71            (Binding.qualify true name (Binding.name "simps"))),
    72            Code.add_default_eqn_attrib :: map (Attrib.internal o K)
    73              [Simplifier.simp_add, Nitpick_Simps.add]), [eq]) #> snd) (names ~~ eqs) lthy
    74       end)
    75 
    76 (** ensuring sort constraints **)
    77 
    78 fun perhaps_constrain thy insts raw_vs =
    79   let
    80     fun meet (T, sort) = Sorts.meet_sort (Sign.classes_of thy) 
    81       (Logic.varifyT_global T, sort);
    82     val vtab = Vartab.empty
    83       |> fold (fn (v, sort) => Vartab.update ((v, 0), sort)) raw_vs
    84       |> fold meet insts;
    85   in SOME (fn (v, _) => (v, (the o Vartab.lookup vtab) (v, 0)))
    86   end handle Sorts.CLASS_ERROR _ => NONE;
    87 
    88 fun ensure_sort_datatype (((sort_vs, aux_sort), sort), instantiate_datatype) config raw_tycos thy =
    89   let
    90     val algebra = Sign.classes_of thy;
    91     val (descr, raw_vs, tycos, prfx, (names, auxnames), raw_TUs) = Datatype.the_descr thy raw_tycos
    92     val vs = (map o apsnd) (curry (Sorts.inter_sort algebra) sort_vs) raw_vs
    93     fun insts_of sort constr  = (map (rpair sort) o flat o maps snd o maps snd)
    94       (Datatype_Aux.interpret_construction descr vs constr)
    95     val insts = insts_of sort  { atyp = single, dtyp = (K o K o K) [] }
    96       @ insts_of aux_sort { atyp = K [], dtyp = K o K }
    97     val has_inst = exists (fn tyco => can (Sorts.mg_domain algebra tyco) sort) tycos;
    98   in if has_inst then thy
    99     else case perhaps_constrain thy insts vs
   100      of SOME constrain => instantiate_datatype config descr
   101           (map constrain vs) tycos prfx (names, auxnames)
   102             ((pairself o map o map_atyps) (fn TFree v => TFree (constrain v)) raw_TUs) thy
   103       | NONE => thy
   104   end;
   105   
   106 (** generic parametric compilation **)
   107 
   108 fun gen_mk_parametric_generator_expr ((mk_generator_expr, out_of_bounds), T) ctxt ts =
   109   let
   110     val if_t = Const (@{const_name "If"}, @{typ bool} --> T --> T --> T)
   111     fun mk_if (index, (t, eval_terms)) else_t =
   112       if_t $ (HOLogic.eq_const @{typ code_numeral} $ Bound 0 $ HOLogic.mk_number @{typ code_numeral} index) $
   113         (mk_generator_expr ctxt (t, eval_terms)) $ else_t
   114   in
   115     absdummy (@{typ "code_numeral"}, fold_rev mk_if (1 upto (length ts) ~~ ts) out_of_bounds)
   116   end
   117 
   118 (** post-processing of function terms **)
   119 
   120 fun dest_fun_upd (Const (@{const_name fun_upd}, _) $ t0 $ t1 $ t2) = (t0, (t1, t2))
   121   | dest_fun_upd t = raise TERM ("dest_fun_upd", [t])
   122 
   123 fun mk_fun_upd T1 T2 (t1, t2) t = 
   124   Const (@{const_name fun_upd}, (T1 --> T2) --> T1 --> T2 --> T1 --> T2) $ t $ t1 $ t2
   125 
   126 fun dest_fun_upds t =
   127   case try dest_fun_upd t of
   128     NONE =>
   129       (case t of
   130         Abs (_, _, _) => ([], t) 
   131       | _ => raise TERM ("dest_fun_upds", [t]))
   132   | SOME (t0, (t1, t2)) => apfst (cons (t1, t2)) (dest_fun_upds t0)
   133 
   134 fun make_fun_upds T1 T2 (tps, t) = fold_rev (mk_fun_upd T1 T2) tps t
   135 
   136 fun make_set T1 [] = Const (@{const_abbrev Set.empty}, T1 --> @{typ bool})
   137   | make_set T1 ((_, @{const False}) :: tps) = make_set T1 tps
   138   | make_set T1 ((t1, @{const True}) :: tps) =
   139     Const (@{const_name insert}, T1 --> (T1 --> @{typ bool}) --> T1 --> @{typ bool})
   140       $ t1 $ (make_set T1 tps)
   141   | make_set T1 ((_, t) :: tps) = raise TERM ("make_set", [t])
   142 
   143 fun make_coset T [] = Const (@{const_abbrev UNIV}, T --> @{typ bool})
   144   | make_coset T tps = 
   145     let
   146       val U = T --> @{typ bool}
   147       fun invert @{const False} = @{const True}
   148         | invert @{const True} = @{const False}
   149     in
   150       Const (@{const_name "Groups.minus_class.minus"}, U --> U --> U)
   151         $ Const (@{const_abbrev UNIV}, U) $ make_set T (map (apsnd invert) tps)
   152     end
   153 
   154 fun make_map T1 T2 [] = Const (@{const_abbrev Map.empty}, T1 --> T2)
   155   | make_map T1 T2 ((_, Const (@{const_name None}, _)) :: tps) = make_map T1 T2 tps
   156   | make_map T1 T2 ((t1, t2) :: tps) = mk_fun_upd T1 T2 (t1, t2) (make_map T1 T2 tps)
   157   
   158 fun post_process_term t =
   159   let
   160     fun map_Abs f t =
   161       case t of Abs (x, T, t') => Abs (x, T, f t') | _ => raise TERM ("map_Abs", [t]) 
   162     fun process_args t = case strip_comb t of
   163       (c as Const (_, _), ts) => list_comb (c, map post_process_term ts)
   164   in
   165     case fastype_of t of
   166       Type (@{type_name fun}, [T1, T2]) =>
   167         (case try dest_fun_upds t of
   168           SOME (tps, t) =>
   169             (map (pairself post_process_term) tps, map_Abs post_process_term t)
   170             |> (case T2 of
   171               @{typ bool} => 
   172                 (case t of
   173                    Abs(_, _, @{const False}) => fst #> rev #> make_set T1
   174                  | Abs(_, _, @{const True}) => fst #> rev #> make_coset T1
   175                  | Abs(_, _, Const (@{const_name undefined}, _)) => fst #> rev #> make_set T1
   176                  | _ => raise TERM ("post_process_term", [t]))
   177             | Type (@{type_name option}, _) =>
   178                 (case t of
   179                   Abs(_, _, Const (@{const_name None}, _)) => fst #> make_map T1 T2
   180                 | Abs(_, _, Const (@{const_name undefined}, _)) => fst #> make_map T1 T2
   181                 | _ => make_fun_upds T1 T2)
   182             | _ => make_fun_upds T1 T2)
   183         | NONE => process_args t)
   184     | _ => process_args t
   185   end
   186   
   187 
   188 end;