(* ========================================================================= *) (* FLYSPECK - BOOK FORMALIZATION *) (* *) (* Chapter: nonlinear inequalities *) (* Author: Thomas Hales *) (* Date: 2012-06-02 *) (* ========================================================================= *) (* Generates ocaml function module (Sphere2). C++ Functions from HOL-Light specs. C++ Interval code for inequalities from HOL-Light specs. It uses many lemmas from functional_equation.hl *) (* to fix: proj_y1 = sqrt_x1 ,etc. to reorganize: move optimize.hl material on C++ generation here. Leave optimize.hl as the preprocessing module. *) flyspeck_needs "general/flyspeck_lib.hl";; flyspeck_needs "nonlinear/functional_equation.hl";; flyspeck_needs "nonlinear/optimize.hl";; flyspeck_needs "nonlinear/parse_ineq.hl";; flyspeck_needs "nonlinear/function_list.hl";; module Auto_lib = struct let join_comma = Flyspeck_lib.join_comma;; let join_space = Flyspeck_lib.join_space;; let join_lines = Flyspeck_lib.join_lines;; let functions = Function_list.functions();; let ocaml_code = let strip_all b = snd(strip_forall (concl (Nonlinear_lemma.strip_let b))) in let ocam f = Parse_ineq.ocaml_function (strip_all f) in let header = "(* code automatically generated from Parse_ineq.ocaml_code *)\n\n"^ "module Sphere2 = struct\n\n"^ "let sqrt = Pervasives.sqrt;;\n\n" ^ "let safesqrt = Pervasives.sqrt;;\n\n" ^ "let cos = Pervasives.cos;;\n\n" ^ "let sin = Pervasives.sin;;\n\n" ^ "let log = Pervasives.log;;\n\n" ^ "let asn = Pervasives.asin;;\n\n" ^ "let atn = Pervasives.atan;;\n\n" ^ "let hminus = 1.2317544220903043901;;\n\n" ^ "let pow2 x = x ** (2.0);;\n\n" in let tailer = "end;;\n" in header ^ (Flyspeck_lib.join_lines (map ocam functions)) ^ tailer;; (* Load module Sphere2 *) let sphere2_ml = Filename.temp_file "sphere2" ".ml";; Flyspeck_lib.output_filestring sphere2_ml ocaml_code;; loadt sphere2_ml;; let break_functional_lemma thm = let strip_all b = snd(strip_forall (concl (Nonlinear_lemma.strip_let b))) in let (h,ts) = strip_comb (strip_all thm) in let isdomain h = (fst(dest_const h) = "domain6") in let namebody = if isdomain h then tl ts else ts in (List.nth namebody 0),List.nth namebody 1;; let break_term x = break_functional_lemma (ASSUME x);; let rec real_arity ty = let real_ty = `:real` in if (is_vartype ty) then 0 else if (ty = real_ty) then 1 else let (a,b) = dest_type ty in if not(a = "fun" && hd b = real_ty && List.length b = 2) then 0 else 1 + real_arity (hd(tl b));; let mk_testing_string thm = let native = Optimize.native_fun in let (name,body') = break_functional_lemma thm in let name' = fst (strip_comb name) in let name' = fst (dest_const name') in let cname = Lib.assocd name' native name' in let _ = not(cname="NOT_IMPLEMENTED") or failwith "mk_testing:excluded" in let evalname = let s = Printf.sprintf "Sphere2.%s 6.36 4.2 4.3 4.4 4.5 4.6" name' in let (b,s')= Flyspeck_lib.eval_command s in let _ = b or failwith ("evalname: "^name') in let split = Str.split (Str.regexp "[ \n]") in let r = hd (List.rev (split s')) in let f = float_of_string r in let _ = not(0=Pervasives.compare nan f) or failwith "nan" in f in let mk_string = Printf.sprintf " epsValue(\"%s\",%s,%12.12f);" name' cname evalname in mk_string;; let mk_n_testing_string thm = let native = Optimize.native_fun in let (name,body') = break_functional_lemma thm in let name' = fst (strip_comb name) in let (name',ty) = dest_const name' in let rarity = real_arity ty in let nargs = rarity - 7 in let _ = (rarity >= 8) or failwith "mk_n_testing_string" in let args = map (fun i -> 0.04 +. (float_of_int i)/. 10.0) (1--nargs) in let os = join_space (map (Printf.sprintf "%f") args) in (* was interval::interval(".."). Changed 2013/08/14. *) let sargs = join_comma (map (Printf.sprintf "interval(\"%f\")") args) in let cname = Lib.assocd name' native name' in let _ = not(cname="NOT_IMPLEMENTED") or failwith "mk_testing:excluded" in let evalname = let s = Printf.sprintf "Sphere2.%s %s 6.36 4.2 4.3 4.4 4.5 4.6" name' os in let (b,s')= Flyspeck_lib.eval_command s in let _ = b or failwith ("evalname: "^name') in let split = Str.split (Str.regexp "[ \n]") in let r = hd (List.rev (split s')) in let f = float_of_string r in let _ = not(0=Pervasives.compare nan f) or failwith "nan" in f in let mk_string = Printf.sprintf " epsValue(\"%s\",%s(%s),%12.12f);" name' cname sargs evalname in mk_string;; let all_testing_string = let can_test = filter (can mk_testing_string) functions in let can_test_n = filter (can mk_n_testing_string) functions in Flyspeck_lib.join_lines ( (map mk_testing_string can_test) @ (map mk_n_testing_string can_test_n));; let testing_code = Printf.sprintf "\nvoid selfTest() { cout << \" -- loading test_auto test\" << endl << flush;\n %s cout << \" -- done loading test_auto test\" << endl << flush; }\n" all_testing_string;; let not_tested = filter (fun t -> not (can mk_testing_string t) && not (can mk_n_testing_string t)) functions;; (* following is copied and adapted from optimize.hl *) let paren s = "("^s^")";; let i_mk = Optimize.i_mk;; let string_of_num' = Optimize.string_of_num';; let dest_decimal = Optimize.dest_decimal;; let real_ty = `:real`;; let f1_ty = `:real->real`;; let f6_ty = `:real->real->real->real->real->real->real` ;; let f7_ty = `:real->real->real->real->real->real->real->real` ;; let f8_ty = `:real->real->real->real->real->real->real->real->real` ;; let f9_ty = `:real->real->real->real->real->real->real->real->real->real` ;; real_arity `:real->real->real->real->real` = 5;; let f6to6_ty = `:(real->real->real->real->real->real->real) -> (real->real->real->real->real->real->real)`;; let infix6_ty = `:(real->real->real->real->real->real->real) -> (real->real->real->real->real->real->real) -> (real->real->real->real->real->real->real)` ;; let scalar6_ty = `:(real->real->real->real->real->real->real) -> (real) -> (real->real->real->real->real->real->real)` ;; let tyvar_inst = let realty = `:real` in let u = setify(List.flatten (map (type_vars_in_term o concl) functions)) in map (fun t-> (realty,t)) u;; type_of (inst [(`:real`,`:A`)] `x:A`);; let nonnative_functional_terms = let f = map ((inst tyvar_inst)o concl) functions in let native = map fst Optimize.native_fun in let name t = fst(dest_const(fst(strip_comb(fst(break_term t))))) in let m t = not (mem (name t) native) in filter m f ;; let real_types = setify(map (type_of o fst o strip_comb o fst o break_term) nonnative_functional_terms);; List.length real_types;; let terms_with_type ty = filter (fun t -> ty = type_of(fst(strip_comb( fst(break_term t))))) nonnative_functional_terms;; let terms_with_real_arity_ge8 = filter (fun t -> 8 <= real_arity (type_of(fst(strip_comb( fst(break_term t)))))) nonnative_functional_terms;; let f0_terms = (terms_with_type real_ty);; let f0_code = let f0_template = Printf.sprintf "static const interval %s (\"%20.20f\");" in let f0_mk thm = let (name,body') = break_functional_lemma thm in let name' = fst (strip_comb name) in let name' = fst (dest_const name') in let s = Printf.sprintf "Sphere2.%s" name' in let (b,s')= Flyspeck_lib.eval_command s in let _ = b or failwith ("evalname: "^name') in let split = Str.split (Str.regexp "[ \n]") in let r = hd (List.rev (split s')) in let warn = "// Warning: "^name'^" computed by floating point\n" in let r' = float_of_string r in warn^(f0_template name' r') in Flyspeck_lib.join_lines (map (f0_mk o ASSUME) f0_terms);; let native_fun = Optimize.native_fun;; let native_infix = [ ("add6","+"); ("mul6","*"); ("sub6","-"); ("div6","/"); ("scalar6","*"); ];; let native_interval = [ ("hminus","hminus") ];; let f0_name = let f0_auto = map (fst o dest_const o fst o break_term) f0_terms in fun s -> if (mem s f0_auto) then s else try (Lib.assoc s native_interval) with Failure _ -> failwith (s^" find: real_name") ;; let fun_name = let fun_auto = map (fst o dest_const o fst o strip_comb o fst o break_term) nonnative_functional_terms in fun s-> try (Lib.assoc s native_fun) with Failure _ -> if (mem s fun_auto) then s else failwith ("fun_name not found: "^s);; let is_comma = let c = "," in fun t -> let (t,_) = strip_comb t in (is_const t && fst (dest_const t) = c);; let cpp_string_of_term = let rec soh t = if is_var t then fst (dest_var t) else let (f,xs) = strip_comb t in let ifix i = let [a;b] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in let (fv,ty) = if is_var f then let (fv,ty) = (dest_var f) in let _ = warn true ("variable function name: "^fv) in (fv,ty) else if (is_const f) then (dest_const f) else failwith ("var/const expected:" ^ string_of_term f) in match fv with | "real_add" -> ifix "+" | "real_mul" -> ifix "*" | "real_div" -> ifix "/" | "real_sub" -> ifix "-" | "," -> ifix "," | "\\/" -> ifix "\\/" | "real_neg" -> let [a] = xs in "(-" ^ soh a ^ ")" | "real_of_num" -> let [a] = xs in i_mk(soh a) | "NUMERAL" -> let [_] = xs in string_of_num' (dest_numeral t) | "<" -> let [a;b] = xs in paren(soh a ^ " < " ^ soh b) | ">" -> let [a;b] = xs in paren(soh a ^ " > " ^ soh b) | "+" -> let [a;b] = xs in paren(soh a ^ " + " ^ soh b) | "*" -> let [a;b] = xs in paren(soh a ^ " * " ^ soh b) | "DECIMAL" -> i_mk(string_of_num' (dest_decimal t)) | _ -> if (ty = real_ty) then paren(f0_name fv) else if (ty= infix6_ty) or (ty=scalar6_ty) then let op = (try Lib.assoc fv native_infix with Failure _ -> failwith ("parse infix6 "^fv)) in ifix op else (let name = fun_name fv in if (xs=[]) then paren name else let p = if (List.length xs = 1 && is_comma (hd xs)) then I else paren in let args = p (join_comma (map soh xs)) in paren (name^args)) in fun t -> try (soh t) with Failure s -> failwith (s^" ....... "^string_of_term t);; (* make functions of 6 variables *) let f6_code = let f6_template = Printf.sprintf "static const Function %s = %s;\n" in let f6_terms = (terms_with_type f6_ty) in let f6_auto = let b = (fst o dest_const o fst o strip_comb o fst o break_term) in let nat = map fst native_fun in filter (fun t -> not (mem (b t) nat)) f6_terms in let f6_mk tt = let (name1,body') = break_term tt in let name' = fst (strip_comb name1) in let name' = fst (dest_const name') in f6_template name' (cpp_string_of_term body') in join_lines (map f6_mk f6_auto);; let fn_code = let fn_template = Printf.sprintf "static const Function %s(%s) { return (%s); }\n" in let fn_arg_template = Printf.sprintf "const interval& %s" in let fn_terms = terms_with_real_arity_ge8 in (* (terms_with_type f7_ty)@ (terms_with_type f8_ty) @ (terms_with_type f9_ty) in *) let fn_auto = let b = (fst o dest_const o fst o strip_comb o fst o break_term) in let nat = map fst native_fun in filter (fun t -> not (mem (b t) nat)) fn_terms in let fn_mk tt = let (name1,body') = break_term tt in let (name',args) = (strip_comb name1) in let ags = join_comma (map (fn_arg_template o fst o dest_var) args) in let name' = fst (dest_const name') in fn_template name' ags (cpp_string_of_term body') in join_lines (map fn_mk fn_auto);; (* make 6 to 6 *) let f6to6_template = Printf.sprintf "static const Function %s(const Function& %s) { return %s; }\n";; let f6to6_terms = terms_with_type f6to6_ty;; let f6to6_mk tt = let (name1,body') = break_term tt in let (name',param) = strip_comb name1 in let _ = List.length param = 1 or failwith ("one parameter expected "^ string_of_term tt) in let name' = fst (dest_const name') in let param = fst (dest_var (hd param)) in f6to6_template name' param (cpp_string_of_term body');; let f6to6_code = join_lines (map f6to6_mk f6to6_terms);; let tmpfile = flyspeck_dir^"/../interval_code/test_auto.cc";; let interval_code = f0_code ^ f6to6_code ^ f6_code ^ fn_code^ testing_code;; (* based on optimize, but is enhanced with autogenerated code interval_code. *) let mkfile_code t s tags = let cpp_header = Optimize.cpp_header() in let cpp_tail = Optimize.cpp_tail() in let isquad = Optimize.is_quad_cluster tags in let p = if isquad then Optimize.mk_cppq_proc else Optimize.mk_cpp_proc in Flyspeck_lib.output_filestring tmpfile (join_lines [cpp_header;interval_code;(p t s tags);cpp_tail]);; (* let testid = "9563139965 d";; let idq = hd(Ineq.getexact testid);; let [(_,tags,post)] = Optimize.preprocess_split_idq idq;; mkfile_code false post testid tags;; *) (* This is an enhanced version of what is in optimize.hl. It uses mkfile_code, which adds autogenerated interval_code to what is in Optimize.mkfile_cppq. *) let execute_interval ex tags s testineq = let interval_dir = flyspeck_dir^"/../interval_code" in let _ = mkfile_code testineq s tags in let _ = Optimize.compile_cpp() in let _ = (not ex) or (0= Sys.command(interval_dir^"/test_auto")) or failwith "interval execution error" in ();; let testsplit_idq ex idq = let splits = Optimize.preprocess_split_idq idq in map (fun (s,tags,testineq) -> execute_interval ex tags s testineq) splits;; let testsplit ex s = testsplit_idq ex (hd (Ineq.getexact s));; (* *************************************************************************** *) (* Prep.prep_ineqs cases. *) (* no further processing for these. *) (* *************************************************************************** *) let test_noprocessing_idq ex idq = let (s,tags,testineq) = Optimize.idq_fields idq in execute_interval ex tags s testineq;; (* let ineqs = !Prep.pre_ineqs *) let test_prep ineqs ex s = let idq = filter (fun idq -> idq.idv = s) ineqs in test_noprocessing_idq ex (hd idq);; let test_prep_case_split ineqs ex (s,case,t) = let s' = Printf.sprintf "%s split(%d/%d)" s case t in (* let _ = Sys.command("sleep 3") in *) test_prep ineqs ex s';; end;;