added new method "smt": an oracle-based connection to external SMT solvers
authorboehmes
Fri, 18 Sep 2009 18:13:19 +0200
changeset 32618 42865636d006
parent 32608 c0056c2c1d17
child 32619 02f45a09a9f2
added new method "smt": an oracle-based connection to external SMT solvers
CONTRIBUTORS
NEWS
etc/components
src/HOL/IsaMakefile
src/HOL/SMT/Examples/SMT_Examples.thy
src/HOL/SMT/IsaMakefile
src/HOL/SMT/ROOT.ML
src/HOL/SMT/SMT.thy
src/HOL/SMT/SMT_Definitions.thy
src/HOL/SMT/Tools/cvc3_solver.ML
src/HOL/SMT/Tools/smt_builtin.ML
src/HOL/SMT/Tools/smt_monomorph.ML
src/HOL/SMT/Tools/smt_normalize.ML
src/HOL/SMT/Tools/smt_solver.ML
src/HOL/SMT/Tools/smt_translate.ML
src/HOL/SMT/Tools/smtlib_interface.ML
src/HOL/SMT/Tools/yices_solver.ML
src/HOL/SMT/Tools/z3_interface.ML
src/HOL/SMT/Tools/z3_model.ML
src/HOL/SMT/Tools/z3_solver.ML
src/HOL/SMT/etc/settings
src/HOL/SMT/lib/scripts/remote_smt.pl
--- a/CONTRIBUTORS	Fri Sep 18 14:40:24 2009 +0200
+++ b/CONTRIBUTORS	Fri Sep 18 18:13:19 2009 +0200
@@ -7,6 +7,9 @@
 Contributions to this Isabelle version
 --------------------------------------
 
+* September 2009: Sascha Boehme, TUM
+  SMT method using external SMT solvers
+
 * September 2009: Florian Haftmann, TUM
   Refinement of Sets and Lattices
 
--- a/NEWS	Fri Sep 18 14:40:24 2009 +0200
+++ b/NEWS	Fri Sep 18 18:13:19 2009 +0200
@@ -18,6 +18,13 @@
 
 *** HOL ***
 
+* New proof method "smt" for a combination of first-order logic
+with equality, linear and nonlinear (natural/integer/real)
+arithmetic, and fixed-size bitvectors; there is also basic
+support for higher-order features (esp. lambda abstractions).
+It is an incomplete decision procedure based on external SMT
+solvers using the oracle mechanism.
+
 * Reorganization of number theory:
   * former session NumberTheory now named Old_Number_Theory
   * new session Number_Theory by Jeremy Avigad; if possible, prefer this.
--- a/etc/components	Fri Sep 18 14:40:24 2009 +0200
+++ b/etc/components	Fri Sep 18 18:13:19 2009 +0200
@@ -15,3 +15,4 @@
 src/HOL/Tools/ATP_Manager
 src/HOL/Mirabelle
 src/HOL/Library/Sum_Of_Squares
+src/HOL/SMT
--- a/src/HOL/IsaMakefile	Fri Sep 18 14:40:24 2009 +0200
+++ b/src/HOL/IsaMakefile	Fri Sep 18 18:13:19 2009 +0200
@@ -40,6 +40,7 @@
   HOL-Prolog \
   HOL-SET-Protocol \
   HOL-SizeChange \
+  HOL-SMT \
   HOL-Statespace \
   HOL-Subst \
       TLA-Buffer \
@@ -1134,6 +1135,19 @@
 	@$(ISABELLE_TOOL) usedir $(OUT)/HOL Mirabelle
 
 
+## HOL-SMT
+
+HOL-SMT: HOL-Word $(LOG)/HOL-SMT.gz
+
+$(LOG)/HOL-SMT.gz: $(OUT)/HOL-Word SMT/SMT_Definitions.thy SMT/SMT.thy \
+  SMT/Tools/smt_normalize.ML SMT/Tools/smt_monomorph.ML \
+  SMT/Tools/smt_translate.ML SMT/Tools/smt_builtin.ML \
+  SMT/Tools/smtlib_interface.ML SMT/Tools/smt_solver.ML \
+  SMT/Tools/cvc3_solver.ML SMT/Tools/yices_solver.ML \
+  SMT/Tools/z3_interface.ML SMT/Tools/z3_solver.ML SMT/Tools/z3_model.ML
+	@cd SMT; $(ISABELLE_TOOL) usedir -b -g true $(OUT)/HOL-Word HOL-SMT
+
+
 ## clean
 
 clean:
@@ -1156,4 +1170,4 @@
 		$(LOG)/HOL-Unix.gz $(OUT)/HOL-Word $(LOG)/HOL-Word.gz	\
 		$(LOG)/HOL-Word-Examples.gz $(OUT)/HOL-NSA		\
 		$(LOG)/HOL-NSA.gz $(LOG)/HOL-NSA-Examples.gz            \
