boehmes@40651
|
1 |
(* Title: HOL/Tools/SMT/smt_config.ML
|
boehmes@40651
|
2 |
Author: Sascha Boehme, TU Muenchen
|
boehmes@40651
|
3 |
|
boehmes@40651
|
4 |
Configuration options and diagnostic tools for SMT.
|
boehmes@40651
|
5 |
*)
|
boehmes@40651
|
6 |
|
boehmes@40651
|
7 |
signature SMT_CONFIG =
|
boehmes@40651
|
8 |
sig
|
boehmes@40651
|
9 |
(*solver*)
|
boehmes@41680
|
10 |
type solver_info = {
|
boehmes@41680
|
11 |
name: string,
|
boehmes@41680
|
12 |
class: SMT_Utils.class,
|
boehmes@41680
|
13 |
avail: unit -> bool,
|
boehmes@41680
|
14 |
options: Proof.context -> string list }
|
boehmes@41680
|
15 |
val add_solver: solver_info -> Context.generic -> Context.generic
|
boehmes@40651
|
16 |
val set_solver_options: string * string -> Context.generic -> Context.generic
|
boehmes@47607
|
17 |
val is_available: Proof.context -> string -> bool
|
boehmes@41680
|
18 |
val available_solvers_of: Proof.context -> string list
|
boehmes@40651
|
19 |
val select_solver: string -> Context.generic -> Context.generic
|
boehmes@40651
|
20 |
val solver_of: Proof.context -> string
|
boehmes@41372
|
21 |
val solver_class_of: Proof.context -> SMT_Utils.class
|
boehmes@40651
|
22 |
val solver_options_of: Proof.context -> string list
|
boehmes@40651
|
23 |
|
boehmes@40651
|
24 |
(*options*)
|
boehmes@40651
|
25 |
val oracle: bool Config.T
|
boehmes@40651
|
26 |
val datatypes: bool Config.T
|
boehmes@40651
|
27 |
val timeout: real Config.T
|
boehmes@41369
|
28 |
val random_seed: int Config.T
|
boehmes@40651
|
29 |
val fixed: bool Config.T
|
boehmes@40651
|
30 |
val verbose: bool Config.T
|
boehmes@40651
|
31 |
val trace: bool Config.T
|
boehmes@40651
|
32 |
val trace_used_facts: bool Config.T
|
boehmes@40651
|
33 |
val monomorph_limit: int Config.T
|
boehmes@42633
|
34 |
val monomorph_instances: int Config.T
|
boehmes@43061
|
35 |
val monomorph_full: bool Config.T
|
boehmes@41373
|
36 |
val infer_triggers: bool Config.T
|
boehmes@40651
|
37 |
val drop_bad_facts: bool Config.T
|
boehmes@40651
|
38 |
val filter_only_facts: bool Config.T
|
boehmes@40816
|
39 |
val debug_files: string Config.T
|
boehmes@40651
|
40 |
|
boehmes@40651
|
41 |
(*tools*)
|
boehmes@40651
|
42 |
val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
|
boehmes@40651
|
43 |
|
boehmes@40651
|
44 |
(*diagnostics*)
|
boehmes@40651
|
45 |
val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
|
boehmes@40651
|
46 |
val verbose_msg: Proof.context -> ('a -> string) -> 'a -> unit
|
boehmes@40651
|
47 |
|
boehmes@40651
|
48 |
(*certificates*)
|
boehmes@40651
|
49 |
val select_certificates: string -> Context.generic -> Context.generic
|
boehmes@40651
|
50 |
val certificates_of: Proof.context -> Cache_IO.cache option
|
boehmes@40651
|
51 |
|
boehmes@40651
|
52 |
(*setup*)
|
boehmes@40651
|
53 |
val setup: theory -> theory
|
boehmes@40651
|
54 |
val print_setup: Proof.context -> unit
|
boehmes@40651
|
55 |
end
|
boehmes@40651
|
56 |
|
boehmes@40651
|
57 |
structure SMT_Config: SMT_CONFIG =
|
boehmes@40651
|
58 |
struct
|
boehmes@40651
|
59 |
|
boehmes@40651
|
60 |
(* solver *)
|
boehmes@40651
|
61 |
|
boehmes@41680
|
62 |
type solver_info = {
|
boehmes@41680
|
63 |
name: string,
|
boehmes@41680
|
64 |
class: SMT_Utils.class,
|
boehmes@41680
|
65 |
avail: unit -> bool,
|
boehmes@41680
|
66 |
options: Proof.context -> string list }
|
boehmes@41680
|
67 |
|
wenzelm@46913
|
68 |
(* FIXME just one data slot (record) per program unit *)
|
boehmes@40651
|
69 |
structure Solvers = Generic_Data
|
boehmes@40651
|
70 |
(
|
boehmes@41680
|
71 |
type T = (solver_info * string list) Symtab.table * string option
|
boehmes@40651
|
72 |
val empty = (Symtab.empty, NONE)
|
boehmes@40651
|
73 |
val extend = I
|
boehmes@41747
|
74 |
fun merge ((ss1, s1), (ss2, s2)) =
|
boehmes@41747
|
75 |
(Symtab.merge (K true) (ss1, ss2), merge_options (s1, s2))
|
boehmes@40651
|
76 |
)
|
boehmes@40651
|
77 |
|
boehmes@40651
|
78 |
fun set_solver_options (name, options) =
|
boehmes@40651
|
79 |
let val opts = String.tokens (Symbol.is_ascii_blank o str) options
|
boehmes@41307
|
80 |
in Solvers.map (apfst (Symtab.map_entry name (apsnd (K opts)))) end
|
boehmes@40651
|
81 |
|
boehmes@41680
|
82 |
fun add_solver (info as {name, ...} : solver_info) context =
|
boehmes@40651
|
83 |
if Symtab.defined (fst (Solvers.get context)) name then
|
boehmes@40651
|
84 |
error ("Solver already registered: " ^ quote name)
|
boehmes@40651
|
85 |
else
|
boehmes@40651
|
86 |
context
|
boehmes@41680
|
87 |
|> Solvers.map (apfst (Symtab.update (name, (info, []))))
|
boehmes@40651
|
88 |
|> Context.map_theory (Attrib.setup (Binding.name (name ^ "_options"))
|
wenzelm@47823
|
89 |
(Scan.lift (@{keyword "="} |-- Args.name) >>
|
boehmes@40651
|
90 |
(Thm.declaration_attribute o K o set_solver_options o pair name))
|
boehmes@40651
|
91 |
("Additional command line options for SMT solver " ^ quote name))
|
boehmes@40651
|
92 |
|
boehmes@41680
|
93 |
fun all_solvers_of ctxt = Symtab.keys (fst (Solvers.get (Context.Proof ctxt)))
|
boehmes@41680
|
94 |
|
boehmes@41680
|
95 |
fun solver_name_of ctxt = snd (Solvers.get (Context.Proof ctxt))
|
boehmes@41680
|
96 |
|
boehmes@41680
|
97 |
fun is_available ctxt name =
|
boehmes@41680
|
98 |
(case Symtab.lookup (fst (Solvers.get (Context.Proof ctxt))) name of
|
boehmes@41680
|
99 |
SOME ({avail, ...}, _) => avail ()
|
boehmes@41680
|
100 |
| NONE => false)
|
boehmes@41680
|
101 |
|
boehmes@41680
|
102 |
fun available_solvers_of ctxt =
|
boehmes@41680
|
103 |
filter (is_available ctxt) (all_solvers_of ctxt)
|
boehmes@41680
|
104 |
|
boehmes@41746
|
105 |
fun warn_solver context name =
|
boehmes@41746
|
106 |
Context_Position.if_visible_proof context
|
boehmes@41746
|
107 |
warning ("The SMT solver " ^ quote name ^ " is not installed.")
|
boehmes@41680
|
108 |
|
boehmes@40651
|
109 |
fun select_solver name context =
|
boehmes@41680
|
110 |
let
|
boehmes@41680
|
111 |
val ctxt = Context.proof_of context
|
boehmes@41680
|
112 |
val upd = Solvers.map (apsnd (K (SOME name)))
|
boehmes@41680
|
113 |
in
|
boehmes@41680
|
114 |
if not (member (op =) (all_solvers_of ctxt) name) then
|
boehmes@41680
|
115 |
error ("Trying to select unknown solver: " ^ quote name)
|
boehmes@41746
|
116 |
else if not (is_available ctxt name) then
|
boehmes@41746
|
117 |
(warn_solver context name; upd context)
|
boehmes@41680
|
118 |
else upd context
|
boehmes@41680
|
119 |
end
|
boehmes@40651
|
120 |
|
boehmes@41307
|
121 |
fun no_solver_err () = error "No SMT solver selected"
|
boehmes@40651
|
122 |
|
boehmes@40651
|
123 |
fun solver_of ctxt =
|
boehmes@41680
|
124 |
(case solver_name_of ctxt of
|
boehmes@41680
|
125 |
SOME name => name
|
boehmes@41680
|
126 |
| NONE => no_solver_err ())
|
boehmes@41680
|
127 |
|
boehmes@41680
|
128 |
fun solver_info_of default select ctxt =
|
boehmes@41307
|
129 |
(case Solvers.get (Context.Proof ctxt) of
|
boehmes@41680
|
130 |
(solvers, SOME name) => select (Symtab.lookup solvers name)
|
boehmes@41680
|
131 |
| (_, NONE) => default ())
|
boehmes@41307
|
132 |
|
boehmes@41307
|
133 |
fun solver_class_of ctxt =
|
boehmes@41680
|
134 |
solver_info_of no_solver_err (#class o fst o the) ctxt
|
boehmes@40651
|
135 |
|
boehmes@40651
|
136 |
fun solver_options_of ctxt =
|
boehmes@41680
|
137 |
let
|
boehmes@41680
|
138 |
fun all_options NONE = []
|
boehmes@41686
|
139 |
| all_options (SOME ({options, ...} : solver_info, opts)) =
|
boehmes@41686
|
140 |
opts @ options ctxt
|
boehmes@41680
|
141 |
in solver_info_of (K []) all_options ctxt end
|
boehmes@40651
|
142 |
|
boehmes@40651
|
143 |
val setup_solver =
|
boehmes@40651
|
144 |
Attrib.setup @{binding smt_solver}
|
wenzelm@47823
|
145 |
(Scan.lift (@{keyword "="} |-- Args.name) >>
|
boehmes@40651
|
146 |
(Thm.declaration_attribute o K o select_solver))
|
boehmes@40651
|
147 |
"SMT solver configuration"
|
boehmes@40651
|
148 |
|
boehmes@40651
|
149 |
|
boehmes@40651
|
150 |
(* options *)
|
boehmes@40651
|
151 |
|
wenzelm@43487
|
152 |
val oracle = Attrib.setup_config_bool @{binding smt_oracle} (K true)
|
wenzelm@43487
|
153 |
val datatypes = Attrib.setup_config_bool @{binding smt_datatypes} (K false)
|
wenzelm@43487
|
154 |
val timeout = Attrib.setup_config_real @{binding smt_timeout} (K 30.0)
|
wenzelm@43487
|
155 |
val random_seed = Attrib.setup_config_int @{binding smt_random_seed} (K 1)
|
wenzelm@43487
|
156 |
val fixed = Attrib.setup_config_bool @{binding smt_fixed} (K false)
|
wenzelm@43487
|
157 |
val verbose = Attrib.setup_config_bool @{binding smt_verbose} (K true)
|
wenzelm@43487
|
158 |
val trace = Attrib.setup_config_bool @{binding smt_trace} (K false)
|
wenzelm@43487
|
159 |
val trace_used_facts = Attrib.setup_config_bool @{binding smt_trace_used_facts} (K false)
|
wenzelm@43487
|
160 |
val monomorph_limit = Attrib.setup_config_int @{binding smt_monomorph_limit} (K 10)
|
wenzelm@43487
|
161 |
val monomorph_instances = Attrib.setup_config_int @{binding smt_monomorph_instances} (K 500)
|
wenzelm@43487
|
162 |
val monomorph_full = Attrib.setup_config_bool @{binding smt_monomorph_full} (K true)
|
wenzelm@43487
|
163 |
val infer_triggers = Attrib.setup_config_bool @{binding smt_infer_triggers} (K false)
|
wenzelm@43487
|
164 |
val drop_bad_facts = Attrib.setup_config_bool @{binding smt_drop_bad_facts} (K false)
|
wenzelm@43487
|
165 |
val filter_only_facts = Attrib.setup_config_bool @{binding smt_filter_only_facts} (K false)
|
wenzelm@43487
|
166 |
val debug_files = Attrib.setup_config_string @{binding smt_debug_files} (K "")
|
boehmes@40651
|
167 |
|
boehmes@40651
|
168 |
|
boehmes@40651
|
169 |
(* diagnostics *)
|
boehmes@40651
|
170 |
|
boehmes@40651
|
171 |
fun cond_trace flag f x = if flag then tracing ("SMT: " ^ f x) else ()
|
boehmes@40651
|
172 |
|
boehmes@40651
|
173 |
fun verbose_msg ctxt = cond_trace (Config.get ctxt verbose)
|
boehmes@40651
|
174 |
|
boehmes@40651
|
175 |
fun trace_msg ctxt = cond_trace (Config.get ctxt trace)
|
boehmes@40651
|
176 |
|
boehmes@40651
|
177 |
|
boehmes@40651
|
178 |
(* tools *)
|
boehmes@40651
|
179 |
|
boehmes@40651
|
180 |
fun with_timeout ctxt f x =
|
boehmes@40651
|
181 |
TimeLimit.timeLimit (seconds (Config.get ctxt timeout)) f x
|
boehmes@40651
|
182 |
handle TimeLimit.TimeOut => raise SMT_Failure.SMT SMT_Failure.Time_Out
|
boehmes@40651
|
183 |
|
boehmes@40651
|
184 |
|
boehmes@40651
|
185 |
(* certificates *)
|
boehmes@40651
|
186 |
|
wenzelm@46913
|
187 |
(* FIXME just one data slot (record) per program unit *)
|
boehmes@40651
|
188 |
structure Certificates = Generic_Data
|
boehmes@40651
|
189 |
(
|
boehmes@40651
|
190 |
type T = Cache_IO.cache option
|
boehmes@40651
|
191 |
val empty = NONE
|
boehmes@40651
|
192 |
val extend = I
|
wenzelm@41720
|
193 |
fun merge (s, _) = s (* FIXME merge options!? *)
|
boehmes@40651
|
194 |
)
|
boehmes@40651
|
195 |
|
boehmes@40651
|
196 |
val get_certificates_path =
|
boehmes@40651
|
197 |
Option.map (Cache_IO.cache_path_of) o Certificates.get o Context.Proof
|
boehmes@40651
|
198 |
|
boehmes@40757
|
199 |
fun select_certificates name context = context |> Certificates.put (
|
boehmes@40651
|
200 |
if name = "" then NONE
|
boehmes@40757
|
201 |
else
|
boehmes@40757
|
202 |
Path.explode name
|
boehmes@40757
|
203 |
|> Path.append (Thy_Load.master_directory (Context.theory_of context))
|
boehmes@40757
|
204 |
|> SOME o Cache_IO.make)
|
boehmes@40651
|
205 |
|
boehmes@40651
|
206 |
val certificates_of = Certificates.get o Context.Proof
|
boehmes@40651
|
207 |
|
boehmes@40651
|
208 |
val setup_certificates =
|
boehmes@40651
|
209 |
Attrib.setup @{binding smt_certificates}
|
wenzelm@47823
|
210 |
(Scan.lift (@{keyword "="} |-- Args.name) >>
|
boehmes@40651
|
211 |
(Thm.declaration_attribute o K o select_certificates))
|
boehmes@40651
|
212 |
"SMT certificates configuration"
|
boehmes@40651
|
213 |
|
boehmes@40651
|
214 |
|
boehmes@40651
|
215 |
(* setup *)
|
boehmes@40651
|
216 |
|
boehmes@40651
|
217 |
val setup =
|
boehmes@40651
|
218 |
setup_solver #>
|
boehmes@40651
|
219 |
setup_certificates
|
boehmes@40651
|
220 |
|
boehmes@40651
|
221 |
fun print_setup ctxt =
|
boehmes@40651
|
222 |
let
|
boehmes@40651
|
223 |
fun string_of_bool b = if b then "true" else "false"
|
boehmes@40651
|
224 |
|
boehmes@41680
|
225 |
val names = available_solvers_of ctxt
|
boehmes@40651
|
226 |
val ns = if null names then ["(none)"] else sort_strings names
|
boehmes@41680
|
227 |
val n = the_default "(none)" (solver_name_of ctxt)
|
boehmes@40651
|
228 |
val opts = solver_options_of ctxt
|
boehmes@40651
|
229 |
|
boehmes@40651
|
230 |
val t = string_of_real (Config.get ctxt timeout)
|
boehmes@40651
|
231 |
|
boehmes@40651
|
232 |
val certs_filename =
|
boehmes@40651
|
233 |
(case get_certificates_path ctxt of
|
wenzelm@42815
|
234 |
SOME path => Path.print path
|
boehmes@40651
|
235 |
| NONE => "(disabled)")
|
boehmes@40651
|
236 |
in
|
boehmes@40651
|
237 |
Pretty.writeln (Pretty.big_list "SMT setup:" [
|
boehmes@40651
|
238 |
Pretty.str ("Current SMT solver: " ^ n),
|
boehmes@40651
|
239 |
Pretty.str ("Current SMT solver options: " ^ space_implode " " opts),
|
boehmes@40651
|
240 |
Pretty.str_list "Available SMT solvers: " "" ns,
|
boehmes@40651
|
241 |
Pretty.str ("Current timeout: " ^ t ^ " seconds"),
|
boehmes@40651
|
242 |
Pretty.str ("With proofs: " ^
|
boehmes@40651
|
243 |
string_of_bool (not (Config.get ctxt oracle))),
|
boehmes@40651
|
244 |
Pretty.str ("Certificates cache: " ^ certs_filename),
|
boehmes@40651
|
245 |
Pretty.str ("Fixed certificates: " ^
|
boehmes@40651
|
246 |
string_of_bool (Config.get ctxt fixed))])
|
boehmes@40651
|
247 |
end
|
boehmes@40651
|
248 |
|
boehmes@40651
|
249 |
val _ =
|
boehmes@40651
|
250 |
Outer_Syntax.improper_command "smt_status"
|
boehmes@40651
|
251 |
("show the available SMT solvers, the currently selected SMT solver, " ^
|
boehmes@40651
|
252 |
"and the values of SMT configuration options")
|
boehmes@40651
|
253 |
Keyword.diag
|
boehmes@40651
|
254 |
(Scan.succeed (Toplevel.no_timing o Toplevel.keep (fn state =>
|
boehmes@40651
|
255 |
print_setup (Toplevel.context_of state))))
|
boehmes@40651
|
256 |
|
boehmes@40651
|
257 |
end
|