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} |