-                $(LOG)/HOL-Mirabelle.gz
+                $(LOG)/HOL-Mirabelle.gz $(LOG)/HOL-SMT.gz
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Examples/SMT_Examples.thy	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,182 @@
+(*  Title:       SMT_Examples.thy
+    Author:      Sascha Böhme, TU Muenchen
+*)
+
+header {* Examples for the 'smt' tactic. *}
+
+theory SMT_Examples
+imports "../SMT"
+begin
+
+declare [[smt_solver=z3, z3_proofs=false]]
+declare [[smt_trace=true]] (*FIXME*)
+
+
+section {* Propositional and first-order logic *}
+
+lemma "True" by smt
+lemma "p \<or> \<not>p" by smt
+lemma "(p \<and> True) = p" by smt
+lemma "(p \<or> q) \<and> \<not>p \<Longrightarrow> q" by smt
+lemma "(a \<and> b) \<or> (c \<and> d) \<Longrightarrow> (a \<and> b) \<or> (c \<and> d)" by smt
+lemma "P=P=P=P=P=P=P=P=P=P" by smt
+
+axiomatization symm_f :: "'a \<Rightarrow> 'a \<Rightarrow> 'a" where
+  symm_f: "symm_f x y = symm_f y x"
+lemma "a = a \<and> symm_f a b = symm_f b a" by (smt add: symm_f)
+
+
+section {* Linear arithmetic *}
+
+lemma "(3::int) = 3" by smt
+lemma "(3::real) = 3" by smt
+lemma "(3 :: int) + 1 = 4" by smt
+lemma "max (3::int) 8 > 5" by smt
+lemma "abs (x :: real) + abs y \<ge> abs (x + y)" by smt
+lemma "let x = (2 :: int) in x + x \<noteq> 5" by smt
+
+text{* 
+The following example was taken from HOL/ex/PresburgerEx.thy, where it says:
+
+  This following theorem proves that all solutions to the
+  recurrence relation $x_{i+2} = |x_{i+1}| - x_i$ are periodic with
+  period 9.  The example was brought to our attention by John
+  Harrison. It does does not require Presburger arithmetic but merely
+  quantifier-free linear arithmetic and holds for the rationals as well.
+
+  Warning: it takes (in 2006) over 4.2 minutes! 
+
+There, it is proved by "arith". SMT is able to prove this within a fraction
+of one second.
+*}
+
+lemma "\<lbrakk> x3 = abs x2 - x1; x4 = abs x3 - x2; x5 = abs x4 - x3;
+         x6 = abs x5 - x4; x7 = abs x6 - x5; x8 = abs x7 - x6;
+         x9 = abs x8 - x7; x10 = abs x9 - x8; x11 = abs x10 - x9 \<rbrakk>
+ \<Longrightarrow> x1 = x10 & x2 = (x11::int)"
+  by smt
+
+lemma "\<exists>x::int. 0 < x" by smt
+lemma "\<exists>x::real. 0 < x" by smt
+lemma "\<forall>x y::int. x < y \<longrightarrow> (2 * x + 1) < (2 * y)" by smt
+lemma "\<forall>x y::int. (2 * x + 1) \<noteq> (2 * y)" by smt
+lemma "~ (\<exists>x y z::int. 4 * x + -6 * y = (1::int))" by smt
+lemma "~ (\<exists>x::int. False)" by smt
+
+
+section {* Non-linear arithmetic *}
+
+lemma "((x::int) * (1 + y) - x * (1 - y)) = (2 * x * y)" by smt
+lemma
+  "(U::int) + (1 + p) * (b + e) + p * d =
+   U + (2 * (1 + p) * (b + e) + (1 + p) * d + d * p) - (1 + p) * (b + d + e)"
+  by smt
+
+
+section {* Linear arithmetic for natural numbers *}
+
+lemma "a < 3 \<Longrightarrow> (7::nat) > 2 * a" by smt
+lemma "let x = (1::nat) + y in x - y > 0 * x" by smt
+lemma
+  "let x = (1::nat) + y in
+   let P = (if x > 0 then True else False) in
+   False \<or> P = (x - 1 = y) \<or> (\<not>P \<longrightarrow> False)"
+  by smt
+
+
+section {* Bitvectors *}
+
+locale bv
+begin
+
+declare [[smt_solver=z3]]
+
+lemma "(27 :: 4 word) = -5" by smt
+lemma "(27 :: 4 word) = 11" by smt
+lemma "23 < (27::8 word)" by smt
+lemma "27 + 11 = (6::5 word)" by smt
+lemma "7 * 3 = (21::8 word)" by smt
+lemma "11 - 27 = (-16::8 word)" by smt
+lemma "- -11 = (11::5 word)" by smt
+lemma "-40 + 1 = (-39::7 word)" by smt
+lemma "a + 2 * b + c - b = (b + c) + (a :: 32 word)" by smt
+
+lemma "0b110 AND 0b101 = (0b100 :: 32 word)" by smt
+lemma "0b110 OR 0b011 = (0b111 :: 8 word)" by smt
+lemma "0xF0 XOR 0xFF = (0x0F :: 8 word)" by smt
+lemma "NOT (0xF0 :: 16 word) = 0xFF0F" by smt
+
+lemma "word_cat (27::4 word) (27::8 word) = (2843::12 word)" by smt
+lemma "word_cat (0b0011::4 word) (0b1111::6word) = (0b0011001111 :: 10 word)" 
+  by smt
+
+lemma "slice 1 (0b10110 :: 4 word) = (0b11 :: 2 word)" by smt
+
+lemma "ucast (0b1010 :: 4 word) = (0b1010 :: 10 word)" by smt
+lemma "scast (0b1010 :: 4 word) = (0b111010 :: 6 word)" by smt
+
+lemma "bv_lshr 0b10011 2 = (0b100::8 word)" by smt
+lemma "bv_ashr 0b10011 2 = (0b100::8 word)" by smt
+
+lemma "word_rotr 2 0b0110 = (0b1001::4 word)" by smt
+lemma "word_rotl 1 0b1110 = (0b1101::4 word)" by smt
+
+lemma "(x AND 0xff00) OR (x AND 0x00ff) = (x::16 word)" by smt
+
+lemma "w < 256 \<Longrightarrow> (w :: 16 word) AND 0x00FF = w" by smt
+
+end
+
+
+section {* Pairs *}
+
+lemma "fst (x, y) = a \<Longrightarrow> x = a" by smt
+lemma "p1 = (x, y) \<and> p2 = (y, x) \<Longrightarrow> fst p1 = snd p2" by smt
+
+
+section {* Higher-order problems and recursion *}
+
+lemma "(f g x = (g x \<and> True)) \<or> (f g x = True) \<or> (g x = True)" by smt
+lemma "P ((2::int) < 3) = P True" by smt
+lemma "P ((2::int) < 3) = (P True :: bool)" by smt
+lemma "P (0 \<le> (a :: 4 word)) = P True" using [[smt_solver=z3]] by smt
+lemma "id 3 = 3 \<and> id True = True" by (smt add: id_def)
+lemma "i \<noteq> i1 \<and> i \<noteq> i2 \<Longrightarrow> ((f (i1 := v1)) (i2 := v2)) i = f i" by smt
+lemma "map (\<lambda>i::nat. i + 1) [0, 1] = [1, 2]" by (smt add: map.simps)
+lemma "(ALL x. P x) | ~ All P" by smt
+
+fun dec_10 :: "nat \<Rightarrow> nat" where
+  "dec_10 n = (if n < 10 then n else dec_10 (n - 10))"
+lemma "dec_10 (4 * dec_10 4) = 6" by (smt add: dec_10.simps)
+
+axiomatization
+  eval_dioph :: "int list \<Rightarrow> nat list \<Rightarrow> int"
+  where
+  eval_dioph_mod:
+  "eval_dioph ks xs mod int n = eval_dioph ks (map (\<lambda>x. x mod n) xs) mod int n"
+  and
+  eval_dioph_div_mult:
+  "eval_dioph ks (map (\<lambda>x. x div n) xs) * int n +
+   eval_dioph ks (map (\<lambda>x. x mod n) xs) = eval_dioph ks xs"
+lemma
+  "(eval_dioph ks xs = l) =
+   (eval_dioph ks (map (\<lambda>x. x mod 2) xs) mod 2 = l mod 2 \<and>
+    eval_dioph ks (map (\<lambda>x. x div 2) xs) =
+      (l - eval_dioph ks (map (\<lambda>x. x mod 2) xs)) div 2)"
+  by (smt add: eval_dioph_mod[where n=2] eval_dioph_div_mult[where n=2])
+
+
+section {* Monomorphization examples *}
+
+definition P :: "'a \<Rightarrow> bool" where "P x = True"
+lemma poly_P: "P x \<and> (P [x] \<or> \<not>P[x])" by (simp add: P_def)
+lemma "P (1::int)" by (smt add: poly_P)
+
+consts g :: "'a \<Rightarrow> nat"
+axioms
+  g1: "g (Some x) = g [x]"
+  g2: "g None = g []"
+  g3: "g xs = length xs"
+lemma "g (Some (3::int)) = g (Some True)" by (smt add: g1 g2 g3 list.size)
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/IsaMakefile	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,39 @@
+
+## targets
+
+default: HOL-SMT
+images: HOL-SMT
+test: 
+
+all: images test
+
+
+## global settings
+
+SRC = $(ISABELLE_HOME)/src
+OUT = $(ISABELLE_OUTPUT)
+LOG = $(OUT)/log
+
+USEDIR = $(ISATOOL) usedir -v true 
+
+
+## HOL-SMT
+
+HOL-SMT: $(OUT)/HOL-SMT
+
+$(OUT)/HOL-SMT: $(OUT)/HOL-Word ROOT.ML SMT_Definitions.thy SMT.thy \
+  Tools/cancel_conj_disj.ML Tools/smt_normalize.ML Tools/smt_monomorph.ML \
+  Tools/smt_translate.ML Tools/smt_builtin.ML Tools/smtlib_interface.ML \
+  Tools/smt_solver.ML Tools/cvc3_solver.ML Tools/yices_solver.ML \
+  Tools/z3_interface.ML Tools/z3_solver.ML Tools/z3_model.ML \
+  Tools/z3_proof.ML Tools/z3_proof_rules.ML Tools/z3_proof_terms.ML
+	@$(USEDIR) -b HOL-Word HOL-SMT
+
+$(OUT)/HOL-Word:
+	@$(ISATOOL) make HOL-Word -C $(SRC)/HOL
+
+
+## clean
+
+clean:
+	@rm -f $(OUT)/HOL-SMT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/ROOT.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,1 @@
+use_thy "SMT";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/SMT.thy	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,51 @@
+(*  Title:      HOL/SMT/SMT.thy
+    Author:     Sascha Boehme, TU Muenchen
+*)
+
+header {* SMT method using external SMT solvers (CVC3, Yices, Z3) *}
+
+theory SMT
+imports SMT_Definitions
+uses
+  "Tools/smt_normalize.ML"
+  "Tools/smt_monomorph.ML"
+  "Tools/smt_translate.ML"
+  "Tools/smt_solver.ML"
+  "Tools/smtlib_interface.ML"
+  "Tools/cvc3_solver.ML"
+  "Tools/yices_solver.ML"
+  "Tools/z3_model.ML"
+  "Tools/z3_interface.ML"
+  "Tools/z3_solver.ML"
+begin
+
+setup {*
+  SMT_Normalize.setup #>
+  SMT_Solver.setup #>
+  CVC3_Solver.setup #>
+  Yices_Solver.setup #>
+  Z3_Solver.setup
+*}
+
+ML {*
+OuterSyntax.improper_command "smt_status"
+  "Show the available SMT solvers and the currently selected solver."
+  OuterKeyword.diag
+    (Scan.succeed (Toplevel.no_timing o Toplevel.keep (fn state =>
+      SMT_Solver.print_setup (Context.Proof (Toplevel.context_of state)))))
+*}
+
+method_setup smt = {*
+  let fun solver thms ctxt = SMT_Solver.smt_tac ctxt thms
+  in
+    Scan.optional (Scan.lift (Args.add -- Args.colon) |-- Attrib.thms) [] >>
+    (Method.SIMPLE_METHOD' oo solver)
+  end
+*} "Applies an SMT solver to the current goal."
+
+declare [[ smt_solver = z3, smt_timeout = 20, smt_trace = false ]]
+declare [[ smt_unfold_defs = true ]]
+declare [[ z3_proofs = false ]]
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/SMT_Definitions.thy	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,113 @@
+(*  Title:      HOL/SMT/SMT_Definitions.thy
+    Author:     Sascha Boehme, TU Muenchen
+*)
+
+header {* SMT-specific definitions *}
+
+theory SMT_Definitions
+imports Real Word "~~/src/HOL/Decision_Procs/Dense_Linear_Order"
+begin
+
+section {* Triggers for quantifier instantiation *}
+
+text {*
+Some SMT solvers support triggers for quantifier instantiation. Each trigger
+consists of one ore more patterns. A pattern may either be a list of positive
+subterms (the first being tagged by "pat" and the consecutive subterms tagged
+by "andpat"), or a list of negative subterms (the first being tagged by "nopat"
+and the consecutive subterms tagged by "andpat").
+*}
+
+datatype pattern = Pattern
+
+definition pat :: "'a \<Rightarrow> pattern"
+where "pat _ = Pattern"
+
+definition nopat :: "bool \<Rightarrow> pattern"
+where "nopat _ = Pattern"
+
+definition andpat :: "pattern \<Rightarrow> 'a \<Rightarrow> pattern" (infixl "andpat" 60)
+where "_ andpat _ = Pattern"
+
+definition trigger :: "pattern list \<Rightarrow> bool \<Rightarrow> bool"
+where "trigger _ P = P"
+
+
+section {* Arithmetic *}
+
+text {*
+The sign of @{term "op mod :: int \<Rightarrow> int \<Rightarrow> int"} follows the sign of the
+divisor. In contrast to that, the sign of the following operation is that of
+the dividend.
+*}
+
+definition rem :: "int \<Rightarrow> int \<Rightarrow> int" (infixl "rem" 70)
+where "a rem b = 
+  (if (a \<ge> 0 \<and> b < 0) \<or> (a < 0 \<and> b \<ge> 0) then - (a mod b) else a mod b)"
+
+text {* A decision procedure for linear real arithmetic: *}
+
+setup {*
+  Arith_Data.add_tactic "Ferrante-Rackoff" (K FerranteRackoff.dlo_tac)
+*}
+
+
+section {* Bitvectors *}
+
+text {*
+The following definitions provide additional functions not found in HOL-Word.
+*}
+
+definition sdiv :: "'a::len word \<Rightarrow> 'a word \<Rightarrow> 'a word" (infix "sdiv" 70)
+where "w1 sdiv w2 = word_of_int (sint w1 div sint w2)"
+
+definition smod :: "'a::len word \<Rightarrow> 'a word \<Rightarrow> 'a word" (infix "smod" 70)
+  (* sign follows divisor *)
+where "w1 smod w2 = word_of_int (sint w1 mod sint w2)"
+
+definition srem :: "'a::len word \<Rightarrow> 'a word \<Rightarrow> 'a word" (infix "srem" 70)
+  (* sign follows dividend *)
+where "w1 srem w2 = word_of_int (sint w1 rem sint w2)"
+
+definition bv_shl :: "'a::len0 word \<Rightarrow> 'a word \<Rightarrow> 'a word"
+where "bv_shl w1 w2 = (w1 << unat w2)"
+
+definition bv_lshr :: "'a::len0 word \<Rightarrow> 'a word \<Rightarrow> 'a word"
+where "bv_lshr w1 w2 = (w1 >> unat w2)"
+
+definition bv_ashr :: "'a::len word \<Rightarrow> 'a word \<Rightarrow> 'a word"
+where "bv_ashr w1 w2 = (w1 >>> unat w2)"
+
+
+section {* Higher-order encoding *}
+
+definition "apply" where "apply f x = f x"
+
+
+section {* First-order logic *}
+
+text {*
+Some SMT solver formats require a strict separation between formulas and terms.
+The following marker symbols are used internally to separate those categories:
+*}
+
+definition formula :: "bool \<Rightarrow> bool" where "formula x = x"
+definition "term" where "term x = x"
+
+text {*
+Predicate symbols also occurring as function symbols are turned into function
+symbols by translating atomic formulas into terms:
+*}
+
+abbreviation holds :: "bool \<Rightarrow> bool" where "holds \<equiv> (\<lambda>P. term P = term True)"
+
+text {*
+The following constant represents equivalence, to be treated differently than
+the (polymorphic) equality predicate:
+*}
+
+definition iff :: "bool \<Rightarrow> bool \<Rightarrow> bool" (infix "iff" 50) where
+  "(x iff y) = (x = y)"
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/cvc3_solver.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,59 @@
+(*  Title:      HOL/SMT/Tools/cvc3_solver.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Interface of the SMT solver CVC3.
+*)
+
+signature CVC3_SOLVER =
+sig
+  val setup: theory -> theory
+end
+
+structure CVC3_Solver: CVC3_SOLVER =
+struct
+
+val solver_name = "cvc3"
+val env_var = "CVC3_SOLVER"
+
+val options =
+  ["+counterexample", "-lang", "smtlib", "-output-lang", "presentation"]
+
+val is_sat = String.isPrefix "Satisfiable."
+val is_unsat = String.isPrefix "Unsatisfiable."
+val is_unknown = String.isPrefix "Unknown."
+
+fun cex_kind true = "Counterexample"
+  | cex_kind false = "Possible counterexample"
+
+fun raise_cex real ctxt recon ls =
+  let
+    val start = String.isPrefix "%Satisfiable  Variable Assignment: %"
+    val index = find_index start ls
+    val ls = if index > 0 then Library.drop (index + 1, ls) else []
+    val p = Pretty.big_list (cex_kind real ^ " found:") (map Pretty.str ls)
+  in error (Pretty.string_of p) end
+
+fun core_oracle (SMT_Solver.ProofData {context, output, recon, ...}) =
+  let
+    val empty_line = (fn "" => true | _ => false)
+    val split_first = (fn [] => ("", []) | l :: ls => (l, ls))
+    val (l, ls) = split_first (dropwhile empty_line output)
+  in
+    if is_unsat l then @{cprop False}
+    else if is_sat l then raise_cex true context recon ls
+    else if is_unknown l then raise_cex false context recon ls
+    else error (solver_name ^ " failed")
+  end
+
+fun smtlib_solver oracle _ =
+  SMT_Solver.SolverConfig {
+    name = {env_var=env_var, remote_name=solver_name},
+    interface = SMTLIB_Interface.interface,
+    arguments = options,
+    reconstruct = oracle }
+
+val setup =
+  Thm.add_oracle (Binding.name solver_name, core_oracle) #-> (fn (_, oracle) =>
+  SMT_Solver.add_solver (solver_name, smtlib_solver oracle))
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/smt_builtin.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,78 @@
+(*  Title:      HOL/SMT/Tools/smt_builtin.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Tables for built-in symbols.
+*)
+
+signature SMT_BUILTIN =
+sig
+  type sterm = (SMT_Translate.sym, typ) sterm
+  type builtin_fun = typ -> sterm list -> (string * sterm list) option
+  type table = (typ * builtin_fun) list Symtab.table
+
+  val make: (term * string) list -> table
+  val add: term * builtin_fun -> table -> table
+  val lookup: table -> theory -> string * typ -> sterm list ->
+    (string * sterm list) option
+
+  val bv_rotate: (int -> string) -> builtin_fun
+  val bv_extend: (int -> string) -> builtin_fun
+  val bv_extract: (int -> int -> string) -> builtin_fun
+end
+
+structure SMT_Builtin: SMT_BUILTIN =
+struct
+
+structure T = SMT_Translate
+
+type sterm = (SMT_Translate.sym, typ) sterm
+type builtin_fun = typ -> sterm list -> (string * sterm list) option
+type table = (typ * builtin_fun) list Symtab.table
+
+fun make entries =
+  let
+    fun dest (t, bn) =
+      let val (n, T) = Term.dest_Const t
+      in (n, (Logic.varifyT T, K (pair bn))) end
+  in Symtab.make (AList.group (op =) (map dest entries)) end
+
+fun add (t, f) tab =
+  let val (n, T) = apsnd Logic.varifyT (Term.dest_Const t)
+  in Symtab.map_default (n, []) (AList.update (op =) (T, f)) tab end
+
+fun lookup tab thy (n, T) =
+  AList.lookup (Sign.typ_instance thy) (Symtab.lookup_list tab n) T T
+
+
+fun dest_binT T =
+  (case T of
+    Type (@{type_name "Numeral_Type.num0"}, _) => 0
+  | Type (@{type_name "Numeral_Type.num1"}, _) => 1
+  | Type (@{type_name "Numeral_Type.bit0"}, [T]) => 2 * dest_binT T
+  | Type (@{type_name "Numeral_Type.bit1"}, [T]) => 1 + 2 * dest_binT T
+  | _ => raise TYPE ("dest_binT", [T], []))
+
+fun dest_wordT T =
+  (case T of
+    Type (@{type_name "word"}, [T]) => dest_binT T
+  | _ => raise TYPE ("dest_wordT", [T], []))
+
+
+val dest_nat = (fn
+    SApp (SConst (@{const_name nat}, _), [SApp (SNum (i, _), _)]) => SOME i
+  | _ => NONE)
+
+fun bv_rotate mk_name T ts =
+  dest_nat (hd ts) |> Option.map (fn i => (mk_name i, tl ts))
+
+fun bv_extend mk_name T ts =
+  (case (try dest_wordT (domain_type T), try dest_wordT (range_type T)) of
+    (SOME i, SOME j) => if j - i >= 0 then SOME (mk_name (j - i), ts) else NONE
+  | _ => NONE)
+
+fun bv_extract mk_name T ts =
+  (case (try dest_wordT (body_type T), dest_nat (hd ts)) of
+    (SOME i, SOME lb) => SOME (mk_name (i + lb - 1) lb, tl ts)
+  | _ => NONE)
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/smt_monomorph.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,120 @@
+(*  Title:      HOL/SMT/Tools/smt_monomorph.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Monomorphization of terms, i.e., computation of all (necessary) instances.
+*)
+
+signature SMT_MONOMORPH =
+sig
+  val monomorph: theory -> term list -> term list
+end
+
+structure SMT_Monomorph: SMT_MONOMORPH =
+struct
+
+fun selection [] = []
+  | selection (x :: xs) = (x, xs) :: map (apsnd (cons x)) (selection xs)
+
+fun permute [] = []
+  | permute [x] = [[x]]
+  | permute xs = maps (fn (y, ys) => map (cons y) (permute ys)) (selection xs)
+
+fun fold_all f = fold (fn x => maps (f x))
+
+
+val typ_has_tvars = Term.exists_subtype (fn TVar _ => true | _ => false)
+val term_has_tvars = Term.exists_type typ_has_tvars
+
+val ignored = member (op =) [
+  @{const_name All}, @{const_name Ex}, @{const_name Let}, @{const_name If},
+  @{const_name "op ="}, @{const_name zero_class.zero},
+  @{const_name one_class.one}, @{const_name number_of}]
+fun consts_of ts = AList.group (op =) (fold Term.add_consts ts [])
+  |> filter_out (ignored o fst)
+
+val join_consts = curry (AList.join (op =) (K (merge (op =))))
+fun diff_consts cs ds = 
+  let fun diff (n, Ts) =
+    (case AList.lookup (op =) cs n of
+      NONE => SOME (n, Ts)
+    | SOME Us =>
+        let val Ts' = fold (remove (op =)) Us Ts
+        in if null Ts' then NONE else SOME (n, Ts') end)
+  in map_filter diff ds end
+
+fun instances thy is (n, Ts) env =
+  let
+    val Us = these (AList.lookup (op =) is n)
+    val Ts' = filter typ_has_tvars (map (Envir.subst_type env) Ts)
+  in
+    (case map_product pair Ts' Us of
+      [] => [env]
+    | TUs => map_filter (try (fn TU => Sign.typ_match thy TU env)) TUs)
+  end
+
+fun proper_match ps env =
+  forall (forall (not o typ_has_tvars o Envir.subst_type env) o snd) ps
+
+val eq_tab = gen_eq_set (op =) o pairself Vartab.dest
+
+fun specialize thy cs is ((r, ps), ces) (ts, ns) =
+  let
+    val ps' = filter (AList.defined (op =) is o fst) ps
+
+    val envs = permute ps'
+      |> maps (fn ps => fold_all (instances thy is) ps [Vartab.empty])
+      |> filter (proper_match ps')
+      |> filter_out (member eq_tab ces)
+      |> distinct eq_tab
+
+    val us = map (fn env => Envir.subst_term_types env r) envs
+    val ns' = join_consts (diff_consts is (diff_consts cs (consts_of us))) ns
+  in (envs @ ces, (fold (insert (op aconv)) us ts, ns')) end
+
+
+fun incr_tvar_indices i t =
+  let
+    val incrT = Logic.incr_tvar i
+
+    fun incr t =
+      (case t of
+        Const (n, T) => Const (n, incrT T)
+      | Free (n, T) => Free (n, incrT T)
+      | Abs (n, T, t1) => Abs (n, incrT T, incr t1)
+      | t1 $ t2 => incr t1 $ incr t2
+      | _ => t)
+  in incr t end
+
+
+val monomorph_limit = 10
+
+(* Instantiate all polymorphic constants (i.e., constants occurring both with
+   ground types and type variables) with all (necessary) ground types; thereby
+   create copies of terms containing those constants.
+   To prevent non-termination, there is an upper limit for the number of
+   recursions involved in the fixpoint construction. *)
+fun monomorph thy ts =
+  let
+    val (ps, ms) = List.partition term_has_tvars ts
+
+    fun with_tvar (n, Ts) =
+      let val Ts' = filter typ_has_tvars Ts
+      in if null Ts' then NONE else SOME (n, Ts') end
+    fun incr t idx = (incr_tvar_indices idx t, idx + Term.maxidx_of_term t + 1)
+    val rps = fst (fold_map incr ps 0)
+      |> map (fn r => (r, map_filter with_tvar (consts_of [r])))
+
+    fun mono count is ces cs ts =
+      let
+        val spec = specialize thy cs is
+        val (ces', (ts', is')) = fold_map spec (rps ~~ ces) (ts, [])
+        val cs' = join_consts is cs
+      in
+        if null is' then ts'
+        else if count > monomorph_limit then
+          (Output.warning "monomorphization limit reached"; ts')
+        else mono (count + 1) is' ces' cs' ts'
+      end
+  in mono 0 (consts_of ms) (map (K []) rps) [] ms end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/smt_normalize.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,408 @@
+(*  Title:      HOL/SMT/Tools/smt_normalize.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Normalization steps on theorems required by SMT solvers:
+  * unfold trivial let expressions,
+  * replace negative numerals by negated positive numerals,
+  * embed natural numbers into integers,
+  * add extra rules specifying types and constants which occur frequently,
+  * lift lambda terms,
+  * make applications explicit for functions with varying number of arguments,
+  * fully translate into object logic, add universal closure. 
+*)
+
+signature SMT_NORMALIZE =
+sig
+  val normalize_rule: Proof.context -> thm -> thm
+  val instantiate_free: Thm.cterm * Thm.cterm -> thm -> thm
+  val discharge_definition: Thm.cterm -> thm -> thm
+
+  val trivial_let: Proof.context -> thm list -> thm list
+  val positive_numerals: Proof.context -> thm list -> thm list
+  val nat_as_int: Proof.context -> thm list -> thm list
+  val unfold_defs: bool Config.T
+  val add_pair_rules: Proof.context -> thm list -> thm list
+  val add_fun_upd_rules: Proof.context -> thm list -> thm list
+  val add_abs_min_max_rules: Proof.context -> thm list -> thm list
+
+  datatype config =
+    RewriteTrivialLets |
+    RewriteNegativeNumerals |
+    RewriteNaturalNumbers |
+    AddPairRules |
+    AddFunUpdRules |
+    AddAbsMinMaxRules
+
+  val normalize: config list -> Proof.context -> thm list ->
+    Thm.cterm list * thm list
+
+  val setup: theory -> theory
+end
+
+structure SMT_Normalize: SMT_NORMALIZE =
+struct
+
+val norm_binder_conv = Conv.try_conv (More_Conv.rewrs_conv [
+  @{lemma "All P == ALL x. P x" by (rule reflexive)},
+  @{lemma "Ex P == EX x. P x" by (rule reflexive)},
+  @{lemma "Let c P == let x = c in P x" by (rule reflexive)}])
+
+fun cert ctxt = Thm.cterm_of (ProofContext.theory_of ctxt)
+
+fun norm_meta_def cv thm = 
+  let val thm' = Thm.combination thm (Thm.reflexive cv)
+  in Thm.transitive thm' (Thm.beta_conversion false (Thm.rhs_of thm')) end
+
+fun norm_def ctxt thm =
+  (case Thm.prop_of thm of
+    Const (@{const_name "=="}, _) $ _ $ Abs (_, T, _) =>
+      let val v = Var ((Name.uu, #maxidx (Thm.rep_thm thm) + 1), T)
+      in norm_def ctxt (norm_meta_def (cert ctxt v) thm) end
+  | @{term Trueprop} $ (Const (@{const_name "op ="}, _) $ _ $ Abs _) =>
+      norm_def ctxt (thm RS @{thm fun_cong})
+  | _ => thm)
+
+fun normalize_rule ctxt =
+  Conv.fconv_rule (
+    Thm.beta_conversion true then_conv
+    Thm.eta_conversion then_conv
+    More_Conv.bottom_conv (K norm_binder_conv) ctxt) #>
+  norm_def ctxt #>
+  Drule.forall_intr_vars #>
+  Conv.fconv_rule ObjectLogic.atomize
+
+fun instantiate_free (cv, ct) thm =
+  if Term.exists_subterm (equal (Thm.term_of cv)) (Thm.prop_of thm)
+  then Thm.forall_elim ct (Thm.forall_intr cv thm)
+  else thm
+
+fun discharge_definition ct thm =
+  let val (cv, cu) = Thm.dest_equals ct
+  in
+    Thm.implies_intr ct thm
+    |> instantiate_free (cv, cu)
+    |> (fn thm => Thm.implies_elim thm (Thm.reflexive cu))
+  end
+
+fun if_conv c cv1 cv2 ct = (if c (Thm.term_of ct) then cv1 else cv2) ct
+fun if_true_conv c cv = if_conv c cv Conv.all_conv
+
+
+(* simplification of trivial let expressions (whose bound variables occur at
+   most once) *)
+
+local
+  fun count i (Bound j) = if j = i then 1 else 0
+    | count i (t $ u) = count i t + count i u
+    | count i (Abs (_, _, t)) = count (i + 1) t
+    | count _ _ = 0
+
+  fun is_trivial_let (Const (@{const_name Let}, _) $ _ $ Abs (_, _, t)) =
+        (count 0 t <= 1)
+    | is_trivial_let _ = false
+
+  fun let_conv _ = if_true_conv is_trivial_let (Conv.rewr_conv @{thm Let_def})
+
+  fun cond_let_conv ctxt = if_true_conv (Term.exists_subterm is_trivial_let)
+    (More_Conv.top_conv let_conv ctxt)
+in
+fun trivial_let ctxt = map (Conv.fconv_rule (cond_let_conv ctxt))
+end
+
+
+(* rewriting of negative integer numerals into positive numerals *)
+
+local
+  fun neg_numeral @{term Int.Min} = true
+    | neg_numeral _ = false
+  fun is_number_sort thy T = Sign.of_sort thy (T, @{sort number_ring})
+  fun is_neg_number ctxt (Const (@{const_name number_of}, T) $ t) =
+        Term.exists_subterm neg_numeral t andalso
+        is_number_sort (ProofContext.theory_of ctxt) (Term.body_type T)
+    | is_neg_number _ _ = false
+  fun has_neg_number ctxt = Term.exists_subterm (is_neg_number ctxt)
+
+  val pos_numeral_ss = HOL_ss
+    addsimps [@{thm Int.number_of_minus}, @{thm Int.number_of_Min}]
+    addsimps [@{thm Int.numeral_1_eq_1}]
+    addsimps @{thms Int.pred_bin_simps}
+    addsimps @{thms Int.normalize_bin_simps}
+    addsimps @{lemma
+      "Int.Min = - Int.Bit1 Int.Pls"
+      "Int.Bit0 (- Int.Pls) = - Int.Pls"
+      "Int.Bit0 (- k) = - Int.Bit0 k"
+      "Int.Bit1 (- k) = - Int.Bit1 (Int.pred k)"
+      by simp_all (simp add: pred_def)}
+
+  fun pos_conv ctxt = if_conv (is_neg_number ctxt)
+    (Simplifier.rewrite (Simplifier.context ctxt pos_numeral_ss))
+    Conv.no_conv
+
+  fun cond_pos_conv ctxt = if_true_conv (has_neg_number ctxt)
+    (More_Conv.top_sweep_conv pos_conv ctxt)
+in
+fun positive_numerals ctxt = map (Conv.fconv_rule (cond_pos_conv ctxt))
+end
+
+
+(* embedding of standard natural number operations into integer operations *)
+
+local
+  val nat_embedding = @{lemma
+    "nat (int n) = n"
+    "i >= 0 --> int (nat i) = i"
+    "i < 0 --> int (nat i) = 0"
+    by simp_all}
+
+  val nat_rewriting = @{lemma
+    "0 = nat 0"
+    "1 = nat 1"
+    "number_of i = nat (number_of i)"
+    "int (nat 0) = 0"
+    "int (nat 1) = 1"
+    "a < b = (int a < int b)"
+    "a <= b = (int a <= int b)"
+    "Suc a = nat (int a + 1)"
+    "a + b = nat (int a + int b)"
+    "a - b = nat (int a - int b)"
+    "a * b = nat (int a * int b)"
+    "a div b = nat (int a div int b)"
+    "a mod b = nat (int a mod int b)"
+    "int (nat (int a + int b)) = int a + int b"
+    "int (nat (int a * int b)) = int a * int b"
+    "int (nat (int a div int b)) = int a div int b"
+    "int (nat (int a mod int b)) = int a mod int b"
+    by (simp add: nat_mult_distrib nat_div_distrib nat_mod_distrib
+      int_mult[symmetric] zdiv_int[symmetric] zmod_int[symmetric])+}
+
+  fun on_positive num f x = 
+    (case try HOLogic.dest_number (Thm.term_of num) of
+      SOME (_, i) => if i >= 0 then SOME (f x) else NONE
+    | NONE => NONE)
+
+  val cancel_int_nat_ss = HOL_ss
+    addsimps [@{thm Nat_Numeral.nat_number_of}]
+    addsimps [@{thm Nat_Numeral.int_nat_number_of}]
+    addsimps @{thms neg_simps}
+
+  fun cancel_int_nat_simproc _ ss ct = 
+    let
+      val num = Thm.dest_arg (Thm.dest_arg ct)
+      val goal = Thm.mk_binop @{cterm "op == :: int => _"} ct num
+      val simpset = Simplifier.inherit_context ss cancel_int_nat_ss
+      fun tac _ = Simplifier.simp_tac simpset 1
+    in on_positive num (Goal.prove_internal [] goal) tac end
+
+  val nat_ss = HOL_ss
+    addsimps nat_rewriting
+    addsimprocs [Simplifier.make_simproc {
+      name = "cancel_int_nat_num", lhss = [@{cpat "int (nat _)"}],
+      proc = cancel_int_nat_simproc, identifier = [] }]
+
+  fun conv ctxt = Simplifier.rewrite (Simplifier.context ctxt nat_ss)
+
+  val uses_nat_type = Term.exists_type (Term.exists_subtype (equal @{typ nat}))
+in
+fun nat_as_int ctxt thms =
+  let
+    fun norm thm uses_nat =
+      if not (uses_nat_type (Thm.prop_of thm)) then (thm, uses_nat)
+      else (Conv.fconv_rule (conv ctxt) thm, true)
+    val (thms', uses_nat) = fold_map norm thms false
+  in if uses_nat then nat_embedding @ thms' else thms' end
+end
+
+
+(* include additional rules *)
+
+val (unfold_defs, unfold_defs_setup) =
+  Attrib.config_bool "smt_unfold_defs" true
+
+local
+  val pair_rules = [@{thm fst_conv}, @{thm snd_conv}, @{thm pair_collapse}]
+
+  val pair_type = (fn Type (@{type_name "*"}, _) => true | _ => false)
+  val exists_pair_type = Term.exists_type (Term.exists_subtype pair_type)
+
+  val fun_upd_rules = [@{thm fun_upd_same}, @{thm fun_upd_apply}]
+  val is_fun_upd = (fn Const (@{const_name fun_upd}, _) => true | _ => false)
+  val exists_fun_upd = Term.exists_subterm is_fun_upd
+in
+fun add_pair_rules _ thms =
+  thms
+  |> exists (exists_pair_type o Thm.prop_of) thms ? append pair_rules
+
+fun add_fun_upd_rules _ thms =
+  thms
+  |> exists (exists_fun_upd o Thm.prop_of) thms ? append fun_upd_rules
+end
+
+
+local
+  fun mk_entry t thm = (Term.head_of t, (thm, thm RS @{thm eq_reflection}))
+  fun prepare_def thm =
+    (case HOLogic.dest_Trueprop (Thm.prop_of thm) of
+      Const (@{const_name "op ="}, _) $ t $ _ => mk_entry t thm
+    | t => raise TERM ("prepare_def", [t]))
+
+  val defs = map prepare_def [
+    @{thm abs_if[where 'a = int]}, @{thm abs_if[where 'a = real]},
+    @{thm min_def[where 'a = int]}, @{thm min_def[where 'a = real]},
+    @{thm max_def[where 'a = int]}, @{thm max_def[where 'a = real]}]
+
+  fun add_sym t = if AList.defined (op =) defs t then insert (op =) t else I
+  fun add_syms thms = fold (Term.fold_aterms add_sym o Thm.prop_of) thms []
+
+  fun unfold_conv ctxt ct =
+    (case AList.lookup (op =) defs (Term.head_of (Thm.term_of ct)) of
+      SOME (_, eq) => Conv.rewr_conv eq
+    | NONE => Conv.all_conv) ct
+in
+fun add_abs_min_max_rules ctxt thms =
+  if Config.get ctxt unfold_defs
+  then map (Conv.fconv_rule (More_Conv.bottom_conv unfold_conv ctxt)) thms
+  else map fst (map_filter (AList.lookup (op =) defs) (add_syms thms)) @ thms
+end
+
+
+(* lift lambda terms into additional rules *)
+
+local
+  val meta_eq = @{cpat "op =="}
+  val meta_eqT = hd (Thm.dest_ctyp (Thm.ctyp_of_term meta_eq))
+  fun inst_meta cT = Thm.instantiate_cterm ([(meta_eqT, cT)], []) meta_eq
+  fun mk_meta_eq ct cu = Thm.mk_binop (inst_meta (Thm.ctyp_of_term ct)) ct cu
+
+  fun lambda_conv conv =
+    let
+      fun sub_conv cvs ctxt ct =
+        (case Thm.term_of ct of
+          Const (@{const_name All}, _) $ Abs _ => quant_conv cvs ctxt
+        | Const (@{const_name Ex}, _) $ Abs _ => quant_conv cvs ctxt
+        | Const _ $ Abs _ => Conv.arg_conv (at_lambda_conv cvs ctxt)
+        | Const (@{const_name Let}, _) $ _ $ Abs _ => Conv.combination_conv
+            (Conv.arg_conv (sub_conv cvs ctxt)) (abs_conv cvs ctxt)
+        | Abs _ => at_lambda_conv cvs ctxt
+        | _ $ _ => Conv.comb_conv (sub_conv cvs ctxt)
+        | _ => Conv.all_conv) ct
+      and abs_conv cvs = Conv.abs_conv (fn (cv, cx) => sub_conv (cv::cvs) cx)
+      and quant_conv cvs ctxt = Conv.arg_conv (abs_conv cvs ctxt)
+      and at_lambda_conv cvs ctxt = abs_conv cvs ctxt then_conv conv cvs ctxt
+    in sub_conv [] end
+
+  fun used_vars cvs ct =
+    let
+      val lookup = AList.lookup (op aconv) (map (` Thm.term_of) cvs)
+      val add = (fn (SOME ct) => insert (op aconvc) ct | _ => I)
+    in Term.fold_aterms (add o lookup) (Thm.term_of ct) [] end
+
+  val rev_int_fst_ord = rev_order o int_ord o pairself fst
+  fun ordered_values tab =
+    Termtab.fold (fn (_, x) => OrdList.insert rev_int_fst_ord x) tab []
+    |> map snd
+in
+fun lift_lambdas ctxt thms =
+  let
+    val declare_frees = fold (Thm.fold_terms Term.declare_term_frees)
+    val names = ref (declare_frees thms (Name.make_context []))
+    val fresh_name = change_result names o yield_singleton Name.variants
+
+    val defs = ref (Termtab.empty : (int * thm) Termtab.table)
+    fun add_def t thm = change defs (Termtab.update (t, (serial (), thm)))
+    fun make_def cvs eq = Thm.symmetric (fold norm_meta_def cvs eq)
+    fun def_conv cvs ctxt ct =
+      let
+        val cvs' = used_vars cvs ct
+        val ct' = fold Thm.cabs cvs' ct
+      in
+        (case Termtab.lookup (!defs) (Thm.term_of ct') of
+          SOME (_, eq) => make_def cvs' eq
+        | NONE =>
+            let
+              val {t, T, ...} = Thm.rep_cterm ct'
+              val eq = mk_meta_eq (cert ctxt (Free (fresh_name "", T))) ct'
+              val thm = Thm.assume eq
+            in (add_def t thm; make_def cvs' thm) end)
+      end
+    val thms' = map (Conv.fconv_rule (lambda_conv def_conv ctxt)) thms
+    val eqs = ordered_values (!defs)
+  in
+    (maps (#hyps o Thm.crep_thm) eqs, map (normalize_rule ctxt) eqs @ thms')
+  end
+end
+
+
+(* make application explicit for functions with varying number of arguments *)
+
+local
+  val const = prefix "c" and free = prefix "f"
+  fun min i (e as (_, j)) = if i <> j then (true, Int.min (i, j)) else e
+  fun add t i = Symtab.map_default (t, (false, i)) (min i)
+  fun traverse t =
+    (case Term.strip_comb t of
+      (Const (n, _), ts) => add (const n) (length ts) #> fold traverse ts 
+    | (Free (n, _), ts) => add (free n) (length ts) #> fold traverse ts
+    | (Abs (_, _, u), ts) => fold traverse (u :: ts)
+    | (_, ts) => fold traverse ts)
+  val prune = (fn (n, (true, i)) => Symtab.update (n, i) | _ => I)
+  fun prune_tab tab = Symtab.fold prune tab Symtab.empty
+
+  fun binop_conv cv1 cv2 = Conv.combination_conv (Conv.arg_conv cv1) cv2
+  fun nary_conv conv1 conv2 ct =
+    (Conv.combination_conv (nary_conv conv1 conv2) conv2 else_conv conv1) ct
+  fun abs_conv conv tb = Conv.abs_conv (fn (cv, cx) =>
+    let val n = fst (Term.dest_Free (Thm.term_of cv))
+    in conv (Symtab.update (free n, 0) tb) cx end)
+  val apply_rule = @{lemma "f x == apply f x" by (simp add: apply_def)}
+in
+fun explicit_application ctxt thms =
+  let
+    fun sub_conv tb ctxt ct =
+      (case Term.strip_comb (Thm.term_of ct) of
+        (Const (n, _), ts) => app_conv tb (const n) (length ts) ctxt
+      | (Free (n, _), ts) => app_conv tb (free n) (length ts) ctxt
+      | (Abs _, ts) => nary_conv (abs_conv sub_conv tb ctxt) (sub_conv tb ctxt)
+      | (_, ts) => nary_conv Conv.all_conv (sub_conv tb ctxt)) ct
+    and app_conv tb n i ctxt =
+      (case Symtab.lookup tb n of
+        NONE => nary_conv Conv.all_conv (sub_conv tb ctxt)
+      | SOME j => apply_conv tb ctxt (i - j))
+    and apply_conv tb ctxt i ct = (
+      if i = 0 then nary_conv Conv.all_conv (sub_conv tb ctxt)
+      else
+        Conv.rewr_conv apply_rule then_conv
+        binop_conv (apply_conv tb ctxt (i-1)) (sub_conv tb ctxt)) ct
+
+    val tab = prune_tab (fold (traverse o Thm.prop_of) thms Symtab.empty)
+  in map (Conv.fconv_rule (sub_conv tab ctxt)) thms end
+end
+
+
+(* combined normalization *)
+
+datatype config =
+  RewriteTrivialLets |
+  RewriteNegativeNumerals |
+  RewriteNaturalNumbers |
+  AddPairRules |
+  AddFunUpdRules |
+  AddAbsMinMaxRules
+
+fun normalize config ctxt thms =
+  let fun if_enabled c f = member (op =) config c ? f ctxt
+  in
+    thms
+    |> if_enabled RewriteTrivialLets trivial_let
+    |> if_enabled RewriteNegativeNumerals positive_numerals
+    |> if_enabled RewriteNaturalNumbers nat_as_int
+    |> if_enabled AddPairRules add_pair_rules
+    |> if_enabled AddFunUpdRules add_fun_upd_rules
+    |> if_enabled AddAbsMinMaxRules add_abs_min_max_rules
+    |> map (normalize_rule ctxt)
+    |> lift_lambdas ctxt
+    |> apsnd (explicit_application ctxt)
+  end
+
+val setup = unfold_defs_setup
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/smt_solver.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,248 @@
+(*  Title:      HOL/SMT/Tools/smt_solver.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+SMT solvers registry and SMT tactic.
+*)
+
+signature SMT_SOLVER =
+sig
+  exception SMT_COUNTEREXAMPLE of bool * term list
+
+  datatype interface = Interface of {
+    normalize: SMT_Normalize.config list,
+    translate: SMT_Translate.config }
+
+  datatype proof_data = ProofData of {
+    context: Proof.context,
+    output: string list,
+    recon: SMT_Translate.recon,
+    assms: thm list option }
+
+  datatype solver_config = SolverConfig of {
+    name: {env_var: string, remote_name: string},
+    interface: interface,
+    arguments: string list,
+    reconstruct: proof_data -> thm }
+
+  (*options*)
+  val timeout: int Config.T
+  val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
+  val trace: bool Config.T
+  val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
+
+  (*solvers*)
+  type solver = Proof.context -> thm list -> thm
+  type solver_info = Context.generic -> Pretty.T list
+  val add_solver: string * (Proof.context -> solver_config) -> theory ->
+    theory
+  val all_solver_names_of: theory -> string list
+  val add_solver_info: string * solver_info -> theory -> theory
+  val solver_name_of: Context.generic -> string
+  val select_solver: string -> Context.generic -> Context.generic
+  val solver_of: Context.generic -> solver
+
+  (*tactic*)
+  val smt_tac': bool -> Proof.context -> thm list -> int -> Tactical.tactic
+  val smt_tac: Proof.context -> thm list -> int -> Tactical.tactic
+
+  (*setup*)
+  val setup: theory -> theory
+  val print_setup: Context.generic -> unit
+end
+
+structure SMT_Solver: SMT_SOLVER =
+struct
+
+exception SMT_COUNTEREXAMPLE of bool * term list
+
+val theory_of = Context.cases I ProofContext.theory_of
+
+
+datatype interface = Interface of {
+  normalize: SMT_Normalize.config list,
+  translate: SMT_Translate.config }
+
+datatype proof_data = ProofData of {
+  context: Proof.context,
+  output: string list,
+  recon: SMT_Translate.recon,
+  assms: thm list option }
+
+datatype solver_config = SolverConfig of {
+  name: {env_var: string, remote_name: string},
+  interface: interface,
+  arguments: string list,
+  reconstruct: proof_data -> thm }
+
+
+(* SMT options *)
+
+val (timeout, setup_timeout) = Attrib.config_int "smt_timeout" 30
+
+fun with_timeout ctxt f x =
+  TimeLimit.timeLimit (Time.fromSeconds (Config.get ctxt timeout)) f x
+  handle TimeLimit.TimeOut => error ("SMT: timeout")
+
+val (trace, setup_trace) = Attrib.config_bool "smt_trace" false
+
+fun trace_msg ctxt f x =
+  if Config.get ctxt trace then Output.tracing (f x) else ()
+
+
+(* interface to external solvers *)
+
+local
+
+fun with_tmp_files f x =
+  let
+    fun tmp_path () = File.tmp_path (Path.explode ("smt-" ^ serial_string ()))
+    val in_path = tmp_path () and out_path = tmp_path ()
+    val y = Exn.capture (f in_path out_path) x
+    val _ = try File.rm in_path and _ = try File.rm out_path
+  in Exn.release y end
+
+fun run in_path out_path (ctxt, cmd, output) =
+  let
+    val x = File.open_output output in_path
+    val _ = trace_msg ctxt File.read in_path
+
+    val _ = with_timeout ctxt system_out (cmd in_path out_path)
+    fun lines_of path = the_default [] (try (File.fold_lines cons out_path) [])
+    val ls = rev (dropwhile (equal "") (lines_of out_path))
+    val _ = trace_msg ctxt cat_lines ls
+  in (x, ls) end
+
+in
+
+fun run_solver ctxt {env_var, remote_name} args output =
+  let
+    val qf = File.shell_path and qq = enclose "'" "'"
+    val path = getenv env_var and remote = getenv "REMOTE_SMT_SOLVER"
+    fun cmd f1 f2 =
+      if path <> ""
+      then map qq (path :: args) @ [qf f1, ">", qf f2]
+      else map qq (remote :: remote_name :: args) @ [qf f1, qf f2]
+  in with_tmp_files run (ctxt, space_implode " " oo cmd, output) end
+
+end
+
+fun make_proof_data ctxt ((recon, thms), ls) =
+  ProofData {context=ctxt, output=ls, recon=recon, assms=SOME thms}
+
+fun gen_solver solver ctxt prems =
+  let
+    val SolverConfig {name, interface, arguments, reconstruct} = solver ctxt
+    val Interface {normalize=nc, translate=tc} = interface
+    val thy = ProofContext.theory_of ctxt
+  in
+    SMT_Normalize.normalize nc ctxt prems
+    ||> run_solver ctxt name arguments o SMT_Translate.translate tc thy
+    ||> reconstruct o make_proof_data ctxt
+    |-> fold SMT_Normalize.discharge_definition
+  end
+
+
+(* solver store *)
+
+type solver = Proof.context -> thm list -> thm
+type solver_info = Context.generic -> Pretty.T list
+
+structure Solvers = TheoryDataFun
+(
+  type T = ((Proof.context -> solver_config) * solver_info) Symtab.table
+  val empty = Symtab.empty
+  val copy = I
+  val extend = I
+  fun merge _ = Symtab.merge (K true)
+    handle Symtab.DUP name => error ("Duplicate SMT solver: " ^ quote name)
+)
+
+val no_solver = "(none)"
+val add_solver = Solvers.map o Symtab.update_new o apsnd (rpair (K []))
+val all_solver_names_of = Symtab.keys o Solvers.get
+val lookup_solver = Symtab.lookup o Solvers.get
+fun add_solver_info (n, i) = Solvers.map (Symtab.map_entry n (apsnd (K i)))
+
+
+(* selected solver *)
+
+structure SelectedSolver = GenericDataFun
+(
+  type T = serial * string
+  val empty = (serial (), no_solver)
+  val extend = I
+  fun merge _ (sl1 as (s1, _), sl2 as (s2, _)) = if s1 > s2 then sl1 else sl2
+)
+
+val solver_name_of = snd o SelectedSolver.get
+
+fun select_solver name gen =
+  if is_none (lookup_solver (theory_of gen) name)
+  then error ("SMT solver not registered: " ^ quote name)
+  else SelectedSolver.map (K (serial (), name)) gen
+
+fun raw_solver_of gen =
+  (case lookup_solver (theory_of gen) (solver_name_of gen) of
+    NONE => error "No SMT solver selected"
+  | SOME (s, _) => s)
+
+val solver_of = gen_solver o raw_solver_of
+
+
+(* SMT tactic *)
+
+fun smt_unsat_tac solver ctxt rules =
+  Tactic.rtac @{thm ccontr} THEN'
+  SUBPROOF (fn {context, prems, ...} =>
+    Tactic.rtac (solver context (rules @ prems)) 1) ctxt
+
+fun pretty_counterex ctxt (real, ex) =
+  let
+    val msg = if real then "Counterexample found:"
+      else "Potential counterexample found:"
+    val cex = if null ex then [Pretty.str "(no assignments)"]
+      else map (Syntax.pretty_term ctxt) ex
+  in Pretty.string_of (Pretty.big_list msg cex) end
+
+fun smt_tac' pass_smt_exns ctxt =
+  let
+    val solver = solver_of (Context.Proof ctxt)
+    fun safe_solver ctxt thms = solver ctxt thms
+      handle SMT_COUNTEREXAMPLE cex => error (pretty_counterex ctxt cex)
+    val solver' = if pass_smt_exns then solver else safe_solver
+  in smt_unsat_tac solver' ctxt end
+
+val smt_tac = smt_tac' false
+
+
+(* setup *)
+
+val setup =
+  Attrib.setup (Binding.name "smt_solver")
+    (Scan.lift (OuterParse.$$$ "=" |-- Args.name) >>
+      (Thm.declaration_attribute o K o select_solver))
+    "SMT solver configuration" #>
+  setup_timeout #>
+  setup_trace
+
+fun print_setup gen =
+  let
+    val t = string_of_int (Config.get_generic gen timeout)
+    val names = sort string_ord (all_solver_names_of (theory_of gen))
+    val ns = if null names then [no_solver] else names
+    val take_info = (fn (_, []) => NONE | info => SOME info)
+    val infos =
+      theory_of gen
+      |> Symtab.dest o Solvers.get
+      |> map_filter (fn (n, (_, info)) => take_info (n, info gen))
+      |> sort (prod_ord string_ord (K EQUAL))
+      |> map (fn (n, ps) => Pretty.big_list (n ^ ":") ps)
+  in
+    Pretty.writeln (Pretty.big_list "SMT setup:" [
+      Pretty.str ("Current SMT solver: " ^ solver_name_of gen),
+      Pretty.str_list "Available SMT solvers: "  "" ns,
+      Pretty.str ("Current timeout: " ^ t ^ " seconds"),
+      Pretty.big_list "Solver-specific settings:" infos])
+  end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/smt_translate.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,507 @@
+(*  Title:      HOL/SMT/Tools/smt_translate.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Translate theorems into an SMT intermediate format and serialize them,
+depending on an SMT interface.
+*)
+
+signature SMT_TRANSLATE =
+sig
+  (* intermediate term structure *)
+  datatype sym =
+    SConst of string * typ |
+    SFree of string * typ |
+    SNum of int * typ
+  datatype squant = SForall | SExists
+  datatype 'a spattern = SPat of 'a list | SNoPat of 'a list
+  datatype ('a, 'b) sterm =
+    SVar of int |
+    SApp of 'a * ('a, 'b) sterm list |
+    SLet of (string * 'b) * ('a, 'b) sterm * ('a, 'b) sterm |
+    SQuant of squant * (string * 'b) list * ('a, 'b) sterm spattern list *
+      ('a, 'b) sterm
+
+  (* table for built-in symbols *)
+  type builtin_fun = typ -> (sym, typ) sterm list ->
+    (string * (sym, typ) sterm list) option
+  type builtin_table = (typ * builtin_fun) list Symtab.table
+  val builtin_make: (term * string) list -> builtin_table
+  val builtin_add: term * builtin_fun -> builtin_table -> builtin_table
+  val builtin_lookup: builtin_table -> theory -> string * typ ->
+    (sym, typ) sterm list -> (string * (sym, typ) sterm list) option
+  val bv_rotate: (int -> string) -> builtin_fun
+  val bv_extend: (int -> string) -> builtin_fun
+  val bv_extract: (int -> int -> string) -> builtin_fun
+
+  (* configuration options *)
+  datatype prefixes = Prefixes of {
+    var_prefix: string,
+    typ_prefix: string,
+    fun_prefix: string,
+    pred_prefix: string }
+  datatype markers = Markers of {
+    term_marker: string,
+    formula_marker: string }
+  datatype builtins = Builtins of {
+    builtin_typ: typ -> string option,
+    builtin_num: int * typ -> string option,
+    builtin_fun: bool -> builtin_table }
+  datatype sign = Sign of {
+    typs: string list,
+    funs: (string * (string list * string)) list,
+    preds: (string * string list) list }
+  datatype config = Config of {
+    strict: bool,
+    prefixes: prefixes,
+    markers: markers,
+    builtins: builtins,
+    serialize: sign -> (string, string) sterm list -> TextIO.outstream -> unit}
+  datatype recon = Recon of {typs: typ Symtab.table, terms: term Symtab.table}
+
+  val translate: config -> theory -> thm list -> TextIO.outstream ->
+    recon * thm list
+
+  val dest_binT: typ -> int
+  val dest_funT: int -> typ -> typ list * typ
+end
+
+structure SMT_Translate: SMT_TRANSLATE =
+struct
+
+(* Intermediate term structure *)
+
+datatype sym =
+  SConst of string * typ |
+  SFree of string * typ |
+  SNum of int * typ
+datatype squant = SForall | SExists
+datatype 'a spattern = SPat of 'a list | SNoPat of 'a list
+datatype ('a, 'b) sterm =
+  SVar of int |
+  SApp of 'a * ('a, 'b) sterm list |
+  SLet of (string * 'b) * ('a, 'b) sterm * ('a, 'b) sterm |
+  SQuant of squant * (string * 'b) list * ('a, 'b) sterm spattern list *
+    ('a, 'b) sterm
+
+fun app c ts = SApp (c, ts)
+
+fun map_pat f (SPat ps) = SPat (map f ps)
+  | map_pat f (SNoPat ps) = SNoPat (map f ps)
+
+fun fold_map_pat f (SPat ps) = fold_map f ps #>> SPat
+  | fold_map_pat f (SNoPat ps) = fold_map f ps #>> SNoPat
+
+val make_sconst = SConst o Term.dest_Const
+
+
+(* General type destructors. *)
+
+fun dest_binT T =
+  (case T of
+    Type (@{type_name "Numeral_Type.num0"}, _) => 0
+  | Type (@{type_name "Numeral_Type.num1"}, _) => 1
+  | Type (@{type_name "Numeral_Type.bit0"}, [T]) => 2 * dest_binT T
+  | Type (@{type_name "Numeral_Type.bit1"}, [T]) => 1 + 2 * dest_binT T
+  | _ => raise TYPE ("dest_binT", [T], []))
+
+val dest_wordT = (fn
+    Type (@{type_name "word"}, [T]) => dest_binT T
+  | T => raise TYPE ("dest_wordT", [T], []))
+
+val dest_funT =
+  let
+    fun dest Ts 0 T = (rev Ts, T)
+      | dest Ts i (Type ("fun", [T, U])) = dest (T::Ts) (i-1) U
+      | dest _ _ T = raise TYPE ("dest_funT", [T], [])
+  in dest [] end
+
+
+(* Table for built-in symbols *)
+
+type builtin_fun = typ -> (sym, typ) sterm list ->
+  (string * (sym, typ) sterm list) option
+type builtin_table = (typ * builtin_fun) list Symtab.table
+
+fun builtin_make entries =
+  let
+    fun dest (t, bn) =
+      let val (n, T) = Term.dest_Const t
+      in (n, (Logic.varifyT T, K (SOME o pair bn))) end
+  in Symtab.make (AList.group (op =) (map dest entries)) end
+
+fun builtin_add (t, f) tab =
+  let val (n, T) = apsnd Logic.varifyT (Term.dest_Const t)
+  in Symtab.map_default (n, []) (AList.update (op =) (T, f)) tab end
+
+fun builtin_lookup tab thy (n, T) ts =
+  AList.lookup (Sign.typ_instance thy) (Symtab.lookup_list tab n) T
+  |> (fn SOME f => f T ts | NONE => NONE)
+
+local
+  val dest_nat = (fn
+      SApp (SConst (@{const_name nat}, _), [SApp (SNum (i, _), _)]) => SOME i
+    | _ => NONE)
+in
+fun bv_rotate mk_name T ts =
+  dest_nat (hd ts) |> Option.map (fn i => (mk_name i, tl ts))
+
+fun bv_extend mk_name T ts =
+  (case (try dest_wordT (domain_type T), try dest_wordT (range_type T)) of
+    (SOME i, SOME j) => if j - i >= 0 then SOME (mk_name (j - i), ts) else NONE
+  | _ => NONE)
+
+fun bv_extract mk_name T ts =
+  (case (try dest_wordT (body_type T), dest_nat (hd ts)) of
+    (SOME i, SOME lb) => SOME (mk_name (i + lb - 1) lb, tl ts)
+  | _ => NONE)
+end
+
+
+(* Configuration options *)
+
+datatype prefixes = Prefixes of {
+  var_prefix: string,
+  typ_prefix: string,
+  fun_prefix: string,
+  pred_prefix: string }
+datatype markers = Markers of {
+  term_marker: string,
+  formula_marker: string }
+datatype builtins = Builtins of {
+  builtin_typ: typ -> string option,
+  builtin_num: int * typ -> string option,
+  builtin_fun: bool -> builtin_table }
+datatype sign = Sign of {
+  typs: string list,
+  funs: (string * (string list * string)) list,
+  preds: (string * string list) list }
+datatype config = Config of {
+  strict: bool,
+  prefixes: prefixes,
+  markers: markers,
+  builtins: builtins,
+  serialize: sign -> (string, string) sterm list -> TextIO.outstream -> unit}
+datatype recon = Recon of {typs: typ Symtab.table, terms: term Symtab.table}
+
+
+(* Translate Isabelle/HOL terms into SMT intermediate terms.
+   We assume that lambda-lifting has been performed before, i.e., lambda
+   abstractions occur only at quantifiers and let expressions.
+*)
+local
+  val quantifier = (fn
+      @{const_name All} => SOME SForall
+    | @{const_name Ex} => SOME SExists
+    | _ => NONE)
+
+  fun group_quant qname vs (t as Const (q, _) $ Abs (n, T, u)) =
+        if q = qname then group_quant qname ((n, T) :: vs) u else (vs, t)
+    | group_quant qname vs t = (vs, t)
+
+  fun dest_trigger (@{term trigger} $ tl $ t) = (HOLogic.dest_list tl, t)
+    | dest_trigger t = ([], t)
+
+  fun pat f ps (Const (@{const_name pat}, _) $ p) = SPat (rev (f p :: ps))
+    | pat f ps (Const (@{const_name nopat}, _) $ p) = SNoPat (rev (f p :: ps))
+    | pat f ps (Const (@{const_name andpat}, _) $ p $ t) = pat f (f p :: ps) t
+    | pat _ _ t = raise TERM ("pat", [t])
+
+  fun trans Ts t =
+    (case Term.strip_comb t of
+      (t1 as Const (qn, qT), [t2 as Abs (n, T, t3)]) =>
+        (case quantifier qn of
+          SOME q =>
+            let
+              val (vs, u) = group_quant qn [(n, T)] t3
+              val Us = map snd vs @ Ts
+              val (ps, b) = dest_trigger u
+            in SQuant (q, rev vs, map (pat (trans Us) []) ps, trans Us b) end
+        | NONE => raise TERM ("intermediate", [t]))
+    | (Const (@{const_name Let}, _), [t1, Abs (n, T, t2)]) =>
+        SLet ((n, T), trans Ts t1, trans (T :: Ts) t2)
+    | (Const (c as (@{const_name distinct}, _)), [t1]) =>
+        (* this is not type-correct, but will be corrected at a later stage *)
+        SApp (SConst c, map (trans Ts) (HOLogic.dest_list t1))
+    | (Const c, ts) =>
+        (case try HOLogic.dest_number t of
+          SOME (T, i) => SApp (SNum (i, T), [])
+        | NONE => SApp (SConst c, map (trans Ts) ts))
+    | (Free c, ts) => SApp (SFree c, map (trans Ts) ts)
+    | (Bound i, []) => SVar i
+    | _ => raise TERM ("intermediate", [t]))
+in
+fun intermediate ts = map (trans [] o HOLogic.dest_Trueprop) ts
+end
+
+
+(* Separate formulas from terms by adding special marker symbols ("term",
+   "formula"). Atoms "P" whose head symbol also occurs as function symbol are
+   rewritten to "term P = term True". Connectives and built-in predicates
+   occurring at term level are replaced by new constants, and theorems
+   specifying their meaning are added.
+*)
+local
+  (** Add the marker symbols "term" and "formulas" to separate formulas and
+      terms. **)
+
+  val connectives = map make_sconst [@{term True}, @{term False},
+    @{term Not}, @{term "op &"}, @{term "op |"}, @{term "op -->"},
+    @{term "op = :: bool => _"}]
+
+  fun note false c (ps, fs) = (insert (op =) c ps, fs)
+    | note true c (ps, fs) = (ps, insert (op =) c fs)
+
+  val term_marker = SConst (@{const_name term}, Term.dummyT)
+  val formula_marker = SConst (@{const_name formula}, Term.dummyT)
+  fun mark f true t = f true t #>> app term_marker o single
+    | mark f false t = f false t #>> app formula_marker o single
+  fun mark' f false t = f true t #>> app term_marker o single
+    | mark' f true t = f true t
+  val mark_term = app term_marker o single
+  fun lift_term_marker c ts =
+    let val rem = (fn SApp (SConst (@{const_name term}, _), [t]) => t | t => t)
+    in mark_term (SApp (c, map rem ts)) end
+  fun is_term (SApp (SConst (@{const_name term}, _), _)) = true
+    | is_term _ = false
+
+  fun either x = (fn y as SOME _ => y | _ => x)
+  fun get_loc loc i t =
+    (case t of
+      SVar j => if i = j then SOME loc else NONE
+    | SApp (SConst (@{const_name term}, _), us) => get_locs true i us
+    | SApp (SConst (@{const_name formula}, _), us) => get_locs false i us
+    | SApp (_, us) => get_locs loc i us
+    | SLet (_, u1, u2) => either (get_loc true i u1) (get_loc loc (i+1) u2)
+    | SQuant (_, vs, _, u) => get_loc loc (i + length vs) u)
+  and get_locs loc i ts = fold (either o get_loc loc i) ts NONE
+
+  fun sep loc t =
+    (case t of
+      SVar i => pair t
+    | SApp (c as SConst (@{const_name If}, _), u :: us) =>
+        mark sep false u ##>> fold_map (sep loc) us #>> app c o (op ::)
+    | SApp (c, us) =>
+        if not loc andalso member (op =) connectives c
+        then fold_map (sep loc) us #>> app c
+        else note loc c #> fold_map (mark' sep loc) us #>> app c
+    | SLet (v, u1, u2) =>
+        sep loc u2 #-> (fn u2' =>
+        mark sep (the (get_loc loc 0 u2')) u1 #>> (fn u1' =>
+        SLet (v, u1', u2')))
+    | SQuant (q, vs, ps, u) =>
+        fold_map (fold_map_pat (mark sep true)) ps ##>>
+        sep loc u #>> (fn (ps', u') =>
+        SQuant (q, vs, ps', u')))
+
+  (** Rewrite atoms. **)
+
+  val unterm_rule = @{lemma "term x == x" by (simp add: term_def)}
+  val unterm_conv = More_Conv.top_sweep_conv (K (Conv.rewr_conv unterm_rule))
+
+  val dest_word_type = (fn Type (@{type_name word}, [T]) => T | T => T)
+  fun instantiate [] _ = I
+    | instantiate (v :: _) T =
+        Term.subst_TVars [(v, dest_word_type (Term.domain_type T))]
+
+  fun dest_alls (Const (@{const_name All}, _) $ Abs (_, _, t)) = dest_alls t
+    | dest_alls t = t
+  val dest_iff = (fn (Const (@{const_name iff}, _) $ t $ _ ) => t | t => t)
+  val dest_eq = (fn (Const (@{const_name "op ="}, _) $ t $ _ ) => t | t => t)
+  val dest_not = (fn (@{term Not} $ t) => t | t => t)
+  val head_of = HOLogic.dest_Trueprop #> dest_alls #> dest_iff #> dest_not #>
+    dest_eq #> Term.head_of
+
+  fun prepare ctxt thm =
+    let
+      val rule = Conv.fconv_rule (unterm_conv ctxt) thm
+      val prop = Thm.prop_of thm
+      val inst = instantiate (Term.add_tvar_names prop [])
+      fun inst_for T = (singleton intermediate (inst T prop), rule)
+    in (make_sconst (head_of (Thm.prop_of rule)), inst_for) end
+
+  val logicals = map (prepare @{context})
+    @{lemma 
+      "~ holds False"
+      "ALL p. holds (~ p) iff (~ holds p)"
+      "ALL p q. holds (p & q) iff (holds p & holds q)"
+      "ALL p q. holds (p | q) iff (holds p | holds q)"
+      "ALL p q. holds (p --> q) iff (holds p --> holds q)"
+      "ALL p q. holds (p iff q) iff (holds p iff holds q)"
+      "ALL p q. holds (p = q) iff (p = q)"
+      "ALL (a::int) b. holds (a < b) iff (a < b)"
+      "ALL (a::int) b. holds (a <= b) iff (a <= b)"
+      "ALL (a::real) b. holds (a < b) iff (a < b)"
+      "ALL (a::real) b. holds (a <= b) iff (a <= b)"
+      "ALL (a::'a::len0 word) b. holds (a < b) iff (a < b)"
+      "ALL (a::'a::len0 word) b. holds (a <= b) iff (a <= b)"
+      "ALL a b. holds (a <s b) iff (a <s b)"
+      "ALL a b. holds (a <=s b) iff (a <=s b)"
+      by (simp_all add: term_def iff_def)}
+
+  fun is_instance thy (SConst (n, T), SConst (m, U)) =
+        (n = m) andalso Sign.typ_instance thy (T, U)
+    | is_instance _ _ = false
+
+  fun lookup_logical thy (c as SConst (_, T)) =
+        AList.lookup (is_instance thy) logicals c
+        |> Option.map (fn inst_for => inst_for T)
+    | lookup_logical _ _ = NONE
+
+  val s_eq = make_sconst @{term "op = :: bool => _"}
+  val s_True = mark_term (SApp (make_sconst @{term True}, []))
+  fun holds (SApp (c, ts)) = SApp (s_eq, [lift_term_marker c ts, s_True])
+    | holds t = SApp (s_eq, [mark_term t, s_True])
+
+  val rewr_iff = (fn
+      SConst (@{const_name "op ="}, T as @{typ "bool => bool => bool"}) =>
+        SConst (@{const_name iff}, T)
+    | c => c)
+
+  fun rewrite ls =
+    let
+      fun rewr env loc t =
+        (case t of
+          SVar i => if not loc andalso nth env i then holds t else t
+        | SApp (c as SConst (@{const_name term}, _), [u]) =>
+            SApp (c, [rewr env true u])
+        | SApp (c as SConst (@{const_name formula}, _), [u]) =>
+            SApp (c, [rewr env false u])
+        | SApp (c, us) =>
+            let val f = if not loc andalso member (op =) ls c then holds else I
+            in f (SApp (rewr_iff c, map (rewr env loc) us)) end
+        | SLet (v, u1, u2) =>
+            SLet (v, rewr env loc u1, rewr (is_term u1 :: env) loc u2)
+        | SQuant (q, vs, ps, u) =>
+            let val e = replicate (length vs) true @ env
+            in SQuant (q, vs, map (map_pat (rewr e loc)) ps, rewr e loc u) end)
+    in map (rewr [] false) end
+in
+fun separate thy ts =
+  let
+    val (ts', (ps, fs)) = fold_map (sep false) ts ([], [])
+    val eq_name = (fn
+        (SConst (n, _), SConst (m, _)) => n = m
+      | (SFree (n, _), SFree (m, _)) => n = m
+      | _ => false)
+    val ls = filter (member eq_name fs) ps
+    val (us, thms) = split_list (map_filter (lookup_logical thy) fs)
+  in (thms, us @ rewrite ls ts') end
+end
+
+
+(* Collect the signature of intermediate terms, identify built-in symbols,
+   rename uninterpreted symbols and types, make bound variables unique.
+   We require @{term distinct} to be a built-in constant of the SMT solver.
+*)
+local
+  fun empty_nctxt p = (p, 1)
+  fun make_nctxt (pT, pf, pp) = (empty_nctxt pT, empty_nctxt (pf, pp))
+  fun fresh_name (p, i) = (p ^ string_of_int i, (p, i+1))
+  fun fresh_typ (nT, nfp) = fresh_name nT ||> (fn nT' => (nT', nfp))
+  fun fresh_fun loc (nT, ((pf, pp), i)) =
+    let val p = if loc then pf else pp
+    in fresh_name (p, i) ||> (fn (_, i') => (nT, ((pf, pp), i'))) end
+
+  val empty_sign = (Typtab.empty, Termtab.empty, Termtab.empty)
+  fun lookup_typ (typs, _, _) = Typtab.lookup typs
+  fun lookup_fun true (_, funs, _) = Termtab.lookup funs
+    | lookup_fun false (_, _, preds) = Termtab.lookup preds
+  fun add_typ x (typs, funs, preds) = (Typtab.update x typs, funs, preds)
+  fun add_fun true x (typs, funs, preds) = (typs, Termtab.update x funs, preds)
+    | add_fun false x (typs, funs, preds) = (typs, funs, Termtab.update x preds)
+  fun make_sign (typs, funs, preds) = Sign {
+    typs = map snd (Typtab.dest typs),
+    funs = map snd (Termtab.dest funs),
+    preds = map (apsnd fst o snd) (Termtab.dest preds) }
+  fun make_rtab (typs, funs, preds) =
+    let
+      val rTs = Typtab.dest typs |> map swap |> Symtab.make
+      val rts = Termtab.dest funs @ Termtab.dest preds
+        |> map (apfst fst o swap) |> Symtab.make
+    in Recon {typs=rTs, terms=rts} end
+
+  fun either f g x = (case f x of NONE => g x | y => y)
+
+  fun rep_typ (Builtins {builtin_typ, ...}) T (st as (vars, ns, sgn)) =
+    (case either builtin_typ (lookup_typ sgn) T of
+      SOME n => (n, st)
+    | NONE =>
+        let val (n, ns') = fresh_typ ns
+        in (n, (vars, ns', add_typ (T, n) sgn)) end)
+
+  fun rep_var bs (n, T) (vars, ns, sgn) =
+    let val (n', vars') = fresh_name vars
+    in (vars', ns, sgn) |> rep_typ bs T |>> pair n' end
+
+  fun rep_fun bs loc t T i (st as (_, _, sgn0)) =
+    (case lookup_fun loc sgn0 t of
+      SOME (n, _) => (n, st)
+    | NONE =>
+        let
+          val (Us, U) = dest_funT i T
+          val (uns, (vars, ns, sgn)) =
+            st |> fold_map (rep_typ bs) Us ||>> rep_typ bs U
+          val (n, ns') = fresh_fun loc ns
+        in (n, (vars, ns', add_fun loc (t, (n, uns)) sgn)) end)
+
+  fun rep_num (bs as Builtins {builtin_num, ...}) (i, T) st =
+    (case builtin_num (i, T) of
+      SOME n => (n, st)
+    | NONE => rep_fun bs true (HOLogic.mk_number T i) T 0 st)
+in
+fun signature_of prefixes markers builtins thy ts =
+  let
+    val Prefixes {var_prefix, typ_prefix, fun_prefix, pred_prefix} = prefixes
+    val Markers {formula_marker, term_marker} = markers
+    val Builtins {builtin_fun, ...} = builtins
+
+    fun sign loc t =
+      (case t of
+        SVar i => pair (SVar i)
+      | SApp (c as SConst (@{const_name term}, _), [u]) =>
+          sign true u #>> app term_marker o single
+      | SApp (c as SConst (@{const_name formula}, _), [u]) =>
+          sign false u #>> app formula_marker o single
+      | SApp (SConst (c as (_, T)), ts) =>
+          (case builtin_lookup (builtin_fun loc) thy c ts of
+            SOME (n, ts') => fold_map (sign loc) ts' #>> app n
+          | NONE =>
+              rep_fun builtins loc (Const c) T (length ts) ##>>
+              fold_map (sign loc) ts #>> SApp)
+      | SApp (SFree (c as (_, T)), ts) =>
+          rep_fun builtins loc (Free c) T (length ts) ##>>
+          fold_map (sign loc) ts #>> SApp
+      | SApp (SNum n, _) => rep_num builtins n #>> (fn n => SApp (n, []))
+      | SLet (v, u1, u2) =>
+          rep_var builtins v #-> (fn v' =>
+          sign loc u1 ##>> sign loc u2 #>> (fn (u1', u2') =>
+          SLet (v', u1', u2')))
+      | SQuant (q, vs, ps, u) =>
+          fold_map (rep_var builtins) vs ##>>
+          fold_map (fold_map_pat (sign loc)) ps ##>>
+          sign loc u #>> (fn ((vs', ps'), u') =>
+          SQuant (q, vs', ps', u')))
+  in
+    (empty_nctxt var_prefix, make_nctxt (typ_prefix, fun_prefix, pred_prefix),
+      empty_sign)
+    |> fold_map (sign false) ts
+    |> (fn (us, (_, _, sgn)) => (make_rtab sgn, (make_sign sgn, us)))
+  end
+end
+
+
+(* Combination of all translation functions and invocation of serialization. *)
+
+fun translate config thy thms stream =
+  let val Config {strict, prefixes, markers, builtins, serialize} = config
+  in
+    map Thm.prop_of thms
+    |> SMT_Monomorph.monomorph thy
+    |> intermediate
+    |> (if strict then separate thy else pair [])
+    ||>> signature_of prefixes markers builtins thy
+    ||> (fn (sgn, ts) => serialize sgn ts stream)
+    |> (fn ((thms', rtab), _) => (rtab, thms' @ thms))
+  end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/smtlib_interface.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,168 @@
+(*  Title:      HOL/SMT/Tools/smtlib_interface.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Interface to SMT solvers based on the SMT-LIB format.
+*)
+
+signature SMTLIB_INTERFACE =
+sig
+  val basic_builtins: SMT_Translate.builtins
+  val default_attributes: string list
+  val gen_interface: SMT_Translate.builtins -> string list ->
+    SMT_Solver.interface
+  val interface: SMT_Solver.interface
+end
+
+structure SMTLIB_Interface: SMTLIB_INTERFACE =
+struct
+
+structure T = SMT_Translate
+
+
+(* built-in types, functions and predicates *)
+
+val builtin_typ = (fn
+    @{typ int} => SOME "Int"
+  | @{typ real} => SOME "Real"
+  | _ => NONE)
+
+val builtin_num = (fn
+    (i, @{typ int}) => SOME (string_of_int i)
+  | (i, @{typ real}) => SOME (string_of_int i ^ ".0")
+  | _ => NONE)
+
+val builtin_funcs = T.builtin_make [
+  (@{term If}, "ite"),
+  (@{term "uminus :: int => _"}, "~"),
+  (@{term "plus :: int => _"}, "+"),
+  (@{term "minus :: int => _"}, "-"),
+  (@{term "times :: int => _"}, "*"),
+  (@{term "uminus :: real => _"}, "~"),
+  (@{term "plus :: real => _"}, "+"),
+  (@{term "minus :: real => _"}, "-"),
+  (@{term "times :: real => _"}, "*") ]
+
+val builtin_preds = T.builtin_make [
+  (@{term True}, "true"),
+  (@{term False}, "false"),
+  (@{term Not}, "not"),
+  (@{term "op &"}, "and"),
+  (@{term "op |"}, "or"),
+  (@{term "op -->"}, "implies"),
+  (@{term "op iff"}, "iff"),
+  (@{term If}, "if_then_else"),
+  (@{term distinct}, "distinct"),
+  (@{term "op ="}, "="),
+  (@{term "op < :: int => _"}, "<"),
+  (@{term "op <= :: int => _"}, "<="),
+  (@{term "op < :: real => _"}, "<"),
+  (@{term "op <= :: real => _"}, "<=") ]
+
+
+(* serialization *)
+
+fun wr s stream = (TextIO.output (stream, s); stream)
+fun wr_line f = f #> wr "\n"
+
+fun sep f = wr " " #> f
+fun par f = sep (wr "(" #> f #> wr ")")
+
+fun wr1 s = sep (wr s)
+fun wrn f n = (fn [] => wr1 n | ts => par (wr n #> fold f ts))
+fun ins s f = (fn [] => I | x::xs => f x #> fold (fn x => wr1 s #> f x) xs)
+
+val term_marker = "__term"
+val formula_marker = "__form"
+fun dest_marker (T.SApp ("__term", [t])) = SOME (true, t)
+  | dest_marker (T.SApp ("__form", [t])) = SOME (false, t)
+  | dest_marker _ = NONE
+
+val tvar = prefix "?"
+val fvar = prefix "$"
+
+fun wr_expr loc env t =
+  (case t of
+    T.SVar i => wr1 (nth env i)
+  | T.SApp (n, ts) =>
+      (case dest_marker t of
+        SOME (loc', t') => wr_expr loc' env t'
+      | NONE => wrn (wr_expr loc env) n ts)
+  | T.SLet ((v, _), t1, t2) =>
+      if loc then raise TERM ("SMTLIB: let expression in term", [])
+      else
+        let
+          val (loc', t1') = the (dest_marker t1)
+          val (kind, v') = if loc' then ("let", tvar v)  else ("flet", fvar v)
+        in
+          par (wr kind #> par (wr v' #> wr_expr loc' env t1') #>
+            wr_expr loc (v' :: env) t2)
+        end
+  | T.SQuant (q, vs, ps, b) =>
+      let
+        val wr_quant = wr o (fn T.SForall => "forall" | T.SExists => "exists")
+        fun wr_var (n, s) = par (wr (tvar n) #> wr1 s)
+
+        val wre = wr_expr loc (map (tvar o fst) (rev vs) @ env)
+
+        fun wrp s ts = wr1 (":" ^ s ^ "{") #> ins "," wre ts #> wr1 "}"
+        fun wr_pat (T.SPat ts) = wrp "pat" ts
+          | wr_pat (T.SNoPat ts) = wrp "nopat" ts
+      in par (wr_quant q #> fold wr_var vs #> wre b #> fold wr_pat ps) end)
+
+fun serialize attributes (T.Sign {typs, funs, preds}) ts stream =
+  let
+    fun wr_decl (n, Ts) = wr_line (sep (par (wr n #> fold wr1 Ts)))
+  in
+    stream
+    |> wr_line (wr "(benchmark Isabelle")
+    |> fold (wr_line o wr) attributes
+    |> length typs > 0 ?
+         wr_line (wr ":extrasorts" #> par (fold wr1 typs))
+    |> length funs > 0 ? (
+         wr_line (wr ":extrafuns (") #>
+         fold (wr_decl o apsnd (fn (Ts, T) => Ts @ [T])) funs #>
+         wr_line (wr " )"))
+    |> length preds > 0 ? (
+         wr_line (wr ":extrapreds (") #>
+         fold wr_decl preds #>
+         wr_line (wr " )"))
+    |> fold (fn t => wr ":assumption" #> wr_line (wr_expr false [] t)) ts
+    |> wr_line (wr ":formula true")
+    |> wr_line (wr ")")
+    |> K ()
+  end
+
+
+(* SMT solver interface using the SMT-LIB input format *)
+
+val basic_builtins = T.Builtins {
+  builtin_typ = builtin_typ,
+  builtin_num = builtin_num,
+  builtin_fun = (fn true => builtin_funcs | false => builtin_preds) }
+
+val default_attributes = [":logic AUFLIRA", ":status unknown"]
+
+fun gen_interface builtins attributes = SMT_Solver.Interface {
+  normalize = [
+    SMT_Normalize.RewriteTrivialLets,
+    SMT_Normalize.RewriteNegativeNumerals,
+    SMT_Normalize.RewriteNaturalNumbers,
+    SMT_Normalize.AddAbsMinMaxRules,
+    SMT_Normalize.AddPairRules,
+    SMT_Normalize.AddFunUpdRules ],
+  translate = T.Config {
+    strict = true,
+    prefixes = T.Prefixes {
+      var_prefix = "x",
+      typ_prefix = "T",
+      fun_prefix = "uf_",
+      pred_prefix = "up_" },
+    markers = T.Markers {
+      term_marker = term_marker,
+      formula_marker = formula_marker },
+    builtins = builtins,
+    serialize = serialize attributes }}
+
+val interface = gen_interface basic_builtins default_attributes
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/yices_solver.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,52 @@
+(*  Title:      HOL/SMT/Tools/yices_solver.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Interface of the SMT solver Yices.
+*)
+
+signature YICES_SOLVER =
+sig
+  val setup: theory -> theory
+end
+
+structure Yices_Solver: YICES_SOLVER =
+struct
+
+val solver_name = "yices"
+val env_var = "YICES_SOLVER"
+
+val options = ["--evidence", "--smtlib"]
+
+fun cex_kind true = "Counterexample"
+  | cex_kind false = "Possible counterexample"
+
+fun raise_cex real ctxt rtab ls =
+  let val p = Pretty.big_list (cex_kind real ^ " found:") (map Pretty.str ls)
+  in error (Pretty.string_of p) end
+
+structure S = SMT_Solver
+
+fun core_oracle (SMT_Solver.ProofData {context, output, recon, ...}) =
+  let
+    val empty_line = (fn "" => true | _ => false)
+    val split_first = (fn [] => ("", []) | l :: ls => (l, ls))
+    val (l, ls) = split_first (dropwhile empty_line output)
+  in
+    if String.isPrefix "unsat" l then @{cprop False}
+    else if String.isPrefix "sat" l then raise_cex true context recon ls
+    else if String.isPrefix "unknown" l then raise_cex false context recon ls
+    else error (solver_name ^ " failed")
+  end
+
+fun smtlib_solver oracle _ =
+  SMT_Solver.SolverConfig {
+    name = {env_var=env_var, remote_name=solver_name},
+    interface = SMTLIB_Interface.interface,
+    arguments = options,
+    reconstruct = oracle }
+
+val setup =
+  Thm.add_oracle (Binding.name solver_name, core_oracle) #-> (fn (_, oracle) =>
+  SMT_Solver.add_solver (solver_name, smtlib_solver oracle))
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/z3_interface.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,98 @@
+(*  Title:      HOL/SMT/Tools/z3_interface.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Interface to Z3 based on a relaxed version of SMT-LIB.
+*)
+
+signature Z3_INTERFACE =
+sig
+  val interface: SMT_Solver.interface
+end
+
+structure Z3_Interface: Z3_INTERFACE =
+struct
+
+structure T = SMT_Translate
+
+fun mk_name1 n i = n ^ "[" ^ string_of_int i ^ "]"
+fun mk_name2 n i j = n ^ "[" ^ string_of_int i ^ ":" ^ string_of_int j ^ "]"
+
+val builtin_typ = (fn
+    @{typ int} => SOME "Int"
+  | @{typ real} => SOME "Real"
+  | Type (@{type_name word}, [T]) =>
+      Option.map (mk_name1 "BitVec") (try T.dest_binT T)
+  | _ => NONE)
+
+val builtin_num = (fn
+    (i, @{typ int}) => SOME (string_of_int i)
+  | (i, @{typ real}) => SOME (string_of_int i ^ ".0")
+  | (i, Type (@{type_name word}, [T])) =>
+      Option.map (mk_name1 ("bv" ^ string_of_int i)) (try T.dest_binT T)
+  | _ => NONE)
+
+val builtin_funcs = T.builtin_make [
+  (@{term If}, "ite"),
+  (@{term "uminus :: int => _"}, "~"),
+  (@{term "plus :: int => _"}, "+"),
+  (@{term "minus :: int => _"}, "-"),
+  (@{term "times :: int => _"}, "*"),
+  (@{term "op div :: int => _"}, "div"),
+  (@{term "op mod :: int => _"}, "mod"),
+  (@{term "op rem"}, "rem"),
+  (@{term "uminus :: real => _"}, "~"),
+  (@{term "plus :: real => _"}, "+"),
+  (@{term "minus :: real => _"}, "-"),
+  (@{term "times :: real => _"}, "*"),
+  (@{term "op / :: real => _"}, "/"),
+  (@{term "bitNOT :: 'a::len0 word => _"}, "bvnot"),
+  (@{term "op AND :: 'a::len0 word => _"}, "bvand"),
+  (@{term "op OR :: 'a::len0 word => _"}, "bvor"),
+  (@{term "op XOR :: 'a::len0 word => _"}, "bvxor"),
+  (@{term "uminus :: 'a::len0 word => _"}, "bvneg"),
+  (@{term "op + :: 'a::len0 word => _"}, "bvadd"),
+  (@{term "op - :: 'a::len0 word => _"}, "bvsub"),
+  (@{term "op * :: 'a::len0 word => _"}, "bvmul"),
+  (@{term "op div :: 'a::len0 word => _"}, "bvudiv"),
+  (@{term "op mod :: 'a::len0 word => _"}, "bvurem"),
+  (@{term "op sdiv"}, "bvsdiv"),
+  (@{term "op smod"}, "bvsmod"),
+  (@{term "op srem"}, "bvsrem"),
+  (@{term word_cat}, "concat"),
+  (@{term bv_shl}, "bvshl"),
+  (@{term bv_lshr}, "bvlshr"),
+  (@{term bv_ashr}, "bvashr")]
+  |> T.builtin_add (@{term slice}, T.bv_extract (mk_name2 "extract"))
+  |> T.builtin_add (@{term ucast}, T.bv_extend (mk_name1 "zero_extend"))
+  |> T.builtin_add (@{term scast}, T.bv_extend (mk_name1 "sign_extend"))
+  |> T.builtin_add (@{term word_rotl}, T.bv_rotate (mk_name1 "rotate_left"))
+  |> T.builtin_add (@{term word_rotr}, T.bv_rotate (mk_name1 "rotate_right"))
+
+val builtin_preds = T.builtin_make [
+  (@{term True}, "true"),
+  (@{term False}, "false"),
+  (@{term Not}, "not"),
+  (@{term "op &"}, "and"),
+  (@{term "op |"}, "or"),
+  (@{term "op -->"}, "implies"),
+  (@{term "op iff"}, "iff"),
+  (@{term If}, "if_then_else"),
+  (@{term distinct}, "distinct"),
+  (@{term "op ="}, "="),
+  (@{term "op < :: int => _"}, "<"),
+  (@{term "op <= :: int => _"}, "<="),
+  (@{term "op < :: real => _"}, "<"),
+  (@{term "op <= :: real => _"}, "<="),
+  (@{term "op < :: 'a::len0 word => _"}, "bvult"),
+  (@{term "op <= :: 'a::len0 word => _"}, "bvule"),
+  (@{term word_sless}, "bvslt"),
+  (@{term word_sle}, "bvsle")]
+
+val builtins = T.Builtins {
+  builtin_typ = builtin_typ,
+  builtin_num = builtin_num,
+  builtin_fun = (fn true => builtin_funcs | false => builtin_preds) }
+
+val interface = SMTLIB_Interface.gen_interface builtins []
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/z3_model.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,159 @@
+(*  Title:      HOL/SMT/Tools/z3_model.ML
+    Author:     Sascha Boehme and Philipp Meyer, TU Muenchen
+
+Parser for counterexamples generated by Z3.
+*)
+
+signature Z3_MODEL =
+sig
+  val parse_counterex: SMT_Translate.recon -> string list -> term list
+end
+
+structure Z3_Model: Z3_MODEL =
+struct
+
+(* parsing primitives *)
+
+fun lift f (x, y) = apsnd (pair x) (f y)
+fun lift' f v (x, y) = apsnd (rpair y) (f v x)
+
+fun $$ s = lift (Scan.$$ s)
+fun this s = lift (Scan.this_string s)
+
+fun par scan = $$ "(" |-- scan --| $$ ")"
+
+val digit = (fn
+  "0" => SOME 0 | "1" => SOME 1 | "2" => SOME 2 | "3" => SOME 3 |
+  "4" => SOME 4 | "5" => SOME 5 | "6" => SOME 6 | "7" => SOME 7 |
+  "8" => SOME 8 | "9" => SOME 9 | _ => NONE)
+
+val nat_num = Scan.repeat1 (Scan.some digit) >>
+  (fn ds => fold (fn d => fn i => i * 10 + d) ds 0)
+val int_num = Scan.optional (Scan.$$ "-" >> K (fn i => ~i)) I :|--
+  (fn sign => nat_num >> sign)
+
+val is_char = Symbol.is_ascii_letter orf Symbol.is_ascii_digit orf
+  member (op =) (explode "_+*-/%~=<>$&|?!.@^#")
+val name = Scan.many1 is_char >> implode
+
+
+(* parsing counterexamples *)
+
+datatype context = Context of {
+  ttab: term Symtab.table,
+  nctxt: Name.context,
+  vtab: term Inttab.table }
+
+fun make_context (ttab, nctxt, vtab) =
+  Context {ttab=ttab, nctxt=nctxt, vtab=vtab}
+
+fun empty_context (SMT_Translate.Recon {terms, ...}) =
+  let
+    val ns = Symtab.fold (Term.add_free_names o snd) terms []
+    val nctxt = Name.make_context ns
+  in make_context (terms, nctxt, Inttab.empty) end
+
+fun map_context f (Context {ttab, nctxt, vtab}) =
+  make_context (f (ttab, nctxt, vtab))
+
+fun fresh_name (cx as Context {nctxt, ...}) =
+  let val (n, nctxt') = yield_singleton Name.variants "" nctxt
+  in (n, map_context (fn (ttab, _, vtab) => (ttab, nctxt', vtab)) cx) end
+
+fun ident name (cx as Context {ttab, ...}) = 
+  (case Symtab.lookup ttab name of
+    SOME t => (t, cx)
+  | NONE =>
+      let val (n, cx') = fresh_name cx
+      in (Free (n, Term.dummyT), cx) end)
+
+fun set_value t i = map_context (fn (ttab, nctxt, vtab) =>
+  (ttab, nctxt, Inttab.update (i, t) vtab))
+
+fun get_value T i (cx as Context {vtab, ...}) =
+  (case Inttab.lookup vtab i of
+    SOME t => (t, cx)
+  | _ => cx |> fresh_name |-> (fn n =>
+      let val t = Free (n, T)
+      in set_value t i #> pair t end))
+
+
+fun space s = lift (Scan.many Symbol.is_ascii_blank) s
+fun spaced p = p --| space
+
+val key = spaced (lift name) #-> lift' ident
+val mapping = spaced (this "->")
+fun in_braces p = spaced ($$ "{") |-- p --| spaced ($$ "}")
+
+val bool_expr =
+  this "true" >> K @{term True} ||
+  this "false" >> K @{term False}
+
+fun number_expr T =
+  let
+    val num = lift int_num >> HOLogic.mk_number T
+    fun frac n d = Const (@{const_name divide}, T --> T --> T) $ n $ d
+  in num :|-- (fn n => Scan.optional ($$ "/" |-- num >> frac n) n) end
+
+val value = this "val!" |-- lift nat_num
+fun value_expr T = value #-> lift' (get_value T)
+
+val domT = Term.domain_type
+val ranT = Term.range_type
+fun const_array T t = Abs ("x", T, t)
+fun upd_array T ((a, t), u) =
+  Const (@{const_name fun_upd}, [T, domT T, ranT T] ---> T) $ a $ t $ u
+fun array_expr T st = if not (can domT T) then Scan.fail st else st |> (
+  par (spaced (this "const") |-- expr (ranT T)) >> const_array (domT T) ||
+  par (spaced (this "store") |-- spaced (array_expr T) --
+    expr (Term.domain_type T) -- expr (Term.range_type T)) >> upd_array T)
+
+and expr T st =
+  spaced (bool_expr || number_expr T || value_expr T || array_expr T) st
+
+fun const_val t =
+  let fun rep u = spaced value #-> apfst o set_value u #> pair []
+  in
+    if can HOLogic.dest_number t then rep t
+    else if t = @{term TT} then rep @{term True}
+    else expr (Term.fastype_of t) >> (fn u => [HOLogic.mk_eq (t, u)])
+  end
+
+fun func_value T = mapping |-- expr T
+
+fun first_pat T =
+  let
+    fun args T = if not (can domT T) then Scan.succeed [] else
+      expr (domT T) ::: args (ranT T)
+    fun value ts = func_value (snd (SMT_Translate.dest_funT (length ts) T))
+  in args T :-- value end
+
+fun func_pat (Ts, T) = fold_map expr Ts -- func_value T
+fun else_pat (Ts, T) =
+  let fun else_arg T cx = cx |> fresh_name |>> (fn n => Free (n, T))
+  in
+    fold_map (lift' else_arg) Ts ##>>
+    spaced (this "else") |-- func_value T
+  end
+fun next_pats T (fts as (ts, _)) =
+  let val Tps = SMT_Translate.dest_funT (length ts) T
+  in Scan.repeat (func_pat Tps) @@@ (else_pat Tps >> single) >> cons fts end
+
+fun mk_def' f (ts, t) = HOLogic.mk_eq (Term.list_comb (f, ts), t)
+fun mk_def (Const (@{const_name apply}, _)) (u :: us, t) = mk_def' u (us, t)
+  | mk_def f (ts, t) = mk_def' f (ts, t)
+fun func_pats t =
+  let val T = Term.fastype_of t
+  in first_pat T :|-- next_pats T >> map (mk_def t) end
+
+val assign =
+  key --| mapping :|-- (fn t => in_braces (func_pats t) || const_val t)
+
+val cex = space |-- Scan.repeat assign
+
+fun parse_counterex recon ls =
+  (empty_context recon, explode (cat_lines ls))
+  |> Scan.catch (Scan.finite' Symbol.stopper (Scan.error cex))
+  |> flat o fst
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/Tools/z3_solver.ML	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,83 @@
+(*  Title:      HOL/SMT/Tools/z3_solver.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Interface of the SMT solver Z3.
+*)
+
+signature Z3_SOLVER =
+sig
+  val proofs: bool Config.T
+  val options: string Config.T
+
+  val setup: theory -> theory
+end
+
+structure Z3_Solver: Z3_SOLVER =
+struct
+
+val solver_name = "z3"
+val env_var = "Z3_SOLVER"
+
+val (proofs, proofs_setup) = Attrib.config_bool "z3_proofs" false
+val (options, options_setup) = Attrib.config_string "z3_options" ""
+
+fun add xs ys = ys @ xs
+
+fun get_options ctxt =
+  ["MODEL=true", "PRE_SIMPLIFY_EXPR=false", "CONTEXT_SIMPLIFIER=false"]
+  |> Config.get ctxt proofs ? add ["DISPLAY_PROOF=true", "PROOF_MODE=2"]
+  |> add (space_explode " " (Config.get ctxt options))
+
+fun pretty_config context = [
+  Pretty.str ("With proofs: " ^
+    (if Config.get_generic context proofs then "true" else "false")),
+  Pretty.str ("Options: " ^
+    space_implode " " (get_options (Context.proof_of context))) ]
+
+fun cmdline_options ctxt =
+  get_options ctxt
+  |> add ["-smt"]
+
+fun raise_cex real recon ls =
+  let val cex = Z3_Model.parse_counterex recon ls
+  in raise SMT_Solver.SMT_COUNTEREXAMPLE (real, cex) end
+
+fun check_unsat recon output =
+  let
+    val raw = not o String.isPrefix "WARNING" orf String.isPrefix "ERROR"
+    val (ls, l) = the_default ([], "") (try split_last (filter raw output))
+  in
+    if String.isPrefix "unsat" l then ls
+    else if String.isPrefix "sat" l then raise_cex true recon ls
+    else if String.isPrefix "unknown" l then raise_cex false recon ls
+    else error (solver_name ^ " failed")
+  end
+
+fun core_oracle (SMT_Solver.ProofData {output, recon, ...}) =
+  check_unsat recon output
+  |> K @{cprop False}
+
+(* FIXME
+fun prover (SMT_Solver.ProofData {context, output, recon, assms}) =
+  check_unsat recon output
+  |> Z3_Proof.reconstruct context assms recon
+*)
+
+fun solver oracle ctxt =
+  let val with_proof = Config.get ctxt proofs
+  in
+    SMT_Solver.SolverConfig {
+      name = {env_var=env_var, remote_name=solver_name},
+      interface = Z3_Interface.interface,
+      arguments = cmdline_options ctxt,
+      reconstruct = (*FIXME:if with_proof then prover else*) oracle }
+  end
+
+val setup =
+  proofs_setup #>
+  options_setup #>
+  Thm.add_oracle (Binding.name solver_name, core_oracle) #-> (fn (_, oracle) =>
+  SMT_Solver.add_solver (solver_name, solver oracle)) #>
+  SMT_Solver.add_solver_info (solver_name, pretty_config)
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/etc/settings	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,13 @@
+ISABELLE_SMT="$COMPONENT"
+
+REMOTE_SMT_SOLVER="$ISABELLE_SMT/lib/scripts/remote_smt.pl"
+
+REMOTE_SMT_URL="http://www4.in.tum.de/smt/smt"
+
+#
+# Paths to local SMT solvers:
+#
+# CVC_SOLVER=PATH
+# YICES_SOLVER=PATH
+# Z3_SOLVER=PATH
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/SMT/lib/scripts/remote_smt.pl	Fri Sep 18 18:13:19 2009 +0200
@@ -0,0 +1,43 @@
+#!/usr/bin/env perl -w
+#
+# Script to invoke remote SMT solvers.
+# Author: Sascha Böhme
+#
+
+use strict;
+use LWP;
+
+
+# environment
+
+my $remote_smt_url = $ENV{"REMOTE_SMT_URL"};
+
+
+# arguments
+
+my $solver = $ARGV[0];
+my @options = @ARGV[1 .. ($#ARGV - 2)];
+my $problem_file = $ARGV[-2];
+my $output_file = $ARGV[-1];
+
+
+# call solver
+
+my $agent = LWP::UserAgent->new;
+$agent->agent("SMT-Request");
+$agent->timeout(180);
+my $response = $agent->post($remote_smt_url, [
+  "Solver" => $solver,
+  "Options" => join(" ", @options),
+  "Problem" => [$problem_file] ],
+  "Content_Type" => "form-data");
+if (not $response->is_success) {
+  print "HTTP-Error: " . $response->message . "\n";
+  exit 1;
+}
+else {
+  open(FILE, ">$output_file");
+  print FILE $response->content;
+  close(FILE);
+}
+