1 (* =========================================================== *)
2 (* OCaml verification procedure *)
3 (* Authors: Thomas C. Hales, Alexey Solovyev *)
5 (* =========================================================== *)
7 (* port of recurse.cc *)
10 This is the code that verifies a disjunct of nonlinear inequalities.
11 The are given as a list (tf:tfunction list). If tf = [f1;....;fk], then
12 the list represents the inequality (f1 < 0 \/ f2 < 0 .... fk < 0).
14 The end user should only need to define a cell option,
15 and then call recursive_verifier, which recursively bisects the domain
16 until a partition of the domain is found on which verifier_cell gives
17 a pass on each piece of the partition.
21 needs "verifier/interval_m/taylor.ml";;
22 needs "verifier/interval_m/report.ml";;
23 needs "verifier_options.hl";;
25 module Recurse = struct
32 open Verifier_options;;
36 only_check_deriv1_negative : bool;
37 is_using_dihmax : bool;
38 is_using_bigface126 : bool;
41 allow_derivatives : bool;
42 mutable iteration_count : int;
43 iteration_limit : int;
44 recursion_depth : int;
51 (* cell verification is complex, and we use exceptions to
52 exit as soon as the status has been determined. *)
63 | Cell_pass of mono_status list list * bool
64 | Cell_pass_mono of mono_status list list * mono_status
66 | Cell_inconclusive_ti of (mono_status list list * taylor_interval * float list * float list * float list * float list)
67 | Cell_inconclusive of (mono_status list list * float list * float list * float list * float list);;
69 exception Return of cell_status;;
72 | Result_false of (float list * float list)
73 | Result_pass of (bool * float list * float list)
74 | Result_pass_mono of mono_status
75 | Result_pass_ref of int
76 | Result_mono of mono_status list * result_tree
77 (* variable, convex_flag, r1, r2 *)
78 | Result_glue of (int * bool * result_tree * result_tree);;
85 | P_result_pass of p_status * bool
86 | P_result_mono of p_status * mono_status list * p_result_tree
87 | P_result_glue of p_status * int * bool * p_result_tree * p_result_tree
88 | P_result_ref of int;;
90 let rec result_size r =
92 | Result_false _ -> failwith "False result detected"
93 | Result_mono (_,r1) -> result_size r1
94 | Result_glue (_, _, r1, r2) -> result_size r1 + result_size r2
95 | Result_pass_mono _ -> 1
99 let rec p_result_size r =
101 | P_result_pass _ -> 1
102 | P_result_mono (_, _, r1) -> p_result_size r1
103 | P_result_glue (_, _, _, r1, r2) -> p_result_size r1 + p_result_size r2
107 let return c = raise (Return c);;
110 (* error checking and reporting functions *)
112 let string_of_domain x =
114 Printf.sprintf "{%f, %f, %f, %f, %f, %f, %f, %f}" (n x 0) (n x 1) (n x 2) (n x 3) (n x 4) (n x 5) (n x 6) (n x 7);;
116 let string3 (x,z,s) = (string_of_domain x ^"\n"^ string_of_domain z ^ "\n" ^ s);;
118 let boolify _ = true;;
120 let report_current = boolify o Report.report_timed o string3;;
122 let report_error = boolify o Report.report_error o string3;;
124 let report_fatal = boolify o Report.report_fatal o string3;;
126 (* let t = [0.1;0.2;0.3;0.4;0.5;0.6] in report_error (t,t,"ok");; *)
129 let end_count = ref 0 in
131 let _ = end_count := !end_count + 1 in
132 (0 = ( !end_count mod 1000));;
134 let check_limit opt depth =
135 let _ = opt.iteration_count <- opt.iteration_count + 1 in
136 ( opt.iteration_count < opt.iteration_limit or opt.iteration_limit = 0 ) &&
137 (depth < opt.recursion_depth);;
139 let sgn x = if (x.lo > 0.0) then 1 else if (x.hi < 0.0) then -1 else 0;;
141 let rec same_sgn x y = (x = []) or (sgn (hd x) = sgn (hd y) && same_sgn (tl x) (tl y));;
146 let rec has_monotone opt tf ti domain0 x z x0 z0 is found = match is with
147 | [] -> (x,z,x0,z0,List.rev found)
148 | j::js when (mth x j >= mth z j) ->
149 has_monotone opt tf ti domain0 x z x0 z0 js found
152 if opt.raw_int_flag then
153 try evalf0 tf (j + 1) (fst domain0) (snd domain0)
154 with Unstable -> mk_interval (-1.0,1.0)
156 mk_interval (-1.0, 1.0) in
157 let allpos_df0, allpos_ti = df_int.lo >= opt.eps, lower_partial ti j >= opt.eps in
158 let allneg_df0, allneg_ti = df_int.hi < ~-.(opt.eps), upper_partial ti j < ~-.(opt.eps) in
159 if (allpos_df0 or allpos_ti) then
161 {variable = j + 1; decr_flag = false; df0_flag = allpos_df0; ti_flag = allpos_ti} in
162 if opt.mono_pass && mth z j < mth z0 j then return (Cell_pass_mono ([], status))
164 let setj u = table (fun i -> (if i=j then mth z j else mth u i)) in
165 has_monotone opt tf ti domain0 (setj x) (setj z)
166 (setj x0) (setj z0) js (status :: found)
167 else if (allneg_df0 or allneg_ti) then
169 {variable = j + 1; decr_flag = true; df0_flag = allneg_df0; ti_flag = allneg_ti} in
170 if opt.mono_pass && mth x j > mth x0 j then return (Cell_pass_mono ([], status))
172 let setj u = table (fun i -> (if i=j then mth x j else mth u i)) in
173 has_monotone opt tf ti domain0 (setj x) (setj z)
174 (setj x0) (setj z0) js (status :: found)
175 else has_monotone opt tf ti domain0 x z x0 z0 js found;;
177 (* loop as long as monotonicity keeps making progress. *)
179 let rec going_strong(x,z,x0,z0,tf,opt,mono) =
180 let (y,w) = center_form (x,z) in
181 let maxwidth = maxl w in
183 if opt.raw_int_flag then
184 try evalf0 tf 0 x z with Unstable -> one
187 let _ = target0.hi >= ~-.(opt.eps) or return (Cell_pass (mono, true)) in
189 try evalf tf x z with Unstable -> return (Cell_inconclusive (mono,x,z,x0,z0)) in
190 let _ = upper_bound target >= ~-.(opt.eps) or return (Cell_pass (mono, false)) in
191 let _ = lower_bound target < 0.0 or return Cell_counterexample in
192 let epsilon_width = 1.0e-8 in
193 let _ = (maxwidth >= epsilon_width) or return Cell_counterexample in
194 let (x,z,x0,z0,strong) =
195 if (opt.allow_derivatives) then
197 has_monotone opt tf target (x,z) x z x0 z0 iter8 []
198 with Return (Cell_pass_mono (_, status)) -> return (Cell_pass_mono (mono, status))
199 else (x,z,x0,z0,[]) in
200 if (strong <> []) then
201 going_strong(x,z,x0,z0,tf,opt,mono @ [strong])
203 (target,x,z,x0,z0,maxwidth,mono);;
207 This procedure is mostly guided by heuristics that don't require formal
208 verification. In particular, no justification is required for tossing out inequalities
209 (since they appear as disjuncts, we can choose which one to prove).
211 Formal verification is required whenever a Cell_passes is issued,
212 and whenever the domain (x,z) is restricted.
214 The record (x0,z0) of the current outer boundary must be restricted to (x,z)
215 whenever an inequality is tossed out.
218 let rec verify_cell (x,z,x0,z0,tf,opt) =
220 let _ = not(periodic_count () && !info_print_level >= 2) or report_current (x,z,"periodic report") in
221 let (ti,x,z,x0,z0,maxwidth,mono) = going_strong(x,z,x0,z0,tf,opt,[]) in
222 if opt.convex_flag then
223 Cell_inconclusive_ti (mono,ti,x,z,x0,z0)
225 Cell_inconclusive (mono,x,z,x0,z0)
229 let recursive_verifier (x,z,x0,z0,tf,opt) =
230 let w_init, indices = unzip (filter (fun p -> fst p > 1e-8) (zip (map2 (-.) z x) (1--length x))) in
231 let ws = map2 (-.) z x in
232 let total_vol = itlist ( *. ) w_init 1.0 in
233 let verified_vol = ref 0.0 in
234 let last_report = ref 0 in
235 let compute_vol x z w =
236 let rec compute i indices x z w =
239 | (r :: t) when r = i ->
240 let l = hd z -. hd x in
241 (if l > 1e-8 then l else hd w) *. compute (i + 1) t (tl x) (tl z) (tl w)
242 | _ -> compute (i + 1) indices (tl x) (tl z) (tl w) in
243 compute 1 indices x z w in
244 let update_verified_vol x z w =
245 if !info_print_level > 0 then
246 let _ = verified_vol := !verified_vol +. compute_vol x z w in
247 let verified = int_of_float (!verified_vol /. total_vol *. 100.5) in
248 if verified > !last_report then
249 let _ = last_report := verified in report0 (sprintf "%d " !last_report) else ()
252 let rec rec_verifier (depth,x,z,x0,z0,w0,tf) =
253 let _ = check_limit opt depth or report_fatal(x,z,Printf.sprintf "depth %d" depth) in
254 let split_and_verify j x z x0 z0 convex_flag =
255 let ( ++ ), ( / ) = up(); upadd, updiv in
256 let yj = (mth x j ++ mth z j) / 2.0 in
257 let delta b v = table (fun i-> if (i = j && b) then yj else mth v i) in
260 x, table (fun i -> if i = j then mth x i else mth z i)
262 delta false x, delta true z in
265 table (fun i -> if i = j then mth z i else mth x i), z
267 delta true x, delta false z in
268 let w1 = table (fun i -> if i = j then mth w0 i / 2.0 else mth w0 i) in
269 let r1 = rec_verifier(depth+1,x1,z1,x0,z0,w1,tf) in
271 | Result_false t -> Result_false t
273 (let r2 = rec_verifier(depth+1,x2,z2,x0,z0,w1,tf) in
275 | Result_false t -> Result_false t
276 | _ -> Result_glue (j, convex_flag, r1, r2)) in
278 let add_mono mono r1 =
279 itlist (fun m r -> Result_mono (m, r)) mono r1 in
281 match verify_cell(x,z,x0,z0,tf,opt) with
282 | Cell_counterexample -> Result_false (x,z)
283 | Cell_pass (mono, f0_flag) ->
284 let _ = update_verified_vol x z w0 in
285 add_mono mono (Result_pass (f0_flag,x,z))
286 | Cell_pass_mono (mono, status) ->
287 let _ = update_verified_vol x z w0 in
288 add_mono mono (Result_pass_mono status)
289 | Cell_inconclusive_ti(mono,ti,x,z,x0,z0) ->
290 let dds = map (fun i -> mth (mth ti.dd i) i, i) iter8 in
291 let convex_dds = filter (fun dd, i -> dd.lo >= opt.eps && mth x i < mth z i) dds in
292 let convex_i = map snd convex_dds in
293 let w2 = List.map2 upsub z x in
294 let convex_flag, ws, ws_i =
295 if convex_dds = [] then
298 true, map (mth w2) convex_i, convex_i in
299 let maxwidth2 = maxl ws in
300 let j_wide = try( find (fun i -> mth w2 i = maxwidth2) ws_i) with
301 | _ -> failwith "recursive_verifier find" in
302 add_mono mono (split_and_verify j_wide x z x0 z0 convex_flag)
304 | Cell_inconclusive(mono,x,z,x0,z0) ->
305 let w2 = List.map2 upsub z x in
306 let maxwidth2 = maxl w2 in
307 let j_wide = try( find (fun i -> mth w2 i = maxwidth2) iter8) with
308 | _ -> failwith "recursive_verifier find" in
309 add_mono mono (split_and_verify j_wide x z x0 z0 false) in
311 rec_verifier (0,x,z,x0,z0,ws,tf);;