src/HOL/Nitpick_Examples/minipick.ML
changeset 45062 9598cada31b3
parent 45035 60d2c03d5c70
child 45128 5af3a3203a76
equal deleted inserted replaced
45061:39519609abe0 45062:9598cada31b3
     5 Finite model generation for HOL formulas using Kodkod, minimalistic version.
     5 Finite model generation for HOL formulas using Kodkod, minimalistic version.
     6 *)
     6 *)
     7 
     7 
     8 signature MINIPICK =
     8 signature MINIPICK =
     9 sig
     9 sig
    10   datatype rep = S_Rep | R_Rep
    10   val minipick : Proof.context -> int -> term -> string
    11   type styp = Nitpick_Util.styp
    11   val minipick_expect : Proof.context -> string -> int -> term -> unit
    12 
       
    13   val vars_for_bound_var :
       
    14     (typ -> int) -> rep -> typ list -> int -> Kodkod.rel_expr list
       
    15   val rel_expr_for_bound_var :
       
    16     (typ -> int) -> rep -> typ list -> int -> Kodkod.rel_expr
       
    17   val decls_for : rep -> (typ -> int) -> typ list -> typ -> Kodkod.decl list
       
    18   val false_atom : Kodkod.rel_expr
       
    19   val true_atom : Kodkod.rel_expr
       
    20   val formula_from_atom : Kodkod.rel_expr -> Kodkod.formula
       
    21   val atom_from_formula : Kodkod.formula -> Kodkod.rel_expr
       
    22   val kodkod_problem_from_term :
       
    23     Proof.context -> (typ -> int) -> term -> Kodkod.problem
       
    24   val solve_any_kodkod_problem : theory -> Kodkod.problem list -> string
       
    25 end;
    12 end;
    26 
    13 
    27 structure Minipick : MINIPICK =
    14 structure Minipick : MINIPICK =
    28 struct
    15 struct
    29 
    16 
    31 open Nitpick_Util
    18 open Nitpick_Util
    32 open Nitpick_HOL
    19 open Nitpick_HOL
    33 open Nitpick_Peephole
    20 open Nitpick_Peephole
    34 open Nitpick_Kodkod
    21 open Nitpick_Kodkod
    35 
    22 
    36 datatype rep = S_Rep | R_Rep
    23 datatype rep =
    37 
    24   S_Rep |
    38 fun check_type ctxt (Type (@{type_name fun}, Ts)) =
    25   R_Rep of bool
    39     List.app (check_type ctxt) Ts
    26 
    40   | check_type ctxt (Type (@{type_name prod}, Ts)) =
    27 fun check_type ctxt raw_infinite (Type (@{type_name fun}, Ts)) =
    41     List.app (check_type ctxt) Ts
    28     List.app (check_type ctxt raw_infinite) Ts
    42   | check_type _ @{typ bool} = ()
    29   | check_type ctxt raw_infinite (Type (@{type_name prod}, Ts)) =
    43   | check_type _ (TFree (_, @{sort "{}"})) = ()
    30     List.app (check_type ctxt raw_infinite) Ts
    44   | check_type _ (TFree (_, @{sort HOL.type})) = ()
    31   | check_type _ _ @{typ bool} = ()
    45   | check_type ctxt T =
    32   | check_type _ _ (TFree (_, @{sort "{}"})) = ()
    46     raise NOT_SUPPORTED ("type " ^ quote (Syntax.string_of_typ ctxt T))
    33   | check_type _ _ (TFree (_, @{sort HOL.type})) = ()
       
    34   | check_type ctxt raw_infinite T =
       
    35     if raw_infinite T then ()
       
    36     else raise NOT_SUPPORTED ("type " ^ quote (Syntax.string_of_typ ctxt T))
    47 
    37 
    48 fun atom_schema_of S_Rep card (Type (@{type_name fun}, [T1, T2])) =
    38 fun atom_schema_of S_Rep card (Type (@{type_name fun}, [T1, T2])) =
    49     replicate_list (card T1) (atom_schema_of S_Rep card T2)
    39     replicate_list (card T1) (atom_schema_of S_Rep card T2)
    50   | atom_schema_of R_Rep card (Type (@{type_name fun}, [T1, @{typ bool}])) =
    40   | atom_schema_of (R_Rep true) card
       
    41                    (Type (@{type_name fun}, [T1, @{typ bool}])) =
    51     atom_schema_of S_Rep card T1
    42     atom_schema_of S_Rep card T1
    52   | atom_schema_of R_Rep card (Type (@{type_name fun}, [T1, T2])) =
    43   | atom_schema_of (rep as R_Rep _) card (Type (@{type_name fun}, [T1, T2])) =
    53     atom_schema_of S_Rep card T1 @ atom_schema_of R_Rep card T2
    44     atom_schema_of S_Rep card T1 @ atom_schema_of rep card T2
    54   | atom_schema_of _ card (Type (@{type_name prod}, Ts)) =
    45   | atom_schema_of _ card (Type (@{type_name prod}, Ts)) =
    55     maps (atom_schema_of S_Rep card) Ts
    46     maps (atom_schema_of S_Rep card) Ts
    56   | atom_schema_of _ card T = [card T]
    47   | atom_schema_of _ card T = [card T]
    57 val arity_of = length ooo atom_schema_of
    48 val arity_of = length ooo atom_schema_of
       
    49 val atom_seqs_of = map (AtomSeq o rpair 0) ooo atom_schema_of
       
    50 val atom_seq_product_of = foldl1 Product ooo atom_seqs_of
    58 
    51 
    59 fun index_for_bound_var _ [_] 0 = 0
    52 fun index_for_bound_var _ [_] 0 = 0
    60   | index_for_bound_var card (_ :: Ts) 0 =
    53   | index_for_bound_var card (_ :: Ts) 0 =
    61     index_for_bound_var card Ts 0 + arity_of S_Rep card (hd Ts)
    54     index_for_bound_var card Ts 0 + arity_of S_Rep card (hd Ts)
    62   | index_for_bound_var card Ts n = index_for_bound_var card (tl Ts) (n - 1)
    55   | index_for_bound_var card Ts n = index_for_bound_var card (tl Ts) (n - 1)
    66 val rel_expr_for_bound_var = foldl1 Product oooo vars_for_bound_var
    59 val rel_expr_for_bound_var = foldl1 Product oooo vars_for_bound_var
    67 fun decls_for R card Ts T =
    60 fun decls_for R card Ts T =
    68   map2 (curry DeclOne o pair 1)
    61   map2 (curry DeclOne o pair 1)
    69        (index_seq (index_for_bound_var card (T :: Ts) 0)
    62        (index_seq (index_for_bound_var card (T :: Ts) 0)
    70                   (arity_of R card (nth (T :: Ts) 0)))
    63                   (arity_of R card (nth (T :: Ts) 0)))
    71        (map (AtomSeq o rpair 0) (atom_schema_of R card T))
    64        (atom_seqs_of R card T)
    72 
    65 
    73 val atom_product = foldl1 Product o map Atom
    66 val atom_product = foldl1 Product o map Atom
    74 
    67 
    75 val false_atom = Atom 0
    68 val false_atom_num = 0
    76 val true_atom = Atom 1
    69 val true_atom_num = 1
    77 
    70 val false_atom = Atom false_atom_num
    78 fun formula_from_atom r = RelEq (r, true_atom)
    71 val true_atom = Atom true_atom_num
    79 fun atom_from_formula f = RelIf (f, true_atom, false_atom)
    72 
    80 
    73 fun kodkod_formula_from_term ctxt total card complete concrete frees =
    81 fun kodkod_formula_from_term ctxt card frees =
       
    82   let
    74   let
    83     fun R_rep_from_S_rep (Type (@{type_name fun}, [T1, @{typ bool}])) r =
    75     fun F_from_S_rep (SOME false) r = Not (RelEq (r, false_atom))
    84         let
    76       | F_from_S_rep _ r = RelEq (r, true_atom)
    85           val jss = atom_schema_of S_Rep card T1 |> map (rpair 0)
    77     fun S_rep_from_F NONE f = RelIf (f, true_atom, false_atom)
    86                     |> all_combinations
    78       | S_rep_from_F (SOME true) f = RelIf (f, true_atom, None)
    87         in
    79       | S_rep_from_F (SOME false) f = RelIf (Not f, false_atom, None)
    88           map2 (fn i => fn js =>
    80     fun R_rep_from_S_rep (Type (@{type_name fun}, [T1, T2])) r =
    89                    RelIf (formula_from_atom (Project (r, [Num i])),
    81         if total andalso T2 = bool_T then
    90                           atom_product js, empty_n_ary_rel (length js)))
    82           let
    91                (index_seq 0 (length jss)) jss
    83             val jss = atom_schema_of S_Rep card T1 |> map (rpair 0)
    92           |> foldl1 Union
    84                       |> all_combinations
    93         end
    85           in
    94       | R_rep_from_S_rep (Type (@{type_name fun}, [T1, T2])) r =
    86             map2 (fn i => fn js =>
    95         let
    87 (*
    96           val jss = atom_schema_of S_Rep card T1 |> map (rpair 0)
    88                      RelIf (F_from_S_rep NONE (Project (r, [Num i])),
    97                     |> all_combinations
    89                             atom_product js, empty_n_ary_rel (length js))
    98           val arity2 = arity_of S_Rep card T2
    90 *)
    99         in
    91                      Join (Project (r, [Num i]),
   100           map2 (fn i => fn js =>
    92                            atom_product (false_atom_num :: js))
   101                    Product (atom_product js,
    93                  ) (index_seq 0 (length jss)) jss
   102                             Project (r, num_seq (i * arity2) arity2)
    94             |> foldl1 Union
   103                             |> R_rep_from_S_rep T2))
    95           end
   104                (index_seq 0 (length jss)) jss
    96         else
   105           |> foldl1 Union
    97           let
   106         end
    98             val jss = atom_schema_of S_Rep card T1 |> map (rpair 0)
       
    99                       |> all_combinations
       
   100             val arity2 = arity_of S_Rep card T2
       
   101           in
       
   102             map2 (fn i => fn js =>
       
   103                      Product (atom_product js,
       
   104                               Project (r, num_seq (i * arity2) arity2)
       
   105                               |> R_rep_from_S_rep T2))
       
   106                  (index_seq 0 (length jss)) jss
       
   107             |> foldl1 Union
       
   108           end
   107       | R_rep_from_S_rep _ r = r
   109       | R_rep_from_S_rep _ r = r
   108     fun S_rep_from_R_rep Ts (T as Type (@{type_name fun}, _)) r =
   110     fun S_rep_from_R_rep Ts (T as Type (@{type_name fun}, _)) r =
   109         Comprehension (decls_for S_Rep card Ts T,
   111         Comprehension (decls_for S_Rep card Ts T,
   110             RelEq (R_rep_from_S_rep T
   112             RelEq (R_rep_from_S_rep T
   111                        (rel_expr_for_bound_var card S_Rep (T :: Ts) 0), r))
   113                        (rel_expr_for_bound_var card S_Rep (T :: Ts) 0), r))
   112       | S_rep_from_R_rep _ _ r = r
   114       | S_rep_from_R_rep _ _ r = r
   113     fun to_F Ts t =
   115     fun partial_eq pos Ts (Type (@{type_name fun}, [T1, T2])) t1 t2 =
       
   116         HOLogic.mk_all ("x", T1,
       
   117                         HOLogic.eq_const T2 $ (incr_boundvars 1 t1 $ Bound 0)
       
   118                         $ (incr_boundvars 1 t2 $ Bound 0))
       
   119         |> to_F (SOME pos) Ts
       
   120       | partial_eq pos Ts T t1 t2 =
       
   121         if pos andalso not (concrete T) then
       
   122           False
       
   123         else
       
   124           (t1, t2) |> pairself (to_R_rep Ts)
       
   125                    |> (if pos then Some o Intersect else Lone o Union)
       
   126     and to_F pos Ts t =
   114       (case t of
   127       (case t of
   115          @{const Not} $ t1 => Not (to_F Ts t1)
   128          @{const Not} $ t1 => Not (to_F (Option.map not pos) Ts t1)
   116        | @{const False} => False
   129        | @{const False} => False
   117        | @{const True} => True
   130        | @{const True} => True
   118        | Const (@{const_name All}, _) $ Abs (_, T, t') =>
   131        | Const (@{const_name All}, _) $ Abs (_, T, t') =>
   119          All (decls_for S_Rep card Ts T, to_F (T :: Ts) t')
   132          if pos = SOME true andalso not (complete T) then False
       
   133          else All (decls_for S_Rep card Ts T, to_F pos (T :: Ts) t')
   120        | (t0 as Const (@{const_name All}, _)) $ t1 =>
   134        | (t0 as Const (@{const_name All}, _)) $ t1 =>
   121          to_F Ts (t0 $ eta_expand Ts t1 1)
   135          to_F pos Ts (t0 $ eta_expand Ts t1 1)
   122        | Const (@{const_name Ex}, _) $ Abs (_, T, t') =>
   136        | Const (@{const_name Ex}, _) $ Abs (_, T, t') =>
   123          Exist (decls_for S_Rep card Ts T, to_F (T :: Ts) t')
   137          if pos = SOME false andalso not (complete T) then True
       
   138          else Exist (decls_for S_Rep card Ts T, to_F pos (T :: Ts) t')
   124        | (t0 as Const (@{const_name Ex}, _)) $ t1 =>
   139        | (t0 as Const (@{const_name Ex}, _)) $ t1 =>
   125          to_F Ts (t0 $ eta_expand Ts t1 1)
   140          to_F pos Ts (t0 $ eta_expand Ts t1 1)
   126        | Const (@{const_name HOL.eq}, _) $ t1 $ t2 =>
   141        | Const (@{const_name HOL.eq}, Type (_, [T, _])) $ t1 $ t2 =>
   127          RelEq (to_R_rep Ts t1, to_R_rep Ts t2)
   142          (case pos of
       
   143             NONE => RelEq (to_R_rep Ts t1, to_R_rep Ts t2)
       
   144           | SOME pos => partial_eq pos Ts T t1 t2)
   128        | Const (@{const_name ord_class.less_eq},
   145        | Const (@{const_name ord_class.less_eq},
   129                 Type (@{type_name fun},
   146                 Type (@{type_name fun},
   130                       [Type (@{type_name fun}, [_, @{typ bool}]), _]))
   147                       [Type (@{type_name fun}, [T', @{typ bool}]), _]))
   131          $ t1 $ t2 =>
   148          $ t1 $ t2 =>
   132          Subset (to_R_rep Ts t1, to_R_rep Ts t2)
   149          (case pos of
   133        | @{const HOL.conj} $ t1 $ t2 => And (to_F Ts t1, to_F Ts t2)
   150             NONE => Subset (to_R_rep Ts t1, to_R_rep Ts t2)
   134        | @{const HOL.disj} $ t1 $ t2 => Or (to_F Ts t1, to_F Ts t2)
   151           | SOME true =>
   135        | @{const HOL.implies} $ t1 $ t2 => Implies (to_F Ts t1, to_F Ts t2)
   152             Subset (Difference (atom_seq_product_of S_Rep card T',
   136        | t1 $ t2 => Subset (to_S_rep Ts t2, to_R_rep Ts t1)
   153                                 Join (to_R_rep Ts t1, false_atom)),
   137        | Free _ => raise SAME ()
   154                     Join (to_R_rep Ts t2, true_atom))
   138        | Term.Var _ => raise SAME ()
   155           | SOME false =>
   139        | Bound _ => raise SAME ()
   156             Subset (Join (to_R_rep Ts t1, true_atom),
   140        | Const (s, _) => raise NOT_SUPPORTED ("constant " ^ quote s)
   157                     Difference (atom_seq_product_of S_Rep card T',
   141        | _ => raise TERM ("Minipick.kodkod_formula_from_term.to_F", [t]))
   158                                 Join (to_R_rep Ts t2, false_atom))))
   142       handle SAME () => formula_from_atom (to_R_rep Ts t)
   159        | @{const HOL.conj} $ t1 $ t2 => And (to_F pos Ts t1, to_F pos Ts t2)
       
   160        | @{const HOL.disj} $ t1 $ t2 => Or (to_F pos Ts t1, to_F pos Ts t2)
       
   161        | @{const HOL.implies} $ t1 $ t2 =>
       
   162          Implies (to_F (Option.map not pos) Ts t1, to_F pos Ts t2)
       
   163        | t1 $ t2 =>
       
   164          (case pos of
       
   165             NONE => Subset (to_S_rep Ts t2, to_R_rep Ts t1)
       
   166           | SOME pos =>
       
   167             let
       
   168               val kt1 = to_R_rep Ts t1
       
   169               val kt2 = to_S_rep Ts t2
       
   170               val kT = atom_seq_product_of S_Rep card (fastype_of1 (Ts, t2))
       
   171             in
       
   172               if pos then
       
   173                 Not (Subset (kt2, Difference (kT, Join (kt1, true_atom))))
       
   174               else
       
   175                 Subset (kt2, Difference (kT, Join (kt1, false_atom)))
       
   176             end)
       
   177        | _ => raise SAME ())
       
   178       handle SAME () => F_from_S_rep pos (to_R_rep Ts t)
   143     and to_S_rep Ts t =
   179     and to_S_rep Ts t =
   144       case t of
   180       case t of
   145         Const (@{const_name Pair}, _) $ t1 $ t2 =>
   181         Const (@{const_name Pair}, _) $ t1 $ t2 =>
   146         Product (to_S_rep Ts t1, to_S_rep Ts t2)
   182         Product (to_S_rep Ts t1, to_S_rep Ts t2)
   147       | Const (@{const_name Pair}, _) $ _ => to_S_rep Ts (eta_expand Ts t 1)
   183       | Const (@{const_name Pair}, _) $ _ => to_S_rep Ts (eta_expand Ts t 1)
   158           val fst_arity = pair_arity - snd_arity
   194           val fst_arity = pair_arity - snd_arity
   159         in Project (to_S_rep Ts t1, num_seq fst_arity snd_arity) end
   195         in Project (to_S_rep Ts t1, num_seq fst_arity snd_arity) end
   160       | Const (@{const_name snd}, _) => to_S_rep Ts (eta_expand Ts t 1)
   196       | Const (@{const_name snd}, _) => to_S_rep Ts (eta_expand Ts t 1)
   161       | Bound j => rel_expr_for_bound_var card S_Rep Ts j
   197       | Bound j => rel_expr_for_bound_var card S_Rep Ts j
   162       | _ => S_rep_from_R_rep Ts (fastype_of1 (Ts, t)) (to_R_rep Ts t)
   198       | _ => S_rep_from_R_rep Ts (fastype_of1 (Ts, t)) (to_R_rep Ts t)
       
   199     and partial_set_op swap1 swap2 op1 op2 Ts t1 t2 =
       
   200       let
       
   201         val kt1 = to_R_rep Ts t1
       
   202         val kt2 = to_R_rep Ts t2
       
   203         val (a11, a21) = (false_atom, true_atom) |> swap1 ? swap
       
   204         val (a12, a22) = (false_atom, true_atom) |> swap2 ? swap
       
   205       in
       
   206         Union (Product (op1 (Join (kt1, a11), Join (kt2, a12)), true_atom),
       
   207                Product (op2 (Join (kt1, a21), Join (kt2, a22)), false_atom))
       
   208       end
   163     and to_R_rep Ts t =
   209     and to_R_rep Ts t =
   164       (case t of
   210       (case t of
   165          @{const Not} => to_R_rep Ts (eta_expand Ts t 1)
   211          @{const Not} => to_R_rep Ts (eta_expand Ts t 1)
   166        | Const (@{const_name All}, _) => to_R_rep Ts (eta_expand Ts t 1)
   212        | Const (@{const_name All}, _) => to_R_rep Ts (eta_expand Ts t 1)
   167        | Const (@{const_name Ex}, _) => to_R_rep Ts (eta_expand Ts t 1)
   213        | Const (@{const_name Ex}, _) => to_R_rep Ts (eta_expand Ts t 1)
   178        | @{const HOL.disj} $ _ => to_R_rep Ts (eta_expand Ts t 1)
   224        | @{const HOL.disj} $ _ => to_R_rep Ts (eta_expand Ts t 1)
   179        | @{const HOL.disj} => to_R_rep Ts (eta_expand Ts t 2)
   225        | @{const HOL.disj} => to_R_rep Ts (eta_expand Ts t 2)
   180        | @{const HOL.implies} $ _ => to_R_rep Ts (eta_expand Ts t 1)
   226        | @{const HOL.implies} $ _ => to_R_rep Ts (eta_expand Ts t 1)
   181        | @{const HOL.implies} => to_R_rep Ts (eta_expand Ts t 2)
   227        | @{const HOL.implies} => to_R_rep Ts (eta_expand Ts t 2)
   182        | Const (@{const_name bot_class.bot},
   228        | Const (@{const_name bot_class.bot},
   183                 T as Type (@{type_name fun}, [_, @{typ bool}])) =>
   229                 T as Type (@{type_name fun}, [T', @{typ bool}])) =>
   184          empty_n_ary_rel (arity_of R_Rep card T)
   230          if total then empty_n_ary_rel (arity_of (R_Rep total) card T)
   185        | Const (@{const_name insert}, _) $ t1 $ t2 =>
   231          else Product (atom_seq_product_of (R_Rep total) card T', false_atom)
   186          Union (to_S_rep Ts t1, to_R_rep Ts t2)
   232        | Const (@{const_name top_class.top},
       
   233                 T as Type (@{type_name fun}, [T', @{typ bool}])) =>
       
   234          if total then atom_seq_product_of (R_Rep total) card T
       
   235          else Product (atom_seq_product_of (R_Rep total) card T', true_atom)
       
   236        | Const (@{const_name insert}, Type (_, [T, _])) $ t1 $ t2 =>
       
   237          if total then
       
   238            Union (to_S_rep Ts t1, to_R_rep Ts t2)
       
   239          else
       
   240            let
       
   241              val kt1 = to_S_rep Ts t1
       
   242              val kt2 = to_R_rep Ts t2
       
   243            in
       
   244              RelIf (Some kt1,
       
   245                     if arity_of S_Rep card T = 1 then
       
   246                       Override (kt2, Product (kt1, true_atom))
       
   247                     else
       
   248                       Union (Difference (kt2, Product (kt1, false_atom)),
       
   249                              Product (kt1, true_atom)),
       
   250                     Difference (kt2, Product (atom_seq_product_of S_Rep card T,
       
   251                                               false_atom)))
       
   252            end
   187        | Const (@{const_name insert}, _) $ _ => to_R_rep Ts (eta_expand Ts t 1)
   253        | Const (@{const_name insert}, _) $ _ => to_R_rep Ts (eta_expand Ts t 1)
   188        | Const (@{const_name insert}, _) => to_R_rep Ts (eta_expand Ts t 2)
   254        | Const (@{const_name insert}, _) => to_R_rep Ts (eta_expand Ts t 2)
   189        | Const (@{const_name trancl}, _) $ t1 =>
   255        | Const (@{const_name trancl},
   190          if arity_of R_Rep card (fastype_of1 (Ts, t1)) = 2 then
   256                 Type (_, [Type (_, [Type (_, [T', _]), _]), _])) $ t1 =>
   191            Closure (to_R_rep Ts t1)
   257          if arity_of S_Rep card T' = 1 then
       
   258            if total then
       
   259              Closure (to_R_rep Ts t1)
       
   260            else
       
   261              let
       
   262                val kt1 = to_R_rep Ts t1
       
   263                val true_core_kt = Closure (Join (kt1, true_atom))
       
   264                val kTx =
       
   265                  atom_seq_product_of S_Rep card (HOLogic.mk_prodT (`I T'))
       
   266                val false_mantle_kt =
       
   267                  Difference (kTx,
       
   268                      Closure (Difference (kTx, Join (kt1, false_atom))))
       
   269              in
       
   270                Union (Product (Difference (false_mantle_kt, true_core_kt),
       
   271                                false_atom),
       
   272                       Product (true_core_kt, true_atom))
       
   273              end
   192          else
   274          else
   193            raise NOT_SUPPORTED "transitive closure for function or pair type"
   275            raise NOT_SUPPORTED "transitive closure for function or pair type"
   194        | Const (@{const_name trancl}, _) => to_R_rep Ts (eta_expand Ts t 1)
   276        | Const (@{const_name trancl}, _) => to_R_rep Ts (eta_expand Ts t 1)
   195        | Const (@{const_name inf_class.inf},
   277        | Const (@{const_name inf_class.inf},
   196                 Type (@{type_name fun},
   278                 Type (@{type_name fun},
   197                       [Type (@{type_name fun}, [_, @{typ bool}]), _]))
   279                       [Type (@{type_name fun}, [_, @{typ bool}]), _]))
   198          $ t1 $ t2 =>
   280          $ t1 $ t2 =>
   199          Intersect (to_R_rep Ts t1, to_R_rep Ts t2)
   281          if total then Intersect (to_R_rep Ts t1, to_R_rep Ts t2)
       
   282          else partial_set_op true true Intersect Union Ts t1 t2
   200        | Const (@{const_name inf_class.inf}, _) $ _ =>
   283        | Const (@{const_name inf_class.inf}, _) $ _ =>
   201          to_R_rep Ts (eta_expand Ts t 1)
   284          to_R_rep Ts (eta_expand Ts t 1)
   202        | Const (@{const_name inf_class.inf}, _) =>
   285        | Const (@{const_name inf_class.inf}, _) =>
   203          to_R_rep Ts (eta_expand Ts t 2)
   286          to_R_rep Ts (eta_expand Ts t 2)
   204        | Const (@{const_name sup_class.sup},
   287        | Const (@{const_name sup_class.sup},
   205                 Type (@{type_name fun},
   288                 Type (@{type_name fun},
   206                       [Type (@{type_name fun}, [_, @{typ bool}]), _]))
   289                       [Type (@{type_name fun}, [_, @{typ bool}]), _]))
   207          $ t1 $ t2 =>
   290          $ t1 $ t2 =>
   208          Union (to_R_rep Ts t1, to_R_rep Ts t2)
   291          if total then Union (to_R_rep Ts t1, to_R_rep Ts t2)
       
   292          else partial_set_op true true Union Intersect Ts t1 t2
   209        | Const (@{const_name sup_class.sup}, _) $ _ =>
   293        | Const (@{const_name sup_class.sup}, _) $ _ =>
   210          to_R_rep Ts (eta_expand Ts t 1)
   294          to_R_rep Ts (eta_expand Ts t 1)
   211        | Const (@{const_name sup_class.sup}, _) =>
   295        | Const (@{const_name sup_class.sup}, _) =>
   212          to_R_rep Ts (eta_expand Ts t 2)
   296          to_R_rep Ts (eta_expand Ts t 2)
   213        | Const (@{const_name minus_class.minus},
   297        | Const (@{const_name minus_class.minus},
   214                 Type (@{type_name fun},
   298                 Type (@{type_name fun},
   215                       [Type (@{type_name fun}, [_, @{typ bool}]), _]))
   299                       [Type (@{type_name fun}, [_, @{typ bool}]), _]))
   216          $ t1 $ t2 =>
   300          $ t1 $ t2 =>
   217          Difference (to_R_rep Ts t1, to_R_rep Ts t2)
   301          if total then Difference (to_R_rep Ts t1, to_R_rep Ts t2)
       
   302          else partial_set_op true false Intersect Union Ts t1 t2
   218        | Const (@{const_name minus_class.minus},
   303        | Const (@{const_name minus_class.minus},
   219                 Type (@{type_name fun},
   304                 Type (@{type_name fun},
   220                       [Type (@{type_name fun}, [_, @{typ bool}]), _])) $ _ =>
   305                       [Type (@{type_name fun}, [_, @{typ bool}]), _])) $ _ =>
   221          to_R_rep Ts (eta_expand Ts t 1)
   306          to_R_rep Ts (eta_expand Ts t 1)
   222        | Const (@{const_name minus_class.minus},
   307        | Const (@{const_name minus_class.minus},
   223                 Type (@{type_name fun},
   308                 Type (@{type_name fun},
   224                       [Type (@{type_name fun}, [_, @{typ bool}]), _])) =>
   309                       [Type (@{type_name fun}, [_, @{typ bool}]), _])) =>
   225          to_R_rep Ts (eta_expand Ts t 2)
   310          to_R_rep Ts (eta_expand Ts t 2)
   226        | Const (@{const_name Pair}, _) $ _ $ _ => raise SAME ()
   311        | Const (@{const_name Pair}, _) $ _ $ _ => to_S_rep Ts t
   227        | Const (@{const_name Pair}, _) $ _ => raise SAME ()
   312        | Const (@{const_name Pair}, _) $ _ => to_S_rep Ts t
   228        | Const (@{const_name Pair}, _) => raise SAME ()
   313        | Const (@{const_name Pair}, _) => to_S_rep Ts t
   229        | Const (@{const_name fst}, _) $ _ => raise SAME ()
   314        | Const (@{const_name fst}, _) $ _ => raise SAME ()
   230        | Const (@{const_name fst}, _) => raise SAME ()
   315        | Const (@{const_name fst}, _) => raise SAME ()
   231        | Const (@{const_name snd}, _) $ _ => raise SAME ()
   316        | Const (@{const_name snd}, _) $ _ => raise SAME ()
   232        | Const (@{const_name snd}, _) => raise SAME ()
   317        | Const (@{const_name snd}, _) => raise SAME ()
   233        | Const (_, @{typ bool}) => atom_from_formula (to_F Ts t)
   318        | @{const False} => false_atom
       
   319        | @{const True} => true_atom
   234        | Free (x as (_, T)) =>
   320        | Free (x as (_, T)) =>
   235          Rel (arity_of R_Rep card T, find_index (curry (op =) x) frees)
   321          Rel (arity_of (R_Rep total) card T, find_index (curry (op =) x) frees)
   236        | Term.Var _ => raise NOT_SUPPORTED "schematic variables"
   322        | Term.Var _ => raise NOT_SUPPORTED "schematic variables"
   237        | Bound _ => raise SAME ()
   323        | Bound _ => raise SAME ()
   238        | Abs (_, T, t') =>
   324        | Abs (_, T, t') =>
   239          (case fastype_of1 (T :: Ts, t') of
   325          (case (total, fastype_of1 (T :: Ts, t')) of
   240             @{typ bool} => Comprehension (decls_for S_Rep card Ts T,
   326             (true, @{typ bool}) =>
   241                                           to_F (T :: Ts) t')
   327             Comprehension (decls_for S_Rep card Ts T, to_F NONE (T :: Ts) t')
   242           | T' => Comprehension (decls_for S_Rep card Ts T @
   328           | (_, T') =>
   243                                  decls_for R_Rep card (T :: Ts) T',
   329             Comprehension (decls_for S_Rep card Ts T @
   244                                  Subset (rel_expr_for_bound_var card R_Rep
   330                            decls_for (R_Rep total) card (T :: Ts) T',
   245                                                               (T' :: T :: Ts) 0,
   331                            Subset (rel_expr_for_bound_var card (R_Rep total)
   246                                          to_R_rep (T :: Ts) t')))
   332                                                           (T' :: T :: Ts) 0,
       
   333                                    to_R_rep (T :: Ts) t')))
   247        | t1 $ t2 =>
   334        | t1 $ t2 =>
   248          (case fastype_of1 (Ts, t) of
   335          (case fastype_of1 (Ts, t) of
   249             @{typ bool} => atom_from_formula (to_F Ts t)
   336             @{typ bool} =>
       
   337             if total then
       
   338               S_rep_from_F NONE (to_F NONE Ts t)
       
   339             else
       
   340               RelIf (to_F (SOME true) Ts t, true_atom,
       
   341                      RelIf (Not (to_F (SOME false) Ts t), false_atom,
       
   342                      None))
   250           | T =>
   343           | T =>
   251             let val T2 = fastype_of1 (Ts, t2) in
   344             let val T2 = fastype_of1 (Ts, t2) in
   252               case arity_of S_Rep card T2 of
   345               case arity_of S_Rep card T2 of
   253                 1 => Join (to_S_rep Ts t2, to_R_rep Ts t1)
   346                 1 => Join (to_S_rep Ts t2, to_R_rep Ts t1)
   254               | arity2 =>
   347               | arity2 =>
   255                 let val res_arity = arity_of R_Rep card T in
   348                 let val res_arity = arity_of (R_Rep total) card T in
   256                   Project (Intersect
   349                   Project (Intersect
   257                       (Product (to_S_rep Ts t2,
   350                       (Product (to_S_rep Ts t2,
   258                                 atom_schema_of R_Rep card T
   351                                 atom_seq_product_of (R_Rep total) card T),
   259                                 |> map (AtomSeq o rpair 0) |> foldl1 Product),
       
   260                        to_R_rep Ts t1),
   352                        to_R_rep Ts t1),
   261                       num_seq arity2 res_arity)
   353                       num_seq arity2 res_arity)
   262                 end
   354                 end
   263             end)
   355             end)
   264        | _ => raise NOT_SUPPORTED ("term " ^
   356        | _ => raise NOT_SUPPORTED ("term " ^
   265                                    quote (Syntax.string_of_term ctxt t)))
   357                                    quote (Syntax.string_of_term ctxt t)))
   266       handle SAME () => R_rep_from_S_rep (fastype_of1 (Ts, t)) (to_S_rep Ts t)
   358       handle SAME () => R_rep_from_S_rep (fastype_of1 (Ts, t)) (to_S_rep Ts t)
   267   in to_F [] end
   359   in to_F (if total then NONE else SOME true) [] end
   268 
   360 
   269 fun bound_for_free card i (s, T) =
   361 fun bound_for_free total card i (s, T) =
   270   let val js = atom_schema_of R_Rep card T in
   362   let val js = atom_schema_of (R_Rep total) card T in
   271     ([((length js, i), s)],
   363     ([((length js, i), s)],
   272      [TupleSet [], atom_schema_of R_Rep card T |> map (rpair 0)
   364      [TupleSet [], atom_schema_of (R_Rep total) card T |> map (rpair 0)
   273                    |> tuple_set_from_atom_schema])
   365                    |> tuple_set_from_atom_schema])
   274   end
   366   end
   275 
   367 
   276 fun declarative_axiom_for_rel_expr card Ts (Type (@{type_name fun}, [T1, T2]))
   368 fun declarative_axiom_for_rel_expr total card Ts
   277                                    r =
   369                                    (Type (@{type_name fun}, [T1, T2])) r =
   278     if body_type T2 = bool_T then
   370     if total andalso body_type T2 = bool_T then
   279       True
   371       True
   280     else
   372     else
   281       All (decls_for S_Rep card Ts T1,
   373       All (decls_for S_Rep card Ts T1,
   282            declarative_axiom_for_rel_expr card (T1 :: Ts) T2
   374            declarative_axiom_for_rel_expr total card (T1 :: Ts) T2
   283                (List.foldl Join r (vars_for_bound_var card S_Rep (T1 :: Ts) 0)))
   375                (List.foldl Join r (vars_for_bound_var card S_Rep (T1 :: Ts) 0)))
   284   | declarative_axiom_for_rel_expr _ _ _ r = One r
   376   | declarative_axiom_for_rel_expr total _ _ _ r =
   285 fun declarative_axiom_for_free card i (_, T) =
   377     (if total then One else Lone) r
   286   declarative_axiom_for_rel_expr card [] T (Rel (arity_of R_Rep card T, i))
   378 fun declarative_axiom_for_free total card i (_, T) =
   287 
   379   declarative_axiom_for_rel_expr total card [] T
   288 fun kodkod_problem_from_term ctxt raw_card t =
   380       (Rel (arity_of (R_Rep total) card T, i))
       
   381 
       
   382 fun kodkod_problem_from_term ctxt total raw_card raw_infinite t =
   289   let
   383   let
   290     val thy = ProofContext.theory_of ctxt
   384     val thy = ProofContext.theory_of ctxt
   291     fun card (Type (@{type_name fun}, [T1, T2])) =
   385     fun card (Type (@{type_name fun}, [T1, T2])) =
   292         reasonable_power (card T2) (card T1)
   386         reasonable_power (card T2) (card T1)
   293       | card (Type (@{type_name prod}, [T1, T2])) = card T1 * card T2
   387       | card (Type (@{type_name prod}, [T1, T2])) = card T1 * card T2
   294       | card @{typ bool} = 2
   388       | card @{typ bool} = 2
   295       | card T = Int.max (1, raw_card T)
   389       | card T = Int.max (1, raw_card T)
       
   390     fun complete (Type (@{type_name fun}, [T1, T2])) =
       
   391         concrete T1 andalso complete T2
       
   392       | complete (Type (@{type_name prod}, Ts)) = forall complete Ts
       
   393       | complete T = not (raw_infinite T)
       
   394     and concrete (Type (@{type_name fun}, [T1, T2])) =
       
   395         complete T1 andalso concrete T2
       
   396       | concrete (Type (@{type_name prod}, Ts)) = forall concrete Ts
       
   397       | concrete _ = true
   296     val neg_t = @{const Not} $ Object_Logic.atomize_term thy t
   398     val neg_t = @{const Not} $ Object_Logic.atomize_term thy t
   297     val _ = fold_types (K o check_type ctxt) neg_t ()
   399     val _ = fold_types (K o check_type ctxt raw_infinite) neg_t ()
   298     val frees = Term.add_frees neg_t []
   400     val frees = Term.add_frees neg_t []
   299     val bounds = map2 (bound_for_free card) (index_seq 0 (length frees)) frees
   401     val bounds =
       
   402       map2 (bound_for_free total card) (index_seq 0 (length frees)) frees
   300     val declarative_axioms =
   403     val declarative_axioms =
   301       map2 (declarative_axiom_for_free card) (index_seq 0 (length frees)) frees
   404       map2 (declarative_axiom_for_free total card)
   302     val formula = kodkod_formula_from_term ctxt card frees neg_t
   405            (index_seq 0 (length frees)) frees
   303                   |> fold_rev (curry And) declarative_axioms
   406     val formula =
       
   407       neg_t |> kodkod_formula_from_term ctxt total card complete concrete frees 
       
   408             |> fold_rev (curry And) declarative_axioms
   304     val univ_card = univ_card 0 0 0 bounds formula
   409     val univ_card = univ_card 0 0 0 bounds formula
   305   in
   410   in
   306     {comment = "", settings = [], univ_card = univ_card, tuple_assigns = [],
   411     {comment = "", settings = [], univ_card = univ_card, tuple_assigns = [],
   307      bounds = bounds, int_bounds = [], expr_assigns = [], formula = formula}
   412      bounds = bounds, int_bounds = [], expr_assigns = [], formula = formula}
   308   end
   413   end
   322     | Normal _ => "genuine"
   427     | Normal _ => "genuine"
   323     | TimedOut _ => "unknown"
   428     | TimedOut _ => "unknown"
   324     | Error (s, _) => error ("Kodkod error: " ^ s)
   429     | Error (s, _) => error ("Kodkod error: " ^ s)
   325   end
   430   end
   326 
   431 
       
   432 val default_raw_infinite = member (op =) [@{typ nat}, @{typ int}]
       
   433 
       
   434 fun minipick ctxt n t =
       
   435   let
       
   436     val thy = ProofContext.theory_of ctxt
       
   437     val {total_consts, ...} = Nitpick_Isar.default_params thy []
       
   438     val totals =
       
   439       total_consts |> Option.map single |> the_default [true, false]
       
   440     fun problem_for (total, k) =
       
   441       kodkod_problem_from_term ctxt total (K k) default_raw_infinite t
       
   442   in
       
   443     (totals, 1 upto n)
       
   444     |-> map_product pair
       
   445     |> map problem_for
       
   446     |> solve_any_kodkod_problem (Proof_Context.theory_of ctxt)
       
   447   end
       
   448 
       
   449 fun minipick_expect ctxt expect n t =
       
   450   if getenv "KODKODI" <> "" then
       
   451     if minipick ctxt n t = expect then ()
       
   452     else error ("\"minipick_expect\" expected " ^ quote expect)
       
   453   else
       
   454     ()
       
   455 
   327 end;
   456 end;