1 (* Title: HOL/Tools/Nitpick/nitpick_kodkod.ML
2 Author: Jasmin Blanchette, TU Muenchen
3 Copyright 2008, 2009, 2010
5 Kodkod problem generator part of Kodkod.
8 signature NITPICK_KODKOD =
10 type hol_context = Nitpick_HOL.hol_context
11 type datatype_spec = Nitpick_Scope.datatype_spec
12 type kodkod_constrs = Nitpick_Peephole.kodkod_constrs
13 type nut = Nitpick_Nut.nut
15 structure NameTable : TABLE
18 int -> int -> int -> Kodkod.bound list -> Kodkod.formula -> int
19 val check_bits : int -> Kodkod.formula -> unit
20 val check_arity : string -> int -> int -> unit
21 val kk_tuple : bool -> int -> int list -> Kodkod.tuple
22 val tuple_set_from_atom_schema : (int * int) list -> Kodkod.tuple_set
23 val sequential_int_bounds : int -> Kodkod.int_bound list
24 val pow_of_two_int_bounds : int -> int -> Kodkod.int_bound list
25 val bounds_and_axioms_for_built_in_rels_in_formulas :
26 bool -> int -> int -> int -> int -> Kodkod.formula list
27 -> Kodkod.bound list * Kodkod.formula list
28 val bound_for_plain_rel : Proof.context -> bool -> nut -> Kodkod.bound
29 val bound_for_sel_rel :
30 Proof.context -> bool -> (typ * (nut * int) list option) list
31 -> datatype_spec list -> nut -> Kodkod.bound
32 val merge_bounds : Kodkod.bound list -> Kodkod.bound list
33 val kodkod_formula_from_nut :
34 int Typtab.table -> kodkod_constrs -> nut -> Kodkod.formula
35 val needed_values_for_datatype :
36 nut list -> int Typtab.table -> datatype_spec -> (nut * int) list option
37 val declarative_axiom_for_plain_rel : kodkod_constrs -> nut -> Kodkod.formula
38 val declarative_axioms_for_datatypes :
39 hol_context -> bool -> nut list -> (typ * (nut * int) list option) list
40 -> int -> int -> int Typtab.table -> kodkod_constrs -> nut NameTable.table
41 -> datatype_spec list -> Kodkod.formula list
44 structure Nitpick_Kodkod : NITPICK_KODKOD =
56 fun pull x xs = x :: filter_out (curry (op =) x) xs
58 fun is_datatype_acyclic ({co = false, standard = true, deep = true, ...}
59 : datatype_spec) = true
60 | is_datatype_acyclic _ = false
62 fun flip_nums n = index_seq 1 n @ [0] |> map KK.Num
64 fun univ_card nat_card int_card main_j0 bounds formula =
66 fun rel_expr_func r k =
69 | KK.AtomSeq (k', j0) => j0 + k'
73 KK.Tuple js => fold Integer.max (map (Integer.add 1) js) k
75 fun tuple_set_func ts k =
76 Int.max (k, case ts of KK.TupleAtomSeq (k', j0) => j0 + k' | _ => 0)
77 val expr_F = {formula_func = K I, rel_expr_func = rel_expr_func,
79 val tuple_F = {tuple_func = tuple_func, tuple_set_func = tuple_set_func}
80 val card = fold (KK.fold_bound expr_F tuple_F) bounds 1
81 |> KK.fold_formula expr_F formula
82 in Int.max (main_j0 + fold Integer.max [2, nat_card, int_card] 0, card) end
84 fun check_bits bits formula =
86 fun int_expr_func (KK.Num k) () =
87 if is_twos_complement_representable bits k then
90 raise TOO_SMALL ("Nitpick_Kodkod.check_bits",
91 "\"bits\" value " ^ string_of_int bits ^
92 " too small for problem")
93 | int_expr_func _ () = ()
94 val expr_F = {formula_func = K I, rel_expr_func = K I,
95 int_expr_func = int_expr_func}
96 in KK.fold_formula expr_F formula () end
98 fun check_arity guilty_party univ_card n =
99 if n > KK.max_arity univ_card then
100 raise TOO_LARGE ("Nitpick_Kodkod.check_arity",
101 "arity " ^ string_of_int n ^
102 (if guilty_party = "" then
105 " of Kodkod relation associated with " ^
106 quote (original_name guilty_party)) ^
107 " too large for a universe of size " ^
108 string_of_int univ_card)
112 fun kk_tuple debug univ_card js =
116 KK.TupleIndex (length js,
117 fold (fn j => fn accum => accum * univ_card + j) js 0)
119 (* This code is not just a silly optimization: It works around a limitation in
120 Kodkodi, whereby {} (i.e., KK.TupleProduct) is always given the cardinality
121 of the bound in which it appears, resulting in Kodkod arity errors. *)
122 fun tuple_product (ts as KK.TupleSet []) _ = ts
123 | tuple_product _ (ts as KK.TupleSet []) = ts
124 | tuple_product ts1 ts2 = KK.TupleProduct (ts1, ts2)
126 val tuple_set_from_atom_schema = fold1 tuple_product o map KK.TupleAtomSeq
127 val upper_bound_for_rep = tuple_set_from_atom_schema o atom_schema_of_rep
129 val single_atom = KK.TupleSet o single o KK.Tuple o single
130 fun sequential_int_bounds n = [(NONE, map single_atom (index_seq 0 n))]
131 fun pow_of_two_int_bounds bits j0 =
134 | aux 1 pow_of_two j = [(SOME (~ pow_of_two), [single_atom j])]
135 | aux iter pow_of_two j =
136 (SOME pow_of_two, [single_atom j]) ::
137 aux (iter - 1) (2 * pow_of_two) (j + 1)
138 in aux (bits + 1) 1 j0 end
140 fun built_in_rels_in_formulas formulas =
142 fun rel_expr_func (KK.Rel (x as (_, j))) =
143 (j < 0 andalso x <> unsigned_bit_word_sel_rel andalso
144 x <> signed_bit_word_sel_rel)
146 | rel_expr_func _ = I
147 val expr_F = {formula_func = K I, rel_expr_func = rel_expr_func,
149 in fold (KK.fold_formula expr_F) formulas [] end
151 val max_table_size = 65536
153 fun check_table_size k =
154 if k > max_table_size then
155 raise TOO_LARGE ("Nitpick_Kodkod.check_table_size",
156 "precomputed table too large (" ^ string_of_int k ^ ")")
160 fun tabulate_func1 debug univ_card (k, j0) f =
162 map_filter (fn j1 => let val j2 = f j1 in
164 SOME (kk_tuple debug univ_card [j1 + j0, j2 + j0])
167 end) (index_seq 0 k))
168 fun tabulate_op2 debug univ_card (k, j0) res_j0 f =
169 (check_table_size (k * k);
170 map_filter (fn j => let
176 SOME (kk_tuple debug univ_card
177 [j1 + j0, j2 + j0, j3 + res_j0])
180 end) (index_seq 0 (k * k)))
181 fun tabulate_op2_2 debug univ_card (k, j0) res_j0 f =
182 (check_table_size (k * k);
183 map_filter (fn j => let
186 val (j3, j4) = f (j1, j2)
188 if j3 >= 0 andalso j4 >= 0 then
189 SOME (kk_tuple debug univ_card
190 [j1 + j0, j2 + j0, j3 + res_j0,
194 end) (index_seq 0 (k * k)))
195 fun tabulate_nat_op2 debug univ_card (k, j0) f =
196 tabulate_op2 debug univ_card (k, j0) j0 (atom_for_nat (k, 0) o f)
197 fun tabulate_int_op2 debug univ_card (k, j0) f =
198 tabulate_op2 debug univ_card (k, j0) j0
199 (atom_for_int (k, 0) o f o pairself (int_for_atom (k, 0)))
200 fun tabulate_int_op2_2 debug univ_card (k, j0) f =
201 tabulate_op2_2 debug univ_card (k, j0) j0
202 (pairself (atom_for_int (k, 0)) o f
203 o pairself (int_for_atom (k, 0)))
205 fun isa_div (m, n) = m div n handle General.Div => 0
206 fun isa_mod (m, n) = m mod n handle General.Div => m
207 fun isa_gcd (m, 0) = m
208 | isa_gcd (m, n) = isa_gcd (n, isa_mod (m, n))
209 fun isa_lcm (m, n) = isa_div (m * n, isa_gcd (m, n))
210 val isa_zgcd = isa_gcd o pairself abs
211 fun isa_norm_frac (m, n) =
212 if n < 0 then isa_norm_frac (~m, ~n)
213 else if m = 0 orelse n = 0 then (0, 1)
214 else let val p = isa_zgcd (m, n) in (isa_div (m, p), isa_div (n, p)) end
216 fun tabulate_built_in_rel debug univ_card nat_card int_card j0
218 (check_arity "" univ_card n;
220 ("not3", tabulate_func1 debug univ_card (2, j0) (curry (op -) 1))
221 else if x = suc_rel then
222 ("suc", tabulate_func1 debug univ_card (univ_card - j0 - 1, j0)
224 else if x = nat_add_rel then
225 ("nat_add", tabulate_nat_op2 debug univ_card (nat_card, j0) (op +))
226 else if x = int_add_rel then
227 ("int_add", tabulate_int_op2 debug univ_card (int_card, j0) (op +))
228 else if x = nat_subtract_rel then
230 tabulate_op2 debug univ_card (nat_card, j0) j0 (uncurry nat_minus))
231 else if x = int_subtract_rel then
232 ("int_subtract", tabulate_int_op2 debug univ_card (int_card, j0) (op -))
233 else if x = nat_multiply_rel then
234 ("nat_multiply", tabulate_nat_op2 debug univ_card (nat_card, j0) (op * ))
235 else if x = int_multiply_rel then
236 ("int_multiply", tabulate_int_op2 debug univ_card (int_card, j0) (op * ))
237 else if x = nat_divide_rel then
238 ("nat_divide", tabulate_nat_op2 debug univ_card (nat_card, j0) isa_div)
239 else if x = int_divide_rel then
240 ("int_divide", tabulate_int_op2 debug univ_card (int_card, j0) isa_div)
241 else if x = nat_less_rel then
242 ("nat_less", tabulate_nat_op2 debug univ_card (nat_card, j0)
243 (int_from_bool o op <))
244 else if x = int_less_rel then
245 ("int_less", tabulate_int_op2 debug univ_card (int_card, j0)
246 (int_from_bool o op <))
247 else if x = gcd_rel then
248 ("gcd", tabulate_nat_op2 debug univ_card (nat_card, j0) isa_gcd)
249 else if x = lcm_rel then
250 ("lcm", tabulate_nat_op2 debug univ_card (nat_card, j0) isa_lcm)
251 else if x = norm_frac_rel then
252 ("norm_frac", tabulate_int_op2_2 debug univ_card (int_card, j0)
255 raise ARG ("Nitpick_Kodkod.tabulate_built_in_rel", "unknown relation"))
257 fun bound_for_built_in_rel debug univ_card nat_card int_card main_j0
259 if n = 2 andalso j <= suc_rels_base then
260 let val (y as (k, j0), tabulate) = atom_seq_for_suc_rel x in
263 [KK.TupleSet (tabulate_func1 debug univ_card (k - 1, j0)
266 [KK.TupleSet [], tuple_set_from_atom_schema [y, y]])
270 val (nick, ts) = tabulate_built_in_rel debug univ_card nat_card int_card
272 in ([(x, nick)], [KK.TupleSet ts]) end
274 fun axiom_for_built_in_rel (x as (n, j)) =
275 if n = 2 andalso j <= suc_rels_base then
276 let val (y as (k, j0), tabulate) = atom_seq_for_suc_rel x in
280 SOME (KK.No (KK.Rel x))
282 SOME (KK.TotalOrdering (x, KK.AtomSeq y, KK.Atom j0, KK.Atom (j0 + 1)))
286 fun bounds_and_axioms_for_built_in_rels_in_formulas debug univ_card nat_card
287 int_card main_j0 formulas =
288 let val rels = built_in_rels_in_formulas formulas in
289 (map (bound_for_built_in_rel debug univ_card nat_card int_card main_j0)
291 map_filter axiom_for_built_in_rel rels)
294 fun bound_comment ctxt debug nick T R =
296 (if debug then " :: " ^ unyxml (Syntax.string_of_typ ctxt T) else "") ^
297 " : " ^ string_for_rep R
299 fun bound_for_plain_rel ctxt debug (u as FreeRel (x, T, R, nick)) =
300 ([(x, bound_comment ctxt debug nick T R)],
301 if nick = @{const_name bisim_iterator_max} then
303 Atom (k, j0) => [single_atom (k - 1 + j0)]
304 | _ => raise NUT ("Nitpick_Kodkod.bound_for_plain_rel", [u])
306 [KK.TupleSet [], upper_bound_for_rep R])
307 | bound_for_plain_rel _ _ u =
308 raise NUT ("Nitpick_Kodkod.bound_for_plain_rel", [u])
310 fun is_datatype_nat_like ({typ, constrs, ...} : datatype_spec) =
313 (case constrs |> map (snd o #const) |> List.partition is_fun_type of
314 ([Type (_, Ts1)], [T2]) => forall (curry (op =) typ) (T2 :: Ts1)
318 fun needed_values need_vals T =
319 AList.lookup (op =) need_vals T |> the_default NONE |> these
321 fun all_values_are_needed need_vals ({typ, card, ...} : datatype_spec) =
322 length (needed_values need_vals typ) = card
324 fun is_sel_of_constr x (Construct (sel_us, _, _, _), _) =
325 exists (fn FreeRel (x', _, _, _) => x = x' | _ => false) sel_us
326 | is_sel_of_constr _ _ = false
328 fun bound_for_sel_rel ctxt debug need_vals dtypes
329 (FreeRel (x, T as Type (@{type_name fun}, [T1, T2]),
330 R as Func (Atom (_, j0), R2), nick)) =
332 val constr_s = original_name nick
333 val {delta, epsilon, exclusive, explicit_max, ...} =
334 constr_spec dtypes (constr_s, T1)
335 val dtype as {card, ...} = datatype_spec dtypes T1 |> the
336 val T1_need_vals = needed_values need_vals T1
338 ([(x, bound_comment ctxt debug nick T R)],
340 val discr = (R2 = Formula Neut)
341 val complete_need_vals = (length T1_need_vals = card)
342 val (my_need_vals, other_need_vals) =
343 T1_need_vals |> List.partition (is_sel_of_constr x)
344 fun atom_seq_for_self_rec j =
345 if is_datatype_nat_like dtype then (1, j + j0 - 1) else (j, j0)
346 fun exact_bound_for_perhaps_needy_atom j =
347 case AList.find (op =) my_need_vals j of
350 val n = sel_no_from_name nick
353 Construct (_, _, _, arg_us) => nth arg_us n
354 | _ => raise Fail "expected \"Construct\""
355 val T2_need_vals = needed_values need_vals T2
357 case AList.lookup (op =) T2_need_vals arg_u of
358 SOME arg_j => SOME (KK.TupleAtomSeq (1, arg_j))
362 fun n_fold_tuple_union [] = KK.TupleSet []
363 | n_fold_tuple_union (ts :: tss) =
364 fold (curry (KK.TupleUnion o swap)) tss ts
365 fun tuple_perhaps_needy_atom upper j =
368 ? (fn ts => tuple_product ts
369 (case exact_bound_for_perhaps_needy_atom j of
371 | NONE => if upper then upper_bound_for_rep R2
372 else KK.TupleSet []))
373 fun bound_tuples upper =
374 if null T1_need_vals then
376 KK.TupleAtomSeq (epsilon - delta, delta + j0)
378 ? (fn ts => tuple_product ts (upper_bound_for_rep R2))
382 (if complete_need_vals then
383 my_need_vals |> map snd
385 index_seq (delta + j0) (epsilon - delta)
386 |> filter_out (member (op = o apsnd snd) other_need_vals))
387 |> map (tuple_perhaps_needy_atom upper)
388 |> n_fold_tuple_union
390 if explicit_max = 0 orelse
391 (complete_need_vals andalso null my_need_vals) then
396 |> not (exclusive orelse all_values_are_needed need_vals dtype)
397 ? cons (KK.TupleSet [])
400 if T1 = T2 andalso epsilon > delta andalso
401 is_datatype_acyclic dtype then
402 index_seq delta (epsilon - delta)
403 |> map (fn j => tuple_product (KK.TupleSet [KK.Tuple [j + j0]])
404 (KK.TupleAtomSeq (atom_seq_for_self_rec j)))
405 |> n_fold_tuple_union
411 | bound_for_sel_rel _ _ _ _ u =
412 raise NUT ("Nitpick_Kodkod.bound_for_sel_rel", [u])
414 fun merge_bounds bs =
416 fun arity (zs, _) = fst (fst (hd zs))
417 fun add_bound ds b [] = List.revAppend (ds, [b])
418 | add_bound ds b (c :: cs) =
419 if arity b = arity c andalso snd b = snd c then
420 List.revAppend (ds, (fst c @ fst b, snd c) :: cs)
422 add_bound (c :: ds) b cs
423 in fold (add_bound []) bs [] end
425 fun unary_var_seq j0 n = map (curry KK.Var 1) (index_seq j0 n)
427 val singleton_from_combination = foldl1 KK.Product o map KK.Atom
428 fun all_singletons_for_rep R =
429 if is_lone_rep R then
430 all_combinations_for_rep R |> map singleton_from_combination
432 raise REP ("Nitpick_Kodkod.all_singletons_for_rep", [R])
434 fun unpack_products (KK.Product (r1, r2)) =
435 unpack_products r1 @ unpack_products r2
436 | unpack_products r = [r]
437 fun unpack_joins (KK.Join (r1, r2)) = unpack_joins r1 @ unpack_joins r2
438 | unpack_joins r = [r]
440 val empty_rel_for_rep = empty_n_ary_rel o arity_of_rep
441 fun full_rel_for_rep R =
442 case atom_schema_of_rep R of
443 [] => raise REP ("Nitpick_Kodkod.full_rel_for_rep", [R])
444 | schema => foldl1 KK.Product (map KK.AtomSeq schema)
446 fun decls_for_atom_schema j0 schema =
447 map2 (fn j => fn x => KK.DeclOne ((1, j), KK.AtomSeq x))
448 (index_seq j0 (length schema)) schema
450 fun d_n_ary_function ({kk_all, kk_join, kk_lone, kk_one, ...} : kodkod_constrs)
452 let val body_R = body_rep R in
453 if is_lone_rep body_R then
455 val binder_schema = atom_schema_of_reps (binder_reps R)
456 val body_schema = atom_schema_of_rep body_R
457 val one = is_one_rep body_R
458 val opt_x = case r of KK.Rel x => SOME x | _ => NONE
460 if opt_x <> NONE andalso length binder_schema = 1 andalso
461 length body_schema = 1 then
462 (if one then KK.Function else KK.Functional)
463 (the opt_x, KK.AtomSeq (hd binder_schema),
464 KK.AtomSeq (hd body_schema))
467 val decls = decls_for_atom_schema ~1 binder_schema
468 val vars = unary_var_seq ~1 (length binder_schema)
469 val kk_xone = if one then kk_one else kk_lone
470 in kk_all decls (kk_xone (fold kk_join vars r)) end
475 fun kk_n_ary_function kk R (r as KK.Rel x) =
476 if not (is_opt_rep R) then
479 else if x = nat_add_rel then
480 formula_for_bool (card_of_rep (body_rep R) = 1)
481 else if x = nat_multiply_rel then
482 formula_for_bool (card_of_rep (body_rep R) <= 2)
484 d_n_ary_function kk R r
485 else if x = nat_subtract_rel then
488 d_n_ary_function kk R r
489 | kk_n_ary_function kk R r = d_n_ary_function kk R r
491 fun kk_disjoint_sets _ [] = KK.True
492 | kk_disjoint_sets (kk as {kk_and, kk_no, kk_intersect, ...} : kodkod_constrs)
494 fold (kk_and o kk_no o kk_intersect r) rs (kk_disjoint_sets kk rs)
496 fun basic_rel_rel_let j ({kk_rel_let, ...} : kodkod_constrs) f r =
497 if inline_rel_expr r then
500 let val x = (KK.arity_of_rel_expr r, j) in
501 kk_rel_let [KK.AssignRelReg (x, r)] (f (KK.RelReg x))
503 val single_rel_rel_let = basic_rel_rel_let 0
504 fun double_rel_rel_let kk f r1 r2 =
505 single_rel_rel_let kk (fn r1 => basic_rel_rel_let 1 kk (f r1) r2) r1
506 fun triple_rel_rel_let kk f r1 r2 r3 =
507 double_rel_rel_let kk
508 (fn r1 => fn r2 => basic_rel_rel_let 2 kk (f r1 r2) r3) r1 r2
510 fun atom_from_formula ({kk_rel_if, ...} : kodkod_constrs) j0 f =
511 kk_rel_if f (KK.Atom (j0 + 1)) (KK.Atom j0)
512 fun rel_expr_from_formula kk R f =
514 Atom (2, j0) => atom_from_formula kk j0 f
515 | _ => raise REP ("Nitpick_Kodkod.rel_expr_from_formula", [R])
517 fun unpack_vect_in_chunks ({kk_project_seq, ...} : kodkod_constrs) chunk_arity
519 List.tabulate (num_chunks, fn j => kk_project_seq r (j * chunk_arity)
523 (kk as {kk_intersect, kk_product, kk_join, kk_project_seq, ...}) one R1
525 case arity_of_rep R1 of
528 let val unpacked_rs1 = unpack_products r1 in
529 if one andalso length unpacked_rs1 = arity1 then
530 fold kk_join unpacked_rs1 r2
531 else if one andalso inline_rel_expr r1 then
532 fold kk_join (unpack_vect_in_chunks kk 1 arity1 r1) r2
535 (kk_intersect (kk_product r1 (full_rel_for_rep res_R)) r2)
536 arity1 (arity_of_rep res_R)
539 fun kk_case_switch (kk as {kk_union, kk_product, ...}) R1 R2 r rs1 rs2 =
541 else kk_n_fold_join kk true R1 R2 r (fold1 kk_union (map2 kk_product rs1 rs2))
543 val lone_rep_fallback_max_card = 4096
546 fun lone_rep_fallback kk new_R old_R r =
547 if old_R = new_R then
550 let val card = card_of_rep old_R in
551 if is_lone_rep old_R andalso is_lone_rep new_R andalso
552 card = card_of_rep new_R then
553 if card >= lone_rep_fallback_max_card then
554 raise TOO_LARGE ("Nitpick_Kodkod.lone_rep_fallback",
555 "too high cardinality (" ^ string_of_int card ^ ")")
557 kk_case_switch kk old_R new_R r (all_singletons_for_rep old_R)
558 (all_singletons_for_rep new_R)
560 raise REP ("Nitpick_Kodkod.lone_rep_fallback", [old_R, new_R])
562 and atom_from_rel_expr kk x old_R r =
566 val dom_card = card_of_rep R1
567 val R2' = case R2 of Atom _ => R2 | _ => Atom (card_of_rep R2, some_j0)
569 atom_from_rel_expr kk x (Vect (dom_card, R2'))
570 (vect_from_rel_expr kk dom_card R2' old_R r)
572 | Opt _ => raise REP ("Nitpick_Kodkod.atom_from_rel_expr", [old_R])
573 | _ => lone_rep_fallback kk (Atom x) old_R r
574 and struct_from_rel_expr kk Rs old_R r =
576 Atom _ => lone_rep_fallback kk (Struct Rs) old_R r
580 else if map card_of_rep Rs' = map card_of_rep Rs then
582 val old_arities = map arity_of_rep Rs'
583 val old_offsets = offset_list old_arities
584 val old_rs = map2 (#kk_project_seq kk r) old_offsets old_arities
586 fold1 (#kk_product kk)
587 (map3 (rel_expr_from_rel_expr kk) Rs Rs' old_rs)
590 lone_rep_fallback kk (Struct Rs) old_R r
591 | _ => raise REP ("Nitpick_Kodkod.struct_from_rel_expr", [old_R])
592 and vect_from_rel_expr kk k R old_R r =
594 Atom _ => lone_rep_fallback kk (Vect (k, R)) old_R r
596 if k = k' andalso R = R' then r
597 else lone_rep_fallback kk (Vect (k, R)) old_R r
598 | Func (R1, Formula Neut) =>
599 if k = card_of_rep R1 then
600 fold1 (#kk_product kk)
602 rel_expr_from_formula kk R (#kk_subset kk arg_r r))
603 (all_singletons_for_rep R1))
605 raise REP ("Nitpick_Kodkod.vect_from_rel_expr", [old_R])
607 fold1 (#kk_product kk)
609 rel_expr_from_rel_expr kk R R2
610 (kk_n_fold_join kk true R1 R2 arg_r r))
611 (all_singletons_for_rep R1))
612 | _ => raise REP ("Nitpick_Kodkod.vect_from_rel_expr", [old_R])
613 and func_from_no_opt_rel_expr kk R1 R2 (Atom x) r =
615 val dom_card = card_of_rep R1
616 val R2' = case R2 of Atom _ => R2 | _ => Atom (card_of_rep R2, some_j0)
618 func_from_no_opt_rel_expr kk R1 R2 (Vect (dom_card, R2'))
619 (vect_from_rel_expr kk dom_card R2' (Atom x) r)
621 | func_from_no_opt_rel_expr kk R1 (Formula Neut) old_R r =
623 Vect (k, Atom (2, j0)) =>
625 val args_rs = all_singletons_for_rep R1
626 val vals_rs = unpack_vect_in_chunks kk 1 k r
627 fun empty_or_singleton_set_for arg_r val_r =
628 #kk_join kk val_r (#kk_product kk (KK.Atom (j0 + 1)) arg_r)
630 fold1 (#kk_union kk) (map2 empty_or_singleton_set_for args_rs vals_rs)
632 | Func (R1', Formula Neut) =>
637 val schema = atom_schema_of_rep R1
638 val r1 = fold1 (#kk_product kk) (unary_var_seq ~1 (length schema))
639 |> rel_expr_from_rel_expr kk R1' R1
640 val kk_xeq = (if is_one_rep R1' then #kk_subset else #kk_rel_eq) kk
642 #kk_comprehension kk (decls_for_atom_schema ~1 schema) (kk_xeq r1 r)
644 | Func (R1', Atom (2, j0)) =>
645 func_from_no_opt_rel_expr kk R1 (Formula Neut)
646 (Func (R1', Formula Neut)) (#kk_join kk r (KK.Atom (j0 + 1)))
647 | _ => raise REP ("Nitpick_Kodkod.func_from_no_opt_rel_expr",
648 [old_R, Func (R1, Formula Neut)]))
649 | func_from_no_opt_rel_expr kk R1 R2 old_R r =
653 val args_rs = all_singletons_for_rep R1
654 val vals_rs = unpack_vect_in_chunks kk (arity_of_rep R) k r
655 |> map (rel_expr_from_rel_expr kk R2 R)
656 in fold1 (#kk_union kk) (map2 (#kk_product kk) args_rs vals_rs) end
657 | Func (R1', Formula Neut) =>
659 Atom (x as (2, j0)) =>
660 let val schema = atom_schema_of_rep R1 in
661 if length schema = 1 then
662 #kk_override kk (#kk_product kk (KK.AtomSeq (hd schema))
664 (#kk_product kk r (KK.Atom (j0 + 1)))
667 val r1 = fold1 (#kk_product kk) (unary_var_seq ~1 (length schema))
668 |> rel_expr_from_rel_expr kk R1' R1
669 val r2 = KK.Var (1, ~(length schema) - 1)
670 val r3 = atom_from_formula kk j0 (#kk_subset kk r1 r)
672 #kk_comprehension kk (decls_for_atom_schema ~1 (schema @ [x]))
673 (#kk_subset kk r2 r3)
676 | _ => raise REP ("Nitpick_Kodkod.func_from_no_opt_rel_expr",
677 [old_R, Func (R1, R2)]))
679 if R1 = R1' andalso R2 = R2' then
683 val dom_schema = atom_schema_of_rep R1
684 val ran_schema = atom_schema_of_rep R2
685 val dom_prod = fold1 (#kk_product kk)
686 (unary_var_seq ~1 (length dom_schema))
687 |> rel_expr_from_rel_expr kk R1' R1
688 val ran_prod = fold1 (#kk_product kk)
689 (unary_var_seq (~(length dom_schema) - 1)
691 |> rel_expr_from_rel_expr kk R2' R2
692 val app = kk_n_fold_join kk true R1' R2' dom_prod r
693 val kk_xeq = (if is_one_rep R2' then #kk_subset else #kk_rel_eq) kk
695 #kk_comprehension kk (decls_for_atom_schema ~1
696 (dom_schema @ ran_schema))
697 (kk_xeq ran_prod app)
699 | _ => raise REP ("Nitpick_Kodkod.func_from_no_opt_rel_expr",
700 [old_R, Func (R1, R2)])
701 and rel_expr_from_rel_expr kk new_R old_R r =
703 val unopt_old_R = unopt_rep old_R
704 val unopt_new_R = unopt_rep new_R
706 if unopt_old_R <> old_R andalso unopt_new_R = new_R then
707 raise REP ("Nitpick_Kodkod.rel_expr_from_rel_expr", [old_R, new_R])
708 else if unopt_new_R = unopt_old_R then
712 Atom x => atom_from_rel_expr kk x
713 | Struct Rs => struct_from_rel_expr kk Rs
714 | Vect (k, R') => vect_from_rel_expr kk k R'
715 | Func (R1, R2) => func_from_no_opt_rel_expr kk R1 R2
716 | _ => raise REP ("Nitpick_Kodkod.rel_expr_from_rel_expr",
720 and rel_expr_to_func kk R1 R2 = rel_expr_from_rel_expr kk (Func (R1, R2))
722 fun bit_set_from_atom ({kk_join, ...} : kodkod_constrs) T r =
723 kk_join r (KK.Rel (if T = @{typ "unsigned_bit word"} then
724 unsigned_bit_word_sel_rel
726 signed_bit_word_sel_rel))
727 val int_expr_from_atom = KK.SetSum ooo bit_set_from_atom
728 fun atom_from_int_expr (kk as {kk_rel_eq, kk_comprehension, ...}
729 : kodkod_constrs) T R i =
730 kk_comprehension (decls_for_atom_schema ~1 (atom_schema_of_rep R))
731 (kk_rel_eq (bit_set_from_atom kk T (KK.Var (1, ~1)))
734 fun kodkod_formula_from_nut ofs
735 (kk as {kk_all, kk_exist, kk_formula_let, kk_formula_if, kk_or, kk_not,
736 kk_iff, kk_implies, kk_and, kk_subset, kk_rel_eq, kk_no,
737 kk_lone, kk_some, kk_rel_let, kk_rel_if, kk_union,
738 kk_difference, kk_intersect, kk_product, kk_join, kk_closure,
739 kk_comprehension, kk_project, kk_project_seq, kk_not3,
740 kk_nat_less, kk_int_less, ...}) u =
742 val main_j0 = offset_of_type ofs bool_T
743 val bool_j0 = main_j0
744 val bool_atom_R = Atom (2, main_j0)
745 val false_atom = KK.Atom bool_j0
746 val true_atom = KK.Atom (bool_j0 + 1)
747 fun formula_from_opt_atom polar j0 r =
749 Neg => kk_not (kk_rel_eq r (KK.Atom j0))
750 | _ => kk_rel_eq r (KK.Atom (j0 + 1))
751 val formula_from_atom = formula_from_opt_atom Pos
752 val unpack_formulas =
753 map (formula_from_atom bool_j0) oo unpack_vect_in_chunks kk 1
754 fun kk_vect_set_bool_op connective k r1 r2 =
755 fold1 kk_and (map2 connective (unpack_formulas k r1)
756 (unpack_formulas k r2))
761 Cst (False, _, _) => KK.False
762 | Cst (True, _, _) => KK.True
763 | Op1 (Not, _, _, u1) =>
764 kk_not (to_f_with_polarity (flip_polarity polar) u1)
765 | Op1 (Finite, _, _, u1) =>
766 let val opt1 = is_opt_rep (rep_of u1) in
769 if opt1 then raise NUT ("Nitpick_Kodkod.to_f (Finite)", [u])
771 | Pos => formula_for_bool (not opt1)
774 | Op1 (IsUnknown, _, _, u1) => kk_no (to_r u1)
775 | Op1 (Cast, _, _, u1) => to_f_with_polarity polar u1
776 | Op2 (All, _, _, u1, u2) =>
777 kk_all (untuple to_decl u1) (to_f_with_polarity polar u2)
778 | Op2 (Exist, _, _, u1, u2) =>
779 kk_exist (untuple to_decl u1) (to_f_with_polarity polar u2)
780 | Op2 (Or, _, _, u1, u2) =>
781 kk_or (to_f_with_polarity polar u1) (to_f_with_polarity polar u2)
782 | Op2 (And, _, _, u1, u2) =>
783 kk_and (to_f_with_polarity polar u1) (to_f_with_polarity polar u2)
784 | Op2 (Less, T, Formula polar, u1, u2) =>
785 formula_from_opt_atom polar bool_j0
786 (to_r (Op2 (Less, T, Opt bool_atom_R, u1, u2)))
787 | Op2 (Subset, _, _, u1, u2) =>
789 val dom_T = pseudo_domain_type (type_of u1)
793 case min_rep R1 R2 of
795 | R => (Atom (card_of_domain_from_rep 2 R,
796 offset_of_type ofs dom_T),
797 if is_opt_rep R then Opt bool_atom_R else Formula Neut)
798 val set_R = Func (dom_R, ran_R)
800 if not (is_opt_rep ran_R) then
801 to_set_bool_op kk_implies kk_subset u1 u2
802 else if polar = Neut then
803 raise NUT ("Nitpick_Kodkod.to_f (Subset)", [u])
806 (* FIXME: merge with similar code below *)
807 fun set_to_r widen u =
809 kk_difference (full_rel_for_rep dom_R)
810 (kk_join (to_rep set_R u) false_atom)
812 kk_join (to_rep set_R u) true_atom
813 val widen1 = (polar = Pos andalso is_opt_rep R1)
814 val widen2 = (polar = Neg andalso is_opt_rep R2)
815 in kk_subset (set_to_r widen1 u1) (set_to_r widen2 u2) end
817 | Op2 (DefEq, _, _, u1, u2) =>
818 (case min_rep (rep_of u1) (rep_of u2) of
820 kk_iff (to_f_with_polarity polar u1) (to_f_with_polarity polar u2)
823 fun args (Op2 (Apply, _, _, u1, u2)) = u2 :: args u1
824 | args (Tuple (_, _, us)) = us
826 val opt_arg_us = filter (is_opt_rep o rep_of) (args u1)
828 if null opt_arg_us orelse not (is_Opt min_R) orelse
830 fold (kk_or o (kk_no o to_r)) opt_arg_us
831 (kk_rel_eq (to_rep min_R u1) (to_rep min_R u2))
833 kk_subset (to_rep min_R u1) (to_rep min_R u2)
835 | Op2 (Eq, _, _, u1, u2) =>
836 (case min_rep (rep_of u1) (rep_of u2) of
838 kk_iff (to_f_with_polarity polar u1) (to_f_with_polarity polar u2)
840 if is_opt_rep min_R then
842 (* continuation of hackish optimization *)
843 kk_rel_eq (to_rep min_R u1) (to_rep min_R u2)
844 else if is_Cst Unrep u1 then
845 to_could_be_unrep (polar = Neg) u2
846 else if is_Cst Unrep u2 then
847 to_could_be_unrep (polar = Neg) u1
850 val r1 = to_rep min_R u1
851 val r2 = to_rep min_R u2
852 val both_opt = forall (is_opt_rep o rep_of) [u1, u2]
857 else if is_lone_rep min_R andalso
858 arity_of_rep min_R = 1 then
859 kk_some (kk_intersect r1 r2)
863 if is_lone_rep min_R then
864 if arity_of_rep min_R = 1 then
865 kk_lone (kk_union r1 r2)
866 else if not both_opt then
867 (r1, r2) |> is_opt_rep (rep_of u2) ? swap
874 formula_from_opt_atom polar bool_j0
875 (to_guard [u1, u2] bool_atom_R
876 (rel_expr_from_formula kk bool_atom_R
881 val r1 = to_rep min_R u1
882 val r2 = to_rep min_R u2
884 if is_one_rep min_R then
886 val rs1 = unpack_products r1
887 val rs2 = unpack_products r2
889 if length rs1 = length rs2 andalso
890 map KK.arity_of_rel_expr rs1
891 = map KK.arity_of_rel_expr rs2 then
892 fold1 kk_and (map2 kk_subset rs1 rs2)
899 | Op2 (Apply, T, _, u1, u2) =>
900 (case (polar, rep_of u1) of
901 (Neg, Func (R, Formula Neut)) => kk_subset (to_opt R u2) (to_r u1)
903 to_f_with_polarity polar
904 (Op2 (Apply, T, Opt (Atom (2, offset_of_type ofs T)), u1, u2)))
905 | Op3 (Let, _, _, u1, u2, u3) =>
906 kk_formula_let [to_expr_assign u1 u2] (to_f_with_polarity polar u3)
907 | Op3 (If, _, _, u1, u2, u3) =>
908 kk_formula_if (to_f u1) (to_f_with_polarity polar u2)
909 (to_f_with_polarity polar u3)
910 | FormulaReg (j, _, _) => KK.FormulaReg j
911 | _ => raise NUT ("Nitpick_Kodkod.to_f", [u]))
912 | Atom (2, j0) => formula_from_atom j0 (to_r u)
913 | _ => raise NUT ("Nitpick_Kodkod.to_f", [u])
914 and to_f_with_polarity polar u =
917 | Atom (2, j0) => formula_from_atom j0 (to_r u)
918 | Opt (Atom (2, j0)) => formula_from_opt_atom polar j0 (to_r u)
919 | _ => raise NUT ("Nitpick_Kodkod.to_f_with_polarity", [u])
922 Cst (False, _, Atom _) => false_atom
923 | Cst (True, _, Atom _) => true_atom
924 | Cst (Iden, _, Func (Struct [R1, R2], Formula Neut)) =>
925 if R1 = R2 andalso arity_of_rep R1 = 1 then
926 kk_intersect KK.Iden (kk_product (full_rel_for_rep R1) KK.Univ)
929 val schema1 = atom_schema_of_rep R1
930 val schema2 = atom_schema_of_rep R2
931 val arity1 = length schema1
932 val arity2 = length schema2
933 val r1 = fold1 kk_product (unary_var_seq 0 arity1)
934 val r2 = fold1 kk_product (unary_var_seq arity1 arity2)
935 val min_R = min_rep R1 R2
938 (decls_for_atom_schema 0 (schema1 @ schema2))
939 (kk_rel_eq (rel_expr_from_rel_expr kk min_R R1 r1)
940 (rel_expr_from_rel_expr kk min_R R2 r2))
942 | Cst (Iden, _, Func (Atom (1, j0), Formula Neut)) => KK.Atom j0
943 | Cst (Iden, T as Type (@{type_name set}, [T1]), R as Func (R1, _)) =>
944 to_rep R (Cst (Iden, T, Func (one_rep ofs T1 R1, Formula Neut)))
945 | Cst (Num j, T, R) =>
946 if is_word_type T then
947 atom_from_int_expr kk T R (KK.Num j)
948 else if T = int_T then
949 case atom_for_int (card_of_rep R, offset_of_type ofs int_T) j of
950 ~1 => if is_opt_rep R then KK.None
951 else raise NUT ("Nitpick_Kodkod.to_r (Num)", [u])
954 if j < card_of_rep R then KK.Atom (j + offset_of_type ofs T)
955 else if is_opt_rep R then KK.None
956 else raise NUT ("Nitpick_Kodkod.to_r (Num)", [u])
957 | Cst (Unknown, _, R) => empty_rel_for_rep R
958 | Cst (Unrep, _, R) => empty_rel_for_rep R
959 | Cst (Suc, T as @{typ "unsigned_bit word => unsigned_bit word"}, R) =>
960 to_bit_word_unary_op T R (curry KK.Add (KK.Num 1))
961 | Cst (Suc, @{typ "nat => nat"}, Func (Atom x, _)) =>
962 kk_intersect (KK.Rel suc_rel) (kk_product KK.Univ (KK.AtomSeq x))
963 | Cst (Suc, _, Func (Atom _, _)) => KK.Rel suc_rel
964 | Cst (Add, Type (_, [@{typ nat}, _]), _) => KK.Rel nat_add_rel
965 | Cst (Add, Type (_, [@{typ int}, _]), _) => KK.Rel int_add_rel
966 | Cst (Add, T as Type (_, [@{typ "unsigned_bit word"}, _]), R) =>
967 to_bit_word_binary_op T R NONE (SOME (curry KK.Add))
968 | Cst (Add, T as Type (_, [@{typ "signed_bit word"}, _]), R) =>
969 to_bit_word_binary_op T R
970 (SOME (fn i1 => fn i2 => fn i3 =>
971 kk_implies (KK.LE (KK.Num 0, KK.BitXor (i1, i2)))
972 (KK.LE (KK.Num 0, KK.BitXor (i2, i3)))))
973 (SOME (curry KK.Add))
974 | Cst (Subtract, Type (_, [@{typ nat}, _]), _) =>
975 KK.Rel nat_subtract_rel
976 | Cst (Subtract, Type (_, [@{typ int}, _]), _) =>
977 KK.Rel int_subtract_rel
978 | Cst (Subtract, T as Type (_, [@{typ "unsigned_bit word"}, _]), R) =>
979 to_bit_word_binary_op T R NONE
980 (SOME (fn i1 => fn i2 =>
981 KK.IntIf (KK.LE (i1, i2), KK.Num 0, KK.Sub (i1, i2))))
982 | Cst (Subtract, T as Type (_, [@{typ "signed_bit word"}, _]), R) =>
983 to_bit_word_binary_op T R
984 (SOME (fn i1 => fn i2 => fn i3 =>
985 kk_implies (KK.LT (KK.BitXor (i1, i2), KK.Num 0))
986 (KK.LT (KK.BitXor (i2, i3), KK.Num 0))))
987 (SOME (curry KK.Sub))
988 | Cst (Multiply, Type (_, [@{typ nat}, _]), _) =>
989 KK.Rel nat_multiply_rel
990 | Cst (Multiply, Type (_, [@{typ int}, _]), _) =>
991 KK.Rel int_multiply_rel
993 T as Type (_, [Type (@{type_name word}, [bit_T]), _]), R) =>
994 to_bit_word_binary_op T R
995 (SOME (fn i1 => fn i2 => fn i3 =>
996 kk_or (KK.IntEq (i2, KK.Num 0))
997 (KK.IntEq (KK.Div (i3, i2), i1)
998 |> bit_T = @{typ signed_bit}
999 ? kk_and (KK.LE (KK.Num 0,
1000 foldl1 KK.BitAnd [i1, i2, i3])))))
1001 (SOME (curry KK.Mult))
1002 | Cst (Divide, Type (_, [@{typ nat}, _]), _) => KK.Rel nat_divide_rel
1003 | Cst (Divide, Type (_, [@{typ int}, _]), _) => KK.Rel int_divide_rel
1004 | Cst (Divide, T as Type (_, [@{typ "unsigned_bit word"}, _]), R) =>
1005 to_bit_word_binary_op T R NONE
1006 (SOME (fn i1 => fn i2 =>
1007 KK.IntIf (KK.IntEq (i2, KK.Num 0),
1008 KK.Num 0, KK.Div (i1, i2))))
1009 | Cst (Divide, T as Type (_, [@{typ "signed_bit word"}, _]), R) =>
1010 to_bit_word_binary_op T R
1011 (SOME (fn i1 => fn i2 => fn i3 =>
1012 KK.LE (KK.Num 0, foldl1 KK.BitAnd [i1, i2, i3])))
1013 (SOME (fn i1 => fn i2 =>
1014 KK.IntIf (kk_and (KK.LT (i1, KK.Num 0))
1015 (KK.LT (KK.Num 0, i2)),
1016 KK.Sub (KK.Div (KK.Add (i1, KK.Num 1), i2), KK.Num 1),
1017 KK.IntIf (kk_and (KK.LT (KK.Num 0, i1))
1018 (KK.LT (i2, KK.Num 0)),
1019 KK.Sub (KK.Div (KK.Sub (i1, KK.Num 1), i2), KK.Num 1),
1020 KK.IntIf (KK.IntEq (i2, KK.Num 0),
1021 KK.Num 0, KK.Div (i1, i2))))))
1022 | Cst (Gcd, _, _) => KK.Rel gcd_rel
1023 | Cst (Lcm, _, _) => KK.Rel lcm_rel
1024 | Cst (Fracs, _, Func (Atom (1, _), _)) => KK.None
1025 | Cst (Fracs, _, Func (Struct _, _)) =>
1026 kk_project_seq (KK.Rel norm_frac_rel) 2 2
1027 | Cst (NormFrac, _, _) => KK.Rel norm_frac_rel
1028 | Cst (NatToInt, Type (_, [@{typ nat}, _]), Func (Atom _, Atom _)) =>
1030 | Cst (NatToInt, Type (_, [@{typ nat}, _]),
1031 Func (Atom (_, nat_j0), Opt (Atom (int_k, int_j0)))) =>
1032 if nat_j0 = int_j0 then
1033 kk_intersect KK.Iden
1034 (kk_product (KK.AtomSeq (max_int_for_card int_k + 1, nat_j0))
1037 raise BAD ("Nitpick_Kodkod.to_r (NatToInt)", "\"nat_j0 <> int_j0\"")
1038 | Cst (NatToInt, T as Type (_, [@{typ "unsigned_bit word"}, _]), R) =>
1039 to_bit_word_unary_op T R I
1040 | Cst (IntToNat, Type (_, [@{typ int}, _]),
1041 Func (Atom (int_k, int_j0), nat_R)) =>
1043 val abs_card = max_int_for_card int_k + 1
1044 val (nat_k, nat_j0) = the_single (atom_schema_of_rep nat_R)
1045 val overlap = Int.min (nat_k, abs_card)
1047 if nat_j0 = int_j0 then
1048 kk_union (kk_product (KK.AtomSeq (int_k - abs_card,
1051 (kk_intersect KK.Iden
1052 (kk_product (KK.AtomSeq (overlap, int_j0)) KK.Univ))
1054 raise BAD ("Nitpick_Kodkod.to_r (IntToNat)", "\"nat_j0 <> int_j0\"")
1056 | Cst (IntToNat, T as Type (_, [@{typ "signed_bit word"}, _]), R) =>
1057 to_bit_word_unary_op T R
1058 (fn i => KK.IntIf (KK.LE (i, KK.Num 0), KK.Num 0, i))
1059 | Op1 (Not, _, R, u1) => kk_not3 (to_rep R u1)
1060 | Op1 (Finite, _, Opt (Atom _), _) => KK.None
1061 | Op1 (Converse, T, R, u1) =>
1063 val (b_T, a_T) = HOLogic.dest_prodT (pseudo_domain_type T)
1066 Func (Struct [R1, R2], _) => (R1, R2)
1068 if card_of_rep R1 <> 1 then
1069 raise REP ("Nitpick_Kodkod.to_r (Converse)", [R])
1071 pairself (Atom o pair 1 o offset_of_type ofs) (b_T, a_T)
1072 | _ => raise REP ("Nitpick_Kodkod.to_r (Converse)", [R])
1073 val body_R = body_rep R
1074 val a_arity = arity_of_rep a_R
1075 val b_arity = arity_of_rep b_R
1076 val ab_arity = a_arity + b_arity
1077 val body_arity = arity_of_rep body_R
1079 kk_project (to_rep (Func (Struct [a_R, b_R], body_R)) u1)
1080 (map KK.Num (index_seq a_arity b_arity @
1081 index_seq 0 a_arity @
1082 index_seq ab_arity body_arity))
1083 |> rel_expr_from_rel_expr kk R (Func (Struct [b_R, a_R], body_R))
1085 | Op1 (Closure, _, R, u1) =>
1086 if is_opt_rep R then
1089 val R' = rep_to_binary_rel_rep ofs T1 (unopt_rep (rep_of u1))
1090 val R'' = opt_rep ofs T1 R'
1092 single_rel_rel_let kk
1095 val true_r = kk_closure (kk_join r true_atom)
1096 val full_r = full_rel_for_rep R'
1097 val false_r = kk_difference full_r
1098 (kk_closure (kk_difference full_r
1099 (kk_join r false_atom)))
1101 rel_expr_from_rel_expr kk R R''
1102 (kk_union (kk_product true_r true_atom)
1103 (kk_product false_r false_atom))
1104 end) (to_rep R'' u1)
1107 let val R' = rep_to_binary_rel_rep ofs (type_of u1) (rep_of u1) in
1108 rel_expr_from_rel_expr kk R R' (kk_closure (to_rep R' u1))
1110 | Op1 (SingletonSet, _, Func (R1, Opt _), Cst (Unrep, _, _)) =>
1111 kk_product (full_rel_for_rep R1) false_atom
1112 | Op1 (SingletonSet, _, R, u1) =>
1114 Func (R1, Formula Neut) => to_rep R1 u1
1115 | Func (R1, Opt _) =>
1116 single_rel_rel_let kk
1117 (fn r => kk_rel_if (kk_no r) (empty_rel_for_rep R)
1118 (rel_expr_to_func kk R1 bool_atom_R
1119 (Func (R1, Formula Neut)) r))
1121 | _ => raise NUT ("Nitpick_Kodkod.to_r (SingletonSet)", [u]))
1122 | Op1 (SafeThe, _, R, u1) =>
1123 if is_opt_rep R then
1124 kk_join (to_rep (Func (unopt_rep R, Opt bool_atom_R)) u1) true_atom
1126 to_rep (Func (R, Formula Neut)) u1
1127 | Op1 (First, _, R, u1) => to_nth_pair_sel 0 R u1
1128 | Op1 (Second, _, R, u1) => to_nth_pair_sel 1 R u1
1129 | Op1 (Cast, _, R, u1) =>
1132 (case unopt_rep R of
1133 Atom (2, j0) => atom_from_formula kk j0 (to_f u1)
1134 | _ => raise SAME ())
1135 | _ => raise SAME ())
1136 handle SAME () => rel_expr_from_rel_expr kk R (rep_of u1) (to_r u1))
1137 | Op2 (All, T, R as Opt _, u1, u2) =>
1138 to_r (Op1 (Not, T, R,
1139 Op2 (Exist, T, R, u1, Op1 (Not, T, rep_of u2, u2))))
1140 | Op2 (Exist, _, Opt _, u1, u2) =>
1141 let val rs1 = untuple to_decl u1 in
1142 if not (is_opt_rep (rep_of u2)) then
1143 kk_rel_if (kk_exist rs1 (to_f u2)) true_atom KK.None
1145 let val r2 = to_r u2 in
1146 kk_union (kk_rel_if (kk_exist rs1 (kk_rel_eq r2 true_atom))
1148 (kk_rel_if (kk_all rs1 (kk_rel_eq r2 false_atom))
1152 | Op2 (Or, _, _, u1, u2) =>
1153 if is_opt_rep (rep_of u1) then kk_rel_if (to_f u2) true_atom (to_r u1)
1154 else kk_rel_if (to_f u1) true_atom (to_r u2)
1155 | Op2 (And, _, _, u1, u2) =>
1156 if is_opt_rep (rep_of u1) then kk_rel_if (to_f u2) (to_r u1) false_atom
1157 else kk_rel_if (to_f u1) (to_r u2) false_atom
1158 | Op2 (Less, _, _, u1, u2) =>
1161 if is_Cst Unrep u1 then to_compare_with_unrep u2 false_atom
1162 else if is_Cst Unrep u2 then to_compare_with_unrep u1 true_atom
1163 else kk_nat_less (to_integer u1) (to_integer u2)
1164 | @{typ int} => kk_int_less (to_integer u1) (to_integer u2)
1167 val R1 = Opt (Atom (card_of_rep (rep_of u1),
1168 offset_of_type ofs (type_of u1)))
1170 double_rel_rel_let kk
1173 (fold kk_and (map_filter (fn (u, r) =>
1174 if is_opt_rep (rep_of u) then SOME (kk_some r)
1175 else NONE) [(u1, r1), (u2, r2)]) KK.True)
1176 (atom_from_formula kk bool_j0 (KK.LT (pairself
1177 (int_expr_from_atom kk (type_of u1)) (r1, r2))))
1179 (to_rep R1 u1) (to_rep R1 u2)
1181 | Op2 (Triad, _, Opt (Atom (2, j0)), u1, u2) =>
1187 atom_from_formula kk j0 f1
1189 kk_union (kk_rel_if f1 true_atom KK.None)
1190 (kk_rel_if f2 KK.None false_atom)
1192 | Op2 (Composition, _, R, u1, u2) =>
1194 val (a_T, b_T) = HOLogic.dest_prodT (pseudo_domain_type (type_of u1))
1195 val (_, c_T) = HOLogic.dest_prodT (pseudo_domain_type (type_of u2))
1196 val ab_k = card_of_domain_from_rep 2 (rep_of u1)
1197 val bc_k = card_of_domain_from_rep 2 (rep_of u2)
1198 val ac_k = card_of_domain_from_rep 2 R
1199 val a_k = exact_root 2 (ac_k * ab_k div bc_k)
1200 val b_k = exact_root 2 (ab_k * bc_k div ac_k)
1201 val c_k = exact_root 2 (bc_k * ac_k div ab_k)
1202 val a_R = Atom (a_k, offset_of_type ofs a_T)
1203 val b_R = Atom (b_k, offset_of_type ofs b_T)
1204 val c_R = Atom (c_k, offset_of_type ofs c_T)
1205 val body_R = body_rep R
1209 kk_join (to_rep (Func (Struct [a_R, b_R], Formula Neut)) u1)
1210 (to_rep (Func (Struct [b_R, c_R], Formula Neut)) u2)
1211 | Opt (Atom (2, _)) =>
1213 (* FIXME: merge with similar code above *)
1215 kk_join (to_rep (Func (Struct [R1, R2], body_R)) u) true_atom
1218 (full_rel_for_rep (Struct [R1, R2]))
1219 (kk_join (to_rep (Func (Struct [R1, R2], body_R)) u)
1223 (kk_product (kk_join (must a_R b_R u1) (must b_R c_R u2))
1225 (kk_product (kk_difference
1226 (full_rel_for_rep (Struct [a_R, c_R]))
1227 (kk_join (may a_R b_R u1) (may b_R c_R u2)))
1230 | _ => raise NUT ("Nitpick_Kodkod.to_r (Composition)", [u]))
1231 |> rel_expr_from_rel_expr kk R (Func (Struct [a_R, c_R], body_R))
1233 | Op2 (Apply, @{typ nat}, _,
1234 Op2 (Apply, _, _, Cst (Subtract, _, _), u1), u2) =>
1235 if is_Cst Unrep u2 andalso not (is_opt_rep (rep_of u1)) then
1236 KK.Atom (offset_of_type ofs nat_T)
1238 fold kk_join (map to_integer [u1, u2]) (KK.Rel nat_subtract_rel)
1239 | Op2 (Apply, _, R, u1, u2) => to_apply R u1 u2
1240 | Op2 (Lambda, _, R as Opt (Atom (1, j0)), u1, u2) =>
1241 to_guard [u1, u2] R (KK.Atom j0)
1242 | Op2 (Lambda, _, Func (_, Formula Neut), u1, u2) =>
1243 kk_comprehension (untuple to_decl u1) (to_f u2)
1244 | Op2 (Lambda, _, Func (_, R2), u1, u2) =>
1246 val dom_decls = untuple to_decl u1
1247 val ran_schema = atom_schema_of_rep R2
1248 val ran_decls = decls_for_atom_schema ~1 ran_schema
1249 val ran_vars = unary_var_seq ~1 (length ran_decls)
1251 kk_comprehension (dom_decls @ ran_decls)
1252 (kk_subset (fold1 kk_product ran_vars)
1255 | Op3 (Let, _, R, u1, u2, u3) =>
1256 kk_rel_let [to_expr_assign u1 u2] (to_rep R u3)
1257 | Op3 (If, _, R, u1, u2, u3) =>
1258 if is_opt_rep (rep_of u1) then
1259 triple_rel_rel_let kk
1260 (fn r1 => fn r2 => fn r3 =>
1261 let val empty_r = empty_rel_for_rep R in
1263 [kk_rel_if (kk_rel_eq r1 true_atom) r2 empty_r,
1264 kk_rel_if (kk_rel_eq r1 false_atom) r3 empty_r,
1265 kk_rel_if (kk_rel_eq r2 r3)
1266 (if inline_rel_expr r2 then r2 else r3) empty_r]
1268 (to_r u1) (to_rep R u2) (to_rep R u3)
1270 kk_rel_if (to_f u1) (to_rep R u2) (to_rep R u3)
1271 | Tuple (_, R, us) =>
1272 (case unopt_rep R of
1273 Struct Rs => to_product Rs us
1274 | Vect (k, R) => to_product (replicate k R) us
1276 kk_rel_if (kk_some (fold1 kk_product (map to_r us)))
1277 (KK.Atom j0) KK.None
1278 | _ => raise NUT ("Nitpick_Kodkod.to_r (Tuple)", [u]))
1279 | Construct ([u'], _, _, []) => to_r u'
1280 | Construct (discr_u :: sel_us, _, _, arg_us) =>
1283 map2 (fn sel_u => fn arg_u =>
1285 val (R1, R2) = dest_Func (rep_of sel_u)
1286 val sel_r = to_r sel_u
1287 val arg_r = to_opt R2 arg_u
1289 if is_one_rep R2 then
1290 kk_n_fold_join kk true R2 R1 arg_r
1291 (kk_project sel_r (flip_nums (arity_of_rep R2)))
1293 kk_comprehension [KK.DeclOne ((1, ~1), to_r discr_u)]
1294 (kk_rel_eq (kk_join (KK.Var (1, ~1)) sel_r) arg_r)
1295 |> is_opt_rep (rep_of arg_u) ? to_guard [arg_u] R1
1297 in fold1 kk_intersect set_rs end
1298 | BoundRel (x, _, _, _) => KK.Var x
1299 | FreeRel (x, _, _, _) => KK.Rel x
1300 | RelReg (j, _, R) => KK.RelReg (arity_of_rep R, j)
1301 | u => raise NUT ("Nitpick_Kodkod.to_r", [u])
1302 and to_decl (BoundRel (x, _, R, _)) =
1303 KK.DeclOne (x, KK.AtomSeq (the_single (atom_schema_of_rep R)))
1304 | to_decl u = raise NUT ("Nitpick_Kodkod.to_decl", [u])
1305 and to_expr_assign (FormulaReg (j, _, _)) u =
1306 KK.AssignFormulaReg (j, to_f u)
1307 | to_expr_assign (RelReg (j, _, R)) u =
1308 KK.AssignRelReg ((arity_of_rep R, j), to_r u)
1309 | to_expr_assign u1 _ = raise NUT ("Nitpick_Kodkod.to_expr_assign", [u1])
1310 and to_atom (x as (_, j0)) u =
1312 Formula _ => atom_from_formula kk j0 (to_f u)
1313 | R => atom_from_rel_expr kk x R (to_r u)
1314 and to_struct Rs u = struct_from_rel_expr kk Rs (rep_of u) (to_r u)
1315 and to_vect k R u = vect_from_rel_expr kk k R (rep_of u) (to_r u)
1316 and to_func R1 R2 u = rel_expr_to_func kk R1 R2 (rep_of u) (to_r u)
1318 let val old_R = rep_of u in
1319 if is_opt_rep old_R then
1320 rel_expr_from_rel_expr kk (Opt R) old_R (to_r u)
1324 and to_rep (Atom x) u = to_atom x u
1325 | to_rep (Struct Rs) u = to_struct Rs u
1326 | to_rep (Vect (k, R)) u = to_vect k R u
1327 | to_rep (Func (R1, R2)) u = to_func R1 R2 u
1328 | to_rep (Opt R) u = to_opt R u
1329 | to_rep R _ = raise REP ("Nitpick_Kodkod.to_rep", [R])
1330 and to_integer u = to_opt (one_rep ofs (type_of u) (rep_of u)) u
1331 and to_guard guard_us R r =
1333 val unpacked_rs = unpack_joins r
1334 val plain_guard_rs =
1335 map to_r (filter (is_Opt o rep_of) guard_us)
1336 |> filter_out (member (op =) unpacked_rs)
1338 filter ((is_Func andf is_opt_rep) o rep_of) guard_us
1339 val func_guard_rs = map to_r func_guard_us
1341 map kk_no plain_guard_rs @
1342 map2 (kk_not oo kk_n_ary_function kk)
1343 (map (unopt_rep o rep_of) func_guard_us) func_guard_rs
1345 if null guard_fs then r
1346 else kk_rel_if (fold1 kk_or guard_fs) (empty_rel_for_rep R) r
1348 and to_project new_R old_R r j0 =
1349 rel_expr_from_rel_expr kk new_R old_R
1350 (kk_project_seq r j0 (arity_of_rep old_R))
1351 and to_product Rs us = fold1 kk_product (map (uncurry to_opt) (Rs ~~ us))
1352 and to_nth_pair_sel n res_R u =
1354 Tuple (_, _, us) => to_rep res_R (nth us n)
1357 val (a_T, b_T) = HOLogic.dest_prodT (type_of u)
1360 Struct (Rs as [_, _]) => Rs
1363 val res_card = card_of_rep res_R
1364 val other_card = card_of_rep R div res_card
1365 val (a_card, b_card) = (res_card, other_card)
1368 [Atom (a_card, offset_of_type ofs a_T),
1369 Atom (b_card, offset_of_type ofs b_T)]
1371 val nth_R = nth Rs n
1372 val j0 = if n = 0 then 0 else arity_of_rep (hd Rs)
1373 in to_project res_R nth_R (to_rep (Opt (Struct Rs)) u) j0 end
1374 and to_set_bool_op connective set_oper u1 u2 =
1376 val min_R = min_rep (rep_of u1) (rep_of u2)
1377 val r1 = to_rep min_R u1
1378 val r2 = to_rep min_R u2
1381 Vect (k, Atom _) => kk_vect_set_bool_op connective k r1 r2
1383 (case body_rep R' of
1384 Formula Neut => set_oper r1 r2
1385 | Atom _ => set_oper (kk_join r1 true_atom) (kk_join r2 true_atom)
1386 | _ => raise REP ("Nitpick_Kodkod.to_set_bool_op", [min_R]))
1387 | _ => raise REP ("Nitpick_Kodkod.to_set_bool_op", [min_R])
1389 and to_bit_word_unary_op T R oper =
1391 val Ts = strip_type T ||> single |> op @
1392 fun int_arg j = int_expr_from_atom kk (nth Ts j) (KK.Var (1, j))
1394 kk_comprehension (decls_for_atom_schema 0 (atom_schema_of_rep R))
1396 (map (fn j => KK.AssignIntReg (j, int_arg j)) (0 upto 1),
1397 KK.IntEq (KK.IntReg 1, oper (KK.IntReg 0))))
1399 and to_bit_word_binary_op T R opt_guard opt_oper =
1401 val Ts = strip_type T ||> single |> op @
1402 fun int_arg j = int_expr_from_atom kk (nth Ts j) (KK.Var (1, j))
1404 kk_comprehension (decls_for_atom_schema 0 (atom_schema_of_rep R))
1406 (map (fn j => KK.AssignIntReg (j, int_arg j)) (0 upto 2),
1411 [guard (KK.IntReg 0) (KK.IntReg 1) (KK.IntReg 2)]) @
1415 [KK.IntEq (KK.IntReg 2,
1416 oper (KK.IntReg 0) (KK.IntReg 1))]))))
1418 and to_apply (R as Formula _) _ _ =
1419 raise REP ("Nitpick_Kodkod.to_apply", [R])
1420 | to_apply res_R func_u arg_u =
1421 case unopt_rep (rep_of func_u) of
1423 to_guard [arg_u] res_R
1424 (rel_expr_from_rel_expr kk res_R (Atom (1, j0)) (to_r func_u))
1427 val dom_card = card_of_rep (rep_of arg_u)
1429 Atom (exact_root dom_card k,
1430 offset_of_type ofs (pseudo_range_type (type_of func_u)))
1432 to_apply_vect dom_card ran_R res_R (to_vect dom_card ran_R func_u)
1436 to_guard [arg_u] res_R
1437 (rel_expr_from_rel_expr kk res_R R' (to_r func_u))
1438 | Vect (k, R') => to_apply_vect k R' res_R (to_r func_u) arg_u
1439 | Func (R, Formula Neut) =>
1440 to_guard [arg_u] res_R (rel_expr_from_formula kk res_R
1441 (kk_subset (to_opt R arg_u) (to_r func_u)))
1443 rel_expr_from_rel_expr kk res_R R2
1444 (kk_n_fold_join kk true R1 R2 (to_opt R1 arg_u) (to_r func_u))
1445 |> body_rep R2 = Formula Neut ? to_guard [arg_u] res_R
1446 | _ => raise NUT ("Nitpick_Kodkod.to_apply", [func_u])
1447 and to_apply_vect k R' res_R func_r arg_u =
1449 val arg_R = one_rep ofs (type_of arg_u) (unopt_rep (rep_of arg_u))
1450 val vect_r = vect_from_rel_expr kk k res_R (Vect (k, R')) func_r
1451 val vect_rs = unpack_vect_in_chunks kk (arity_of_rep res_R) k vect_r
1453 kk_case_switch kk arg_R res_R (to_opt arg_R arg_u)
1454 (all_singletons_for_rep arg_R) vect_rs
1456 and to_could_be_unrep neg u =
1457 if neg andalso is_opt_rep (rep_of u) then kk_no (to_r u) else KK.False
1458 and to_compare_with_unrep u r =
1459 if is_opt_rep (rep_of u) then
1460 kk_rel_if (kk_some (to_r u)) r (empty_rel_for_rep (rep_of u))
1463 in to_f_with_polarity Pos u end
1465 fun declarative_axiom_for_plain_rel kk (FreeRel (x, _, R as Func _, nick)) =
1466 kk_n_ary_function kk (R |> nick = @{const_name List.set} ? unopt_rep)
1468 | declarative_axiom_for_plain_rel ({kk_lone, kk_one, ...} : kodkod_constrs)
1469 (FreeRel (x, _, R, _)) =
1470 if is_one_rep R then kk_one (KK.Rel x)
1471 else if is_lone_rep R andalso card_of_rep R > 1 then kk_lone (KK.Rel x)
1473 | declarative_axiom_for_plain_rel _ u =
1474 raise NUT ("Nitpick_Kodkod.declarative_axiom_for_plain_rel", [u])
1476 fun const_triple rel_table (x as (s, T)) =
1477 case the_name rel_table (ConstName (s, T, Any)) of
1478 FreeRel ((n, j), _, R, _) => (KK.Rel (n, j), R, n)
1479 | _ => raise TERM ("Nitpick_Kodkod.const_triple", [Const x])
1481 fun discr_rel_expr rel_table = #1 o const_triple rel_table o discr_for_constr
1483 fun nfa_transitions_for_sel hol_ctxt binarize
1484 ({kk_project, ...} : kodkod_constrs) rel_table
1485 (dtypes : datatype_spec list) constr_x n =
1488 binarized_and_boxed_nth_sel_for_constr hol_ctxt binarize constr_x n
1489 val (r, R, arity) = const_triple rel_table x
1490 val type_schema = type_schema_of_rep T R
1492 map_filter (fn (j, T) =>
1493 if forall (not_equal T o #typ) dtypes then NONE
1494 else SOME ((x, kk_project r (map KK.Num [0, j])), T))
1495 (index_seq 1 (arity - 1) ~~ tl type_schema)
1497 fun nfa_transitions_for_constr hol_ctxt binarize kk rel_table dtypes
1499 maps (nfa_transitions_for_sel hol_ctxt binarize kk rel_table dtypes x)
1500 (index_seq 0 (num_sels_for_constr_type T))
1501 fun nfa_entry_for_datatype _ _ _ _ _ ({co = true, ...} : datatype_spec) = NONE
1502 | nfa_entry_for_datatype _ _ _ _ _ {standard = false, ...} = NONE
1503 | nfa_entry_for_datatype _ _ _ _ _ {deep = false, ...} = NONE
1504 | nfa_entry_for_datatype hol_ctxt binarize kk rel_table dtypes
1505 {typ, constrs, ...} =
1506 SOME (typ, maps (nfa_transitions_for_constr hol_ctxt binarize kk rel_table
1507 dtypes o #const) constrs)
1509 val empty_rel = KK.Product (KK.None, KK.None)
1511 fun direct_path_rel_exprs nfa start_T final_T =
1512 case AList.lookup (op =) nfa final_T of
1513 SOME trans => map (snd o fst) (filter (curry (op =) start_T o snd) trans)
1515 and any_path_rel_expr ({kk_union, ...} : kodkod_constrs) nfa [] start_T
1517 fold kk_union (direct_path_rel_exprs nfa start_T final_T)
1518 (if start_T = final_T then KK.Iden else empty_rel)
1519 | any_path_rel_expr (kk as {kk_union, ...}) nfa (T :: Ts) start_T final_T =
1520 kk_union (any_path_rel_expr kk nfa Ts start_T final_T)
1521 (knot_path_rel_expr kk nfa Ts start_T T final_T)
1522 and knot_path_rel_expr (kk as {kk_join, kk_reflexive_closure, ...}) nfa Ts
1523 start_T knot_T final_T =
1524 kk_join (kk_join (any_path_rel_expr kk nfa Ts knot_T final_T)
1525 (kk_reflexive_closure (loop_path_rel_expr kk nfa Ts knot_T)))
1526 (any_path_rel_expr kk nfa Ts start_T knot_T)
1527 and loop_path_rel_expr ({kk_union, ...} : kodkod_constrs) nfa [] start_T =
1528 fold kk_union (direct_path_rel_exprs nfa start_T start_T) empty_rel
1529 | loop_path_rel_expr (kk as {kk_union, kk_closure, ...}) nfa (T :: Ts)
1532 kk_closure (loop_path_rel_expr kk nfa Ts start_T)
1534 kk_union (loop_path_rel_expr kk nfa Ts start_T)
1535 (knot_path_rel_expr kk nfa Ts start_T T start_T)
1537 fun add_nfa_to_graph [] = I
1538 | add_nfa_to_graph ((_, []) :: nfa) = add_nfa_to_graph nfa
1539 | add_nfa_to_graph ((T, ((_, T') :: transitions)) :: nfa) =
1540 add_nfa_to_graph ((T, transitions) :: nfa) o Typ_Graph.add_edge (T, T') o
1541 Typ_Graph.default_node (T', ()) o Typ_Graph.default_node (T, ())
1543 fun strongly_connected_sub_nfas nfa =
1544 add_nfa_to_graph nfa Typ_Graph.empty
1545 |> Typ_Graph.strong_conn
1546 |> map (fn keys => filter (member (op =) keys o fst) nfa)
1548 fun acyclicity_axiom_for_datatype (kk as {kk_no, kk_intersect, ...}) nfa
1551 (loop_path_rel_expr kk nfa (pull start_T (map fst nfa)) start_T)
1553 (* Cycle breaking in the bounds takes care of singly recursive datatypes, hence
1554 the first equation. *)
1555 fun acyclicity_axioms_for_datatypes _ [_] = []
1556 | acyclicity_axioms_for_datatypes kk nfas =
1557 maps (fn nfa => map (acyclicity_axiom_for_datatype kk nfa o fst) nfa) nfas
1559 fun atom_equation_for_nut ofs kk (u, j) =
1560 let val dummy_u = RelReg (0, type_of u, rep_of u) in
1561 case Op2 (DefEq, bool_T, Formula Pos, dummy_u, u)
1562 |> kodkod_formula_from_nut ofs kk of
1563 KK.RelEq (KK.RelReg _, r) => SOME (KK.RelEq (KK.Atom j, r))
1564 | _ => raise BAD ("Nitpick_Kodkod.atom_equation_for_nut",
1565 "malformed Kodkod formula")
1568 fun needed_values_for_datatype [] _ _ = SOME []
1569 | needed_values_for_datatype need_us ofs
1570 ({typ, card, constrs, ...} : datatype_spec) =
1572 fun aux (u as Construct (FreeRel (_, _, _, s) :: _, T, _, us)) =
1575 | accum as SOME (loose, fixed) =>
1577 case AList.lookup (op =) fixed u of
1581 val constr_s = constr_name_for_sel_like s
1582 val {delta, epsilon, ...} =
1584 |> List.find (fn {const, ...} => fst const = constr_s)
1586 val j0 = offset_of_type ofs T
1588 case find_first (fn j => j >= delta andalso
1589 j < delta + epsilon) loose of
1591 SOME (remove (op =) j loose, (u, j0 + j) :: fixed)
1598 SOME (index_seq 0 card, []) |> fold aux need_us |> Option.map (rev o snd)
1601 fun needed_value_axioms_for_datatype _ _ _ (_, NONE) = [KK.False]
1602 | needed_value_axioms_for_datatype ofs kk dtypes (T, SOME fixed) =
1603 if is_datatype_nat_like (the (datatype_spec dtypes T)) then []
1604 else fixed |> map_filter (atom_equation_for_nut ofs kk)
1606 fun all_ge ({kk_join, kk_reflexive_closure, ...} : kodkod_constrs) z r =
1607 kk_join r (kk_reflexive_closure (KK.Rel (suc_rel_for_atom_seq z)))
1608 fun gt ({kk_subset, kk_join, kk_closure, ...} : kodkod_constrs) z r1 r2 =
1609 kk_subset r1 (kk_join r2 (kk_closure (KK.Rel (suc_rel_for_atom_seq z))))
1611 fun constr_quadruple ({const = (s, T), delta, epsilon, ...} : constr_spec) =
1612 (delta, (epsilon, (num_binder_types T, s)))
1614 prod_ord int_ord (prod_ord int_ord (prod_ord int_ord string_ord))
1615 o pairself constr_quadruple
1617 fun datatype_ord (({card = card1, self_rec = self_rec1, constrs = constr1, ...},
1618 {card = card2, self_rec = self_rec2, constrs = constr2, ...})
1619 : datatype_spec * datatype_spec) =
1620 prod_ord int_ord (prod_ord bool_ord int_ord)
1621 ((card1, (self_rec1, length constr1)),
1622 (card2, (self_rec2, length constr2)))
1624 (* We must absolutely tabulate "suc" for all datatypes whose selector bounds
1625 break cycles; otherwise, we may end up with two incompatible symmetry
1626 breaking orders, leading to spurious models. *)
1627 fun should_tabulate_suc_for_type dtypes T =
1628 is_asymmetric_nondatatype T orelse
1629 case datatype_spec dtypes T of
1630 SOME {self_rec, ...} => self_rec
1633 fun lex_order_rel_expr (kk as {kk_implies, kk_and, kk_subset, kk_join, ...})
1634 dtypes sel_quadruples =
1635 case sel_quadruples of
1637 | ((r, Func (Atom _, Atom x), 2), (_, Type (_, [_, T]))) :: sel_quadruples' =>
1638 let val z = (x, should_tabulate_suc_for_type dtypes T) in
1639 if null sel_quadruples' then
1640 gt kk z (kk_join (KK.Var (1, 1)) r) (kk_join (KK.Var (1, 0)) r)
1642 kk_and (kk_subset (kk_join (KK.Var (1, 1)) r)
1643 (all_ge kk z (kk_join (KK.Var (1, 0)) r)))
1644 (kk_implies (kk_subset (kk_join (KK.Var (1, 1)) r)
1645 (kk_join (KK.Var (1, 0)) r))
1646 (lex_order_rel_expr kk dtypes sel_quadruples'))
1648 (* Skip constructors components that aren't atoms, since we cannot compare
1650 | _ :: sel_quadruples' => lex_order_rel_expr kk dtypes sel_quadruples'
1652 fun is_nil_like_constr_type dtypes T =
1653 case datatype_spec dtypes T of
1654 SOME {constrs, ...} =>
1655 (case filter_out (is_self_recursive_constr_type o snd o #const) constrs of
1656 [{const = (_, T'), ...}] => T = T'
1660 fun sym_break_axioms_for_constr_pair hol_ctxt binarize
1661 (kk as {kk_all, kk_or, kk_implies, kk_and, kk_some, kk_intersect,
1662 kk_join, ...}) rel_table nfas dtypes
1664 ({const = const1 as (_, T1), delta = delta1, epsilon = epsilon1, ...},
1665 {const = const2 as (_, _), delta = delta2, epsilon = epsilon2, ...})
1666 : constr_spec * constr_spec) =
1668 val dataT = body_type T1
1669 val nfa = nfas |> find_first (exists (curry (op =) dataT o fst)) |> these
1670 val rec_Ts = nfa |> map fst
1671 fun rec_and_nonrec_sels (x as (_, T)) =
1672 index_seq 0 (num_sels_for_constr_type T)
1673 |> map (binarized_and_boxed_nth_sel_for_constr hol_ctxt binarize x)
1674 |> List.partition (member (op =) rec_Ts o range_type o snd)
1675 val sel_xs1 = rec_and_nonrec_sels const1 |> op @
1677 if constr_ord = EQUAL andalso null sel_xs1 then
1682 (case #2 (const_triple rel_table (discr_for_constr const1)) of
1683 Func (Atom x, Formula _) => x
1684 | R => raise REP ("Nitpick_Kodkod.sym_break_axioms_for_constr_pair",
1685 [R]), should_tabulate_suc_for_type dtypes dataT)
1686 val (rec_sel_xs2, nonrec_sel_xs2) = rec_and_nonrec_sels const2
1687 val sel_xs2 = rec_sel_xs2 @ nonrec_sel_xs2
1688 fun sel_quadruples2 () = sel_xs2 |> map (`(const_triple rel_table))
1689 (* If the two constructors are the same, we drop the first selector
1690 because that one is always checked by the lexicographic order.
1691 We sometimes also filter out direct subterms, because those are
1692 already handled by the acyclicity breaking in the bound
1694 fun filter_out_sels no_direct sel_xs =
1697 (constr_ord = EQUAL andalso x = hd sel_xs) orelse
1699 (no_direct orelse not (member (op =) sel_xs x)))))
1700 fun subterms_r no_direct sel_xs j =
1701 loop_path_rel_expr kk (map (filter_out_sels no_direct sel_xs) nfa)
1702 (filter_out (curry (op =) dataT) (map fst nfa)) dataT
1703 |> kk_join (KK.Var (1, j))
1705 [kk_all [KK.DeclOne ((1, 0), discr_rel_expr rel_table const1),
1706 KK.DeclOne ((1, 1), discr_rel_expr rel_table const2)]
1708 (if delta2 >= epsilon1 then KK.True
1709 else if delta1 >= epsilon2 - 1 then KK.False
1710 else gt kk z (KK.Var (1, 1)) (KK.Var (1, 0)))
1712 (if is_nil_like_constr_type dtypes T1 then
1715 kk_some (kk_intersect (subterms_r false sel_xs2 1)
1716 (all_ge kk z (KK.Var (1, 0)))))
1720 (lex_order_rel_expr kk dtypes (sel_quadruples2 ()))
1721 (kk_all [KK.DeclOne ((1, 2),
1722 subterms_r true sel_xs1 0)]
1723 (gt kk z (KK.Var (1, 1)) (KK.Var (1, 2))))
1725 kk_all [KK.DeclOne ((1, 2),
1726 subterms_r false sel_xs1 0)]
1727 (gt kk z (KK.Var (1, 1)) (KK.Var (1, 2)))
1728 | GREATER => KK.False)))]
1732 fun sym_break_axioms_for_datatype hol_ctxt binarize kk rel_table nfas dtypes
1733 ({constrs, ...} : datatype_spec) =
1735 val constrs = sort constr_ord constrs
1736 val constr_pairs = all_distinct_unordered_pairs_of constrs
1738 map (pair EQUAL) (constrs ~~ constrs) @
1739 map (pair LESS) constr_pairs @
1740 map (pair GREATER) (map swap constr_pairs)
1741 |> maps (sym_break_axioms_for_constr_pair hol_ctxt binarize kk rel_table
1745 fun is_datatype_in_needed_value T (Construct (_, T', _, us)) =
1746 T = T' orelse exists (is_datatype_in_needed_value T) us
1747 | is_datatype_in_needed_value _ _ = false
1749 val min_sym_break_card = 7
1751 fun sym_break_axioms_for_datatypes hol_ctxt binarize need_us datatype_sym_break
1752 kk rel_table nfas dtypes =
1753 if datatype_sym_break = 0 then
1756 dtypes |> filter is_datatype_acyclic
1757 |> filter (fn {constrs = [_], ...} => false
1758 | {card, constrs, ...} =>
1759 card >= min_sym_break_card andalso
1760 forall (forall (not o is_higher_order_type)
1761 o binder_types o snd o #const) constrs)
1764 exists (is_datatype_in_needed_value typ) need_us)
1766 dtypes' |> length dtypes' > datatype_sym_break
1767 ? (sort (datatype_ord o swap)
1768 #> take datatype_sym_break))
1769 |> maps (sym_break_axioms_for_datatype hol_ctxt binarize kk rel_table
1772 fun sel_axioms_for_sel hol_ctxt binarize j0
1773 (kk as {kk_all, kk_formula_if, kk_subset, kk_no, kk_join, ...})
1774 need_vals rel_table dom_r (dtype as {typ, ...})
1775 ({const, delta, epsilon, exclusive, ...} : constr_spec) n =
1777 val x = binarized_and_boxed_nth_sel_for_constr hol_ctxt binarize const n
1778 val (r, R, _) = const_triple rel_table x
1782 | _ => raise BAD ("Nitpick_Kodkod.sel_axioms_for_sel", "non-Rel")
1783 val R2 = dest_Func R |> snd
1784 val z = (epsilon - delta, delta + j0)
1787 [kk_n_ary_function kk (Func (Atom z, R2)) r]
1788 else if all_values_are_needed need_vals dtype then
1789 typ |> needed_values need_vals
1790 |> filter (is_sel_of_constr rel_x)
1791 |> map (fn (_, j) => kk_n_ary_function kk R2 (kk_join (KK.Atom j) r))
1793 let val r' = kk_join (KK.Var (1, 0)) r in
1794 [kk_all [KK.DeclOne ((1, 0), KK.AtomSeq z)]
1795 (kk_formula_if (kk_subset (KK.Var (1, 0)) dom_r)
1796 (kk_n_ary_function kk R2 r') (kk_no r'))]
1799 fun sel_axioms_for_constr hol_ctxt binarize bits j0 kk need_vals rel_table
1800 dtype (constr as {const, delta, epsilon, explicit_max, ...}) =
1802 val honors_explicit_max =
1803 explicit_max < 0 orelse epsilon - delta <= explicit_max
1805 if explicit_max = 0 then
1806 [formula_for_bool honors_explicit_max]
1809 val dom_r = discr_rel_expr rel_table const
1811 if honors_explicit_max then
1813 else if bits = 0 orelse
1814 is_twos_complement_representable bits (epsilon - delta) then
1815 KK.LE (KK.Cardinality dom_r, KK.Num explicit_max)
1817 raise TOO_SMALL ("Nitpick_Kodkod.sel_axioms_for_constr",
1818 "\"bits\" value " ^ string_of_int bits ^
1819 " too small for \"max\"")
1822 maps (sel_axioms_for_sel hol_ctxt binarize j0 kk need_vals rel_table
1824 (index_seq 0 (num_sels_for_constr_type (snd const)))
1827 fun sel_axioms_for_datatype hol_ctxt binarize bits j0 kk rel_table need_vals
1828 (dtype as {constrs, ...}) =
1829 maps (sel_axioms_for_constr hol_ctxt binarize bits j0 kk rel_table need_vals
1832 fun uniqueness_axioms_for_constr hol_ctxt binarize
1833 ({kk_all, kk_implies, kk_and, kk_rel_eq, kk_lone, kk_join, ...}
1834 : kodkod_constrs) need_vals rel_table dtype
1835 ({const, ...} : constr_spec) =
1837 fun conjunct_for_sel r =
1838 kk_rel_eq (kk_join (KK.Var (1, 0)) r) (kk_join (KK.Var (1, 1)) r)
1839 val num_sels = num_sels_for_constr_type (snd const)
1841 map (const_triple rel_table
1842 o binarized_and_boxed_nth_sel_for_constr hol_ctxt binarize const)
1843 (~1 upto num_sels - 1)
1844 val set_r = triples |> hd |> #1
1846 if num_sels = 0 then
1848 else if all_values_are_needed need_vals dtype then
1851 [kk_all (map (KK.DeclOne o rpair set_r o pair 1) [0, 1])
1853 (fold1 kk_and (map (conjunct_for_sel o #1) (tl triples)))
1854 (kk_rel_eq (KK.Var (1, 0)) (KK.Var (1, 1))))]
1856 fun uniqueness_axioms_for_datatype hol_ctxt binarize kk need_vals rel_table
1857 (dtype as {constrs, ...}) =
1858 maps (uniqueness_axioms_for_constr hol_ctxt binarize kk need_vals rel_table
1861 fun effective_constr_max ({delta, epsilon, ...} : constr_spec) = epsilon - delta
1862 fun partition_axioms_for_datatype j0 (kk as {kk_rel_eq, kk_union, ...})
1863 need_vals rel_table (dtype as {card, constrs, ...}) =
1864 if forall #exclusive constrs then
1865 [Integer.sum (map effective_constr_max constrs) = card |> formula_for_bool]
1866 else if all_values_are_needed need_vals dtype then
1869 let val rs = map (discr_rel_expr rel_table o #const) constrs in
1870 [kk_rel_eq (fold1 kk_union rs) (KK.AtomSeq (card, j0)),
1871 kk_disjoint_sets kk rs]
1874 fun other_axioms_for_datatype _ _ _ _ _ _ _ {deep = false, ...} = []
1875 | other_axioms_for_datatype hol_ctxt binarize need_vals bits ofs kk rel_table
1876 (dtype as {typ, ...}) =
1877 let val j0 = offset_of_type ofs typ in
1878 sel_axioms_for_datatype hol_ctxt binarize bits j0 kk need_vals rel_table
1880 uniqueness_axioms_for_datatype hol_ctxt binarize kk need_vals rel_table
1882 partition_axioms_for_datatype j0 kk need_vals rel_table dtype
1885 fun declarative_axioms_for_datatypes hol_ctxt binarize need_us need_vals
1886 datatype_sym_break bits ofs kk rel_table dtypes =
1889 dtypes |> map_filter (nfa_entry_for_datatype hol_ctxt binarize kk
1891 |> strongly_connected_sub_nfas
1893 acyclicity_axioms_for_datatypes kk nfas @
1894 maps (needed_value_axioms_for_datatype ofs kk dtypes) need_vals @
1895 sym_break_axioms_for_datatypes hol_ctxt binarize need_us datatype_sym_break
1896 kk rel_table nfas dtypes @
1897 maps (other_axioms_for_datatype hol_ctxt binarize need_vals bits ofs kk