better modularization: moved SMT configuration options and diagnostics as well as SMT failure and exception into separate structures (both of which are loaded first and consequently are available to other SMT structures)
authorboehmes
Mon, 08 Nov 2010 12:13:44 +0100
changeset 40424 7550b2cba1cb
parent 40423 6923b39ad91f
child 40425 c9b5e0fcee31
better modularization: moved SMT configuration options and diagnostics as well as SMT failure and exception into separate structures (both of which are loaded first and consequently are available to other SMT structures)
NEWS
src/HOL/IsaMakefile
src/HOL/SMT.thy
src/HOL/Tools/SMT/smt_config.ML
src/HOL/Tools/SMT/smt_failure.ML
src/HOL/Tools/SMT/smt_monomorph.ML
src/HOL/Tools/SMT/smt_normalize.ML
src/HOL/Tools/SMT/smt_setup_solvers.ML
src/HOL/Tools/SMT/smt_solver.ML
src/HOL/Tools/SMT/z3_proof_parser.ML
src/HOL/Tools/SMT/z3_proof_reconstruction.ML
src/HOL/Tools/Sledgehammer/sledgehammer.ML
--- a/NEWS	Mon Nov 08 11:49:28 2010 +0100
+++ b/NEWS	Mon Nov 08 12:13:44 2010 +0100
@@ -350,9 +350,10 @@
     z3_trace_assms ~> smt_trace_used_facts
     INCOMPATIBILITY.
   - Added:
+    smt_verbose
+    smt_datatypes
     cvc3_options
     yices_options
-    smt_datatypes
 
 * Removed [split_format ... and ... and ...] version of
 [split_format].  Potential INCOMPATIBILITY.
--- a/src/HOL/IsaMakefile	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/IsaMakefile	Mon Nov 08 12:13:44 2010 +0100
@@ -340,6 +340,8 @@
   Tools/smallvalue_generators.ML \
   Tools/SMT/smtlib_interface.ML \
   Tools/SMT/smt_builtin.ML \
+  Tools/SMT/smt_config.ML \
+  Tools/SMT/smt_failure.ML \
   Tools/SMT/smt_monomorph.ML \
   Tools/SMT/smt_normalize.ML \
   Tools/SMT/smt_setup_solvers.ML \
--- a/src/HOL/SMT.thy	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/SMT.thy	Mon Nov 08 12:13:44 2010 +0100
@@ -8,7 +8,9 @@
 imports List
 uses
   "Tools/Datatype/datatype_selectors.ML"
-  ("Tools/SMT/smt_monomorph.ML")
+  "Tools/SMT/smt_failure.ML"
+  "Tools/SMT/smt_config.ML"
+  "Tools/SMT/smt_monomorph.ML"
   ("Tools/SMT/smt_builtin.ML")
   ("Tools/SMT/smt_normalize.ML")
   ("Tools/SMT/smt_translate.ML")
@@ -126,7 +128,6 @@
 
 subsection {* Setup *}
 
-use "Tools/SMT/smt_monomorph.ML"
 use "Tools/SMT/smt_builtin.ML"
 use "Tools/SMT/smt_normalize.ML"
 use "Tools/SMT/smt_translate.ML"
