src/HOL/Tools/SMT/smt_config.ML
author wenzelm
Thu, 15 Mar 2012 20:07:00 +0100
changeset 47823 94aa7b81bcf6
parent 47607 4dc7ddb47350
child 47836 5c6955f487e5
permissions -rw-r--r--
prefer formally checked @{keyword} parser;
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