27 struct |
32 struct |
28 |
33 |
29 open PropLogic; |
34 open PropLogic; |
30 |
35 |
31 (* ------------------------------------------------------------------------- *) |
36 (* ------------------------------------------------------------------------- *) |
32 (* Type of SAT solvers: given a propositional formula, a satisfying *) |
37 (* should be raised by an external SAT solver to indicate that the solver is *) |
|
38 (* not configured properly *) |
|
39 (* ------------------------------------------------------------------------- *) |
|
40 |
|
41 exception NOT_CONFIGURED; |
|
42 |
|
43 (* ------------------------------------------------------------------------- *) |
|
44 (* type of partial (satisfying) assignments: 'a i = None' means that 'a' is *) |
|
45 (* a satisfying assigment regardless of the value of variable 'i' *) |
|
46 (* ------------------------------------------------------------------------- *) |
|
47 |
|
48 type assignment = int -> bool option; |
|
49 |
|
50 (* ------------------------------------------------------------------------- *) |
|
51 (* return type of SAT solvers: if the result is 'SATISFIABLE', a satisfying *) |
|
52 (* assignment must be returned as well *) |
|
53 (* ------------------------------------------------------------------------- *) |
|
54 |
|
55 datatype result = SATISFIABLE of assignment |
|
56 | UNSATISFIABLE |
|
57 | UNKNOWN; |
|
58 |
|
59 (* ------------------------------------------------------------------------- *) |
|
60 (* type of SAT solvers: given a propositional formula, a satisfying *) |
33 (* assignment may be returned *) |
61 (* assignment may be returned *) |
34 (* - 'Some None' means that no satisfying assignment was found *) |
62 (* ------------------------------------------------------------------------- *) |
35 (* - 'None' means that the solver was not configured/installed properly *) |
63 |
36 (* ------------------------------------------------------------------------- *) |
64 type solver = prop_formula -> result; |
37 |
|
38 type solver = prop_formula -> (int -> bool) option option; |
|
39 |
65 |
40 (* ------------------------------------------------------------------------- *) |
66 (* ------------------------------------------------------------------------- *) |
41 (* write_dimacs_cnf_file: serializes a formula 'fm' of propositional logic *) |
67 (* write_dimacs_cnf_file: serializes a formula 'fm' of propositional logic *) |
42 (* to a file in DIMACS CNF format (see "Satisfiability Suggested *) |
68 (* to a file in DIMACS CNF format (see "Satisfiability Suggested *) |
43 (* Format", May 8 1993, Section 2.1) *) |
69 (* Format", May 8 1993, Section 2.1) *) |
44 (* Note: 'fm' must not contain a variable index less than 1. *) |
70 (* Note: 'fm' must not contain a variable index less than 1. *) |
45 (* Note: 'fm' is converted into (definitional) CNF. *) |
71 (* Note: 'fm' must be given in CNF. *) |
46 (* ------------------------------------------------------------------------- *) |
72 (* ------------------------------------------------------------------------- *) |
47 |
73 |
48 (* Path.T -> prop_formula -> unit *) |
74 (* Path.T -> prop_formula -> unit *) |
49 |
75 |
50 fun write_dimacs_cnf_file path fm = |
76 fun write_dimacs_cnf_file path fm = |
68 error "formula is not in CNF" |
94 error "formula is not in CNF" |
69 | cnf_string (BoolVar i) = |
95 | cnf_string (BoolVar i) = |
70 (assert (i>=1) "formula contains a variable index less than 1"; |
96 (assert (i>=1) "formula contains a variable index less than 1"; |
71 string_of_int i) |
97 string_of_int i) |
72 | cnf_string (Not fm) = |
98 | cnf_string (Not fm) = |
73 "-" ^ (cnf_string fm) |
99 "-" ^ cnf_string fm |
74 | cnf_string (Or (fm1,fm2)) = |
100 | cnf_string (Or (fm1,fm2)) = |
75 (cnf_string fm1) ^ " " ^ (cnf_string fm2) |
101 cnf_string fm1 ^ " " ^ cnf_string fm2 |
76 | cnf_string (And (fm1,fm2)) = |
102 | cnf_string (And (fm1,fm2)) = |
77 (cnf_string fm1) ^ " 0\n" ^ (cnf_string fm2) |
103 cnf_string fm1 ^ " 0\n" ^ cnf_string fm2 |
78 in |
104 in |
79 File.write path |
105 File.write path |
80 (let |
106 (let |
81 val cnf = (cnf_True_False_elim o defcnf) fm (* conversion into def. CNF *) |
107 val fm' = cnf_True_False_elim fm |
82 val number_of_vars = maxidx cnf |
108 val number_of_vars = maxidx fm' |
83 val number_of_clauses = cnf_number_of_clauses cnf |
109 val number_of_clauses = cnf_number_of_clauses fm' |
|
110 val cnfstring = cnf_string fm' |
84 in |
111 in |
85 "c This file was generated by SatSolver.write_dimacs_cnf_file\n" ^ |
112 "c This file was generated by SatSolver.write_dimacs_cnf_file\n" ^ |
86 "c (c) Tjark Weber\n" ^ |
113 "c (c) Tjark Weber\n" ^ |
87 "p cnf " ^ (string_of_int number_of_vars) ^ " " ^ (string_of_int number_of_clauses) ^ "\n" ^ |
114 "p cnf " ^ string_of_int number_of_vars ^ " " ^ string_of_int number_of_clauses ^ "\n" ^ |
88 (cnf_string cnf) ^ "\n" |
115 cnfstring ^ " 0\n" |
89 end) |
116 end) |
90 end; |
117 end; |
91 |
118 |
92 (* ------------------------------------------------------------------------- *) |
119 (* ------------------------------------------------------------------------- *) |
93 (* write_dimacs_sat_file: serializes a formula 'fm' of propositional logic *) |
120 (* write_dimacs_sat_file: serializes a formula 'fm' of propositional logic *) |
107 "+()" |
134 "+()" |
108 | sat_string (BoolVar i) = |
135 | sat_string (BoolVar i) = |
109 (assert (i>=1) "formula contains a variable index less than 1"; |
136 (assert (i>=1) "formula contains a variable index less than 1"; |
110 string_of_int i) |
137 string_of_int i) |
111 | sat_string (Not fm) = |
138 | sat_string (Not fm) = |
112 "-(" ^ (sat_string fm) ^ ")" |
139 "-(" ^ sat_string fm ^ ")" |
113 | sat_string (Or (fm1,fm2)) = |
140 | sat_string (Or (fm1,fm2)) = |
114 "+(" ^ (sat_string fm1) ^ " " ^ (sat_string fm2) ^ ")" |
141 "+(" ^ sat_string fm1 ^ " " ^ sat_string fm2 ^ ")" |
115 | sat_string (And (fm1,fm2)) = |
142 | sat_string (And (fm1,fm2)) = |
116 "*(" ^ (sat_string fm1) ^ " " ^ (sat_string fm2) ^ ")" |
143 "*(" ^ sat_string fm1 ^ " " ^ sat_string fm2 ^ ")" |
117 in |
144 in |
118 File.write path |
145 File.write path |
119 (let |
146 (let |
120 val number_of_vars = Int.max (maxidx fm, 1) |
147 val number_of_vars = Int.max (maxidx fm, 1) |
121 in |
148 in |
122 "c This file was generated by SatSolver.write_dimacs_sat_file\n" ^ |
149 "c This file was generated by SatSolver.write_dimacs_sat_file\n" ^ |
123 "c (c) Tjark Weber\n" ^ |
150 "c (c) Tjark Weber\n" ^ |
124 "p sat " ^ (string_of_int number_of_vars) ^ "\n" ^ |
151 "p sat " ^ string_of_int number_of_vars ^ "\n" ^ |
125 "(" ^ (sat_string fm) ^ ")\n" |
152 "(" ^ sat_string fm ^ ")\n" |
126 end) |
153 end) |
127 end; |
154 end; |
128 |
155 |
129 (* ------------------------------------------------------------------------- *) |
156 (* ------------------------------------------------------------------------- *) |
130 (* parse_std_result_file: scans a SAT solver's output file for a satisfying *) |
157 (* parse_std_result_file: scans a SAT solver's output file for a satisfying *) |
131 (* variable assignment. Returns the assignment, or 'None' if the SAT *) |
158 (* variable assignment. Returns the assignment, or 'UNSATISFIABLE' if *) |
132 (* solver did not find one. The file format must be as follows: *) |
159 (* the file contains 'unsatisfiable', or 'UNKNOWN' if the file contains *) |
133 (* ,----- *) |
160 (* neither 'satisfiable' nor 'unsatisfiable'. Empty lines are ignored. *) |
134 (* | 0 or more lines not containing 'success' *) |
161 (* The assignment must be given in one or more lines immediately after *) |
135 (* | A line containing 'success' as a substring *) |
162 (* the line that contains 'satisfiable'. These lines must begin with *) |
136 (* | A line ASSIGNMENT containing integers, separated by " " *) |
163 (* 'assignment_prefix'. Variables must be separated by " ". Non- *) |
137 (* | 0 or more lines *) |
164 (* integer strings are ignored. If variable i is contained in the *) |
138 (* `----- *) |
165 (* assignment, then i is interpreted as 'true'. If ~i is contained in *) |
139 (* If variable i is contained in ASSIGNMENT, then i is interpreted as *) |
166 (* the assignment, then i is interpreted as 'false'. Otherwise the *) |
140 (* 'true'. If ~i is contained in ASSIGNMENT, then i is interpreted as *) |
167 (* value of i is taken to be unspecified. *) |
141 (* 'false'. *) |
168 (* ------------------------------------------------------------------------- *) |
142 (* ------------------------------------------------------------------------- *) |
169 |
143 |
170 (* Path.T -> string * string * string -> result *) |
144 (* Path.T -> string -> (int -> bool) option *) |
171 |
145 |
172 fun parse_std_result_file path (satisfiable, assignment_prefix, unsatisfiable) = |
146 fun parse_std_result_file path success = |
|
147 let |
173 let |
148 (* 'a option -> 'a Library.option *) |
174 (* 'a option -> 'a Library.option *) |
149 fun option (SOME a) = |
175 fun option (SOME a) = |
150 Some a |
176 Some a |
151 | option NONE = |
177 | option NONE = |
152 None |
178 None |
153 (* string -> int list *) |
179 (* string -> int list *) |
154 fun int_list_from_string s = |
180 fun int_list_from_string s = |
155 mapfilter (option o Int.fromString) (space_explode " " s) |
181 mapfilter (option o Int.fromString) (space_explode " " s) |
156 (* int list -> int -> bool *) |
182 (* int list -> assignment *) |
157 fun assignment_from_list [] i = |
183 fun assignment_from_list [] i = |
158 false (* could be 'true' just as well; the SAT solver didn't provide a value for this variable *) |
184 None (* the SAT solver didn't provide a value for this variable *) |
159 | assignment_from_list (x::xs) i = |
185 | assignment_from_list (x::xs) i = |
160 if x=i then true |
186 if x=i then (Some true) |
161 else if x=(~i) then false |
187 else if x=(~i) then (Some false) |
162 else assignment_from_list xs i |
188 else assignment_from_list xs i |
|
189 (* int list -> string list -> assignment *) |
|
190 fun parse_assignment xs [] = |
|
191 assignment_from_list xs |
|
192 | parse_assignment xs (line::lines) = |
|
193 if String.isPrefix assignment_prefix line then |
|
194 parse_assignment (xs @ int_list_from_string line) lines |
|
195 else |
|
196 assignment_from_list xs |
163 (* string -> string -> bool *) |
197 (* string -> string -> bool *) |
164 fun is_substring needle haystack = |
198 fun is_substring needle haystack = |
165 let |
199 let |
166 val length1 = String.size needle |
200 val length1 = String.size needle |
167 val length2 = String.size haystack |
201 val length2 = String.size haystack |
170 false |
204 false |
171 else if needle = String.substring (haystack, 0, length1) then |
205 else if needle = String.substring (haystack, 0, length1) then |
172 true |
206 true |
173 else is_substring needle (String.substring (haystack, 1, length2-1)) |
207 else is_substring needle (String.substring (haystack, 1, length2-1)) |
174 end |
208 end |
175 (* string list -> int list option *) |
209 (* string list -> result *) |
176 fun parse_lines [] = |
210 fun parse_lines [] = |
177 None |
211 UNKNOWN |
178 | parse_lines (line::lines) = |
212 | parse_lines (line::lines) = |
179 if is_substring success line then |
213 if is_substring satisfiable line then |
180 (* the next line must be a list of integers *) |
214 SATISFIABLE (parse_assignment [] lines) |
181 (Some o assignment_from_list o int_list_from_string o hd) lines |
215 else if is_substring unsatisfiable line then |
|
216 UNSATISFIABLE |
182 else |
217 else |
183 parse_lines lines |
218 parse_lines lines |
184 in |
219 in |
185 (parse_lines o split_lines o File.read) path |
220 (parse_lines o (filter (fn l => l <> "")) o split_lines o File.read) path |
186 end; |
221 end; |
187 |
222 |
188 (* ------------------------------------------------------------------------- *) |
223 (* ------------------------------------------------------------------------- *) |
189 (* make_external_solver: call 'writefn', execute 'cmd', call 'readfn' *) |
224 (* make_external_solver: call 'writefn', execute 'cmd', call 'readfn' *) |
190 (* ------------------------------------------------------------------------- *) |
225 (* ------------------------------------------------------------------------- *) |
191 |
226 |
192 (* string -> (prop_formula -> unit) -> (unit -> (int -> bool) option) -> prop_formula -> (int -> bool) option *) |
227 (* string -> (PropLogic.prop_formula -> unit) -> (unit -> result) -> solver *) |
193 |
228 |
194 fun make_external_solver cmd writefn readfn fm = |
229 fun make_external_solver cmd writefn readfn fm = |
195 (writefn fm; |
230 (writefn fm; system cmd; readfn ()); |
196 assert ((system cmd)=0) ("system command " ^ quote cmd ^ " failed (make sure the SAT solver is installed)"); |
|
197 readfn ()); |
|
198 |
231 |
199 (* ------------------------------------------------------------------------- *) |
232 (* ------------------------------------------------------------------------- *) |
200 (* solvers: a (reference to a) table of all registered SAT solvers *) |
233 (* solvers: a (reference to a) table of all registered SAT solvers *) |
201 (* ------------------------------------------------------------------------- *) |
234 (* ------------------------------------------------------------------------- *) |
202 |
235 |
253 (* set the lowest bit that wasn't set before, keep the higher bits *) |
286 (* set the lowest bit that wasn't set before, keep the higher bits *) |
254 Some (y::x::xs) |
287 Some (y::x::xs) |
255 (* int list -> int -> bool *) |
288 (* int list -> int -> bool *) |
256 fun assignment_from_list xs i = |
289 fun assignment_from_list xs i = |
257 i mem xs |
290 i mem xs |
258 (* int list -> (int -> bool) option *) |
291 (* int list -> SatSolver.result *) |
259 fun solver_loop xs = |
292 fun solver_loop xs = |
260 if PropLogic.eval (assignment_from_list xs) fm then |
293 if PropLogic.eval (assignment_from_list xs) fm then |
261 Some (assignment_from_list xs) |
294 SatSolver.SATISFIABLE (Some o (assignment_from_list xs)) |
262 else |
295 else |
263 (case next_list xs indices of |
296 (case next_list xs indices of |
264 Some xs' => solver_loop xs' |
297 Some xs' => solver_loop xs' |
265 | None => None) |
298 | None => SatSolver.UNSATISFIABLE) |
266 in |
299 in |
267 (* start with the "first" assignment (all variables are interpreted as 'False') *) |
300 (* start with the "first" assignment (all variables are interpreted as 'false') *) |
268 solver_loop [] |
301 solver_loop [] |
269 end |
302 end |
270 in |
303 in |
271 SatSolver.add_solver ("enumerate", Some o enum_solver) |
304 SatSolver.add_solver ("enumerate", enum_solver) |
272 end; |
305 end; |
273 |
306 |
274 (* ------------------------------------------------------------------------- *) |
307 (* ------------------------------------------------------------------------- *) |
275 (* Internal SAT solver, available as 'SatSolver.invoke_solver "dpll"' -- a *) |
308 (* Internal SAT solver, available as 'SatSolver.invoke_solver "dpll"' -- a *) |
276 (* simple implementation of the DPLL algorithm (cf. L. Zhang, S. Malik: "The *) |
309 (* simple implementation of the DPLL algorithm (cf. L. Zhang, S. Malik: "The *) |
340 case dpll (x::xs') fm' of (* passing fm' rather than fm should save some simplification work *) |
373 case dpll (x::xs') fm' of (* passing fm' rather than fm should save some simplification work *) |
341 Some xs'' => Some xs'' |
374 Some xs'' => Some xs'' |
342 | None => dpll ((~x)::xs') fm' (* now try interpreting 'x' as 'False' *) |
375 | None => dpll ((~x)::xs') fm' (* now try interpreting 'x' as 'False' *) |
343 end |
376 end |
344 end |
377 end |
345 (* int list -> int -> bool *) |
378 (* int list -> assignment *) |
346 fun assignment_from_list [] i = |
379 fun assignment_from_list [] i = |
347 false (* could be 'true' just as well; the DPLL procedure didn't provide a value for this variable *) |
380 None (* the DPLL procedure didn't provide a value for this variable *) |
348 | assignment_from_list (x::xs) i = |
381 | assignment_from_list (x::xs) i = |
349 if x=i then true |
382 if x=i then (Some true) |
350 else if x=(~i) then false |
383 else if x=(~i) then (Some false) |
351 else assignment_from_list xs i |
384 else assignment_from_list xs i |
352 in |
385 in |
353 (* initially, no variable is interpreted yet *) |
386 (* initially, no variable is interpreted yet *) |
354 apsome assignment_from_list (dpll [] fm') |
387 case dpll [] fm' of |
|
388 Some assignment => SatSolver.SATISFIABLE (assignment_from_list assignment) |
|
389 | None => SatSolver.UNSATISFIABLE |
355 end |
390 end |
356 end (* local *) |
391 end (* local *) |
357 in |
392 in |
358 SatSolver.add_solver ("dpll", Some o dpll_solver) |
393 SatSolver.add_solver ("dpll", dpll_solver) |
359 end; |
394 end; |
360 |
395 |
361 (* ------------------------------------------------------------------------- *) |
396 (* ------------------------------------------------------------------------- *) |
362 (* Internal SAT solver, available as 'SatSolver.invoke_solver "auto"': uses *) |
397 (* Internal SAT solver, available as 'SatSolver.invoke_solver "auto"': uses *) |
363 (* the first installed solver (other than "auto" itself) *) |
398 (* all installed solvers (other than "auto" itself) until one returns either *) |
|
399 (* SATISFIABLE or UNSATISFIABLE *) |
364 (* ------------------------------------------------------------------------- *) |
400 (* ------------------------------------------------------------------------- *) |
365 |
401 |
366 let |
402 let |
367 fun auto_solver fm = |
403 fun auto_solver fm = |
368 get_first (fn (name,solver) => |
404 let |
|
405 fun loop [] = |
|
406 SatSolver.UNKNOWN |
|
407 | loop ((name, solver)::solvers) = |
369 if name="auto" then |
408 if name="auto" then |
370 None |
409 (* do not call solver "auto" from within "auto" *) |
|
410 loop solvers |
371 else |
411 else |
372 ((if name="dpll" orelse name="enumerate" then |
412 ( |
|
413 (if name="dpll" orelse name="enumerate" then |
373 warning ("Using SAT solver " ^ quote name ^ "; for better performance, consider using an external solver.") |
414 warning ("Using SAT solver " ^ quote name ^ "; for better performance, consider using an external solver.") |
374 else |
415 else |
375 ()); |
416 ()); |
376 solver fm)) (rev (!SatSolver.solvers)) |
417 (* apply 'solver' to 'fm' *) |
|
418 (case solver fm of |
|
419 SatSolver.SATISFIABLE a => SatSolver.SATISFIABLE a |
|
420 | SatSolver.UNSATISFIABLE => SatSolver.UNSATISFIABLE |
|
421 | SatSolver.UNKNOWN => loop solvers) |
|
422 handle SatSolver.NOT_CONFIGURED => loop solvers |
|
423 ) |
|
424 in |
|
425 loop (rev (!SatSolver.solvers)) |
|
426 end |
377 in |
427 in |
378 SatSolver.add_solver ("auto", auto_solver) |
428 SatSolver.add_solver ("auto", auto_solver) |
379 end; |
429 end; |
380 |
430 |
381 (* ------------------------------------------------------------------------- *) |
431 (* ------------------------------------------------------------------------- *) |
382 (* ZChaff, Version 2003.12.04 *) |
432 (* ZChaff, Version 2003.12.04 (http://www.princeton.edu/~chaff/zchaff.html) *) |
383 (* ------------------------------------------------------------------------- *) |
433 (* ------------------------------------------------------------------------- *) |
384 |
434 |
385 let |
435 let |
386 fun zchaff fm = |
436 fun zchaff fm = |
387 let |
437 let |
388 val inname = "isabelle.cnf" |
438 val _ = if (getenv "ZCHAFF_HOME") = "" then raise SatSolver.NOT_CONFIGURED else () |
389 val outname = "result" |
439 val inpath = File.tmp_path (Path.unpack "isabelle.cnf") |
390 val inpath = File.tmp_path (Path.unpack inname) |
440 val outpath = File.tmp_path (Path.unpack "result") |
391 val outpath = File.tmp_path (Path.unpack outname) |
|
392 val cmd = (getenv "ZCHAFF_HOME") ^ "/zchaff " ^ (Path.pack inpath) ^ " > " ^ (Path.pack outpath) |
441 val cmd = (getenv "ZCHAFF_HOME") ^ "/zchaff " ^ (Path.pack inpath) ^ " > " ^ (Path.pack outpath) |
393 fun writefn fm = SatSolver.write_dimacs_cnf_file inpath fm |
442 fun writefn fm = SatSolver.write_dimacs_cnf_file inpath (PropLogic.defcnf fm) |
394 fun readfn () = SatSolver.parse_std_result_file outpath "Verify Solution successful. Instance satisfiable" |
443 fun readfn () = SatSolver.parse_std_result_file outpath ("Verify Solution successful. Instance satisfiable", "", "Instance unsatisfiable") |
395 val _ = assert (not (File.exists inpath)) ("file " ^ quote (Path.pack inpath) ^ " exists, please delete (will not overwrite)") |
444 val _ = assert (not (File.exists inpath)) ("file " ^ quote (Path.pack inpath) ^ " exists, please delete (will not overwrite)") |
396 val _ = assert (not (File.exists outpath)) ("file " ^ quote (Path.pack outpath) ^ " exists, please delete (will not overwrite)") |
445 val _ = assert (not (File.exists outpath)) ("file " ^ quote (Path.pack outpath) ^ " exists, please delete (will not overwrite)") |
397 val assignment = SatSolver.make_external_solver cmd writefn readfn fm |
446 val result = SatSolver.make_external_solver cmd writefn readfn fm |
398 val _ = (File.rm inpath handle _ => ()) |
447 val _ = (File.rm inpath handle _ => ()) |
399 val _ = (File.rm outpath handle _ => ()) |
448 val _ = (File.rm outpath handle _ => ()) |
400 in |
449 in |
401 assignment |
450 result |
402 end |
451 end |
403 in |
452 in |
404 SatSolver.add_solver ("zchaff", (fn fm => if getenv "ZCHAFF_HOME" <> "" then Some (zchaff fm) else None)) |
453 SatSolver.add_solver ("zchaff", zchaff) |
|
454 end; |
|
455 |
|
456 (* ------------------------------------------------------------------------- *) |
|
457 (* BerkMin 561 (http://eigold.tripod.com/BerkMin.html) *) |
|
458 (* ------------------------------------------------------------------------- *) |
|
459 |
|
460 let |
|
461 fun berkmin fm = |
|
462 let |
|
463 val _ = if (getenv "BERKMIN_HOME") = "" orelse (getenv "BERKMIN_EXE") = "" then raise SatSolver.NOT_CONFIGURED else () |
|
464 val inpath = File.tmp_path (Path.unpack "isabelle.cnf") |
|
465 val outpath = File.tmp_path (Path.unpack "result") |
|
466 val cmd = (getenv "BERKMIN_HOME") ^ "/" ^ (getenv "BERKMIN_EXE") ^ " " ^ (Path.pack inpath) ^ " > " ^ (Path.pack outpath) |
|
467 fun writefn fm = SatSolver.write_dimacs_cnf_file inpath (PropLogic.defcnf fm) |
|
468 fun readfn () = SatSolver.parse_std_result_file outpath ("Satisfiable !!", "solution =", "UNSATISFIABLE !!") |
|
469 val _ = assert (not (File.exists inpath)) ("file " ^ quote (Path.pack inpath) ^ " exists, please delete (will not overwrite)") |
|
470 val _ = assert (not (File.exists outpath)) ("file " ^ quote (Path.pack outpath) ^ " exists, please delete (will not overwrite)") |
|
471 val result = SatSolver.make_external_solver cmd writefn readfn fm |
|
472 val _ = (File.rm inpath handle _ => ()) |
|
473 val _ = (File.rm outpath handle _ => ()) |
|
474 in |
|
475 result |
|
476 end |
|
477 in |
|
478 SatSolver.add_solver ("berkmin", berkmin) |
|
479 end; |
|
480 |
|
481 (* ------------------------------------------------------------------------- *) |
|
482 (* Jerusat 1.3 (http://www.cs.tau.ac.il/~ale1/) *) |
|
483 (* ------------------------------------------------------------------------- *) |
|
484 |
|
485 let |
|
486 fun jerusat fm = |
|
487 let |
|
488 val _ = if (getenv "JERUSAT_HOME") = "" then raise SatSolver.NOT_CONFIGURED else () |
|
489 val inpath = File.tmp_path (Path.unpack "isabelle.cnf") |
|
490 val outpath = File.tmp_path (Path.unpack "result") |
|
491 val cmd = (getenv "JERUSAT_HOME") ^ "/Jerusat1.3 " ^ (Path.pack inpath) ^ " > " ^ (Path.pack outpath) |
|
492 fun writefn fm = SatSolver.write_dimacs_cnf_file inpath (PropLogic.defcnf fm) |
|
493 fun readfn () = SatSolver.parse_std_result_file outpath ("s SATISFIABLE", "v ", "s UNSATISFIABLE") |
|
494 val _ = assert (not (File.exists inpath)) ("file " ^ quote (Path.pack inpath) ^ " exists, please delete (will not overwrite)") |
|
495 val _ = assert (not (File.exists outpath)) ("file " ^ quote (Path.pack outpath) ^ " exists, please delete (will not overwrite)") |
|
496 val result = SatSolver.make_external_solver cmd writefn readfn fm |
|
497 val _ = (File.rm inpath handle _ => ()) |
|
498 val _ = (File.rm outpath handle _ => ()) |
|
499 in |
|
500 result |
|
501 end |
|
502 in |
|
503 SatSolver.add_solver ("jerusat", jerusat) |
405 end; |
504 end; |
406 |
505 |
407 (* ------------------------------------------------------------------------- *) |
506 (* ------------------------------------------------------------------------- *) |
408 (* Add code for other SAT solvers below. *) |
507 (* Add code for other SAT solvers below. *) |
409 (* ------------------------------------------------------------------------- *) |
508 (* ------------------------------------------------------------------------- *) |
410 |
509 |
411 (* |
510 (* |
412 let |
511 let |
413 fun mysolver fm = ... |
512 fun mysolver fm = ... |
414 in |
513 in |
415 SatSolver.add_solver ("myname", (fn fm => if mysolver_is_installed then Some (mysolver fm) else None)); -- register the solver |
514 SatSolver.add_solver ("myname", (fn fm => if mysolver_is_configured then mysolver fm else raise SatSolver.NOT_CONFIGURED)); -- register the solver |
416 end; |
515 end; |
417 |
516 |
418 -- the solver is now available as SatSolver.invoke_solver "myname" |
517 -- the solver is now available as SatSolver.invoke_solver "myname" |
419 *) |
518 *) |