@@ -141,6 +142,7 @@
 use "Tools/SMT/smt_setup_solvers.ML"
 
 setup {*
+  SMT_Config.setup #>
   SMT_Solver.setup #>
   Z3_Proof_Reconstruction.setup #>
   SMT_Setup_Solvers.setup
@@ -241,6 +243,13 @@
 subsection {* Tracing *}
 
 text {*
+The SMT method, when applied, traces important information.  To
+make it entirely silent, set the following option to @{text false}.
+*}
+
+declare [[ smt_verbose = true ]]
+
+text {*
 For tracing the generated problem file given to the SMT solver as
 well as the returned result of the solver, the option
 @{text smt_trace} should be set to @{text true}.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Tools/SMT/smt_config.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -0,0 +1,232 @@
+(*  Title:      HOL/Tools/SMT/smt_config.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Configuration options and diagnostic tools for SMT.
+*)
+
+signature SMT_CONFIG =
+sig
+  (*solver*)
+  val add_solver: string -> Context.generic -> Context.generic
+  val set_solver_options: string * string -> Context.generic -> Context.generic
+  val select_solver: string -> Context.generic -> Context.generic
+  val solver_of: Proof.context -> string
+  val solver_options_of: Proof.context -> string list
+
+  (*options*)
+  val oracle: bool Config.T
+  val datatypes: bool Config.T
+  val timeout: real Config.T
+  val fixed: bool Config.T
+  val verbose: bool Config.T
+  val traceN: string
+  val trace: bool Config.T
+  val trace_used_facts: bool Config.T
+  val monomorph_limit: int Config.T
+  val drop_bad_facts: bool Config.T
+  val filter_only_facts: bool Config.T
+
+  (*tools*)
+  val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
+
+  (*diagnostics*)
+  val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
+  val verbose_msg: Proof.context -> ('a -> string) -> 'a -> unit
+
+  (*certificates*)
+  val select_certificates: string -> Context.generic -> Context.generic
+  val certificates_of: Proof.context -> Cache_IO.cache option
+
+  (*setup*)
+  val setup: theory -> theory
+  val print_setup: Proof.context -> unit
+end
+
+structure SMT_Config: SMT_CONFIG =
+struct
+
+(* solver *)
+
+structure Solvers = Generic_Data
+(
+  type T = string list Symtab.table * string option
+  val empty = (Symtab.empty, NONE)
+  val extend = I
+  fun merge ((ss1, s), (ss2, _)) = (Symtab.merge (K true) (ss1, ss2), s)
+)
+
+fun set_solver_options (name, options) =
+  let val opts = String.tokens (Symbol.is_ascii_blank o str) options
+  in Solvers.map (apfst (Symtab.map_entry name (K opts))) end
+
+fun add_solver name context =
+  if Symtab.defined (fst (Solvers.get context)) name then
+    error ("Solver already registered: " ^ quote name)
+  else
+    context
+    |> Solvers.map (apfst (Symtab.update (name, [])))
+    |> Context.map_theory (Attrib.setup (Binding.name (name ^ "_options"))
+        (Scan.lift (Parse.$$$ "=" |-- Args.name) >>
+          (Thm.declaration_attribute o K o set_solver_options o pair name))
+        ("Additional command line options for SMT solver " ^ quote name))
+
+fun select_solver name context =
+  if Symtab.defined (fst (Solvers.get context)) name then
+    Solvers.map (apsnd (K (SOME name))) context
+  else error ("Trying to select unknown solver: " ^ quote name)
+
+val lookup_solver = snd o Solvers.get o Context.Proof
+
+fun solver_of ctxt =
+  (case lookup_solver ctxt of
+    SOME name => name
+  | NONE => error "No SMT solver selected")
+
+fun solver_options_of ctxt =
+  (case lookup_solver ctxt of
+    NONE => []
+  | SOME name =>
+      Symtab.lookup_list (fst (Solvers.get (Context.Proof ctxt))) name)
+
+val setup_solver =
+  Attrib.setup @{binding smt_solver}
+    (Scan.lift (Parse.$$$ "=" |-- Args.name) >>
+      (Thm.declaration_attribute o K o select_solver))
+    "SMT solver configuration"
+
+
+(* options *)
+
+val oracleN = "smt_oracle"
+val (oracle, setup_oracle) = Attrib.config_bool oracleN (K true)
+
+val datatypesN = "smt_datatypes"
+val (datatypes, setup_datatypes) = Attrib.config_bool datatypesN (K false)
+
+val timeoutN = "smt_timeout"
+val (timeout, setup_timeout) = Attrib.config_real timeoutN (K 30.0)
+
+val fixedN = "smt_fixed"
+val (fixed, setup_fixed) = Attrib.config_bool fixedN (K false)
+
+val verboseN = "smt_verbose"
+val (verbose, setup_verbose) = Attrib.config_bool verboseN (K true)
+
+val traceN = "smt_trace"
+val (trace, setup_trace) = Attrib.config_bool traceN (K false)
+
+val trace_used_factsN = "smt_trace_used_facts"
+val (trace_used_facts, setup_trace_used_facts) =
+  Attrib.config_bool trace_used_factsN (K false)
+
+val monomorph_limitN = "smt_monomorph_limit"
+val (monomorph_limit, setup_monomorph_limit) =
+  Attrib.config_int monomorph_limitN (K 10)
+
+val drop_bad_factsN = "smt_drop_bad_facts"
+val (drop_bad_facts, setup_drop_bad_facts) =
+  Attrib.config_bool drop_bad_factsN (K false)
+
+val filter_only_factsN = "smt_filter_only_facts"
+val (filter_only_facts, setup_filter_only_facts) =
+  Attrib.config_bool filter_only_factsN (K false)
+
+val setup_options =
+  setup_oracle #>
+  setup_datatypes #>
+  setup_timeout #>
+  setup_fixed #>
+  setup_trace #>
+  setup_verbose #>
+  setup_monomorph_limit #>
+  setup_drop_bad_facts #>
+  setup_filter_only_facts #>
+  setup_trace_used_facts
+
+
+(* diagnostics *)
+
+fun cond_trace flag f x = if flag then tracing ("SMT: " ^ f x) else ()
+
+fun verbose_msg ctxt = cond_trace (Config.get ctxt verbose)
+
+fun trace_msg ctxt = cond_trace (Config.get ctxt trace)
+
+
+(* tools *)
+
+fun with_timeout ctxt f x =
+  TimeLimit.timeLimit (seconds (Config.get ctxt timeout)) f x
+  handle TimeLimit.TimeOut => raise SMT_Failure.SMT SMT_Failure.Time_Out
+
+
+(* certificates *)
+
+structure Certificates = Generic_Data
+(
+  type T = Cache_IO.cache option
+  val empty = NONE
+  val extend = I
+  fun merge (s, _) = s
+)
+
+val get_certificates_path =
+  Option.map (Cache_IO.cache_path_of) o Certificates.get o Context.Proof
+
+fun select_certificates name = Certificates.put (
+  if name = "" then NONE
+  else SOME (Cache_IO.make (Path.explode name)))
+
+val certificates_of = Certificates.get o Context.Proof
+
+val setup_certificates =
+  Attrib.setup @{binding smt_certificates}
+    (Scan.lift (Parse.$$$ "=" |-- Args.name) >>
+      (Thm.declaration_attribute o K o select_certificates))
+    "SMT certificates configuration"
+
+
+(* setup *)
+
+val setup =
+  setup_solver #>
+  setup_options #>
+  setup_certificates
+
+fun print_setup ctxt =
+  let
+    fun string_of_bool b = if b then "true" else "false"
+
+    val (names, sel) = Solvers.get (Context.Proof ctxt) |> apfst Symtab.keys
+    val ns = if null names then ["(none)"] else sort_strings names
+    val n = the_default "(none)" sel
+    val opts = solver_options_of ctxt
+    
+    val t = string_of_real (Config.get ctxt timeout)
+
+    val certs_filename =
+      (case get_certificates_path ctxt of
+        SOME path => Path.implode path
+      | NONE => "(disabled)")
+  in
+    Pretty.writeln (Pretty.big_list "SMT setup:" [
+      Pretty.str ("Current SMT solver: " ^ n),
+      Pretty.str ("Current SMT solver options: " ^ space_implode " " opts),
+      Pretty.str_list "Available SMT solvers: "  "" ns,
+      Pretty.str ("Current timeout: " ^ t ^ " seconds"),
+      Pretty.str ("With proofs: " ^
+        string_of_bool (not (Config.get ctxt oracle))),
+      Pretty.str ("Certificates cache: " ^ certs_filename),
+      Pretty.str ("Fixed certificates: " ^
+        string_of_bool (Config.get ctxt fixed))])
+  end
+
+val _ =
+  Outer_Syntax.improper_command "smt_status"
+    ("show the available SMT solvers, the currently selected SMT solver, " ^
+      "and the values of SMT configuration options")
+    Keyword.diag
+    (Scan.succeed (Toplevel.no_timing o Toplevel.keep (fn state =>
+      print_setup (Toplevel.context_of state))))
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Tools/SMT/smt_failure.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -0,0 +1,41 @@
+(*  Title:      HOL/Tools/SMT/smt_failure.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Failures and exception of SMT.
+*)
+
+signature SMT_FAILURE =
+sig
+  datatype failure =
+    Counterexample of bool * term list |
+    Time_Out |
+    Out_Of_Memory |
+    Other_Failure of string
+  val string_of_failure: Proof.context -> failure -> string
+  exception SMT of failure
+end
+
+structure SMT_Failure: SMT_FAILURE =
+struct
+
+datatype failure =
+  Counterexample of bool * term list |
+  Time_Out |
+  Out_Of_Memory |
+  Other_Failure of string
+
+fun string_of_failure ctxt (Counterexample (real, ex)) =
+      let
+        val msg = (if real then "C" else "Potential c") ^ "ounterexample found"
+      in
+        if null ex then msg
+        else Pretty.string_of (Pretty.big_list (msg ^ ":")
+          (map (Syntax.pretty_term ctxt) ex))
+      end
+  | string_of_failure _ Time_Out = "Timed out"
+  | string_of_failure _ Out_Of_Memory = "Ran out of memory"
+  | string_of_failure _ (Other_Failure msg) = msg
+
+exception SMT of failure
+
+end
--- a/src/HOL/Tools/SMT/smt_monomorph.ML	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/Tools/SMT/smt_monomorph.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -92,16 +92,19 @@
    computation uses only the constants occurring with schematic type
    variables in the propositions. To ease comparisons, such sets of
    costants are always kept in their initial order. *)
-fun incremental_monomorph thy limit all_grounds new_grounds irules =
+fun incremental_monomorph ctxt limit all_grounds new_grounds irules =
   let
+    val thy = ProofContext.theory_of ctxt
     val all_grounds' = Symtab.merge_list (op =) (all_grounds, new_grounds)
     val spec = specialize thy all_grounds' new_grounds
     val (irs, new_grounds') = fold_map spec irules Symtab.empty
   in
     if Symtab.is_empty new_grounds' then irs
     else if limit > 0
-    then incremental_monomorph thy (limit-1) all_grounds' new_grounds' irs
-    else (warning "SMT: monomorphization limit reached"; irs)
+    then incremental_monomorph ctxt (limit-1) all_grounds' new_grounds' irs
+    else
+     (SMT_Config.verbose_msg ctxt (K "Warning: Monomorphization limit reached")
+      (); irs)
   end
 
 
@@ -175,7 +178,7 @@
       in
         polys
         |> map (fn (i, thm) => ((i, thm), [(Vartab.empty, tvar_consts_of thm)]))
-        |> incremental_monomorph thy limit Symtab.empty grounds
+        |> incremental_monomorph ctxt' limit Symtab.empty grounds
         |> map (apsnd (filter_most_specific thy))
         |> flat o map2 (instantiate thy) Tenvs
         |> append monos
@@ -183,9 +186,6 @@
       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 theorems containing those
@@ -199,6 +199,6 @@
   irules
   |> List.partition (Term.exists_type typ_has_tvars o Thm.prop_of o snd)
   |>> incr_indexes
-  |-> mono_all ctxt monomorph_limit
+  |-> mono_all ctxt (Config.get ctxt SMT_Config.monomorph_limit)
 
 end
--- a/src/HOL/Tools/SMT/smt_normalize.ML	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/Tools/SMT/smt_normalize.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -19,8 +19,7 @@
 sig
   type extra_norm = bool -> (int * thm) list -> Proof.context ->
     (int * thm) list * Proof.context
-  val normalize: (Proof.context -> (thm -> string) -> thm -> unit) -> bool ->
-    extra_norm -> bool -> (int * thm) list -> Proof.context ->
+  val normalize: extra_norm -> bool -> (int * thm) list -> Proof.context ->
     (int * thm) list * Proof.context
   val atomize_conv: Proof.context -> conv
   val eta_expand_conv: (Proof.context -> conv) -> Proof.context -> conv
@@ -247,7 +246,7 @@
             then eta_args_conv norm_conv
               (length (Term.binder_types T) - length ts)
             else args_conv o norm_conv
-        | (_, ts) => args_conv o norm_conv)) ctxt ct
+        | _ => args_conv o norm_conv)) ctxt ct
 
   fun is_normed ctxt t =
     (case t of
@@ -516,15 +515,15 @@
 
 fun with_context f irules ctxt = (f ctxt irules, ctxt)
 
-fun normalize trace keep_assms extra_norm with_datatypes irules ctxt =
+fun normalize extra_norm with_datatypes irules ctxt =
   let
     fun norm f ctxt' (i, thm) =
-      if keep_assms then SOME (i, f ctxt' thm)
-      else
+      if Config.get ctxt' SMT_Config.drop_bad_facts then
         (case try (f ctxt') thm of
           SOME thm' => SOME (i, thm')
-        | NONE => (trace ctxt' (prefix ("SMT warning: " ^
+        | NONE => (SMT_Config.verbose_msg ctxt' (prefix ("Warning: " ^
             "dropping assumption: ") o Display.string_of_thm ctxt') thm; NONE))
+      else SOME (i, f ctxt' thm)
   in
     irules
     |> trivial_distinct ctxt
--- a/src/HOL/Tools/SMT/smt_setup_solvers.ML	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/Tools/SMT/smt_setup_solvers.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -16,9 +16,9 @@
   if String.isPrefix unsat line then SMT_Solver.Unsat
   else if String.isPrefix sat line then SMT_Solver.Sat
   else if String.isPrefix unknown line then SMT_Solver.Unknown
-  else raise SMT_Solver.SMT (SMT_Solver.Other_Failure ("Solver " ^
+  else raise SMT_Failure.SMT (SMT_Failure.Other_Failure ("Solver " ^
     quote solver_name ^ " failed. Enable SMT tracing by setting the " ^
-    "configuration option " ^ quote SMT_Solver.traceN ^ " and " ^
+    "configuration option " ^ quote SMT_Config.traceN ^ " and " ^
     " see the trace for details."))
 
 fun on_first_line test_outcome solver_name lines =
@@ -60,14 +60,14 @@
 
 fun z3_options ctxt =
   ["MODEL=true", "PRE_SIMPLIFY_EXPR=false", "CONTEXT_SIMPLIFIER=false", "-smt"]
-  |> not (Config.get ctxt SMT_Solver.oracle) ?
+  |> not (Config.get ctxt SMT_Config.oracle) ?
        append ["DISPLAY_PROOF=true","PROOF_MODE=2"]
 
 fun z3_on_last_line solver_name lines =
   let
     fun junk l =
       if String.isPrefix "WARNING: Out of allocated virtual memory" l
-      then raise SMT_Solver.SMT SMT_Solver.Out_Of_Memory
+      then raise SMT_Failure.SMT SMT_Failure.Out_Of_Memory
       else
         String.isPrefix "WARNING" l orelse
         String.isPrefix "ERROR" l orelse
--- a/src/HOL/Tools/SMT/smt_solver.ML	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/Tools/SMT/smt_solver.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -6,14 +6,7 @@
 
 signature SMT_SOLVER =
 sig
-  datatype failure =
-    Counterexample of bool * term list |
-    Time_Out |
-    Out_Of_Memory |
-    Other_Failure of string
-  val string_of_failure: Proof.context -> string -> failure -> string
-  exception SMT of failure
-
+  (*configuration*)
   type interface = {
     extra_norm: SMT_Normalize.extra_norm,
     translate: SMT_Translate.config }
@@ -30,37 +23,16 @@
     reconstruct: (Proof.context -> SMT_Translate.recon -> string list ->
       (int list * thm) * Proof.context) option }
 
-  (*options*)
-  val oracle: bool Config.T
-  val filter_only: bool Config.T
-  val datatypes: bool Config.T
-  val keep_assms: bool Config.T
-  val timeout: real Config.T
-  val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
-  val traceN: string
-  val trace: bool Config.T
-  val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
-  val trace_used_facts: bool Config.T
-
-  (*certificates*)
-  val fixed_certificates: bool Config.T
-  val select_certificates: string -> Context.generic -> Context.generic
-
-  (*solvers*)
+  (*registry*)
   type solver = bool option -> Proof.context -> (int * thm) list ->
     int list * thm
   val add_solver: solver_config -> theory -> theory
-  val set_solver_options: string -> string -> Context.generic ->
-    Context.generic
-  val all_solver_names_of: Context.generic -> string list
-  val solver_name_of: Context.generic -> string
-  val select_solver: string -> Context.generic -> Context.generic
-  val solver_of: Context.generic -> solver
+  val solver_of: Proof.context -> solver
   val is_locally_installed: Proof.context -> bool
 
   (*filter*)
   val smt_filter: bool -> Time.time -> Proof.state -> ('a * thm) list -> int ->
-    {outcome: failure option, used_facts: 'a list,
+    {outcome: SMT_Failure.failure option, used_facts: 'a list,
     run_time_in_msecs: int option}
 
   (*tactic*)
@@ -69,31 +41,15 @@
 
   (*setup*)
   val setup: theory -> theory
-  val print_setup: Context.generic -> unit
 end
 
 structure SMT_Solver: SMT_SOLVER =
 struct
 
-datatype failure =
-  Counterexample of bool * term list |
-  Time_Out |
-  Out_Of_Memory |
-  Other_Failure of string
+structure C = SMT_Config
 
-fun string_of_failure ctxt _ (Counterexample (real, ex)) =
-      let
-        val msg = (if real then "C" else "Potential c") ^ "ounterexample found"
-      in
-        if null ex then msg ^ "."
-        else Pretty.string_of (Pretty.big_list (msg ^ ":")
-          (map (Syntax.pretty_term ctxt) ex))
-      end
-  | string_of_failure _ name Time_Out = name ^ " timed out."
-  | string_of_failure _ name Out_Of_Memory = name ^ " ran out of memory."
-  | string_of_failure _ _ (Other_Failure msg) = msg
 
-exception SMT of failure
+(* configuration *)
 
 type interface = {
   extra_norm: SMT_Normalize.extra_norm,
@@ -114,57 +70,6 @@
     (int list * thm) * Proof.context) option }
 
 
-
-(* SMT options *)
-
-val (oracle, setup_oracle) = Attrib.config_bool "smt_oracle" (K true)
-
-val (filter_only, setup_filter_only) =
-  Attrib.config_bool "smt_filter_only" (K false)
-
-val (datatypes, setup_datatypes) = Attrib.config_bool "smt_datatypes" (K false)
-
-val (keep_assms, setup_keep_assms) =
-  Attrib.config_bool "smt_keep_assms" (K true)
-
-val (timeout, setup_timeout) = Attrib.config_real "smt_timeout" (K 30.0)
-
-fun with_timeout ctxt f x =
-  TimeLimit.timeLimit (seconds (Config.get ctxt timeout)) f x
-  handle TimeLimit.TimeOut => raise SMT Time_Out
-
-val traceN = "smt_trace"
-val (trace, setup_trace) = Attrib.config_bool traceN (K false)
-
-fun trace_msg ctxt f x =
-  if Config.get ctxt trace then tracing (f x) else ()
-
-val (trace_used_facts, setup_trace_used_facts) =
-  Attrib.config_bool "smt_trace_used_facts" (K false)
-
-
-(* SMT certificates *)
-
-val (fixed_certificates, setup_fixed_certificates) =
-  Attrib.config_bool "smt_fixed" (K false)
-
-structure Certificates = Generic_Data
-(
-  type T = Cache_IO.cache option
-  val empty = NONE
-  val extend = I
-  fun merge (s, _) = s
-)
-
-val get_certificates_path =
-  Option.map (Cache_IO.cache_path_of) o Certificates.get
-
-fun select_certificates name = Certificates.put (
-  if name = "" then NONE
-  else SOME (Cache_IO.make (Path.explode name)))
-
-
-
 (* interface to external solvers *)
 
 fun get_local_solver env_var =
@@ -202,12 +107,12 @@
   [File.shell_path problem_path, "2>&1", ">", File.shell_path proof_path])
 
 fun run ctxt cmd args input =
-  (case Certificates.get (Context.Proof ctxt) of
+  (case C.certificates_of ctxt of
     NONE => Cache_IO.run (make_cmd (choose cmd) args) input
   | SOME certs =>
       (case Cache_IO.lookup certs input of
         (NONE, key) =>
-          if Config.get ctxt fixed_certificates
+          if Config.get ctxt C.fixed
           then error ("Bad certificates cache: missing certificate")
           else Cache_IO.run_and_cache certs key (make_cmd (choose cmd) args)
             input
@@ -223,36 +128,37 @@
     fun pretty tag ls = Pretty.string_of (Pretty.big_list tag
       (map Pretty.str ls))
 
-    val _ = trace_msg ctxt (pretty "SMT problem:" o split_lines) input
+    val _ = C.trace_msg ctxt (pretty "Problem:" o split_lines) input
 
-    val (res, err) = with_timeout ctxt (run ctxt cmd args) input
-    val _ = trace_msg ctxt (pretty "SMT solver:") err
+    val (res, err) = C.with_timeout ctxt (run ctxt cmd args) input
+    val _ = C.trace_msg ctxt (pretty "Solver:") err
 
     val ls = rev (snd (chop_while (equal "") (rev res)))
-    val _ = trace_msg ctxt (pretty "SMT result:") ls
+    val _ = C.trace_msg ctxt (pretty "Result:") ls
   in ls end
 
 end
 
-fun trace_assms ctxt = trace_msg ctxt (Pretty.string_of o
-  Pretty.big_list "SMT assertions:" o map (Display.pretty_thm ctxt o snd))
+fun trace_assms ctxt = C.trace_msg ctxt (Pretty.string_of o
+  Pretty.big_list "Assertions:" o map (Display.pretty_thm ctxt o snd))
 
 fun trace_recon_data ctxt ({typs, terms, ...} : SMT_Translate.recon) =
   let
     fun pretty_eq n p = Pretty.block [Pretty.str n, Pretty.str " = ", p]
-    fun pretty_typ (n, T) = pretty_eq n (Syntax.pretty_typ ctxt T)
-    fun pretty_term (n, t) = pretty_eq n (Syntax.pretty_term ctxt t)
+    fun p_typ (n, T) = pretty_eq n (Syntax.pretty_typ ctxt T)
+    fun p_term (n, t) = pretty_eq n (Syntax.pretty_term ctxt t)
   in
-    trace_msg ctxt (fn () => Pretty.string_of (Pretty.big_list "SMT names:" [
-      Pretty.big_list "sorts:" (map pretty_typ (Symtab.dest typs)),
-      Pretty.big_list "functions:" (map pretty_term (Symtab.dest terms))])) ()
+    C.trace_msg ctxt (fn () =>
+      Pretty.string_of (Pretty.big_list "Names:" [
+        Pretty.big_list "sorts:" (map p_typ (Symtab.dest typs)),
+        Pretty.big_list "functions:" (map p_term (Symtab.dest terms))])) ()
   end
 
-fun invoke translate_config name cmd more_opts options irules ctxt =
+fun invoke translate_config name cmd options irules ctxt =
   let
-    val args = more_opts @ options ctxt
+    val args = C.solver_options_of ctxt @ options ctxt
     val comments = ("solver: " ^ name) ::
-      ("timeout: " ^ Time.toString (seconds (Config.get ctxt timeout))) ::
+      ("timeout: " ^ Time.toString (seconds (Config.get ctxt C.timeout))) ::
       "arguments:" :: args
   in
     irules
@@ -283,7 +189,7 @@
     val thms = filter (fn i => i >= 0) idxs
       |> map_filter (AList.lookup (op =) irules)
   in
-    if Config.get ctxt trace_used_facts andalso length thms > 0
+    if Config.get ctxt C.trace_used_facts andalso length thms > 0
     then
       tracing (Pretty.string_of (Pretty.big_list "SMT used facts:"
         (map (Display.pretty_thm ctxt) thms)))
@@ -292,17 +198,15 @@
 
 fun gen_solver name info rm ctxt irules =
   let
-    val {env_var, is_remote, options, more_options, interface, reconstruct} =
-      info
+    val {env_var, is_remote, options, interface, reconstruct} = info
     val {extra_norm, translate} = interface
     val (with_datatypes, translate') =
-      set_has_datatypes (Config.get ctxt datatypes) translate
+      set_has_datatypes (Config.get ctxt C.datatypes) translate
     val cmd = (rm, env_var, is_remote, name)
-    val keep = Config.get ctxt keep_assms
   in
     (irules, ctxt)
-    |-> SMT_Normalize.normalize trace_msg keep extra_norm with_datatypes
-    |-> invoke translate' name cmd more_options options
+    |-> SMT_Normalize.normalize extra_norm with_datatypes
+    |-> invoke translate' name cmd options
     |-> reconstruct
     |-> (fn (idxs, thm) => fn ctxt' => thm
     |> singleton (ProofContext.export ctxt' ctxt)
@@ -313,7 +217,7 @@
 
 
 
-(* solver store *)
+(* registry *)
 
 type solver = bool option -> Proof.context -> (int * thm) list -> int list * thm
 
@@ -321,7 +225,6 @@
   env_var: string,
   is_remote: bool,
   options: Proof.context -> string list,
-  more_options: string list,
   interface: interface,
   reconstruct: string list * SMT_Translate.recon -> Proof.context ->
     (int list * thm) * Proof.context }
@@ -335,24 +238,18 @@
     handle Symtab.DUP name => error ("Duplicate SMT solver: " ^ quote name)
 )
 
-val no_solver = "(none)"
-
-fun set_solver_options name opts = Solvers.map (Symtab.map_entry name (fn
-  {env_var, is_remote, options, interface, reconstruct, ...} =>
-  {env_var=env_var, is_remote=is_remote, options=options,
-   more_options=String.tokens (Symbol.is_ascii_blank o str) opts,
-   interface=interface, reconstruct=reconstruct}))
-
 local
   fun finish outcome cex_parser reconstruct ocl (output, recon) ctxt =
     (case outcome output of
       (Unsat, ls) =>
-        if not (Config.get ctxt oracle) andalso is_some reconstruct
+        if not (Config.get ctxt C.oracle) andalso is_some reconstruct
         then the reconstruct ctxt recon ls
         else (([], ocl ()), ctxt)
     | (result, ls) =>
         let val ts = (case cex_parser of SOME f => f ctxt recon ls | _ => [])
-        in raise SMT (Counterexample (result = Sat, ts)) end)
+        in
+          raise SMT_Failure.SMT (SMT_Failure.Counterexample (result = Sat, ts))
+        end)
 in
 
 fun add_solver cfg =
@@ -363,59 +260,31 @@
     fun core_oracle () = @{cprop False}
 
     fun solver ocl = { env_var=env_var, is_remote=is_remote, options=options,
-      more_options=[], interface=interface,
+      interface=interface,
       reconstruct=finish (outcome name) cex_parser reconstruct ocl }
   in
     Thm.add_oracle (Binding.name name, core_oracle) #-> (fn (_, ocl) =>
     Context.theory_map (Solvers.map (Symtab.update_new (name, solver ocl)))) #>
-    Attrib.setup (Binding.name (name ^ "_options"))
-      (Scan.lift (Parse.$$$ "=" |-- Args.name) >>
-        (Thm.declaration_attribute o K o set_solver_options name))
-      ("Additional command line options for SMT solver " ^ quote name)
+    Context.theory_map (C.add_solver name)
   end
 
 end
 
-val all_solver_names_of = Symtab.keys o Solvers.get
-val lookup_solver = Symtab.lookup o Solvers.get
-
-
-
-(* selected solver *)
-
-structure Selected_Solver = Generic_Data
-(
-  type T = string
-  val empty = no_solver
-  val extend = I
-  fun merge (s, _) = s
-)
+fun name_and_solver_of ctxt =
+  let val name = C.solver_of ctxt
+  in (name, the (Symtab.lookup (Solvers.get (Context.Proof ctxt)) name)) end
 
-val solver_name_of = Selected_Solver.get
-
-fun select_solver name context =
-  if is_none (lookup_solver context name)
-  then error ("SMT solver not registered: " ^ quote name)
-  else Selected_Solver.map (K name) context
-
-fun raw_solver_of context name =
-  (case lookup_solver context name of
-    NONE => error "No SMT solver selected"
-  | SOME s => s)
-
-fun solver_of context =
-  let val name = solver_name_of context
-  in gen_solver name (raw_solver_of context name) end
+fun solver_of ctxt =
+  let val (name, raw_solver) = name_and_solver_of ctxt
+  in gen_solver name raw_solver end
 
 fun is_locally_installed ctxt =
-  let
-    val name = solver_name_of (Context.Proof ctxt)
-    val {env_var, ...} = raw_solver_of (Context.Proof ctxt) name
+  let val (_, {env_var, ...}) = name_and_solver_of ctxt
   in is_some (get_local_solver env_var) end
 
 
 
-(* SMT filter *)
+(* filter *)
 
 val has_topsort = Term.exists_type (Term.exists_subtype (fn
     TFree (_, []) => true
@@ -424,19 +293,20 @@
 
 fun smt_solver rm ctxt irules =
   (* without this test, we would run into problems when atomizing the rules: *)
-  if exists (has_topsort o Thm.prop_of o snd) irules
-  then raise SMT (Other_Failure "proof state contains the universal sort {}")
-  else solver_of (Context.Proof ctxt) rm ctxt irules
+  if exists (has_topsort o Thm.prop_of o snd) irules then
+    raise SMT_Failure.SMT (SMT_Failure.Other_Failure ("proof state " ^
+      "contains the universal sort {}"))
+  else solver_of ctxt rm ctxt irules
 
 fun smt_filter run_remote time_limit st xrules i =
   let
     val {facts, goal, ...} = Proof.goal st
     val ctxt =
       Proof.context_of st
-      |> Config.put timeout (Real.fromInt (Time.toSeconds time_limit))
-      |> Config.put oracle false
-      |> Config.put filter_only true
-      |> Config.put keep_assms false
+      |> Config.put C.oracle false
+      |> Config.put C.timeout (Real.fromInt (Time.toSeconds time_limit))
+      |> Config.put C.drop_bad_facts true
+      |> Config.put C.filter_only_facts true
     val ({context=ctxt', prems, concl, ...}, _) = Subgoal.focus ctxt i goal
     val cprop =
       concl
@@ -450,7 +320,8 @@
     |-> map_filter o try o nth
     |> (fn xs => {outcome=NONE, used_facts=xs, run_time_in_msecs=NONE})
   end
-  handle SMT fail => {outcome=SOME fail, used_facts=[], run_time_in_msecs=NONE}
+  handle SMT_Failure.SMT fail => {outcome=SOME fail, used_facts=[],
+    run_time_in_msecs=NONE}
   (* FIXME: measure runtime *)
 
 
@@ -460,14 +331,17 @@
 fun smt_tac' pass_exns ctxt rules =
   CONVERSION (SMT_Normalize.atomize_conv ctxt)
   THEN' Tactic.rtac @{thm ccontr}
-  THEN' SUBPROOF (fn {context=cx, prems, ...} =>
+  THEN' SUBPROOF (fn {context=ctxt', prems, ...} =>
     let
-      fun solve () = snd (smt_solver NONE cx (map (pair ~1) (rules @ prems)))
-      val name = solver_name_of (Context.Proof cx)
-      val trace = trace_msg cx (prefix "SMT: " o string_of_failure cx name)
+      fun solve irules = snd (smt_solver NONE ctxt' irules)
+      val tag = "Solver " ^ C.solver_of ctxt' ^ ": "
+      val str_of = SMT_Failure.string_of_failure ctxt'
+      fun safe_solve irules =
+        if pass_exns then SOME (solve irules)
+        else (SOME (solve irules) handle SMT_Failure.SMT fail =>
+          (C.trace_msg ctxt' (prefix tag o str_of) fail; NONE))
     in
-      (if pass_exns then SOME (solve ())
-       else (SOME (solve ()) handle SMT fail => (trace fail; NONE)))
+      safe_solve (map (pair ~1) (rules @ prems))
       |> (fn SOME thm => Tactic.rtac thm 1 | _ => Tactical.no_tac)
     end) ctxt
 
@@ -483,60 +357,7 @@
 (* setup *)
 
 val setup =
-  Attrib.setup @{binding smt_solver}
-    (Scan.lift (Parse.$$$ "=" |-- Args.name) >>
-      (Thm.declaration_attribute o K o select_solver))
-    "SMT solver configuration" #>
-  setup_oracle #>
-  setup_filter_only #>
-  setup_datatypes #>
-  setup_keep_assms #>
-  setup_timeout #>
-  setup_trace #>
-  setup_trace_used_facts #>
-  setup_fixed_certificates #>
-  Attrib.setup @{binding smt_certificates}
-    (Scan.lift (Parse.$$$ "=" |-- Args.name) >>
-      (Thm.declaration_attribute o K o select_certificates))
-    "SMT certificates" #>
   Method.setup @{binding smt} smt_method
     "Applies an SMT solver to the current goal."
 
-
-fun print_setup context =
-  let
-    val t = Time.toString (seconds (Config.get_generic context timeout))
-    val names = sort_strings (all_solver_names_of context)
-    val ns = if null names then [no_solver] else names
-    val n = solver_name_of context
-    val opts =
-      (case Symtab.lookup (Solvers.get context) n of
-        NONE => []
-      | SOME {more_options, options, ...} =>
-          more_options @ options (Context.proof_of context))
-    val certs_filename =
-      (case get_certificates_path context of
-        SOME path => Path.implode path
-      | NONE => "(disabled)")
-    val fixed = if Config.get_generic context fixed_certificates then "true"
-      else "false"
-  in
-    Pretty.writeln (Pretty.big_list "SMT setup:" [
-      Pretty.str ("Current SMT solver: " ^ n),
-      Pretty.str ("Current SMT solver options: " ^ space_implode " " opts),
-      Pretty.str_list "Available SMT solvers: "  "" ns,
-      Pretty.str ("Current timeout: " ^ t ^ " seconds"),
-      Pretty.str ("With proofs: " ^
-        (if Config.get_generic context oracle then "false" else "true")),
-      Pretty.str ("Certificates cache: " ^ certs_filename),
-      Pretty.str ("Fixed certificates: " ^ fixed)])
-  end
-
-val _ =
-  Outer_Syntax.improper_command "smt_status"
-    "show the available SMT solvers and the currently selected solver"
-    Keyword.diag
-    (Scan.succeed (Toplevel.no_timing o Toplevel.keep (fn state =>
-      print_setup (Context.Proof (Toplevel.context_of state)))))
-
 end
--- a/src/HOL/Tools/SMT/z3_proof_parser.ML	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/Tools/SMT/z3_proof_parser.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -240,7 +240,7 @@
 
 (* core parser *)
 
-fun parse_exn line_no msg = raise SMT_Solver.SMT (SMT_Solver.Other_Failure
+fun parse_exn line_no msg = raise SMT_Failure.SMT (SMT_Failure.Other_Failure
   ("Z3 proof parser (line " ^ string_of_int line_no ^ "): " ^ msg))
 
 fun scan_exn msg ((line_no, _), _) = parse_exn line_no msg
--- a/src/HOL/Tools/SMT/z3_proof_reconstruction.ML	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/Tools/SMT/z3_proof_reconstruction.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -19,7 +19,7 @@
 structure T = Z3_Proof_Tools
 structure L = Z3_Proof_Literals
 
-fun z3_exn msg = raise SMT_Solver.SMT (SMT_Solver.Other_Failure
+fun z3_exn msg = raise SMT_Failure.SMT (SMT_Failure.Other_Failure
   ("Z3 proof reconstruction: " ^ msg))
 
 
@@ -66,11 +66,11 @@
 (** proof tools **)
 
 fun named ctxt name prover ct =
-  let val _ = SMT_Solver.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...")
+  let val _ = SMT_Config.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...")
   in prover ct end
 
 fun NAMED ctxt name tac i st =
-  let val _ = SMT_Solver.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...")
+  let val _ = SMT_Config.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...")
   in tac i st end
 
 fun pretty_goal ctxt thms t =
@@ -90,7 +90,7 @@
     fun apply [] ct = error (try_apply_err ct)
       | apply (prover :: provers) ct =
           (case try prover ct of
-            SOME thm => (SMT_Solver.trace_msg ctxt I "Z3: succeeded"; thm)
+            SOME thm => (SMT_Config.trace_msg ctxt I "Z3: succeeded"; thm)
           | NONE => apply provers ct)
 
   in apply o cons (named ctxt "schematic rules" (by_schematic_rule ctxt)) end
@@ -732,9 +732,9 @@
 in
 fun trace_rule idx prove r ps ct (cxp as (ctxt, ptab)) =
   let
-    val _ = SMT_Solver.trace_msg ctxt (header idx r o count_rules) ptab
+    val _ = SMT_Config.trace_msg ctxt (header idx r o count_rules) ptab
     val result as (p, (ctxt', _)) = prove r ps ct cxp
-    val _ = if not (Config.get ctxt' SMT_Solver.trace) then ()
+    val _ = if not (Config.get ctxt' SMT_Config.trace) then ()
       else check ctxt' idx r ps ct p
   in result end
 end
@@ -844,7 +844,7 @@
     val (idx, (ptab, vars, cx)) = P.parse ctxt typs terms output
     val assms' = prepare_assms cx unfolds assms
   in
-    if Config.get cx SMT_Solver.filter_only
+    if Config.get cx SMT_Config.filter_only_facts
     then ((filter_assms cx assms' ptab idx [], @{thm TrueI}), cx)
     else apfst (pair []) (prove cx assms' vars idx ptab)
   end
--- a/src/HOL/Tools/Sledgehammer/sledgehammer.ML	Mon Nov 08 11:49:28 2010 +0100
+++ b/src/HOL/Tools/Sledgehammer/sledgehammer.ML	Mon Nov 08 12:13:44 2010 +0100
@@ -409,9 +409,9 @@
      run_time_in_msecs = msecs}
   end
 
-fun failure_from_smt_failure (SMT_Solver.Counterexample _) = Unprovable
-  | failure_from_smt_failure SMT_Solver.Time_Out = TimedOut
-  | failure_from_smt_failure SMT_Solver.Out_Of_Memory = OutOfResources
+fun failure_from_smt_failure (SMT_Failure.Counterexample _) = Unprovable
+  | failure_from_smt_failure SMT_Failure.Time_Out = TimedOut
+  | failure_from_smt_failure SMT_Failure.Out_Of_Memory = OutOfResources
   | failure_from_smt_failure _ = UnknownError
 
 val smt_max_iter = 5
@@ -473,10 +473,10 @@
                          (apply_on_subgoal subgoal subgoal_count ^
                           command_call smtN (map fst used_facts)) ^
         minimize_line minimize_command (map fst used_facts)
-      | SOME SMT_Solver.Time_Out => "Timed out."
-      | SOME (SMT_Solver.Counterexample _) => "The SMT problem is unprovable."
+      | SOME SMT_Failure.Time_Out => "Timed out."
+      | SOME (SMT_Failure.Counterexample _) => "The SMT problem is unprovable."
       | SOME failure =>
-        SMT_Solver.string_of_failure ctxt "The SMT solver" failure
+        SMT_Failure.string_of_failure ctxt failure
     val outcome = outcome |> Option.map failure_from_smt_failure (* FIXME *)
   in
     {outcome = outcome, used_facts = used_facts,