flyspeck_needs "nonlinear/prep.hl";; flyspeck_needs "nonlinear/scripts.hl";; module Break_case_exec = struct (* open Sphere2;; *) (* PRELIMINARIES *) let ( MSEC_INC ) = 1000;; (* global parameter for msec target size *) let ERROR_TOLERANCE = 0.3;; (* try for times within MSEC_INC * (1 +/- ERROR_TOLERANCE ). *) let verbose = true;; (* The type iargs is used to record a partition of a nonlinear inequality domain into pieces. The code in this file is used to make the pieces all take approximately MSEC_INC milliseconds to run. The field 'a records the interval arithmetic C++ runtime in milliseconds. The partition is determined from the data and the original domain determined by (x,z), where x and z are lists of real numbers giving the lower left and upper right hand corners of the domain. Iarg_leaf represents a domain with no subpartition. The domain is all of (x,z). Iarg_bisect (i,left,right) is a cut exactly in the middle along the ith variable. The fields left and right give the further partition of the left and right sides. For example if i=1 and (x,z) = [1.0;1.0;1.0],[3.0;3.0;3.0] then the partition goes into (xleft,zleft) = [1.0;1.0;1.0],[3.0;2.0;3.0] and (xright,zright)=[1.0;2.0;1.0],[3.0;3.0;3.0]. Iarg_facet ((i,side),frac,msec,residual) breaks the domain in two unequal parts along the ith coordinate specified by a fraction 0.0 <= frac <= 1.0. The fraction is measured from the left if side=false, and from the right otherwise. For example, if i,side=1,false frac=0.25 and (x,z)= [x0;x1;x2],[z0;z1;z2], then (xleft,rleft)= x,[z0;0.75 * x1+0.25 *z1;z2] and (xright,zright)=[x0;0.75*x1+0.25*z1,z]. The number msec is the C++ runtime for (xleft,rleft), and residual is the recursively defined partition on (xright,zright). For example, if we change side=true and keep the rest of the data the same, then (xleft,rleft)= x,[z0;0.25 * x1+0.75 *z1;z2] and (xright,zright)=[x0;0.25*x1+0.75*z1,z]. The number msec is now the C++ runtime for (xright,right), and residual is the recursively defined partition on (xleft,zleft). So changing the side exchanges right and left all the way along. *) type ('a) iargs = Iarg_facet of ((int * bool) * float * 'a * ('a) iargs) | Iarg_leaf of 'a | Iarg_bisect of (int * ('a) iargs * ('a) iargs);; let rec string_of_iargs = function | Iarg_leaf msec -> Printf.sprintf "\n Iarg_leaf %d" msec | Iarg_facet ((i,b),frac,msec,a) -> Printf.sprintf "\n Iarg_facet ((%d,%s),%3.4f,%d,%s)" i (string_of_bool b) frac msec (string_of_iargs a) | Iarg_bisect(idx,a,b) -> Printf.sprintf "\n Iarg_bisect (%d,%s,%s)" idx (string_of_iargs a) (string_of_iargs b);; let output_case s iargs = let sfull = Printf.sprintf "\nadd_case (\"%s\",%s);;\n" s (string_of_iargs iargs) in let oc = open_out_gen [Open_append;Open_text] 436 (fullpath "nonlinear/break_case_log_more.hl") in (Pervasives.output_string oc (sfull); close_out oc);; let sprintf = Printf.sprintf;; Random.init 0;; let getprep s = hd(filter (fun t -> t.idv = s) (!Prep.prep_ineqs));; (* omit the quad cases for now: *) let idvlist = let nonquad = filter (fun t -> not(Optimize.is_quad_cluster t.tags)) (!Prep.prep_ineqs) in map (fun t -> t.idv) nonquad;; let nth = List.nth;; let rec cart a b = match a with | [] -> [] | a::rest -> (map (fun x -> (a,x)) b) @ cart rest b;; let maxlist xs = List.fold_right max xs (nth xs 0);; let rec trim s = let white c = mem c [' '; '\012'; '\n'; '\r'; '\t'] in let n = String.length s in let subs k = String.sub s k (n-1) in if (n > 0 && white (s.[0])) then trim (subs 1) else if (n > 1 && white (s.[n-1])) then trim (subs 0) else s;; let msec_inc = float_of_int MSEC_INC;; let float_cache = ref (fun() -> 0.0);; let eval_float s = let (b,r) = Flyspeck_lib.eval_command ~silent:false ("float_cache := (fun () -> ("^s^"));;") in let _ = b or (print_string (r^"\n"^s^"\n"); failwith "bad input string") in let t= (!float_cache)() in t;; (* C++ CODE GENERATION. *) let cpp_template_arg = sprintf " const char svn[] = %s; const char ineq_id[] = %s; int testRun(double x1[6],double z1[6]) // autogenerated code { // Warning: not rigorous. The rounding is off by epsilon. Use this only for experiments. interval tx[6]={interval(x1[0],x1[0]),interval(x1[1],x1[1]),interval(x1[2],x1[2]), interval(x1[3],x1[3]),interval(x1[4],x1[4]),interval(x1[5],x1[5]) }; interval tz[6]={interval(z1[0],z1[0]),interval(z1[1],z1[1]),interval(z1[2],z1[2]), interval(z1[3],z1[3]),interval(z1[4],z1[4]),interval(z1[5],z1[5])}; domain x = domain::lowerD(tx); domain z = domain::upperD(tz); domain x0=x; domain z0=z; %s const Function* I[%d] = {%s}; // len ... cellOption opt; opt.allowSharp = %d; // sharp opt.onlyCheckDeriv1Negative = %d; // checkderiv %s // other options. return prove::recursiveVerifier(0,x,z,x0,z0,I,%d,opt); // len }";; let mk_cpp_arg_proc t s tags = let sharp = if mem Sharp tags then 1 else 0 in let checkderiv = if mem Onlycheckderiv1negative tags then 1 else 0 in let ifd b s = if b then s else "" in let (b,f) = Optimize.widthCut tags in let sWidth = ifd b (sprintf "\topt.widthCutoff = %8.16f;\n" f) in let c = map Optimize.cpp_string_of_term in let f (x,y,z) = (c x,c y,c z) in let (aas,bbs,iis) = f (Optimize.dest_nonlin t) in let len = length iis in let sq = Optimize.quoted s in let svn = (Optimize.quoted(Optimize.svn_version())) in cpp_template_arg svn sq (Optimize.cpp_template_t "" iis) len (Optimize.cpp_template_Fc "" len) sharp checkderiv sWidth len;; let mkfile_arg = let cpp_tail = Optimize.join_lines (Optimize.load_file (flyspeck_dir^"/../interval_code/arg_tail.txt")) in let cpp_header = Optimize.cpp_header() in fun t s tags -> Flyspeck_lib.output_filestring Optimize.tmpfile (Optimize.join_lines [cpp_header;Auto_lib.interval_code;(mk_cpp_arg_proc t s tags);cpp_tail]);; let execute_args ex tags s testineq xlist zlist = let x = List.nth xlist in let z = List.nth zlist in let args = sprintf " %f %f %f %f %f %f %f %f %f %f %f %f" (x 0) (x 1) (x 2) (x 3) (x 4) (x 5) (z 0) (z 1) (z 2) (z 3) (z 4) (z 5) in let interval_dir = flyspeck_dir^"/../interval_code" in let _ = mkfile_arg testineq s tags in let _ = Optimize.compile_cpp() in let _ = (not ex) or (0= Sys.command(interval_dir^"/test_auto"^args)) or failwith "interval execution error" in ();; let process_and_prep_args ex (s,tags,case) = let _ = report ("process and prep args: "^s) in let (s,tags,testineq) = (* preprocess debug *) (s,tags,case) in let (x,y,_) = Optimize.dest_nonlin testineq in (execute_args ex tags s testineq , x, y);; let rerun_timer = let run_out = Filename.temp_file "run" ".out" in fun xlist zlist timer -> let x = List.nth xlist in let z = List.nth zlist in let args = sprintf " %f %f %f %f %f %f %f %f %f %f %f %f %f" (x 0) (x 1) (x 2) (x 3) (x 4) (x 5) (z 0) (z 1) (z 2) (z 3) (z 4) (z 5) (float_of_int timer) in let interval_dir = flyspeck_dir^"/../interval_code" in let _ = (0= Sys.command(interval_dir^"/test_auto"^args^" | tee "^run_out)) or failwith "interval execution error" in let outs = trim (process_to_string ("grep msecs "^run_out^" | sed 's/^.*msecs=//' | sed 's/;.*$//' ")) in (* let _ = report (":"^outs^":") in *) let msecs = try (int_of_string (outs)) with _ -> timer in (msecs);; (* DOMAIN CONSTANTS *) let scrub_c t = let th = REWRITE_CONV [Sphere.h0; GSYM Nonlinear_lemma.sol0_over_pi_EQ_const1; ASSUME `hminus = #1.2317544220903216`; ASSUME `pi = #3.1415926535897932385`; ASSUME `sol0 = #0.55128559843253080794`] t in rhs(concl th);; let get_constants_xy s = let (s,tags,case) = Optimize.idq_fields (getprep s) in let (x,y,_) = Optimize.dest_nonlin case in (map scrub_c x,map scrub_c y);; let get_constants s = let (x,y) = get_constants_xy s in x @ y;; let get_float_domain s = let m = map (eval_float o Parse_ineq.ocaml_string_of_term) in let (x,y) = get_constants_xy s in (m x,m y);; (* they all check out on 2013/7/31 find (fun s -> not(can get_float_domain s)) (snd (chop_list 650 idvlist));; *) (* interpolate along edge *) let index_max_width (x ,z) avoid = let w = map (fun (xi,zi) -> zi -. xi) (zip x z) in let avoid_filter = map (fun i -> (mem i avoid)) (0--(List.length x - 1)) in let w' = map (fun (t,b) -> if b then 0.0 else t) (zip w avoid_filter) in let wm = maxlist w' in index wm w';; let facet_opp (i,side)= (i,not side);; let invert_side (_,side) (x,z) = if side then (z,x) else (x,z);; let invert_interpolate (i,side) frac (x,z) = let _ = (0.0 <= frac && frac <= 1.0) or failwith "invert_interpolate: frac out of range " in let _ = List.length x = List.length z or failwith "invert_interpolate: length mismatch" in let n = List.length x in let rg = (0--(n-1)) in let (x,z) = invert_side (i,side) (x,z) in let c = nth x i *. (1.0-. frac) +. nth z i *. frac in let modi (xi,j) = if (i=j) then c else xi in let xm = map modi (zip x rg) in let zm = map modi (zip z rg) in (* partition will be x--zm, xm--z *) invert_side(i,side) (xm,zm);; let interpolate_frac (f1,t1) (f2,t2) = let _ = (0.0 <= f1 && f1 < f2 && f2 <= 1.0 && t1 <= msec_inc && msec_inc <= t2) or failwith "interpolate: out of range" in (msec_inc -. t1) *. (f2 -. f1) /. (t2 -. t1) +. f1;; let run_frac frac facet (x1,z1) timeout = let (xm,zm) = invert_interpolate facet frac (x1,z1) in let m3 = if (not(snd facet)) then rerun_timer x1 zm timeout else rerun_timer xm z1 timeout in ((xm,zm),m3);; let rec recursive_find_frac facet x1 z1 (f1,t1) (f2,t2) = (* last case in a batch may have a small t2, so dont use abs_float in the following line *) if (t2/. msec_inc -. 1.0) < ERROR_TOLERANCE then (f2,int_of_float t2) else if abs_float(t1/. msec_inc -. 1.0) < ERROR_TOLERANCE then (f1,int_of_float t1) else let minwidth = 0.001 in if (f2 <= f1 +. minwidth && t2 < 1.99 *. msec_inc) then (f2,int_of_float t2) else if (f2 <= f1 +. minwidth && t1 > 0.25 *. msec_inc) then (f1,int_of_float t1) else let _ = f1+. minwidth <= f2 or failwith "find_frac width underflow" in let f3 = interpolate_frac (f1,t1) (f2,t2) in let f3 = if (Random.int 4 = 0 && t2 > 1.9*. msec_inc) then (f1+.f2)/. 2.0 +. Random.float (f2 -. f1) /. 2.0 else f3 in let f3 = if (Random.int 3 = 0 && t1 < 0.5*. msec_inc) then f1 +. Random.float (f2 -. f1)/. 2.0 else f3 in let _ = (f1 <= f3 && f3 <= f2) or failwith "recursive_find_frac: out of range" in let ((xm,zm),m3) = run_frac f3 facet (x1,z1) (2 * MSEC_INC) in let _ = if verbose then report (sprintf "recursing fracs %3.3f,%3.3f,%3.3f msecs %d,%d,%d" f1 f3 f2 (int_of_float t1) m3 (int_of_float t2)) in let t3 = float_of_int m3 in if abs_float(t3/. msec_inc -. 1.0) < ERROR_TOLERANCE then (f3,m3) else let ((f1',t1'),(f2',t2')) = if (t3 <= msec_inc) then ((f3,t3),(f2,t2)) else ((f1,t1),(f3,t3)) in recursive_find_frac facet x1 z1 (f1',t1') (f2',t2');; (* DEBUG *) let rec pass_time = function Iarg_bisect (_,a,b) -> pass_time a + pass_time b | Iarg_leaf msec -> msec | Iarg_facet (_,_,msec,c) -> msec + pass_time c;; let rec recheck_pass timeout domain iarg = match iarg with | Iarg_leaf msec -> let (x,z) = domain in let msec' = rerun_timer x z timeout in Iarg_leaf (msec,msec') | Iarg_facet(facet,frac,msec,b) -> let (x,z) = domain in let (xm,zm) = invert_interpolate facet frac domain in let residual = if (not(snd facet)) then (xm,z) else (x,zm) in let (_,msec') = run_frac frac facet domain timeout in Iarg_facet(facet,frac,(msec,msec'), recheck_pass timeout residual b) | Iarg_bisect(idx,a,b) -> let (x,z) = domain in let facet = (idx,false) in let (xm,zm) = invert_interpolate facet 0.5 domain in let partA,partB = ((x,zm),(xm,z)) in Iarg_bisect(idx,recheck_pass timeout partA a,recheck_pass timeout partB b);; (* MAIN PROCEDURES *) let initial_msec = let ft_sec = Scripts.finalize Scripts.finished_times in let ft_msec = Scripts.finalize Scripts.finished_times_msecs in fun s -> try assoc s ft_msec with _ -> 1000 * (assoc s ft_sec );; let initialize s = let msec = initial_msec s in let (x1,z1)=get_float_domain s in let stc = Optimize.idq_fields (getprep s) in let (compile,_,_) = process_and_prep_args false stc in let _ = compile x1 z1 in (x1,z1,msec);; let rec pass_revised avoid ((x,z),msec) = let left = false in let idx = index_max_width (x,z) avoid in let fi = float_of_int in let timeout = 2 * MSEC_INC in let (s0,s1,s2) = (0,1,2) in let facet = (idx,left) in let sz m = let t = fi m /. fi MSEC_INC in if t < 1.0 -. ERROR_TOLERANCE then s0 else if t < 1.999 then s1 else s2 in if msec < timeout then let _ = if verbose then report "FOUND leaf..." in (Iarg_leaf msec) else let (_,m3A) = run_frac 0.5 facet (x,z) timeout in let (_,m3B) = run_frac 0.5 (facet_opp facet) (x,z) timeout in let (m3min,facet,swap) = if m3A<=m3B then (m3A,facet,false) else (m3B,facet_opp facet,true) in let smin = sz m3min in if (smin=s2) then let (xm,zm) = invert_interpolate (idx,left) 0.5 (x,z) in let partA,partB = ((x,zm),(xm,z)) in let _ = if verbose then report "FOUND bisection..." in Iarg_bisect (idx,pass_revised [] (partA,m3A),pass_revised [] (partB,m3B)) else if (smin = s1) then let (xm,zm) = invert_interpolate facet 0.5 (x,z) in let residual= if (snd facet=left) then (xm,z) else (x,zm) in let m3max = if swap then m3A else m3B in let _ = if verbose then report "FOUND 0.5 facet..." in Iarg_facet(facet,0.5,m3min,pass_revised [] (residual,m3max)) else (* smin=s0 *) try ( let (fracC,mC) = recursive_find_frac facet x z (0.5,fi m3min) (1.0,fi msec) in let (xm,zm) = invert_interpolate facet fracC (x,z) in let residual= if (snd facet=left) then (xm,z) else (x,zm) in let mD = rerun_timer (fst residual) (snd residual) timeout in let _ = if verbose then report (sprintf "FOUND %3.3f,%d facet..." fracC mC) in Iarg_facet (facet,fracC,mC,pass_revised [] (residual,mD))) with Failure fail -> let _ = report ("failure "^fail) in pass_revised (idx::avoid) ((x,z),msec);; let run_one save s = let (x1,z1,msec1) = initialize s in let iarg = (pass_revised [] ((x1,z1),msec1)) in let _ = if (save) then output_case s iarg in iarg;; let run_all_over2sec save = let preptimes = map (fun s -> try s,initial_msec s with _ -> failwith s) (idvlist) in let over2sec = (sort (fun (_,s) (_,t) -> s < t) (filter (fun (s,t) -> t > 2000) preptimes)) in let over2 = map fst over2sec in let alldata = map (fun s -> try s,run_one save s with Failure msg -> report s; failwith msg) over2 in alldata;; end;;