author | blanchet |
Fri, 08 Sep 2017 00:02:24 +0200 | |
changeset 66625 | 2cd22f070929 |
parent 66619 | 556e19e43e4d |
child 66627 | 4145169ae609 |
permissions | -rw-r--r-- |
64389 | 1 |
(* Title: HOL/Nunchaku/Tools/nunchaku_commands.ML |
66614
1f1c5d85d232
moved Nunchaku to Main; the goal is to move Nitpick out in the next 1-2 years
blanchet
parents:
66163
diff
changeset
|
2 |
Author: Jasmin Blanchette, VU Amsterdam |
1f1c5d85d232
moved Nunchaku to Main; the goal is to move Nitpick out in the next 1-2 years
blanchet
parents:
66163
diff
changeset
|
3 |
Copyright 2015, 2016, 2017 |
64389 | 4 |
|
5 |
Adds the "nunchaku" and "nunchaku_params" commands to Isabelle/Isar's outer syntax. |
|
6 |
*) |
|
7 |
||
8 |
signature NUNCHAKU_COMMANDS = |
|
9 |
sig |
|
10 |
type params = Nunchaku.params |
|
11 |
||
12 |
val default_params: theory -> (string * string) list -> params |
|
13 |
end; |
|
14 |
||
15 |
structure Nunchaku_Commands : NUNCHAKU_COMMANDS = |
|
16 |
struct |
|
17 |
||
18 |
open Nunchaku_Util; |
|
19 |
open Nunchaku; |
|
20 |
||
21 |
type raw_param = string * string list; |
|
22 |
||
23 |
val default_default_params = |
|
24 |
[("assms", "true"), |
|
66625 | 25 |
("bound_increment", "2"), |
64389 | 26 |
("debug", "false"), |
27 |
("falsify", "true"), |
|
66625 | 28 |
("initial_bound", "2"), |
64389 | 29 |
("max_genuine", "1"), |
30 |
("max_potential", "1"), |
|
31 |
("overlord", "false"), |
|
66163 | 32 |
("solvers", "cvc4 kodkod paradox smbc"), |
64389 | 33 |
("specialize", "true"), |
34 |
("spy", "false"), |
|
35 |
("timeout", "30"), |
|
36 |
("verbose", "false"), |
|
37 |
("wf_timeout", "0.5")]; |
|
38 |
||
66619 | 39 |
val alias_params = |
40 |
[("solver", "solvers")]; |
|
41 |
||
42 |
val negated_alias_params = |
|
64389 | 43 |
[("dont_whack", "whack"), |
44 |
("dont_specialize", "specialize"), |
|
45 |
("dont_spy", "spy"), |
|
46 |
("no_assms", "assms"), |
|
47 |
("no_debug", "debug"), |
|
48 |
("no_overlord", "overlord"), |
|
49 |
("non_mono", "mono"), |
|
50 |
("non_wf", "wf"), |
|
51 |
("quiet", "verbose"), |
|
52 |
("satisfy", "falsify")]; |
|
53 |
||
54 |
fun is_known_raw_param s = |
|
55 |
AList.defined (op =) default_default_params s orelse |
|
66619 | 56 |
AList.defined (op =) alias_params s orelse |
57 |
AList.defined (op =) negated_alias_params s orelse |
|
64389 | 58 |
member (op =) ["atoms", "card", "eval", "expect"] s orelse |
59 |
exists (fn p => String.isPrefix (p ^ " ") s) |
|
60 |
["atoms", "card", "dont_whack", "mono", "non_mono", "non_wf", "wf", "whack"]; |
|
61 |
||
62 |
fun check_raw_param (s, _) = |
|
63 |
if is_known_raw_param s then () else error ("Unknown parameter: " ^ quote s); |
|
64 |
||
65 |
fun unnegate_param_name name = |
|
66619 | 66 |
(case AList.lookup (op =) negated_alias_params name of |
64389 | 67 |
NONE => |
68 |
if String.isPrefix "dont_" name then SOME (unprefix "dont_" name) |
|
69 |
else if String.isPrefix "non_" name then SOME (unprefix "non_" name) |
|
70 |
else NONE |
|
71 |
| some_name => some_name); |
|
72 |
||
73 |
fun normalize_raw_param (name, value) = |
|
66619 | 74 |
(case AList.lookup (op =) alias_params name of |
75 |
SOME alias => [(alias, value)] |
|
76 |
| NONE => |
|
77 |
(case unnegate_param_name name of |
|
78 |
SOME name' => |
|
79 |
[(name', |
|
80 |
(case value of |
|
81 |
["false"] => ["true"] |
|
82 |
| ["true"] => ["false"] |
|
83 |
| [] => ["false"] |
|
84 |
| _ => value))] |
|
85 |
| NONE => [(name, value)])); |
|
64389 | 86 |
|
87 |
structure Data = Theory_Data |
|
88 |
( |
|
89 |
type T = raw_param list |
|
90 |
val empty = default_default_params |> map (apsnd single) |
|
91 |
val extend = I |
|
92 |
fun merge data = AList.merge (op =) (K true) data |
|
93 |
); |
|
94 |
||
95 |
val set_default_raw_param = Data.map o fold (AList.update (op =)) o normalize_raw_param; |
|
96 |
val default_raw_params = Data.get; |
|
97 |
||
98 |
fun is_punctuation s = (s = "," orelse s = "-"); |
|
99 |
||
100 |
fun stringify_raw_param_value [] = "" |
|
101 |
| stringify_raw_param_value [s] = s |
|
102 |
| stringify_raw_param_value (s1 :: s2 :: ss) = |
|
103 |
s1 ^ (if is_punctuation s1 orelse is_punctuation s2 then "" else " ") ^ |
|
104 |
stringify_raw_param_value (s2 :: ss); |
|
105 |
||
106 |
fun extract_params ctxt mode default_params override_params = |
|
107 |
let |
|
108 |
val override_params = maps normalize_raw_param override_params; |
|
109 |
val raw_params = rev override_params @ rev default_params; |
|
110 |
val raw_lookup = AList.lookup (op =) raw_params; |
|
111 |
val lookup = Option.map stringify_raw_param_value o raw_lookup; |
|
112 |
val lookup_string = the_default "" o lookup; |
|
66163 | 113 |
val lookup_strings = these o Option.map (space_explode " ") o lookup; |
64389 | 114 |
|
115 |
fun general_lookup_bool option default_value name = |
|
116 |
(case lookup name of |
|
117 |
SOME s => parse_bool_option option name s |
|
118 |
| NONE => default_value); |
|
119 |
||
120 |
val lookup_bool = the o general_lookup_bool false (SOME false); |
|
121 |
||
122 |
fun lookup_int name = |
|
123 |
(case lookup name of |
|
124 |
SOME s => |
|
125 |
(case Int.fromString s of |
|
126 |
SOME i => i |
|
127 |
| NONE => error ("Parameter " ^ quote name ^ " must be assigned an integer value")) |
|
128 |
| NONE => 0); |
|
129 |
||
130 |
fun int_range_from_string name s = |
|
131 |
(case space_explode "-" s of |
|
132 |
[s] => (s, s) |
|
133 |
| [s1, s2] => (s1, s2) |
|
134 |
| _ => error ("Parameter " ^ quote name ^ " must be assigned a range of integers")) |
|
135 |
|> apply2 Int.fromString; |
|
136 |
||
137 |
fun lookup_assigns read pre of_str = |
|
138 |
(case lookup pre of |
|
139 |
SOME s => [(NONE, of_str s)] |
|
140 |
| NONE => []) @ |
|
141 |
map (fn (name, value) => (SOME (read (String.extract (name, size pre + 1, NONE))), |
|
142 |
of_str (stringify_raw_param_value value))) |
|
143 |
(filter (String.isPrefix (pre ^ " ") o fst) raw_params); |
|
144 |
||
145 |
fun lookup_int_range_assigns read pre = |
|
146 |
lookup_assigns read pre (int_range_from_string pre); |
|
147 |
||
148 |
fun lookup_bool_assigns read pre = |
|
149 |
lookup_assigns read pre (the o parse_bool_option false pre); |
|
150 |
||
151 |
fun lookup_bool_option_assigns read pre = |
|
152 |
lookup_assigns read pre (parse_bool_option true pre); |
|
153 |
||
154 |
fun lookup_strings_assigns read pre = |
|
155 |
lookup_assigns read pre (space_explode " "); |
|
156 |
||
157 |
fun lookup_time name = |
|
158 |
(case lookup name of |
|
159 |
SOME s => parse_time name s |
|
160 |
| NONE => Time.zeroTime); |
|
161 |
||
162 |
val read_type_polymorphic = |
|
163 |
Syntax.read_typ ctxt #> Logic.mk_type |
|
164 |
#> singleton (Variable.polymorphic ctxt) #> Logic.dest_type; |
|
165 |
val read_term_polymorphic = |
|
166 |
Syntax.read_term ctxt #> singleton (Variable.polymorphic ctxt); |
|
167 |
val lookup_term_list_option_polymorphic = |
|
168 |
AList.lookup (op =) raw_params #> Option.map (map read_term_polymorphic); |
|
169 |
||
170 |
fun read_const_polymorphic s = |
|
171 |
(case read_term_polymorphic s of |
|
172 |
Const x => x |
|
173 |
| t => error ("Not a constant: " ^ Syntax.string_of_term ctxt t)); |
|
174 |
||
66163 | 175 |
val solvers = lookup_strings "solvers"; |
176 |
val falsify = lookup_bool "falsify"; |
|
177 |
val assms = lookup_bool "assms"; |
|
178 |
val spy = getenv "NUNCHAKU_SPY" = "yes" orelse lookup_bool "spy"; |
|
179 |
val overlord = lookup_bool "overlord"; |
|
180 |
val expect = lookup_string "expect"; |
|
181 |
||
64389 | 182 |
val wfs = lookup_bool_option_assigns read_const_polymorphic "wf"; |
66625 | 183 |
val initial_bound = lookup_int "initial_bound"; |
184 |
val bound_increment = lookup_int "bound_increment"; |
|
64389 | 185 |
val whacks = lookup_bool_assigns read_term_polymorphic "whack"; |
186 |
val cards = lookup_int_range_assigns read_type_polymorphic "card"; |
|
187 |
val monos = lookup_bool_option_assigns read_type_polymorphic "mono"; |
|
66163 | 188 |
|
64389 | 189 |
val debug = (mode <> Auto_Try andalso lookup_bool "debug"); |
190 |
val verbose = debug orelse (mode <> Auto_Try andalso lookup_bool "verbose"); |
|
66163 | 191 |
val max_potential = if mode = Normal then Int.max (0, lookup_int "max_potential") else 0; |
192 |
val max_genuine = Int.max (0, lookup_int "max_genuine"); |
|
193 |
val evals = these (lookup_term_list_option_polymorphic "eval"); |
|
194 |
val atomss = lookup_strings_assigns read_type_polymorphic "atoms"; |
|
195 |
||
64389 | 196 |
val specialize = lookup_bool "specialize"; |
66163 | 197 |
val multithread = mode = Normal andalso lookup_bool "multithread"; |
198 |
||
64389 | 199 |
val timeout = lookup_time "timeout"; |
200 |
val wf_timeout = lookup_time "wf_timeout"; |
|
201 |
||
202 |
val mode_of_operation_params = |
|
66163 | 203 |
{solvers = solvers, falsify = falsify, assms = assms, spy = spy, overlord = overlord, |
64389 | 204 |
expect = expect}; |
205 |
||
206 |
val scope_of_search_params = |
|
66625 | 207 |
{wfs = wfs, whacks = whacks, initial_bound = initial_bound, bound_increment = bound_increment, |
208 |
cards = cards, monos = monos}; |
|
64389 | 209 |
|
210 |
val output_format_params = |
|
211 |
{verbose = verbose, debug = debug, max_potential = max_potential, max_genuine = max_genuine, |
|
212 |
evals = evals, atomss = atomss}; |
|
213 |
||
214 |
val optimization_params = |
|
215 |
{specialize = specialize, multithread = multithread}; |
|
216 |
||
217 |
val timeout_params = |
|
218 |
{timeout = timeout, wf_timeout = wf_timeout}; |
|
219 |
in |
|
220 |
{mode_of_operation_params = mode_of_operation_params, |
|
221 |
scope_of_search_params = scope_of_search_params, |
|
222 |
output_format_params = output_format_params, |
|
223 |
optimization_params = optimization_params, |
|
224 |
timeout_params = timeout_params} |
|
225 |
end; |
|
226 |
||
227 |
fun default_params thy = |
|
228 |
extract_params (Proof_Context.init_global thy) Normal (default_raw_params thy) |
|
229 |
o map (apsnd single); |
|
230 |
||
231 |
val parse_key = Scan.repeat1 Parse.embedded >> space_implode " "; |
|
232 |
val parse_value = |
|
233 |
Scan.repeat1 (Parse.minus >> single |
|
234 |
|| Scan.repeat1 (Scan.unless Parse.minus (Parse.name || Parse.float_number)) |
|
235 |
|| @{keyword ","} |-- Parse.number >> prefix "," >> single) |
|
236 |
>> flat; |
|
237 |
val parse_param = parse_key -- Scan.optional (@{keyword "="} |-- parse_value) []; |
|
238 |
val parse_params = Scan.optional (@{keyword "["} |-- Parse.list parse_param --| @{keyword "]"}) []; |
|
239 |
||
240 |
fun run_chaku override_params mode i state0 = |
|
241 |
let |
|
242 |
val state = Proof.map_contexts (Try0.silence_methods false) state0; |
|
243 |
val thy = Proof.theory_of state; |
|
244 |
val ctxt = Proof.context_of state; |
|
245 |
val _ = List.app check_raw_param override_params; |
|
246 |
val params = extract_params ctxt mode (default_raw_params thy) override_params; |
|
247 |
in |
|
248 |
(if mode = Auto_Try then perhaps o try else fn f => fn x => f x) |
|
249 |
(fn _ => run_chaku_on_subgoal state params mode i) (unknownN, NONE) |
|
250 |
|> `(fn (outcome_code, _) => outcome_code = genuineN) |
|
251 |
end; |
|
252 |
||
253 |
fun string_for_raw_param (name, value) = |
|
254 |
name ^ " = " ^ stringify_raw_param_value value; |
|
255 |
||
256 |
fun nunchaku_params_trans params = |
|
257 |
Toplevel.theory (fold set_default_raw_param params |
|
258 |
#> tap (fn thy => |
|
259 |
let val params = rev (default_raw_params thy) in |
|
260 |
List.app check_raw_param params; |
|
261 |
writeln ("Default parameters for Nunchaku:\n" ^ |
|
262 |
(params |> map string_for_raw_param |> sort_strings |> cat_lines)) |
|
263 |
end)); |
|
264 |
||
265 |
val _ = |
|
266 |
Outer_Syntax.command @{command_keyword nunchaku} |
|
267 |
"try to find a countermodel using Nunchaku" |
|
268 |
(parse_params -- Scan.optional Parse.nat 1 >> (fn (params, i) => |
|
269 |
Toplevel.keep_proof (fn state => |
|
270 |
ignore (run_chaku params Normal i (Toplevel.proof_of state))))); |
|
271 |
||
272 |
val _ = |
|
273 |
Outer_Syntax.command @{command_keyword nunchaku_params} |
|
274 |
"set and display the default parameters for Nunchaku" |
|
275 |
(parse_params #>> nunchaku_params_trans); |
|
276 |
||
277 |
end; |