src/HOL/SMT/Tools/smt_solver.ML
changeset 35151 117247018b54
parent 35025 0ea45a4d32f3
child 35153 5e8935678ee4
equal deleted inserted replaced
35150:082fa4bd403d 35151:117247018b54
    26   (*options*)
    26   (*options*)
    27   val timeout: int Config.T
    27   val timeout: int Config.T
    28   val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
    28   val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
    29   val trace: bool Config.T
    29   val trace: bool Config.T
    30   val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
    30   val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
       
    31 
       
    32   (*certificates*)
    31   val record: bool Config.T
    33   val record: bool Config.T
    32   val certificates: string Config.T
    34   val select_certificates: string -> Context.generic -> Context.generic
    33 
    35 
    34   (*solvers*)
    36   (*solvers*)
    35   type solver = Proof.context -> thm list -> thm
    37   type solver = Proof.context -> thm list -> thm
    36   type solver_info = Context.generic -> Pretty.T list
    38   type solver_info = Context.generic -> Pretty.T list
    37   val add_solver: string * (Proof.context -> solver_config) -> theory ->
    39   val add_solver: string * (Proof.context -> solver_config) -> theory ->
    86 val (trace, setup_trace) = Attrib.config_bool "smt_trace" false
    88 val (trace, setup_trace) = Attrib.config_bool "smt_trace" false
    87 
    89 
    88 fun trace_msg ctxt f x =
    90 fun trace_msg ctxt f x =
    89   if Config.get ctxt trace then tracing (f x) else ()
    91   if Config.get ctxt trace then tracing (f x) else ()
    90 
    92 
       
    93 
       
    94 (* SMT certificates *)
       
    95 
    91 val (record, setup_record) = Attrib.config_bool "smt_record" true
    96 val (record, setup_record) = Attrib.config_bool "smt_record" true
    92 val no_certificates = ""
    97 
    93 val (certificates, setup_certificates) =
    98 structure Certificates = Generic_Data
    94   Attrib.config_string "smt_certificates" no_certificates
    99 (
    95 
   100   type T = Cache_IO.cache option
       
   101   val empty = NONE
       
   102   val extend = I
       
   103   fun merge (s, _) = s
       
   104 )
       
   105 
       
   106 fun select_certificates name = Certificates.put (
       
   107   if name = "" then NONE
       
   108   else SOME (Cache_IO.make (Path.explode name)))
    96 
   109 
    97 
   110 
    98 (* interface to external solvers *)
   111 (* interface to external solvers *)
    99 
   112 
   100 local
   113 local
   101 
   114 
   102 fun with_files ctxt f =
   115 fun invoke ctxt output f problem_path =
   103   let
       
   104     val paths as (problem_path, proof_path) =
       
   105       "smt-" ^ serial_string ()
       
   106       |> (fn n => (n, n ^ ".proof"))
       
   107       |> pairself (File.tmp_path o Path.explode)
       
   108 
       
   109     val y = Exn.capture f (problem_path, proof_path)
       
   110 
       
   111     val _ = pairself (try File.rm) paths
       
   112   in Exn.release y end
       
   113 
       
   114 fun invoke ctxt output f (paths as (problem_path, proof_path)) =
       
   115   let
   116   let
   116     fun pretty tag ls = Pretty.string_of (Pretty.big_list tag
   117     fun pretty tag ls = Pretty.string_of (Pretty.big_list tag
   117       (map Pretty.str ls))
   118       (map Pretty.str ls))
   118 
   119 
   119     val x = File.open_output output problem_path
   120     val x = File.open_output output problem_path
   120     val _ = trace_msg ctxt (pretty "SMT problem:" o split_lines o File.read)
   121     val _ = trace_msg ctxt (pretty "SMT problem:" o split_lines o File.read)
   121       problem_path
   122       problem_path
   122 
   123 
   123     val (s, _) = with_timeout ctxt f paths
   124     val (res, err) = with_timeout ctxt f problem_path
   124     val _ = trace_msg ctxt (pretty "SMT solver:") (split_lines s)
   125     val _ = trace_msg ctxt (pretty "SMT solver:") err
   125 
   126 
   126     fun lines_of path = the_default [] (try (File.fold_lines cons path) [])
   127     val ls = rev (dropwhile (equal "") (rev res))
   127     val ls = rev (dropwhile (equal "") (lines_of proof_path))
       
   128     val _ = trace_msg ctxt (pretty "SMT result:") ls
   128     val _ = trace_msg ctxt (pretty "SMT result:") ls
   129   in (x, ls) end
   129   in (x, ls) end
   130 
   130 
   131 fun choose {env_var, remote_name} =
   131 fun choose {env_var, remote_name} =
   132   let
   132   let
   133     val local_solver = getenv env_var
   133     val local_solver = getenv env_var
   134     val remote_solver = the_default "" remote_name
   134     val remote_solver = the_default "" remote_name
   135     val remote_url = getenv "REMOTE_SMT_URL"
   135     val remote_url = getenv "REMOTE_SMT_URL"
   136   in
   136   in
   137     if local_solver <> ""
   137     if local_solver <> ""
   138     then (["local", local_solver],
   138     then 
   139       "Invoking local SMT solver " ^ quote local_solver ^ " ...")
   139      (tracing ("Invoking local SMT solver " ^ quote local_solver ^ " ...");
   140     else if remote_solver <> "" andalso remote_url <> ""
   140       [local_solver])
   141     then (["remote", remote_solver],
   141     else if remote_solver <> ""
   142       "Invoking remote SMT solver " ^ quote remote_solver ^ " at " ^
   142     then
   143       quote remote_url ^ " ...")
   143      (tracing ("Invoking remote SMT solver " ^ quote remote_solver ^ " at " ^
       
   144         quote remote_url ^ " ...");
       
   145       [getenv "REMOTE_SMT", remote_solver])
   144     else error ("Undefined Isabelle environment variable: " ^ quote env_var)
   146     else error ("Undefined Isabelle environment variable: " ^ quote env_var)
   145   end
   147   end
   146 
   148 
   147 fun run ctxt cmd args (problem_path, proof_path) =
   149 fun make_cmd solver args problem_path proof_path = space_implode " " (
   148   let
   150   map File.shell_quote (solver @ args) @
   149     val certs = Config.get ctxt certificates
   151   [File.shell_path problem_path, "2>&1", ">", File.shell_path proof_path])
   150     val certs' = 
   152 
   151       if certs = no_certificates then "-"
   153 fun no_cmd _ _ = error ("Bad certificates cache: missing certificate")
   152       else File.shell_path (Path.explode certs)
   154 
   153     val (solver, msg) =
   155 fun run ctxt cmd args problem_path =
   154       if certs = no_certificates orelse Config.get ctxt record
   156   let val certs = Certificates.get (Context.Proof ctxt)
   155       then choose cmd
       
   156       else (["certificate"], "Using certificate from " ^ quote certs' ^ " ...")
       
   157     val _ = tracing msg
       
   158   in
   157   in
   159     bash_output (space_implode " " (
   158     if is_none certs 
   160       File.shell_path (Path.explode (getenv "RUN_SMT_SOLVER")) :: certs' ::
   159     then Cache_IO.run' (make_cmd (choose cmd) args) problem_path
   161       map File.shell_quote (solver @ args) @
   160     else if Config.get ctxt record
   162       map File.shell_path [problem_path, proof_path]) ^ " 2>&1")
   161     then Cache_IO.cached' (the certs) (make_cmd (choose cmd) args) problem_path
       
   162     else
       
   163      (tracing ("Using cached certificate from " ^
       
   164         File.shell_path (Cache_IO.cache_path_of (the certs)) ^ " ...");
       
   165       Cache_IO.cached' (the certs) no_cmd problem_path)
   163   end
   166   end
   164 
   167 
   165 in
   168 in
   166 
   169 
   167 fun run_solver ctxt cmd args output =
   170 fun run_solver ctxt cmd args output =
   168   with_files ctxt (invoke ctxt output (run ctxt cmd args))
   171   Cache_IO.with_tmp_file "smt-" (invoke ctxt output (run ctxt cmd args))
   169 
   172 
   170 end
   173 end
   171 
   174 
   172 fun make_proof_data ctxt ((recon, thms), ls) =
   175 fun make_proof_data ctxt ((recon, thms), ls) =
   173   {context=ctxt, output=ls, recon=recon, assms=SOME thms}
   176   {context=ctxt, output=ls, recon=recon, assms=SOME thms}
   276       (Thm.declaration_attribute o K o select_solver))
   279       (Thm.declaration_attribute o K o select_solver))
   277     "SMT solver configuration" #>
   280     "SMT solver configuration" #>
   278   setup_timeout #>
   281   setup_timeout #>
   279   setup_trace #>
   282   setup_trace #>
   280   setup_record #>
   283   setup_record #>
   281   setup_certificates #>
   284   Attrib.setup (Binding.name "smt_certificates")
       
   285     (Scan.lift (OuterParse.$$$ "=" |-- Args.name) >>
       
   286       (Thm.declaration_attribute o K o select_certificates))
       
   287     "SMT certificates" #>
   282   Method.setup (Binding.name "smt") smt_method
   288   Method.setup (Binding.name "smt") smt_method
   283     "Applies an SMT solver to the current goal."
   289     "Applies an SMT solver to the current goal."
   284 
   290 
   285 
   291 
   286 fun print_setup gen =
   292 fun print_setup gen =