src/HOL/SMT/Tools/smt_solver.ML
changeset 33010 39f73a59e855
parent 32950 5d5e123443b3
child 33017 4fb8a33f74d6
--- a/src/HOL/SMT/Tools/smt_solver.ML	Tue Oct 20 08:10:47 2009 +0200
+++ b/src/HOL/SMT/Tools/smt_solver.ML	Tue Oct 20 10:11:30 2009 +0200
@@ -19,9 +19,9 @@
     assms: thm list option }
 
   datatype solver_config = SolverConfig of {
-    name: {env_var: string, remote_name: string},
+    command: {env_var: string, remote_name: string},
+    arguments: string list,
     interface: interface,
-    arguments: string list,
     reconstruct: proof_data -> thm }
 
   (*options*)
@@ -29,6 +29,8 @@
   val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
   val trace: bool Config.T
   val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
+  val keep: string Config.T
+  val cert: string Config.T
 
   (*solvers*)
   type solver = Proof.context -> thm list -> thm
@@ -67,9 +69,9 @@
   assms: thm list option }
 
 datatype solver_config = SolverConfig of {
-  name: {env_var: string, remote_name: string},
+  command: {env_var: string, remote_name: string},
+  arguments: string list,
   interface: interface,
-  arguments: string list,
   reconstruct: proof_data -> thm }
 
 
@@ -86,17 +88,28 @@
 fun trace_msg ctxt f x =
   if Config.get ctxt trace then tracing (f x) else ()
 
+val (keep, setup_keep) = Attrib.config_string "smt_keep" ""
+val (cert, setup_cert) = Attrib.config_string "smt_cert" ""
+
 
 (* interface to external solvers *)
 
 local
 
-fun with_tmp_files f x =
+fun with_files ctxt 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
+    fun make_names n = (n, n ^ ".proof")
+
+    val keep' = Config.get ctxt keep
+    val paths as (problem_path, proof_path) =
+      if keep' <> "" andalso File.exists (Path.dir (Path.explode keep'))
+      then pairself Path.explode (make_names keep')
+      else pairself (File.tmp_path o Path.explode)
+        (make_names ("smt-" ^ serial_string ()))
+
+    val y = Exn.capture (f problem_path proof_path) x
+
+    val _ = if keep' = "" then (pairself (try File.rm) paths; ()) else ()
   in Exn.release y end
 
 fun run in_path out_path (ctxt, cmd, output) =
@@ -115,12 +128,18 @@
 fun run_solver ctxt {env_var, remote_name} args output =
   let
     val qf = File.shell_path and qq = File.shell_quote
-    val path = getenv env_var and remote = getenv "REMOTE_SMT_SOLVER"
+    val qs = qf o Path.explode
+    val local_name = getenv env_var
+    val cert_name = Config.get ctxt cert
+    val remote = qs (getenv "REMOTE_SMT_SOLVER")
+    val cert_script = qs (getenv "CERT_SMT_SOLVER")
     fun cmd f1 f2 =
-      if path <> ""
-      then map qq (path :: args) @ [qf f1, ">", qf f2]
-      else "perl -w" :: map qq (remote :: remote_name :: args) @ [qf f1, qf f2]
-  in with_tmp_files run (ctxt, space_implode " " oo cmd, output) end
+      if cert_name <> ""
+      then "perl -w" :: [cert_script, qs cert_name, qf f1, ">", qf f2]
+      else if local_name <> ""
+      then qs local_name :: map qq args @ [qf f1, ">", qf f2]
+      else "perl -w" :: remote :: map qq (remote_name :: args) @ [qf f1, qf f2]
+  in with_files ctxt run (ctxt, space_implode " " oo cmd, output) end
 
 end
 
@@ -129,12 +148,12 @@
 
 fun gen_solver solver ctxt prems =
   let
-    val SolverConfig {name, interface, arguments, reconstruct} = solver ctxt
+    val SolverConfig {command, arguments, interface, 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
+    ||> run_solver ctxt command arguments o SMT_Translate.translate tc thy
     ||> reconstruct o make_proof_data ctxt
     |-> fold SMT_Normalize.discharge_definition
   end
@@ -196,8 +215,8 @@
 
 fun pretty_counterex ctxt (real, ex) =
   let
-    val msg = if real then "Counterexample found:"
-      else "Potential counterexample found:"
+    val msg = if real then "SMT: counterexample found:"
+      else "SMT: 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
@@ -212,6 +231,11 @@
 
 val smt_tac = smt_tac' false
 
+val smt_method =
+  Scan.optional (Scan.lift (Args.add -- Args.colon) |-- Attrib.thms) [] >>
+  (fn thms => fn ctxt => METHOD (fn facts =>
+    HEADGOAL (smt_tac ctxt (thms @ facts))))
+
 
 (* setup *)
 
@@ -221,7 +245,11 @@
       (Thm.declaration_attribute o K o select_solver))
     "SMT solver configuration" #>
   setup_timeout #>
-  setup_trace
+  setup_trace #>
+  setup_keep #>
+  setup_cert #>
+  Method.setup (Binding.name "smt") smt_method
+    "Applies an SMT solver to the current goal."
 
 fun print_setup gen =
   let
@@ -243,4 +271,10 @@
       Pretty.big_list "Solver-specific settings:" infos])
   end
 
+val _ = 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 =>
+      print_setup (Context.Proof (Toplevel.context_of state)))))
+
 end