| author | wenzelm | 
| Mon, 02 Nov 2009 21:03:41 +0100 | |
| changeset 33390 | 5b499f36dd25 | 
| parent 33232 | f93390060bbe | 
| child 33705 | 947184dc75c9 | 
| permissions | -rw-r--r-- | 
| 33192 | 1 | (* Title: HOL/Nitpick/Tools/nitpick_util.ML | 
| 2 | Author: Jasmin Blanchette, TU Muenchen | |
| 3 | Copyright 2008, 2009 | |
| 4 | ||
| 5 | General-purpose functions used by the Nitpick modules. | |
| 6 | *) | |
| 7 | ||
| 8 | infix 6 nat_minus | |
| 9 | infix 7 pairf | |
| 10 | ||
| 11 | signature BASIC_NITPICK_UTIL = | |
| 12 | sig | |
| 13 | type styp = string * typ | |
| 14 | end; | |
| 15 | ||
| 16 | signature NITPICK_UTIL = | |
| 17 | sig | |
| 18 | include BASIC_NITPICK_UTIL | |
| 19 | ||
| 20 | datatype polarity = Pos | Neg | Neut | |
| 21 | ||
| 22 | exception ARG of string * string | |
| 23 | exception BAD of string * string | |
| 24 | exception LIMIT of string * string | |
| 25 | exception NOT_SUPPORTED of string | |
| 26 | exception SAME of unit | |
| 27 | ||
| 28 | val nitpick_prefix : string | |
| 29 |   val curry3 : ('a * 'b * 'c -> 'd) -> 'a -> 'b -> 'c -> 'd
 | |
| 30 |   val pairf : ('a -> 'b) * ('a -> 'c) -> 'a -> 'b * 'c
 | |
