1(* Copyright (c) 2009-2011 Tjark Weber. All rights reserved. *) 2 3(* Translation of HOL terms into SMT-LIB 2 format *) 4 5structure SmtLib = struct 6 7local 8 9 (* FIXME: We translate into a fictitious SMT-LIB logic AUFBVNIRA 10 that comprises arrays (A), uninterpreted functions (UF), 11 bit-vectors (BV), non-linear (N) integer (I) and real arithmetic 12 (RA). Unfortunately, there is no actual SMT-LIB logic at the 13 moment that contains all these features: AUFNIRA is missing 14 bit-vectors, while QF_AUFBV is missing quantifiers and 15 arithmetic. See SmtLib_{Theories,Logics}.sml for details. At 16 present, we make no attempt to identify a less expressive SMT-LIB 17 logic based on the constants that actually appear in the goal. *) 18 19 (* For successful proof reconstruction, it is important that the 20 translation implemented in SmtLib_{Theories,Logics}.sml is an 21 inverse of the translation implemented in this file. *) 22 23 val ERR = Feedback.mk_HOL_ERR "SmtLib" 24 val WARNING = Feedback.HOL_WARNING "SmtLib" 25 26 (* (HOL type, a function that maps the type to its SMT-LIB sort name) *) 27 val builtin_types = List.foldl 28 (fn ((ty, x), net) => TypeNet.insert (net, ty, x)) TypeNet.empty [ 29 (Type.bool, Lib.K "Bool"), 30 (intSyntax.int_ty, Lib.K "Int"), 31 (realSyntax.real_ty, Lib.K "Real"), 32 (* bit-vector types *) 33 (wordsSyntax.mk_word_type Type.alpha, fn ty => 34 "(_ BitVec " ^ Arbnum.toString 35 (fcpSyntax.dest_numeric_type (wordsSyntax.dest_word_type ty)) ^ ")") 36 ] 37 38 val apfst_K = Lib.apfst o Lib.K 39 40 (* returns true iff 'ty' is a word type that is not fixed-width *) 41 fun is_non_numeric_word_type ty = 42 not (fcpSyntax.is_numeric_type (wordsSyntax.dest_word_type ty)) 43 handle Feedback.HOL_ERR _ => false 44 45 (* make sure that all word types in 't' are of fixed width; return 's' *) 46 fun apfst_fixed_width s = 47 Lib.apfst (fn t => 48 let 49 val (domtys, rngty) = boolSyntax.strip_fun (Term.type_of t) 50 in 51 if List.exists is_non_numeric_word_type (rngty :: domtys) then 52 raise ERR ("<builtin_symbols." ^ s ^ ">") 53 "not a fixed-width word type" 54 else 55 s 56 end) 57 58 (* (HOL term, a function that maps a pair (rator, rands) to an 59 SMT-LIB symbol and a list of remaining (still-to-be-encoded) 60 argument terms) *) 61 val builtin_symbols = List.foldl (Lib.uncurry Net.insert) Net.empty [ 62 (* Core *) 63 (boolSyntax.T, apfst_K "true"), 64 (boolSyntax.F, apfst_K "false"), 65 (boolSyntax.negation, apfst_K "not"), 66 (boolSyntax.implication, apfst_K "=>"), 67 (boolSyntax.conjunction, apfst_K "and"), 68 (boolSyntax.disjunction, apfst_K "or"), 69 (* (..., "xor"), *) 70 (boolSyntax.equality, apfst_K "="), 71 (* (..., "distinct"), *) 72 (boolSyntax.conditional, apfst_K "ite"), 73 (* Reals_Ints *) 74 (* numerals (excluding 'intSyntax.negate_tm') *) 75 (Term.mk_var ("x", intSyntax.int_ty), Lib.apfst (fn tm => 76 if intSyntax.is_int_literal tm andalso not (intSyntax.is_negated tm) then 77 let 78 val i = intSyntax.int_of_term tm 79 val s = Arbint.toString (Arbint.abs i) 80 val s = String.substring (s, 0, String.size s - 1) 81 in 82 if Arbint.< (i, Arbint.zero) then 83 "(- " ^ s ^ ")" 84 else 85 s 86 end 87 else 88 raise ERR "<builtin_symbols.x:int>" "not a numeral (negated?)")), 89 (intSyntax.negate_tm, apfst_K "-"), 90 (intSyntax.minus_tm, apfst_K "-"), 91 (intSyntax.plus_tm, apfst_K "+"), 92 (intSyntax.mult_tm, apfst_K "*"), 93 (* (..., "div"), *) 94 (* (..., "mod"), *) 95 (intSyntax.absval_tm, apfst_K "abs"), 96 (intSyntax.leq_tm, apfst_K "<="), 97 (intSyntax.less_tm, apfst_K "<"), 98 (intSyntax.geq_tm, apfst_K ">="), 99 (intSyntax.great_tm, apfst_K ">"), 100 (* decimals (excluding 'realSyntax.negate_tm') *) 101 (Term.mk_var ("x", realSyntax.real_ty), Lib.apfst (fn tm => 102 if realSyntax.is_real_literal tm andalso not (realSyntax.is_negated tm) 103 then 104 let 105 val i = realSyntax.int_of_term tm 106 val s = Arbint.toString (Arbint.abs i) 107 val s = String.substring (s, 0, String.size s - 1) 108 val s = s ^ ".0" 109 in 110 if Arbint.< (i, Arbint.zero) then 111 "(- " ^ s ^ ")" 112 else 113 s 114 end 115 else 116 raise ERR "<builtin_symbols.x:real>" "not a decimal (negated?)")), 117 (realSyntax.negate_tm, apfst_K "-"), 118 (realSyntax.minus_tm, apfst_K "-"), 119 (realSyntax.plus_tm, apfst_K "+"), 120 (realSyntax.mult_tm, apfst_K "*"), 121 (realSyntax.div_tm, apfst_K "/"), 122 (realSyntax.leq_tm, apfst_K "<="), 123 (realSyntax.less_tm, apfst_K "<"), 124 (realSyntax.geq_tm, apfst_K ">="), 125 (realSyntax.great_tm, apfst_K ">"), 126 (intrealSyntax.real_of_int_tm, apfst_K "to_real"), 127 (intrealSyntax.INT_FLOOR_tm, apfst_K "to_int"), 128 (intrealSyntax.is_int_tm, apfst_K "is_int"), 129 (* bit-vector constants *) 130 (Term.mk_var ("x", wordsSyntax.mk_word_type Type.alpha), Lib.apfst (fn tm => 131 if wordsSyntax.is_word_literal tm then 132 let 133 val value = wordsSyntax.dest_word_literal tm 134 val width = fcpSyntax.dest_numeric_type (wordsSyntax.dim_of tm) 135 in 136 "(_ bv" ^ Arbnum.toString value ^ " " ^ Arbnum.toString width ^ ")" 137 end 138 else 139 raise ERR "<builtin_symbols.x:'a word>" "not a word literal")), 140 (wordsSyntax.word_concat_tm, fn (t, ts) => 141 SmtLib_Theories.two_args (fn (w1, w2) => 142 let 143 (* make sure that the result in HOL has the expected width *) 144 val dim1 = fcpSyntax.dest_numeric_type (wordsSyntax.dim_of w1) 145 val dim2 = fcpSyntax.dest_numeric_type (wordsSyntax.dim_of w2) 146 val rngty = Lib.snd (boolSyntax.strip_fun (Term.type_of t)) 147 val rngdim = fcpSyntax.dest_numeric_type 148 (wordsSyntax.dest_word_type rngty) 149 val _ = if rngdim = Arbnum.+ (dim1, dim2) then 150 () 151 else ( 152 if !Library.trace > 0 then 153 WARNING "translate_term" "word_concat: wrong result type" 154 else 155 (); 156 raise ERR "<builtin_symbols.word_concat_tm>" "wrong result type" 157 ) 158 in 159 ("concat", ts) 160 end) ts), 161 (wordsSyntax.word_extract_tm, fn (t, ts) => 162 SmtLib_Theories.three_args (fn (i, j, w) => 163 let 164 (* make sure that j <= i < dim(w) *) 165 val i = numSyntax.dest_numeral i 166 val j = numSyntax.dest_numeral j 167 val dim = fcpSyntax.dest_numeric_type (wordsSyntax.dim_of w) 168 val _ = if Arbnum.<= (j, i) then 169 () 170 else ( 171 if !Library.trace > 0 then 172 WARNING "translate_term" 173 "word_extract: second index larger than first" 174 else 175 (); 176 raise ERR "<builtin_symbols.word_extract_tm>" 177 "second index larger than first" 178 ) 179 val _ = if Arbnum.< (i, dim) then 180 () 181 else ( 182 if !Library.trace > 0 then 183 WARNING "translate_term" "word_extract: first index too large" 184 else 185 (); 186 raise ERR "<builtin_symbols.word_extract_tm>" 187 "first index too large" 188 ) 189 (* make sure that the result in HOL has the expected width *) 190 val rngty = Lib.snd (boolSyntax.strip_fun (Term.type_of t)) 191 val rngdim = fcpSyntax.dest_numeric_type 192 (wordsSyntax.dest_word_type rngty) 193 val _ = if rngdim = Arbnum.+ (Arbnum.- (i, j), Arbnum.one) then 194 () 195 else ( 196 if !Library.trace > 0 then 197 WARNING "translate_term" "word_extract: wrong result type" 198 else 199 (); 200 raise ERR "<builtin_symbols.word_extract_tm>" "wrong result type" 201 ) 202 in 203 ("(_ extract " ^ Arbnum.toString i ^ " " ^ Arbnum.toString j ^ ")", 204 [w]) 205 end) ts), 206 (wordsSyntax.word_1comp_tm, apfst_fixed_width "bvnot"), 207 (wordsSyntax.word_and_tm, apfst_fixed_width "bvand"), 208 (wordsSyntax.word_or_tm, apfst_fixed_width "bvor"), 209 (wordsSyntax.word_nand_tm, apfst_fixed_width "bvnand"), 210 (wordsSyntax.word_nor_tm, apfst_fixed_width "bvnor"), 211 (wordsSyntax.word_xor_tm, apfst_fixed_width "bvxor"), 212 (wordsSyntax.word_xnor_tm, apfst_fixed_width "bvxnor"), 213 (wordsSyntax.word_2comp_tm, apfst_fixed_width "bvneg"), 214 (wordsSyntax.word_compare_tm, apfst_fixed_width "bvcomp"), 215 (wordsSyntax.word_add_tm, apfst_fixed_width "bvadd"), 216 (wordsSyntax.word_sub_tm, apfst_fixed_width "bvsub"), 217 (wordsSyntax.word_mul_tm, apfst_fixed_width "bvmul"), 218 (wordsSyntax.word_quot_tm, apfst_fixed_width "bvsdiv"), 219 (wordsSyntax.word_rem_tm, apfst_fixed_width "bvsrem"), 220 (integer_wordSyntax.word_smod_tm, apfst_fixed_width "bvsmod"), 221 (wordsSyntax.word_div_tm, apfst_fixed_width "bvudiv"), 222 (wordsSyntax.word_mod_tm, apfst_fixed_width "bvurem"), 223 (* shift operations with two bit-vector arguments; the corresponding HOL 224 shift operations that take a numeral as their second argument are not 225 supported in SMT-LIB *) 226 (wordsSyntax.word_lsl_bv_tm, apfst_fixed_width "bvshl"), 227 (wordsSyntax.word_lsr_bv_tm, apfst_fixed_width "bvlshr"), 228 (wordsSyntax.word_asr_bv_tm, apfst_fixed_width "bvashr"), 229 (wordsSyntax.word_replicate_tm, fn (t, ts) => 230 SmtLib_Theories.two_args (fn (n, w) => 231 let 232 val n = numSyntax.dest_numeral n 233 (* make sure that the result in HOL has the expected width *) 234 val dim = fcpSyntax.dest_numeric_type (wordsSyntax.dim_of w) 235 val rngty = Lib.snd (boolSyntax.strip_fun (Term.type_of t)) 236 val rngdim = fcpSyntax.dest_numeric_type 237 (wordsSyntax.dest_word_type rngty) 238 val _ = if rngdim = Arbnum.* (n, dim) then 239 () 240 else ( 241 if !Library.trace > 0 then 242 WARNING "translate_term" "word_replicate: wrong result type" 243 else 244 (); 245 raise ERR "<builtin_symbols.word_replicate_tm>" 246 "wrong result type" 247 ) 248 in 249 ("(_ repeat " ^ Arbnum.toString n ^ ")", [w]) 250 end) ts), 251 (wordsSyntax.w2w_tm, fn (t, ts) => 252 SmtLib_Theories.one_arg (fn w => 253 let 254 (* make sure that the result in HOL is at least as long as 'w' *) 255 val dim = fcpSyntax.dest_numeric_type (wordsSyntax.dim_of w) 256 val rngty = Lib.snd (boolSyntax.strip_fun (Term.type_of t)) 257 val rngdim = fcpSyntax.dest_numeric_type 258 (wordsSyntax.dest_word_type rngty) 259 val _ = if Arbnum.>= (rngdim, dim) then 260 () 261 else ( 262 if !Library.trace > 0 then 263 WARNING "translate_term" "w2w: result type too short" 264 else 265 (); 266 raise ERR "<builtin_symbols.w2w_tm>" "result type too short" 267 ) 268 val n = Arbnum.- (rngdim, dim) 269 in 270 ("(_ zero_extend " ^ Arbnum.toString n ^ ")", [w]) 271 end) ts), 272 (wordsSyntax.sw2sw_tm, fn (t, ts) => 273 SmtLib_Theories.one_arg (fn w => 274 let 275 (* make sure that the result in HOL is at least as long as 'w' *) 276 val dim = fcpSyntax.dest_numeric_type (wordsSyntax.dim_of w) 277 val rngty = Lib.snd (boolSyntax.strip_fun (Term.type_of t)) 278 val rngdim = fcpSyntax.dest_numeric_type 279 (wordsSyntax.dest_word_type rngty) 280 val _ = if Arbnum.>= (rngdim, dim) then 281 () 282 else ( 283 if !Library.trace > 0 then 284 WARNING "translate_term" "sw2sw: result type too short" 285 else 286 (); 287 raise ERR "<builtin_symbols.sw2sw_tm>" "result type too short" 288 ) 289 val n = Arbnum.- (rngdim, dim) 290 in 291 ("(_ sign_extend " ^ Arbnum.toString n ^ ")", [w]) 292 end) ts), 293 (* rotation by a numeral; the corresponding HOL rotation operations that 294 take two bit-vector arguments are not supported in SMT-LIB *) 295 (wordsSyntax.word_rol_tm, fn (t, ts) => 296 ( 297 apfst_fixed_width "rotate_left" (t, ()); 298 SmtLib_Theories.two_args (fn (w, n) => 299 ("(_ rotate_left " ^ Arbnum.toString (numSyntax.dest_numeral n) 300 ^ ")", [w])) ts 301 )), 302 (wordsSyntax.word_ror_tm, fn (t, ts) => 303 ( 304 apfst_fixed_width "rotate_right" (t, ()); 305 SmtLib_Theories.two_args (fn (w, n) => 306 ("(_ rotate_right " ^ Arbnum.toString (numSyntax.dest_numeral n) 307 ^ ")", [w])) ts 308 )), 309 (wordsSyntax.word_lo_tm, apfst_fixed_width "bvult"), 310 (wordsSyntax.word_ls_tm, apfst_fixed_width "bvule"), 311 (wordsSyntax.word_hi_tm, apfst_fixed_width "bvugt"), 312 (wordsSyntax.word_hs_tm, apfst_fixed_width "bvuge"), 313 (wordsSyntax.word_lt_tm, apfst_fixed_width "bvslt"), 314 (wordsSyntax.word_le_tm, apfst_fixed_width "bvsle"), 315 (wordsSyntax.word_gt_tm, apfst_fixed_width "bvsgt"), 316 (wordsSyntax.word_ge_tm, apfst_fixed_width "bvsge") 317 ] 318 319 (* SMT-LIB type and function names are uniformly generated as "tN" 320 and "vN", respectively, where N is a number. Prefixes must be 321 distinct. *) 322 323 val ty_prefix = "t" (* for types *) 324 val tm_prefix = "v" (* for terms *) 325 val bv_prefix = "b" (* for bound variables *) 326 327 (* returns an updated accumulator, a (possibly empty) list of 328 SMT-LIB type declarations, and the SMT-LIB representation of the 329 given type *) 330 fun translate_type (tydict, ty) = 331 let 332 val name = Lib.tryfind (fn (_, f) => f ty) 333 (TypeNet.match (builtin_types, ty)) (* may fail *) 334 handle Feedback.HOL_ERR _ => 335 Redblackmap.find (tydict, ty) 336 in 337 (tydict, ([], name)) 338 end 339 handle Redblackmap.NotFound => 340 (* uninterpreted types *) 341 let 342 val name = ty_prefix ^ Int.toString (Redblackmap.numItems tydict) 343 val decl = "(declare-sort " ^ name ^ " 0)\n" 344 in 345 if !Library.trace > 0 andalso Type.is_type ty then 346 WARNING "translate_type" 347 ("uninterpreted type " ^ Hol_pp.type_to_string ty) 348 else 349 (); 350 if !Library.trace > 2 then 351 Feedback.HOL_MESG ("HolSmtLib (SmtLib): inventing name '" ^ name ^ 352 "' for HOL type '" ^ Hol_pp.type_to_string ty ^ "'") 353 else 354 (); 355 (Redblackmap.insert (tydict, ty, name), ([decl], name)) 356 end 357 358 (* SMT-LIB is first-order. Thus, functions can only be applied to 359 arguments of base type, but not to arguments of function type; 360 all completely applied terms must be of base type. 361 362 Thus, higher-order arguments must be abstracted so that they are 363 of (uninterpreted) base type. We achieve this by abstracting the 364 offending function type to a fresh base type, and by abstracting 365 the argument's rator to an uninterpreted term that returns the 366 correct (abstracted) type. Note that the same function/operator 367 may appear both with and without arguments in a HOL formula. 368 'tmdict' maps terms along with the number of their actual 369 arguments to an SMT-LIB representation. *) 370 371 (* returns an updated accumulator, a (possibly empty) list of 372 SMT-LIB (type and term) declarations, and the SMT-LIB 373 representation of the given term *) 374 fun translate_term (acc as (tydict, tmdict), (bounds, tm)) = 375 let 376 fun sexpr x [] = x 377 | sexpr x xs = "(" ^ x ^ " " ^ String.concatWith " " xs ^ ")" 378 fun builtin_symbol (rator, rands) = 379 let 380 val (name, rands) = Lib.tryfind (fn parsefn => parsefn (rator, rands)) 381 (Net.match rator builtin_symbols) (* may fail *) 382 val (acc, declnames) = Lib.foldl_map 383 (fn (a, t) => translate_term (a, (bounds, t))) (acc, rands) 384 val (declss, names) = Lib.split declnames 385 in 386 (acc, (List.concat declss, sexpr name names)) 387 end 388 (* creates a mapping from bound variables to their SMT-LIB names; if a 389 variable is already mapped, we return its existing SMT-LIB name *) 390 fun create_bound_name (bounds, v) = 391 (bounds, Redblackmap.find (bounds, v)) 392 handle Redblackmap.NotFound => 393 let 394 val name = bv_prefix ^ Int.toString (Redblackmap.numItems bounds) 395 in 396 (Redblackmap.insert (bounds, v, name), name) 397 end 398 val tm_has_base_type = not (Lib.can Type.dom_rng (Term.type_of tm)) 399 in 400 (* binders *) 401 let 402 (* perhaps we should use a table of binders instead *) 403 val (binder, (vars, body)) = if boolSyntax.is_forall tm then 404 ("forall", boolSyntax.strip_forall tm) 405 else if boolSyntax.is_exists tm then 406 ("exists", boolSyntax.strip_exists tm) 407 else 408 raise ERR "translate_term" "not a binder" (* handled below *) 409 val (bounds, smtvars) = Lib.foldl_map create_bound_name (bounds, vars) 410 val (tydict, vardecltys) = Lib.foldl_map translate_type 411 (tydict, List.map Term.type_of vars) 412 val (vardeclss, vartys) = Lib.split vardecltys 413 val vardecls = List.concat vardeclss 414 val smtvars = ListPair.mapEq (fn (v, ty) => "(" ^ v ^ " " ^ ty ^ ")") 415 (smtvars, vartys) 416 val (acc, (bodydecls, body)) = translate_term 417 ((tydict, tmdict), (bounds, body)) 418 in 419 (acc, (vardecls @ bodydecls, "(" ^ binder ^ " (" ^ 420 String.concatWith " " smtvars ^ ") " ^ body ^ ")")) 421 end 422 handle Feedback.HOL_ERR _ => 423 424 (* let binder - somewhat similar to quantifiers, but we only 425 translate one let at a time (so we don't have to worry about 426 semantic differences caused by parallel vs. sequential let) *) 427 let 428 val (M, N) = boolSyntax.dest_let tm 429 val (var, body) = Term.dest_abs M 430 val (acc, (Ndecls, N)) = translate_term (acc, (bounds, N)) 431 val (bounds, name) = create_bound_name (bounds, var) 432 val (acc, (bodydecls, body)) = translate_term (acc, (bounds, body)) 433 in 434 (acc, (Ndecls @ bodydecls, 435 "(let ((" ^ name ^ " " ^ N ^ ")) " ^ body ^ ")")) 436 end 437 handle Feedback.HOL_ERR _ => 438 439 (* bound variables may shadow built-in symbols etc. *) 440 (acc, ([], Redblackmap.find (bounds, tm))) 441 handle Redblackmap.NotFound => 442 443 (* translate the entire term (e.g., for numerals), using the dictionary of 444 built-in symbols; however, only do this if 'tm' has base type *) 445 (if tm_has_base_type then 446 builtin_symbol (tm, []) 447 else 448 raise ERR "translate_term" "not first-order") (* handled below *) 449 handle Feedback.HOL_ERR _ => 450 451 (* split the term into rator and rands *) 452 let 453 val (rator, rands) = boolSyntax.strip_comb tm 454 in 455 (* translate the rator as a built-in symbol (applied to its rands); only 456 do this if 'tm' has base type *) 457 (if tm_has_base_type then 458 builtin_symbol (rator, rands) 459 else 460 raise ERR "translate_term" "not first-order") (* handled below *) 461 handle Feedback.HOL_ERR _ => 462 463 let 464 val rands_count = List.length rands 465 val (acc, (decls, name)) = 466 (* translate the rator as a previously defined symbol *) 467 (acc, ([], Redblackmap.find (tmdict, (rator, rands_count)))) 468 handle Redblackmap.NotFound => 469 470 (* translate the rator as a new (i.e., uninterpreted) symbol *) 471 let 472 (* translate 'rator' types required for the rator's 473 SMT-LIB declaration *) 474 fun doms_rng acc 0 ty = 475 (List.rev acc, ty) 476 | doms_rng acc n ty = 477 let 478 val (dom, rng) = Type.dom_rng ty 479 in 480 doms_rng (dom :: acc) (n - 1) rng 481 end 482 (* strip only 'rands_count' many 'domtys', leaving the remaining 483 argument types in 'rngty' *) 484 val (domtys, rngty) = doms_rng [] rands_count (Term.type_of rator) 485 val (tydict, domdecltys) = Lib.foldl_map translate_type 486 (tydict, domtys) 487 val (domdeclss, domtys) = Lib.split domdecltys 488 val domdecls = List.concat domdeclss 489 val (tydict, (rngdecls, rngty)) = translate_type (tydict, rngty) 490 (* invent new name for 'rator' *) 491 val name = tm_prefix ^ Int.toString (Redblackmap.numItems tmdict) 492 val _ = if !Library.trace > 0 andalso Term.is_const rator then 493 WARNING "translate_term" 494 ("uninterpreted constant " ^ Hol_pp.term_to_string rator) 495 else 496 (); 497 val _ = if !Library.trace > 2 then 498 Feedback.HOL_MESG ("HolSmtLib (SmtLib): inventing name '" ^ 499 name ^ "' for HOL term '" ^ Hol_pp.term_to_string rator ^ 500 "' (applied to " ^ Int.toString rands_count ^ " argument(s))") 501 else 502 () 503 val tmdict = Redblackmap.insert (tmdict, (rator, rands_count), name) 504 val decl = "(declare-fun " ^ name ^ " (" ^ 505 String.concatWith " " domtys ^ ") " ^ rngty ^ ")\n" 506 in 507 ((tydict, tmdict), (domdecls @ rngdecls @ [decl], name)) 508 end 509 (* translate 'rands' *) 510 val (acc, declnames) = Lib.foldl_map 511 (fn (a, t) => translate_term (a, (bounds, t))) (acc, rands) 512 val (declss, names) = Lib.split declnames 513 in 514 (acc, (decls @ List.concat declss, sexpr name names)) 515 end 516 end 517 end 518 519 (* Returns a string list representing the input goal in SMT-LIB file 520 format, together with two dictionaries that map types and terms 521 to identifiers used in the SMT-LIB representation. The goal's 522 conclusion is negated before translation into SMT-LIB format. 523 The integer in the term dictionary gives the number of actual 524 arguments to the term. (Because SMT-LIB is first-order, 525 partially applied functions are mapped to different SMT-LIB 526 identifiers, depending on the number of actual arguments.) *) 527 fun goal_to_SmtLib_aux (ts, t) 528 : ((Type.hol_type, string) Redblackmap.dict * 529 (Term.term * int, string) Redblackmap.dict) * string list = 530 let 531 val tydict = Redblackmap.mkDict Type.compare 532 val tmdict = Redblackmap.mkDict 533 (Lib.pair_compare (Term.compare, Int.compare)) 534 val bounds = Redblackmap.mkDict Term.compare 535 val (acc, smtlibs) = Lib.foldl_map 536 (fn (acc, tm) => translate_term (acc, (bounds, tm))) 537 ((tydict, tmdict), ts @ [boolSyntax.mk_neg t]) 538 (* we choose to intertwine declarations and assertions (for no 539 particular reason; an alternative would be to emit all 540 declarations before all assertions) *) 541 val smtlibs = List.foldl 542 (fn ((xs, s), acc) => acc @ xs @ ["(assert " ^ s ^ ")\n"]) [] smtlibs 543 in 544 (acc, [ 545 (* "(set-logic AUFBVNIRA)\n", *) 546 "(set-info :source |Automatically generated from HOL4 by SmtLib.goal_to_SmtLib.\n", 547 "Copyright (c) 2011 Tjark Weber. All rights reserved.|)\n", 548 "(set-info :smt-lib-version 2.0)\n" 549 ] @ smtlibs @ [ 550 "(check-sat)\n" 551 ]) 552 end 553 554in 555 556 val goal_to_SmtLib = 557 Lib.apsnd (fn xs => xs @ ["(exit)\n"]) o goal_to_SmtLib_aux 558 559 val goal_to_SmtLib_with_get_proof = 560 Lib.apsnd (fn xs => xs @ ["(get-proof)\n", "(exit)\n"]) o goal_to_SmtLib_aux 561 562 (* eliminates some HOL terms that are not supported by the SMT-LIB 563 translation *) 564 fun SIMP_TAC simp_let = 565 let 566 open Tactical simpLib 567 val INT_ABS = intLib.ARITH_PROVE 568 ``!x. ABS (x:int) = if x < 0i then 0i - x else x`` 569 in 570 REPEAT Tactic.GEN_TAC THEN 571 (if simp_let then Library.LET_SIMP_TAC else ALL_TAC) THEN 572 SIMP_TAC pureSimps.pure_ss 573 [integerTheory.INT_MIN, integerTheory.INT_MAX, INT_ABS] THEN 574 Library.WORD_SIMP_TAC THEN 575 Library.SET_SIMP_TAC THEN 576 Tactic.BETA_TAC 577 end 578 579end (* local *) 580 581end 582