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