| 31 | val int_for_bool : bool -> int | |
| 32 | val nat_minus : int * int -> int | |
| 33 | val reasonable_power : int -> int -> int | |
| 34 | val exact_log : int -> int -> int | |
| 35 | val exact_root : int -> int -> int | |
| 36 | val offset_list : int list -> int list | |
| 37 | val index_seq : int -> int -> int list | |
| 38 | val filter_indices : int list -> 'a list -> 'a list | |
| 39 | val filter_out_indices : int list -> 'a list -> 'a list | |
| 40 |   val fold1 : ('a -> 'a -> 'a) -> 'a list -> 'a
 | |
| 41 | val replicate_list : int -> 'a list -> 'a list | |
| 42 | val n_fold_cartesian_product : 'a list list -> 'a list list | |
| 43 |   val all_distinct_unordered_pairs_of : ''a list -> (''a * ''a) list
 | |
| 44 | val nth_combination : (int * int) list -> int -> int list | |
| 45 | val all_combinations : (int * int) list -> int list list | |
| 46 | val all_permutations : 'a list -> 'a list list | |
| 47 | val batch_list : int -> 'a list -> 'a list list | |
| 48 | val chunk_list_unevenly : int list -> 'a list -> 'a list list | |
| 49 |   val map3 : ('a -> 'b -> 'c -> 'd) -> 'a list -> 'b list -> 'c list -> 'd list
 | |
| 50 | val double_lookup : | |
| 51 |     ('a * 'a -> bool) -> ('a option * 'b) list -> 'a -> 'b option
 | |
| 52 | val triple_lookup : | |
| 53 |     (''a * ''a -> bool) -> (''a option * 'b) list -> ''a -> 'b option
 | |
| 54 | val is_substring_of : string -> string -> bool | |
| 55 | val serial_commas : string -> string list -> string list | |
| 56 | val plural_s : int -> string | |
| 57 | val plural_s_for_list : 'a list -> string | |
| 58 | val flip_polarity : polarity -> polarity | |
| 59 | val prop_T : typ | |
| 60 | val bool_T : typ | |
| 61 | val nat_T : typ | |
| 62 | val int_T : typ | |
| 63 | val subscript : string -> string | |
| 64 | val nat_subscript : int -> string | |
| 65 |   val time_limit : Time.time option -> ('a -> 'b) -> 'a -> 'b
 | |
| 66 |   val silence : ('a -> 'b) -> 'a -> 'b
 | |
| 67 | val DETERM_TIMEOUT : Time.time option -> tactic -> tactic | |
| 68 |   val setmp_show_all_types : ('a -> 'b) -> 'a -> 'b
 | |
| 69 | val indent_size : int | |
| 70 | val pstrs : string -> Pretty.T list | |
| 71 | val plain_string_from_yxml : string -> string | |
| 72 | val maybe_quote : string -> string | |
| 73 | end | |
| 74 | ||
| 33232 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 75 | structure Nitpick_Util : NITPICK_UTIL = | 
| 33192 | 76 | struct | 
| 77 | ||
| 78 | type styp = string * typ | |
| 79 | ||
| 80 | datatype polarity = Pos | Neg | Neut | |
| 81 | ||
| 82 | exception ARG of string * string | |
| 83 | exception BAD of string * string | |
| 84 | exception LIMIT of string * string | |
| 85 | exception NOT_SUPPORTED of string | |
| 86 | exception SAME of unit | |
| 87 | ||
| 88 | val nitpick_prefix = "Nitpick." | |
| 89 | ||
| 90 | (* ('a * 'b * 'c -> 'd) -> 'a -> 'b -> 'c -> 'd *)
 | |
| 91 | fun curry3 f = fn x => fn y => fn z => f (x, y, z) | |
| 92 | ||
| 93 | (* ('a -> 'b) * ('a -> 'c) -> 'a -> 'b * 'c *)
 | |
| 94 | fun (f pairf g) = fn x => (f x, g x) | |
| 95 | ||
| 96 | (* bool -> int *) | |
| 97 | fun int_for_bool b = if b then 1 else 0 | |
| 98 | (* int * int -> int *) | |
| 99 | fun (i nat_minus j) = if i > j then i - j else 0 | |
| 100 | ||
| 101 | val max_exponent = 16384 | |
| 102 | ||
| 103 | (* int -> int -> int *) | |
| 104 | fun reasonable_power a 0 = 1 | |
| 105 | | reasonable_power a 1 = a | |
| 106 | | reasonable_power 0 _ = 0 | |
| 107 | | reasonable_power 1 _ = 1 | |
| 108 | | reasonable_power a b = | |
| 109 | if b < 0 orelse b > max_exponent then | |
| 33232 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 110 |       raise LIMIT ("Nitpick_Util.reasonable_power",
 | 
| 33192 | 111 |                    "too large exponent (" ^ signed_string_of_int b ^ ")")
 | 
| 112 | else | |
| 113 | let | |
| 114 | val c = reasonable_power a (b div 2) in | |
| 115 | c * c * reasonable_power a (b mod 2) | |
| 116 | end | |
| 117 | ||
| 118 | (* int -> int -> int *) | |
| 119 | fun exact_log m n = | |
| 120 | let | |
| 121 | val r = Math.ln (Real.fromInt n) / Math.ln (Real.fromInt m) |> Real.round | |
| 122 | in | |
| 123 | if reasonable_power m r = n then | |
| 124 | r | |
| 125 | else | |
| 33232 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 126 |       raise ARG ("Nitpick_Util.exact_log",
 | 
| 33192 | 127 | commas (map signed_string_of_int [m, n])) | 
| 128 | end | |
| 129 | ||
| 130 | (* int -> int -> int *) | |
| 131 | fun exact_root m n = | |
| 132 | let val r = Math.pow (Real.fromInt n, 1.0 / (Real.fromInt m)) |> Real.round in | |
| 133 | if reasonable_power r m = n then | |
| 134 | r | |
| 135 | else | |
| 33232 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 136 |       raise ARG ("Nitpick_Util.exact_root",
 | 
| 33192 | 137 | commas (map signed_string_of_int [m, n])) | 
| 138 | end | |
| 139 | ||
| 140 | (* ('a -> 'a -> 'a) -> 'a list -> 'a *)
 | |
| 141 | fun fold1 f = foldl1 (uncurry f) | |
| 142 | ||
| 143 | (* int -> 'a list -> 'a list *) | |
| 144 | fun replicate_list 0 _ = [] | |
| 145 | | replicate_list n xs = xs @ replicate_list (n - 1) xs | |
| 146 | ||
| 147 | (* int list -> int list *) | |
| 148 | fun offset_list ns = rev (tl (fold (fn x => fn xs => (x + hd xs) :: xs) ns [0])) | |
| 149 | (* int -> int -> int list *) | |
| 150 | fun index_seq j0 n = if j0 < 0 then j0 downto j0 - n + 1 else j0 upto j0 + n - 1 | |
| 151 | ||
| 152 | (* int list -> 'a list -> 'a list *) | |
| 153 | fun filter_indices js xs = | |
| 154 | let | |
| 155 | (* int -> int list -> 'a list -> 'a list *) | |
| 156 | fun aux _ [] _ = [] | |
| 157 | | aux i (j :: js) (x :: xs) = | |
| 158 | if i = j then x :: aux (i + 1) js xs else aux (i + 1) (j :: js) xs | |
| 33232 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 159 |       | aux _ _ _ = raise ARG ("Nitpick_Util.filter_indices",
 | 
| 33192 | 160 | "indices unordered or out of range") | 
| 161 | in aux 0 js xs end | |
| 162 | fun filter_out_indices js xs = | |
| 163 | let | |
| 164 | (* int -> int list -> 'a list -> 'a list *) | |
| 165 | fun aux _ [] xs = xs | |
| 166 | | aux i (j :: js) (x :: xs) = | |
| 167 | if i = j then aux (i + 1) js xs else x :: aux (i + 1) (j :: js) xs | |
| 33232 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 168 |       | aux _ _ _ = raise ARG ("Nitpick_Util.filter_out_indices",
 | 
| 33192 | 169 | "indices unordered or out of range") | 
| 170 | in aux 0 js xs end | |
| 171 | ||
| 172 | (* 'a list -> 'a list list -> 'a list list *) | |
| 173 | fun cartesian_product [] _ = [] | |
| 174 | | cartesian_product (x :: xs) yss = | |
| 175 | map (cons x) yss @ cartesian_product xs yss | |
| 176 | (* 'a list list -> 'a list list *) | |
| 177 | fun n_fold_cartesian_product xss = fold_rev cartesian_product xss [[]] | |
| 178 | (* ''a list -> (''a * ''a) list *)
 | |
| 179 | fun all_distinct_unordered_pairs_of [] = [] | |
| 180 | | all_distinct_unordered_pairs_of (x :: xs) = | |
| 181 | map (pair x) xs @ all_distinct_unordered_pairs_of xs | |
| 182 | ||
| 183 | (* (int * int) list -> int -> int list *) | |
| 184 | val nth_combination = | |
| 185 | let | |
| 186 | (* (int * int) list -> int -> int list * int *) | |
| 187 | fun aux [] n = ([], n) | |
| 188 | | aux ((k, j0) :: xs) n = | |
| 189 | let val (js, n) = aux xs n in ((n mod k) + j0 :: js, n div k) end | |
| 190 | in fst oo aux end | |
| 191 | ||
| 192 | (* (int * int) list -> int list list *) | |
| 193 | val all_combinations = n_fold_cartesian_product o map (uncurry index_seq o swap) | |
| 194 | ||
| 195 | (* 'a list -> 'a list list *) | |
| 196 | fun all_permutations [] = [[]] | |
| 197 | | all_permutations xs = | |
| 198 | maps (fn j => map (cons (nth xs j)) (all_permutations (nth_drop j xs))) | |
| 199 | (index_seq 0 (length xs)) | |
| 200 | ||
| 201 | (* int -> 'a list -> 'a list list *) | |
| 202 | fun batch_list _ [] = [] | |
| 203 | | batch_list k xs = | |
| 204 | if length xs <= k then [xs] | |
| 205 | else List.take (xs, k) :: batch_list k (List.drop (xs, k)) | |
| 206 | ||
| 207 | (* int list -> 'a list -> 'a list list *) | |
| 208 | fun chunk_list_unevenly _ [] = [] | |
| 209 | | chunk_list_unevenly [] ys = map single ys | |
| 210 | | chunk_list_unevenly (k :: ks) ys = | |
| 211 | let val (ys1, ys2) = chop k ys in ys1 :: chunk_list_unevenly ks ys2 end | |
| 212 | ||
| 213 | (* ('a -> 'b -> 'c -> 'd) -> 'a list -> 'b list -> 'c list -> 'd list *)
 | |
| 214 | fun map3 _ [] [] [] = [] | |
| 215 | | map3 f (x :: xs) (y :: ys) (z :: zs) = f x y z :: map3 f xs ys zs | |
| 216 | | map3 _ _ _ _ = raise UnequalLengths | |
| 217 | ||
| 218 | (* ('a * 'a -> bool) -> ('a option * 'b) list -> 'a -> 'b option *)
 | |
| 219 | fun double_lookup eq ps key = | |
| 220 | case AList.lookup (fn (SOME x, SOME y) => eq (x, y) | _ => false) ps | |
| 221 | (SOME key) of | |
| 222 | SOME z => SOME z | |
| 223 | | NONE => ps |> find_first (is_none o fst) |> Option.map snd | |
| 224 | (* (''a * ''a -> bool) -> (''a option * 'b) list -> ''a -> 'b option *)
 | |
| 225 | fun triple_lookup eq ps key = | |
| 226 | case AList.lookup (op =) ps (SOME key) of | |
| 227 | SOME z => SOME z | |
| 228 | | NONE => double_lookup eq ps key | |
| 229 | ||
| 230 | (* string -> string -> bool *) | |
| 231 | fun is_substring_of needle stack = | |
| 232 | not (Substring.isEmpty (snd (Substring.position needle | |
| 233 | (Substring.full stack)))) | |
| 234 | ||
| 235 | (* string -> string list -> string list *) | |
| 236 | fun serial_commas _ [] = ["??"] | |
| 237 | | serial_commas _ [s] = [s] | |
| 238 | | serial_commas conj [s1, s2] = [s1, conj, s2] | |
| 239 | | serial_commas conj [s1, s2, s3] = [s1 ^ ",", s2 ^ ",", conj, s3] | |
| 240 | | serial_commas conj (s :: ss) = s ^ "," :: serial_commas conj ss | |
| 241 | ||
| 242 | (* int -> string *) | |
| 243 | fun plural_s n = if n = 1 then "" else "s" | |
| 244 | (* 'a list -> string *) | |
| 245 | fun plural_s_for_list xs = plural_s (length xs) | |
| 246 | ||
| 247 | (* polarity -> polarity *) | |
| 248 | fun flip_polarity Pos = Neg | |
| 249 | | flip_polarity Neg = Pos | |
| 250 | | flip_polarity Neut = Neut | |
| 251 | ||
| 252 | val prop_T = @{typ prop}
 | |
| 253 | val bool_T = @{typ bool}
 | |
| 254 | val nat_T = @{typ nat}
 | |
| 255 | val int_T = @{typ int}
 | |
| 256 | ||
| 257 | (* string -> string *) | |
| 258 | val subscript = implode o map (prefix "\<^isub>") o explode | |
| 259 | (* int -> string *) | |
| 260 | val nat_subscript = subscript o signed_string_of_int | |
| 261 | ||
| 262 | (* Time.time option -> ('a -> 'b) -> 'a -> 'b *)
 | |
| 263 | fun time_limit NONE f = f | |
| 264 | | time_limit (SOME delay) f = TimeLimit.timeLimit delay f | |
| 265 | ||
| 266 | (* (string -> unit) Unsynchronized.ref -> ('a -> 'b) -> 'a -> 'b *)
 | |
| 267 | fun silence_one out_fn = setmp_CRITICAL out_fn (K ()) | |
| 268 | ||
| 269 | (* ('a -> 'b) -> 'a -> 'b *)
 | |
| 270 | fun silence f = | |
| 271 | fold silence_one | |
| 272 | [Output.writeln_fn, Output.priority_fn, Output.tracing_fn, | |
| 273 | Output.warning_fn, Output.error_fn, Output.debug_fn] f | |
| 274 | ||
| 275 | (* Time.time option -> tactic -> tactic *) | |
| 276 | fun DETERM_TIMEOUT delay tac st = | |
| 277 | Seq.of_list (the_list (time_limit delay (fn () => SINGLE tac st) ())) | |
| 278 | ||
| 279 | (* ('a -> 'b) -> 'a -> 'b *)
 | |
| 280 | fun setmp_show_all_types f = | |
| 281 | setmp_CRITICAL show_all_types | |
| 282 | (! show_types orelse ! show_sorts orelse ! show_all_types) f | |
| 283 | ||
| 284 | val indent_size = 2 | |
| 285 | ||
| 286 | (* string -> Pretty.T list *) | |
| 287 | val pstrs = Pretty.breaks o map Pretty.str o space_explode " " | |
| 288 | ||
| 289 | (* XML.tree -> string *) | |
| 290 | fun plain_string_from_xml_tree t = | |
| 291 | Buffer.empty |> XML.add_content t |> Buffer.content | |
| 292 | (* string -> string *) | |
| 293 | val plain_string_from_yxml = plain_string_from_xml_tree o YXML.parse | |
| 294 | ||
| 295 | (* string -> bool *) | |
| 296 | val is_long_identifier = forall Syntax.is_identifier o space_explode "." | |
| 297 | (* string -> string *) | |
| 298 | fun maybe_quote y = | |
| 299 | let val s = plain_string_from_yxml y in | |
| 300 | y |> (not (is_long_identifier (perhaps (try (unprefix "'")) s)) | |
| 301 | orelse OuterKeyword.is_keyword s) ? quote | |
| 302 | end | |
| 303 | ||
| 304 | end; | |
| 305 | ||
| 33232 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 306 | structure Basic_Nitpick_Util : BASIC_NITPICK_UTIL = Nitpick_Util; | 
| 
f93390060bbe
internal renaming in Nitpick and fixed Kodkodi invokation on Linux;
 blanchet parents: 
33192diff
changeset | 307 | open Basic_Nitpick_Util; |