make SMT integration slacker w.r.t. bad apples (facts)
1 (* Title: HOL/Tools/SMT/smt_config.ML
2 Author: Sascha Boehme, TU Muenchen
4 Configuration options and diagnostic tools for SMT.
12 class: Proof.context -> SMT_Utils.class,
14 options: Proof.context -> string list }
15 val add_solver: solver_info -> Context.generic -> Context.generic
16 val set_solver_options: string * string -> Context.generic -> Context.generic
17 val is_available: Proof.context -> string -> bool
18 val available_solvers_of: Proof.context -> string list
19 val select_solver: string -> Context.generic -> Context.generic
20 val solver_of: Proof.context -> string
21 val solver_class_of: Proof.context -> SMT_Utils.class
22 val solver_options_of: Proof.context -> string list
25 val oracle: bool Config.T
26 val datatypes: bool Config.T
27 val timeout: real Config.T
28 val random_seed: int Config.T
29 val read_only_certificates: bool Config.T
30 val verbose: bool Config.T
31 val trace: bool Config.T
32 val trace_used_facts: bool Config.T
33 val monomorph_limit: int Config.T
34 val monomorph_instances: int Config.T
35 val infer_triggers: bool Config.T
36 val filter_only_facts: bool Config.T
37 val debug_files: string Config.T
40 val with_timeout: Proof.context -> ('a -> 'b) -> 'a -> 'b
43 val trace_msg: Proof.context -> ('a -> string) -> 'a -> unit
44 val verbose_msg: Proof.context -> ('a -> string) -> 'a -> unit
47 val select_certificates: string -> Context.generic -> Context.generic
48 val certificates_of: Proof.context -> Cache_IO.cache option
51 val setup: theory -> theory
52 val print_setup: Proof.context -> unit
55 structure SMT_Config: SMT_CONFIG =
62 class: Proof.context -> SMT_Utils.class,
64 options: Proof.context -> string list }
66 (* FIXME just one data slot (record) per program unit *)
67 structure Solvers = Generic_Data
69 type T = (solver_info * string list) Symtab.table * string option
70 val empty = (Symtab.empty, NONE)
72 fun merge ((ss1, s1), (ss2, s2)) =
73 (Symtab.merge (K true) (ss1, ss2), merge_options (s1, s2))
76 fun set_solver_options (name, options) =
77 let val opts = String.tokens (Symbol.is_ascii_blank o str) options
78 in Solvers.map (apfst (Symtab.map_entry name (apsnd (K opts)))) end
80 fun add_solver (info as {name, ...} : solver_info) context =
81 if Symtab.defined (fst (Solvers.get context)) name then
82 error ("Solver already registered: " ^ quote name)
85 |> Solvers.map (apfst (Symtab.update (name, (info, []))))
86 |> Context.map_theory (Attrib.setup (Binding.name (name ^ "_options"))
87 (Scan.lift (@{keyword "="} |-- Args.name) >>
88 (Thm.declaration_attribute o K o set_solver_options o pair name))
89 ("Additional command line options for SMT solver " ^ quote name))
91 fun all_solvers_of ctxt = Symtab.keys (fst (Solvers.get (Context.Proof ctxt)))
93 fun solver_name_of ctxt = snd (Solvers.get (Context.Proof ctxt))
95 fun is_available ctxt name =
96 (case Symtab.lookup (fst (Solvers.get (Context.Proof ctxt))) name of
97 SOME ({avail, ...}, _) => avail ()
100 fun available_solvers_of ctxt =
101 filter (is_available ctxt) (all_solvers_of ctxt)
103 fun warn_solver (Context.Proof ctxt) name =
104 Context_Position.if_visible ctxt
105 warning ("The SMT solver " ^ quote name ^ " is not installed.")
106 | warn_solver _ _ = ();
108 fun select_solver name context =
110 val ctxt = Context.proof_of context
111 val upd = Solvers.map (apsnd (K (SOME name)))
113 if not (member (op =) (all_solvers_of ctxt) name) then
114 error ("Trying to select unknown solver: " ^ quote name)
115 else if not (is_available ctxt name) then
116 (warn_solver context name; upd context)
120 fun no_solver_err () = error "No SMT solver selected"
123 (case solver_name_of ctxt of
125 | NONE => no_solver_err ())
127 fun solver_info_of default select ctxt =
128 (case Solvers.get (Context.Proof ctxt) of
129 (solvers, SOME name) => select (Symtab.lookup solvers name)
130 | (_, NONE) => default ())
132 fun solver_class_of ctxt =
133 let fun class_of ({class, ...}: solver_info, _) = class ctxt
134 in solver_info_of no_solver_err (class_of o the) ctxt end
136 fun solver_options_of ctxt =
138 fun all_options NONE = []
139 | all_options (SOME ({options, ...} : solver_info, opts)) =
141 in solver_info_of (K []) all_options ctxt end
144 Attrib.setup @{binding smt_solver}
145 (Scan.lift (@{keyword "="} |-- Args.name) >>
146 (Thm.declaration_attribute o K o select_solver))
147 "SMT solver configuration"
152 val oracle = Attrib.setup_config_bool @{binding smt_oracle} (K true)
153 val datatypes = Attrib.setup_config_bool @{binding smt_datatypes} (K false)
154 val timeout = Attrib.setup_config_real @{binding smt_timeout} (K 30.0)
155 val random_seed = Attrib.setup_config_int @{binding smt_random_seed} (K 1)
156 val read_only_certificates = Attrib.setup_config_bool @{binding smt_read_only_certificates} (K false)
157 val verbose = Attrib.setup_config_bool @{binding smt_verbose} (K true)
158 val trace = Attrib.setup_config_bool @{binding smt_trace} (K false)
159 val trace_used_facts = Attrib.setup_config_bool @{binding smt_trace_used_facts} (K false)
160 val monomorph_limit = Attrib.setup_config_int @{binding smt_monomorph_limit} (K 10)
161 val monomorph_instances = Attrib.setup_config_int @{binding smt_monomorph_instances} (K 500)
162 val infer_triggers = Attrib.setup_config_bool @{binding smt_infer_triggers} (K false)
163 val filter_only_facts = Attrib.setup_config_bool @{binding smt_filter_only_facts} (K false)
164 val debug_files = Attrib.setup_config_string @{binding smt_debug_files} (K "")
169 fun cond_trace flag f x = if flag then tracing ("SMT: " ^ f x) else ()
171 fun verbose_msg ctxt = cond_trace (Config.get ctxt verbose)
173 fun trace_msg ctxt = cond_trace (Config.get ctxt trace)
178 fun with_timeout ctxt f x =
179 TimeLimit.timeLimit (seconds (Config.get ctxt timeout)) f x
180 handle TimeLimit.TimeOut => raise SMT_Failure.SMT SMT_Failure.Time_Out
185 (* FIXME just one data slot (record) per program unit *)
186 structure Certificates = Generic_Data
188 type T = Cache_IO.cache option
191 fun merge (s, _) = s (* FIXME merge options!? *)
194 val get_certificates_path =
195 Option.map (Cache_IO.cache_path_of) o Certificates.get o Context.Proof
197 fun select_certificates name context = context |> Certificates.put (
198 if name = "" then NONE
201 |> Path.append (Thy_Load.master_directory (Context.theory_of context))
202 |> SOME o Cache_IO.unsynchronized_init)
204 val certificates_of = Certificates.get o Context.Proof
206 val setup_certificates =
207 Attrib.setup @{binding smt_certificates}
208 (Scan.lift (@{keyword "="} |-- Args.name) >>
209 (Thm.declaration_attribute o K o select_certificates))
210 "SMT certificates configuration"
219 fun print_setup ctxt =
221 fun string_of_bool b = if b then "true" else "false"
223 val names = available_solvers_of ctxt
224 val ns = if null names then ["(none)"] else sort_strings names
225 val n = the_default "(none)" (solver_name_of ctxt)
226 val opts = solver_options_of ctxt
228 val t = string_of_real (Config.get ctxt timeout)
231 (case get_certificates_path ctxt of
232 SOME path => Path.print path
233 | NONE => "(disabled)")
235 Pretty.writeln (Pretty.big_list "SMT setup:" [
236 Pretty.str ("Current SMT solver: " ^ n),
237 Pretty.str ("Current SMT solver options: " ^ space_implode " " opts),
238 Pretty.str_list "Available SMT solvers: " "" ns,
239 Pretty.str ("Current timeout: " ^ t ^ " seconds"),
240 Pretty.str ("With proofs: " ^
241 string_of_bool (not (Config.get ctxt oracle))),
242 Pretty.str ("Certificates cache: " ^ certs_filename),
243 Pretty.str ("Fixed certificates: " ^
244 string_of_bool (Config.get ctxt read_only_certificates))])
248 Outer_Syntax.improper_command @{command_spec "smt_status"}
249 "show the available SMT solvers, the currently selected SMT solver, \
250 \and the values of SMT configuration options"
251 (Scan.succeed (Toplevel.keep (print_setup o Toplevel.context_of)))