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;;
35 (* needs "verifier/interval_m/work1.hl";; *)
38 only_check_deriv1_negative : bool;
39 is_using_dihmax : bool;
40 is_using_bigface126 : bool;
43 allow_derivatives : bool;
44 mutable iteration_count : int;
45 iteration_limit : int;
46 recursion_depth : int;
54 (* cell verification is complex, and we use exceptions to
55 exit as soon as the status has been determined. *)
70 let tfs0 = [{tf = tf1; index = 0;};
71 {tf = tf2; index = 1;}];;
74 let all_indices = map (fun (_, f) -> f.index);;
77 | Cell_pass of mono_status list list * (int * bool)
78 | Cell_pass_mono of mono_status list list * (int list * mono_status)
80 | Cell_inconclusive_ti of (taylor_interval * fun_type) list * (mono_status list list * float list * float list * float list * float list)
81 | Cell_inconclusive of fun_type list * (mono_status list list * float list * float list * float list * float list);;
83 exception Return of cell_status;;
86 | Result_false of (float list * float list)
87 (* function number, raw flag *)
88 | Result_pass of (int * bool)
89 | Result_pass_mono of mono_status
90 | Result_pass_ref of int
91 | Result_mono of mono_status list * result_tree
92 (* variable, convex_flag, r1, r2 *)
93 | Result_glue of (int * bool * result_tree * result_tree);;
100 | P_result_pass of p_status * int * bool
101 | P_result_mono of p_status * mono_status list * p_result_tree
102 | P_result_glue of p_status * int * bool * p_result_tree * p_result_tree
103 | P_result_ref of int;;
105 let rec result_size r =
107 | Result_false _ -> failwith "False result detected"
108 | Result_mono (_,r1) -> result_size r1
109 | Result_glue (_, _, r1, r2) -> result_size r1 + result_size r2
110 | Result_pass_mono _ -> 1
114 let rec p_result_size r =
116 | P_result_pass _ -> 1
117 | P_result_mono (_, _, r1) -> p_result_size r1
118 | P_result_glue (_, _, _, r1, r2) -> p_result_size r1 + p_result_size r2
122 let return c = raise (Return c);;
125 (* error checking and reporting functions *)
127 let string_of_domain x =
129 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);;
131 let string3 (x,z,s) = (string_of_domain x ^"\n"^ string_of_domain z ^ "\n" ^ s);;
133 let boolify _ = true;;
135 let report_current = boolify o Report.report_timed o string3;;
137 let report_error = boolify o Report.report_error o string3;;
139 let report_fatal = boolify o Report.report_fatal o string3;;
141 (* let t = [0.1;0.2;0.3;0.4;0.5;0.6] in report_error (t,t,"ok");; *)
144 let end_count = ref 0 in
146 let _ = end_count := !end_count + 1 in
147 (0 = ( !end_count mod 1000));;
149 let check_limit opt depth =
150 let _ = opt.iteration_count <- opt.iteration_count + 1 in
151 ( opt.iteration_count < opt.iteration_limit or opt.iteration_limit = 0 ) &&
152 (depth < opt.recursion_depth);;
154 let sgn x = if (x.lo > 0.0) then 1 else if (x.hi < 0.0) then -1 else 0;;
156 let rec same_sgn x y = (x = []) or (sgn (hd x) = sgn (hd y) && same_sgn (tl x) (tl y));;
159 let dummy_taylor = make_taylor_interval ((mk_line (one, [])), [], []);;
161 (* computes taylor intervals for all functions *)
162 let rec set_targets (x,z,x0,z0,tfs,tis,opt,mono,maxwidth,has_unstable) =
164 let _ = not(has_unstable) or return (Cell_inconclusive (map snd tis, (mono,x,z,x0,z0))) in
167 let tf = (hd tfs).tf and
168 index = (hd tfs).index in
170 if opt.raw_int_flag then
171 try evalf0 tf 0 x z with Unstable -> one
174 let _ = target0.hi >= ~-.(opt.eps) or return (Cell_pass (mono, (index, true))) in
176 let target = evalf tf x z in
177 let _ = upper_bound target >= ~-.(opt.eps) or return (Cell_pass (mono, (index, false))) in
178 set_targets(x,z,x0,z0,tl tfs,(target,hd tfs)::tis,opt,mono,maxwidth,has_unstable)
180 if (2.0 *. maxwidth > opt.width_cutoff) then
181 set_targets(x,z,x0,z0,tl tfs,(dummy_taylor, hd tfs)::tis,opt,mono,maxwidth,true) (* proclaim unstable *)
183 set_targets(x,z,x0,z0,tl tfs,tis,opt,mono,maxwidth,has_unstable) (* drop silently *)
187 let tis = set_targets (xx, zz, xx, zz, tfs0, [], opt0, [], 1.0, false);;
188 let ti = fst (nth tis 0);;
192 let rec delete_false acc tis =
193 if (tis=[]) then List.rev acc
194 else if (lower_bound (fst (hd tis)) > 0.0) then delete_false acc (tl tis)
195 else delete_false (hd tis::acc) (tl tis);;
199 let rec has_monotone opt tis domain0 x z x0 z0 is found = match is with
200 | [] -> (x,z,x0,z0,List.rev found)
201 | j::js when (mth x j >= mth z j) ->
202 has_monotone opt tis domain0 x z x0 z0 js found
205 if opt.raw_int_flag then
208 evalf0 f.tf (j + 1) (fst domain0) (snd domain0)
209 with Unstable -> mk_interval (-1.0,1.0)))
212 [mk_interval (-1.0, 1.0)] in
213 let allpos_df0 = List.fold_left (fun a i -> a && i.lo >= opt.eps) true df_ints and
214 allneg_df0 = List.fold_left (fun a i -> a && i.hi < ~-.(opt.eps)) true df_ints in
215 let allpos_ti = List.fold_left (fun a ti -> a && lower_partial (fst ti) j >= opt.eps) true tis and
216 allneg_ti = List.fold_left (fun a ti -> a && upper_partial (fst ti) j < ~-.(opt.eps)) true tis in
218 if (allpos_df0 or allpos_ti) then
220 {variable = j + 1; decr_flag = false; df0_flag = allpos_df0; ti_flag = allpos_ti} in
221 if opt.mono_pass && mth z j < mth z0 j then
222 return (Cell_pass_mono ([], (all_indices tis, status)))
224 let setj u = table (fun i -> (if i=j then mth z j else mth u i)) in
225 has_monotone opt tis domain0 (setj x) (setj z)
226 (setj x0) (setj z0) js (status :: found)
227 else if (allneg_df0 or allneg_ti) then
229 {variable = j + 1; decr_flag = true; df0_flag = allneg_df0; ti_flag = allneg_ti} in
230 if opt.mono_pass && mth x j > mth x0 j then
231 return (Cell_pass_mono ([], (all_indices tis, status)))
233 let setj u = table (fun i -> (if i=j then mth x j else mth u i)) in
234 has_monotone opt tis domain0 (setj x) (setj z)
235 (setj x0) (setj z0) js (status :: found)
236 else has_monotone opt tis domain0 x z x0 z0 js found;;
238 (* loop as long as monotonicity keeps making progress. *)
240 let rec going_strong(x,z,x0,z0,tfs,opt,mono) =
241 let (y,w) = center_form (x,z) in
242 let maxwidth = maxl w in
243 let tis = set_targets (x,z,x0,z0,tfs,[],opt,mono,maxwidth,false) in
244 let epsilon_width = 1.0e-8 in
245 let _ = (maxwidth >= epsilon_width) or return Cell_counterexample in
246 let tis = delete_false [] tis in
247 let _ = (List.length tis > 0) or return Cell_counterexample in
248 let (x0,z0) = if (length tis < length tfs) then (x,z) else (x0,z0) in
249 let (x,z,x0,z0,strong) =
250 if (opt.allow_derivatives) then
252 has_monotone opt tis (x,z) x z x0 z0 iter8 []
253 with Return (Cell_pass_mono (_, i_status)) ->
254 return (Cell_pass_mono (mono, i_status))
255 else (x,z,x0,z0,[]) in
256 if (strong <> []) then
257 going_strong(x,z,x0,z0,map snd tis,opt,mono @ [strong])
259 (tis,x,z,x0,z0,maxwidth,mono);;
262 let xx = [0.0; -1.0] @ pad;;
263 let zz = [1.0; 0.0] @ pad;;
264 let _, x,z,x0,z0,_,mono = going_strong (xx,zz,xx,zz,tfs0,opt0,[]);;
266 let tis = set_targets (xx,zz,xx,zz,tfs0,[],opt0,[],1.0,false);;
275 if opt.raw_int_flag then
278 evalf0 f.tf (j + 1) (fst domain0) (snd domain0)
279 with Unstable -> mk_interval (-1.0,1.0)))
282 [mk_interval (-1.0, 1.0)];;
283 let allpos_df0 = List.fold_left (fun a i -> a && i.lo >= opt.eps) true df_ints and
284 allneg_df0 = List.fold_left (fun a i -> a && i.hi < ~-.(opt.eps)) true df_ints in
285 let allpos_ti = List.fold_left (fun a ti -> a && lower_partial (fst ti) j >= opt.eps) true tis and
286 allneg_ti = List.fold_left (fun a ti -> a && upper_partial (fst ti) j < ~-.(opt.eps)) true tis in
291 This procedure is mostly guided by heuristics that don't require formal
292 verification. In particular, no justification is required for tossing out inequalities
293 (since they appear as disjuncts, we can choose which one to prove).
295 Formal verification is required whenever a Cell_passes is issued,
296 and whenever the domain (x,z) is restricted.
298 The record (x0,z0) of the current outer boundary must be restricted to (x,z)
299 whenever an inequality is tossed out.
302 let rec verify_cell (x,z,x0,z0,tfs,opt) =
304 let _ = not(periodic_count () && !info_print_level >= 2) or report_current (x,z,"periodic report") in
305 let (tis,x,z,x0,z0,maxwidth,mono) = going_strong(x,z,x0,z0,tfs,opt,[]) in
306 if opt.convex_flag then
307 Cell_inconclusive_ti (tis, (mono,x,z,x0,z0))
309 Cell_inconclusive (map snd tis, (mono,x,z,x0,z0))
313 let recursive_verifier (x,z,x0,z0,tfs,opt) =
314 let w_init, indices = unzip (filter (fun p -> fst p > 1e-8) (zip (map2 (-.) z x) (1--length x))) in
315 let ws = map2 (-.) z x in
316 let total_vol = itlist ( *. ) w_init 1.0 in
317 let verified_vol = ref 0.0 in
318 let last_report = ref 0 in
319 let compute_vol x z w =
320 let rec compute i indices x z w =
323 | (r :: t) when r = i ->
324 let l = hd z -. hd x in
325 (if l > 1e-8 then l else hd w) *. compute (i + 1) t (tl x) (tl z) (tl w)
326 | _ -> compute (i + 1) indices (tl x) (tl z) (tl w) in
327 compute 1 indices x z w in
328 let update_verified_vol x z w =
329 if !info_print_level > 0 then
330 let _ = verified_vol := !verified_vol +. compute_vol x z w in
331 let verified = int_of_float (!verified_vol /. total_vol *. 100.5) in
332 if verified > !last_report then
333 let _ = last_report := verified in report0 (sprintf "%d " !last_report) else ()
336 let add_mono mono r1 =
337 itlist (fun m r -> Result_mono (m, r)) mono r1 in
339 let rec rec_verifier (depth,x,z,x0,z0,w0,tfs) =
340 let split_and_verify tfs j x z x0 z0 convex_flag =
341 let ( ++ ), ( / ) = up(); upadd, updiv in
342 let yj = (mth x j ++ mth z j) / 2.0 in
343 let delta b v = table (fun i-> if (i = j && b) then yj else mth v i) in
346 x, table (fun i -> if i = j then mth x i else mth z i)
348 delta false x, delta true z in
351 table (fun i -> if i = j then mth z i else mth x i), z
353 delta true x, delta false z in
354 let w1 = table (fun i -> if i = j then mth w0 i / 2.0 else mth w0 i) in
355 let r1 = rec_verifier(depth+1,x1,z1,x0,z0,w1,tfs) in
357 | Result_false t -> Result_false t
359 (let r2 = rec_verifier(depth+1,x2,z2,x0,z0,w1,tfs) in
361 | Result_false t -> Result_false t
362 | _ -> Result_glue (j, convex_flag, r1, r2)) in
364 let _ = check_limit opt depth or report_fatal(x,z,Printf.sprintf "depth %d" depth) in
365 match verify_cell(x,z,x0,z0,tfs,opt) with
366 | Cell_counterexample -> Result_false (x,z)
367 | Cell_pass (mono, (i, f0_flag)) ->
368 let _ = update_verified_vol x z w0 in
369 add_mono mono (Result_pass (i, f0_flag))
370 | Cell_pass_mono (mono, (is, status)) ->
371 let _ = update_verified_vol x z w0 in
372 add_mono mono (Result_pass_mono status)
374 (* TODO: convexity *)
375 | Cell_inconclusive_ti (tis, (mono,x,z,x0,z0)) ->
376 let dds = map (fun i -> mth (mth ti.dd i) i, i) iter8 in
377 let convex_dds = filter (fun dd, i -> dd.lo >= opt.eps && mth x i < mth z i) dds in
378 let convex_i = map snd convex_dds in
379 let w2 = List.map2 upsub z x in
380 let convex_flag, ws, ws_i =
381 if convex_dds = [] then
384 true, map (mth w2) convex_i, convex_i in
385 let maxwidth2 = maxl ws in
386 let j_wide = try( find (fun i -> mth w2 i = maxwidth2) ws_i) with
387 | _ -> failwith "recursive_verifier find" in
388 add_mono mono (split_and_verify tfs j_wide x z x0 z0 convex_flag)
390 | Cell_inconclusive_ti _ -> failwith "Convexity is not supported"
391 | Cell_inconclusive (tfs, (mono,x,z,x0,z0)) ->
392 let w2 = List.map2 upsub z x in
393 let maxwidth2 = maxl w2 in
394 let j_wide = try( find (fun i -> mth w2 i = maxwidth2) iter8) with
395 | _ -> failwith "recursive_verifier find" in
396 add_mono mono (split_and_verify tfs j_wide x z x0 z0 false) in
398 rec_verifier (0,x,z,x0,z0,ws,tfs);;
401 let _, tf3, _ = mk_verification_functions_poly 3 `\x:real^2. --(&1 - x$1 * x$1 - x$2 * x$2)`;;
402 let tfs1 = [{tf = tf3; index = 0;}];;
403 let xx = [-0.75; -0.7] @ pad and
404 zz = [0.75; 0.7] @ pad;;
407 verify_cell (xx,zz,xx,zz,tfs1,opt0);;
408 recursive_verifier (xx,zz,xx,zz,tfs1,opt0);;