4 (* Functions for parsing the DIMACS-compliant output of SAT solvers,
5 This is generic. Parser for minisat proof log is in minisatParse.ml *)
8 ** Use Binaryset to encode mapping between HOL variable names
9 ** and DIMACS variable numbers as a set of string*int pairs.
13 ** substringContains s ss
14 ** tests whether substring ss contains string s
17 let substringContains s ss =
18 let re = Str.regexp_string s in
20 (try Str.search_forward re ss 0 with
27 ** parseSat (s1,s2) ss
28 ** returns a list of numbers corresponding to the tokenised
29 ** substring of ss (tokenised wrt Char.isSpace) that starts immediately
30 ** after the first occurrence of s1 and ends just before the first
31 ** occurrence of s2 that is after the first occurrence of s1
34 let parseSat (s1,s2) ss =
35 let p1 = Str.search_forward (Str.regexp s1) ss 0 in
36 let p2 = Str.search_backward (Str.regexp s2) ss (String.length ss) in
37 let ss1 = Str.string_before ss p2 in
38 let ss2 = Str.string_after ss1 (p1+String.length s1) in
39 let ssl = Str.split (Str.regexp "[ \n\t\r]") ss2 in
40 List.map int_of_string ssl
45 ** invokes solver on t and returns SOME s (where s is the satisfying instance
46 ** as a string of integers) or NONE, if unsatisfiable
50 ** Reference containing last command used to invoke a SAT solver
53 let sat_command = ref "undef"
56 ** Test for success of the result of Process.system
57 ** N.B. isSuccess expected to primitive in next release of
58 ** Moscow ML, and Process.status will lose eqtype status
63 (* if fname is NONE, then use a temp file, otherwise assume fname.cnf alredy exists*)
64 let invokeSat sat_solver fname t vc =
67 executable=executable;
69 notime_run=notime_run;
72 failure_string=failure_string;
73 start_string=start_string;
74 end_string=end_string} = sat_solver in
78 None -> List.length(variables t) in
82 (initSatVarMap var_count;
83 ignore (termToDimacs t); (*FIXME: this regenerates sat_var_map:
84 better to save/load it*)
86 | None -> termToDimacsFile None t var_count in
87 let infile = tmp ^ ".cnf" in
88 let outfile = tmp ^ "." ^ name in
89 let ex = Filename.concat satdir executable in
90 let run_cmd = notime_run ex (infile,outfile) in
91 let _ = (sat_command := run_cmd) in
92 let code = Sys.command run_cmd in
94 if ((name = "minisat") or (name = "minisatp") or (code = good_exit))
96 else print_string("Warning:\n Failure signalled by\n " ^ run_cmd ^ "\n") in
97 let ins = Pervasives.open_in outfile in
98 let sat_res = input_all ins in
99 let _ = close_in ins in
100 let result = substringContains failure_string sat_res in
104 let model1 = parseSat(start_string,end_string) sat_res in
111 (subtract (List.map snd (snd(showSatVarMap()))) model1))
113 Some (List.map intToLiteral model2)
117 ** satOracle sat_solver t
118 ** invokes sat_solver on t and returns a theorem tagged by the solver name
119 ** of the form |- (l1 /\ ... ln) ==> t (satisfied with literals l1,...,ln)
120 ** or |- ~t (failure)
123 let satOracle sat_solver t =
124 let res = invokeSat sat_solver None t None in
126 Some l -> mk_thm ([], mk_imp(list_mk_conj l, t))
127 | None -> mk_thm ([], mk_neg t)
130 ** satProve sat_solver t
131 ** invokes sat_solver on t and if a model is found then
132 ** then it is verified using proof in HOL and a theorem
133 ** |- (l1 /\ ... /\ ln) ==> t is returned
134 ** (where l1,...,ln are the literals making up the model);
135 ** Raises satProveError if no model is found.
136 ** Raises satCheckError if the found model is bogus
140 ** satCheck [l1,...,ln] t
141 ** attempts to prove (l1 /\ ... /\ ln) ==> t
142 ** if it succeeds then the theorem is returned, else
143 ** exception satCheckError is raised
146 let EQT_Imp1 = TAUT `!b. b ==> (b<=>T)`
147 let EQF_Imp1 = TAUT `!b. (~b) ==> (b<=>F)`
148 let EQT_Imp2 = TAUT `!b. (b<=>T) ==> b`;;
150 exception Sat_check_error
152 let satCheck model t =
154 let mtm = list_mk_conj model in
155 let th1 = ASSUME mtm in
159 then MP (SPEC (dest_neg(concl th)) EQF_Imp1) th
160 else MP (SPEC (concl th) EQT_Imp1) th)
162 let th3 = SUBS_CONV thl t in
163 let th4 = CONV_RULE(RAND_CONV(REWRITE_CONV[])) th3 in
164 let th5 = MP (SPEC t EQT_Imp2) th4 in
167 Sys.Break -> raise Sys.Break
168 | _ -> raise Sat_check_error;;
170 exception Sat_prove_error
172 (* old interface by MJCG. assumes t is in cnf; only for finding SAT *)
173 let satProve sat_solver t =
174 match invokeSat sat_solver None t None with
175 Some model -> satCheck model t
176 | None -> raise Sat_prove_error