(* ========================================================================== *) (* FLYSPECK - BOOK FORMALIZATION *) (* *) (* Chapter: nonlinear inequalities *) (* Author: Thomas Hales starting from Roland Zumkeller's ccform function *) (* Date: 2010-05-09 *) (* ========================================================================== *) (* Use HOL Light specifications of functions and inequalities to automatically generate code in other languages. ** cfsqp C++ code, ** glpk for linear programming ** Objective Caml export of functions ** LaTeX documentation of inequalities. C++ code generation for interval arithmetic is done separately in optimize.hl. (This file is independent from that one.) CFSQP NOTES Executing the cfsqp produces three output files: /tmp/cfsqp_err.txt, tmp/t.cc tmp/t.o (in the cfsqp directory) Use macro_add to add new function (that is expanded with rewrites) Use autogen_add to add new function (automatic C code generation) *) (* flyspeck_needs "general/flyspeck_lib.hl";; flyspeck_needs "general/sphere.hl";; flyspeck_needs "nonlinear/ineq.hl";; flyspeck_needs "nonlinear/lemma.hl";; *) module Parse_ineq = struct open Sphere;; open Nonlinear_lemma;; open Functional_equation;; let cfsqp_trialcount = ref 500;; let dest_decimal = Flyspeck_lib.dest_decimal;; let string_of_num' = Flyspeck_lib.string_of_num';; let join_comma = Flyspeck_lib.join_comma;; let join_lines = Flyspeck_lib.join_lines;; let join_space = Flyspeck_lib.join_space;; let paren s = "("^ s ^")";; let nub = Flyspeck_lib.nub;; (* moved to lemmas.hl. let strip_let_tm t = snd(dest_eq(concl(REDEPTH_CONV let_CONV t)));; let strip_let t = REWRITE_RULE[REDEPTH_CONV let_CONV (concl t )] t;; *) (* from HOL Light lib.ml *) let rec (--) = fun m n -> if m > n then [] else m::((m + 1) -- n);; (* renamed from output_string to avoid Pervasives module name clash *) let output_filestring = Flyspeck_lib.output_filestring;; (* ======================================== cfsqp generation ======================================== *) let c_string_of_term t = let rec soh t = if is_var t then fst (dest_var t) else let (f,xs) = strip_comb t in let _ = (is_const f) or failwith ("Non-const function name: " ^ string_of_term f) in let ifix i = let [a;b] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in let ifix_swapped i = let [b;a] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in (* soh: *) match fst (dest_const f) with | "real_gt" | "real_ge" | "real_sub" -> ifix "-" | "real_lt" | "real_le" -> ifix_swapped "-" | "real_add" -> ifix "+" | "real_mul" -> ifix "*" | "real_div" -> ifix "/" | "\\/" -> ifix "\\/" | "real_neg" -> let [a] = xs in paren("-" ^ soh a) | "acs" -> let [a] = xs in paren ("acos" ^ (paren (soh a))) | "real_of_num" -> let [a] = xs in 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" -> string_of_num' (dest_decimal t) | "COND" -> let [a;b;c] = xs in paren(soh a ^ " ? " ^ soh b ^ " : " ^ soh c) | "atn2" -> let [ab] = xs in let (a,b) = dest_pair ab in paren("atn2( " ^ soh a ^ "," ^ soh b ^ ")") | s -> paren(s ^ "(" ^ join_comma(map soh xs) ^ ")") in (* c_string_of_term: *) try soh t with Failure s -> failwith (s^" ....... "^string_of_term t);; let constant_names i = let rec cn b =function | Const (s,_) -> s::b | Comb (s,t) -> (cn [] s) @ (cn[] t) @ b | Abs(x,t) -> (cn b t) | _ -> b in nub (sort (<) (cn [] i ));; (* Rewrite unusual terms to prepare for C++ conversion *) (* function calls are dealt with three different ways: - native_c: use the native C code definition of the function. - autogen: automatically generate a C style function - macro_expand: use rewrites to eliminate the function. *) (* Native is the default case. There is no need to list them, except as documentation. *) let native_c = [ ",";"BIT0";"BIT1";"CONS";"DECIMAL"; "NIL"; "NUMERAL"; "_0"; "acs"; "ineq"; "pi"; "adodec"; "bdodec";"real_add"; "real_div";"real_pow";"cos"; "real_ge"; "real_mul"; "real_of_num"; "real_sub"; "machine_eps"; (* -- *) "delta_x";"sol_y";"dih_y";"rhazim"; "lmfun";"lnazim";"hminus"; "wtcount3_y";"wtcount6_y";"beta_bumpA_y";"matan";"sqp";"sqn"; (* added May 2011 *) (* "taum_m_diff_quotient";"taum_m_diff_quotient2"; *) (* added 2012 *) "ell_uvx"; "root"; "h0cut"; ];; let autogen = ref[];; let prep_autogen = (function b -> snd(strip_forall (concl (strip_let b))));; let autogen_remove thm = let thm' = prep_autogen thm in autogen := filter (fun t -> not (t = thm')) !autogen;; let autogen_add thm = let thm' = prep_autogen thm in let _ = autogen_remove thm in (* duplicates create C compile error *) autogen := !autogen @ [thm'];; (* cfsqp autogeneration *) autogen := map prep_autogen [sol0;tau0;hplus;mm1;mm2;vol_x;sqrt8;sqrt2;sqrt3;rho_x; rad2_x;ups_x;eta_x;eta_y;volR; norm2hh;arclength;regular_spherical_polygon_area; beta_bump_force_y; a_spine5;b_spine5;beta_bump_lb;marchal_quartic;vol2r; tame_table_d;delta_x4;dih_x_alt;sol_x;delta4_squared_x;x1_delta_x; quad_root_plus_curry; edge_flat_rewrite;const1;taum;flat_term; taum_y1;taum_y2;taum_y1_y2; arclength_y1;arclength_y2;arc_hhn;asn797k;asnFnhk; lfun_y1;arclength_x_123; acs_sqrt_x1_d4;acs_sqrt_x2_d4; tauq;enclosed_rewrite; Nonlin_def.sol_euler_x_div_sqrtdelta; Nonlin_def.dih_x_div_sqrtdelta_posbranch; dih5_y;dih6_y; num1;Nonlin_def.dnum1; flat_term_x; eulerA_x; Functional_equation.nonf_gamma3_x; Functional_equation.nonf_gamma23_full8_x; Functional_equation.nonf_gamma23_keep135_x; Nonlin_def.gamma2_x_div_azim_v2; Functional_equation.nonf_gamma2_x1_div_a_v2; (* Added 2013-05-20 *) Nonlin_def.mu_y;Nonlin_def.delta_x1;Nonlin_def.taud; Functional_equation.nonf_ups_126; Functional_equation.nonf_gamma3f_x_div_sqrtdelta; ];; (* cfsqp definition macros expansion *) let macros = ref [Sphere.gamma4f];; let macro_remove thm = let _ = macros := filter (fun t -> not (t = thm)) !macros in ();; let macro_add thm = let _ = macro_remove thm in macros := !macros @ [thm];; let get_macro_expand() = (!macros);; macros := ( [gamma4f;gamma4fgcy;vol4f;y_of_x_e;vol_y_e;rad2_y_e; vol3f;vol3r;vol2f;delta4_y;delta4_squared_y;x1_delta_y; gamma3f;gamma23f; (* gamma23f_126_w1;gamma23f_red; *) gamma23f_red_03;gamma23f_126_03; GSYM quadratic_root_plus_curry;REAL_MUL_LZERO; REAL_MUL_RZERO;FST;SND;pathL;pathR;node2_y;node3_y; rhazim2;rhazim3;rhazim_x;rhazim2_x;rhazim3_x; (* functional code *) rotate2;rotate3;rotate4;rotate5;rotate6; uni;constant6;promote3_to_6;promote1_to_6; dummy6; mul6;add6;sub6;scalar6;compose6;I_DEF; functional_proj_x1;functional_proj_y1; functional_proj_x2;functional_proj_y2; functional_proj_x3;functional_proj_y3; functional_proj_x4;functional_proj_y4; functional_proj_x5;functional_proj_y5; functional_proj_x6;functional_proj_y6; Nonlin_def.sol_euler345_x_div_sqrtdelta; Nonlin_def.sol_euler156_x_div_sqrtdelta; Nonlin_def.sol_euler246_x_div_sqrtdelta; Nonlin_def.dih4_x_div_sqrtdelta_posbranch; Nonlin_def.ldih_x_div_sqrtdelta_posbranch; Nonlin_def.ldih2_x_div_sqrtdelta_posbranch; Nonlin_def.ldih2_x_div_sqrtdelta_posbranch; Nonlin_def.ldih3_x_div_sqrtdelta_posbranch; Nonlin_def.ldih5_x_div_sqrtdelta_posbranch; Nonlin_def.ldih6_x_div_sqrtdelta_posbranch; taum_x; edge_flat2_x; delta_126_x; delta_234_x; delta_135_x; (* may 2011 additions *) Nonlin_def.rhazim_x_div_sqrtdelta_posbranch; Nonlin_def.rhazim2_x_div_sqrtdelta_posbranch; Nonlin_def.rhazim3_x_div_sqrtdelta_posbranch; Nonlin_def.tau_residual_x; edge_flat_x; delta_sub1_x; (* 2012 *) (* may 2013 additions *) Nonlin_def.mud_135_x; Nonlin_def.mud_126_x;Nonlin_def.mud_234_x; Nonlin_def.mudLs_234_x;Nonlin_def.mudLs_135_x;Nonlin_def.mudLs_126_x; Nonlin_def.taud_x;Functional_equation.nonfunctional_mu6_x; Functional_equation.nonfunctional_taud_D1; Functional_equation.nonfunctional_taud_D2; Functional_equation.nonfunctional_edge2_126_x; Functional_equation.nonfunctional_edge2_135_x; Functional_equation.nonfunctional_edge2_234_x; Nonlin_def.flat_term2_126_x; Nonlin_def.flat_term2_135_x;Nonlin_def.flat_term2_234_x ] @ (!Ineq.dart_classes));; let prep_term t = let t' = REWRITE_CONV (get_macro_expand()) (strip_let_tm t) in let (a,b)= dest_eq (concl t') in b;; let cc_function t = let args xs = let ls = map (fun s -> "double "^s) xs in join_comma ls in let (lhs,rhs) = dest_eq (prep_term t) in let (f,xs) = strip_comb lhs in let ss = map c_string_of_term xs in let p = Printf.sprintf in let s = join_lines [ p"double %s(" (fst (dest_const f)); args ss; p") { \nreturn ( %s ); \n}\n\n" (c_string_of_term rhs); ] in s;; let dest_ineq ineq = let t = snd(strip_forall (prep_term (ineq))) in let (vs,i) = dest_comb t in let (_,vs) = dest_comb vs in let vs = dest_list vs in let vs = map (fun t -> let (a,b) = dest_pair t in (a,dest_pair b)) vs in let vs = map (fun (a,(b,c)) -> (a, b, c)) vs in (t,vs,disjuncts i);; let c_dest_ineq ineq = let cs = c_string_of_term in let (b,vs,i) = dest_ineq ineq in (cs b, map (fun (a,b,c) -> (cs a, cs b,cs c)) vs,map cs i);; (* generate c++ code of ineq *) let case p i j = Printf.sprintf "case %d: *ret = (%s) - (%s); break;" j (List.nth i j) p;; let vardecl y vs = let varname = map (fun (a,b,c) -> b) vs in let nvs = List.length vs in let v j = Printf.sprintf "double %s = %s[%d];" (List.nth varname j) y j in join_lines (map v (0-- (nvs-1)));; let bounds f vs = let lbs = map f vs in join_comma lbs;; let rec geteps = let getepsf = function Eps t -> t | _ -> 0.0 in function [] -> 0.0 | b::bs -> max(getepsf b) (geteps bs);; let (has_penalty,penalty) = let penalties iqd = filter (function Penalty _ -> true | _ -> false) iqd.tags in let hasp iqd = (List.length (penalties iqd) >0) in let onep iqd = if (hasp iqd) then hd(penalties iqd) else Penalty (0.0,0.0) in (hasp,onep);; let penalty_var iqd = let penalty_ub = function Penalty(a,_) -> string_of_float a in ["0.0","penalty",penalty_ub (penalty iqd)];; let penalty_wt iqd = if has_penalty iqd then match (penalty iqd) with Penalty(_,b) -> (string_of_float b)^" * penalty" else "0.0";; let rec cfsqp_branch = function | [] -> 0 | Cfsqp_branch i ::_ -> i | _::a -> cfsqp_branch a;; let move_first i ls = let (a,b::xs) = chop_list i ls in b::(a @ xs);; let cc_main = "\n\nint main(){ //Mathematica generated test data assert(near (pi(),4.0*atan(1.0))); assert(near (sqrt2(),1.41421356237309)); assert(near (sqrt8(),2.828427124746190)); assert(near (sol0(),0.5512855984325308)); assert(near (tau0(),1.54065864570856)); assert(near (acos(0.3),1.26610367277949)); assert(near(hminus(),1.2317544220903216)); assert(near(hplus(),1.3254)); assert(near(mm1(),1.012080868420655)); assert(near(mm2(),0.0254145072695089)); assert(near(real_pow(1.18,2.),1.3924)); assert(near(marchal_quartic(1.18),0.228828103048681825)); assert(near(lmfun(1.18),0.30769230769230793)); assert(near(lmfun(1.27),0.0)); assert(near(rad2_x(4.1,4.2,4.3,4.4,4.5,4.6),1.6333363881302794)); assert(near(dih_y(2.1,2.2,2.3,2.4,2.5,2.6),1.1884801338917963)); assert(near(sol_y(2.1,2.2,2.3,2.4,2.5,2.6), 0.7703577405137815)); assert(near(sol_y(2, 2, 2, 2.52, 3.91404, 3.464),4.560740765722419)); assert(near(taum(2.1,2.2,2.3,2.4,2.5,2.6),tau_m(2.1,2.2,2.3,2.4,2.5,2.6) )); assert(near(taum(2.1,2.2,2.3,2.4,2.5,2.6),tau_m_alt(2.1,2.2,2.3,2.4,2.5,2.6) )); assert(near(taum(2.1,2.2,2.3,2.4,2.5,2.6),0.4913685097602183)); assert(near(taum(2, 2, 2, 2.52, 3.91404, 3.464),4.009455167289888)); assert(near(ups_x(4.1,4.2,4.3), 52.88)); assert(near(eta_y(2.1,2.2,2.3), 1.272816758217772)); assert(near(beta_bump_force_y(2.1,2.2,2.3,2.4,2.5,2.6), -0.04734449962124398)); assert(near(beta_bump_force_y(2.5,2.05,2.1,2.6,2.15,2.2), beta_bumpA_y(2.5,2.05,2.1,2.6,2.15,2.2))); assert(near(atn2(1.2,1.3),atan(1.3/1.2))); assert(near(edge_flat(2.1,2.2,2.3,2.5,2.6),4.273045018670291)); assert(near(flat_term(2.1),-0.4452691371955056)); assert(near(enclosed(2.02,2.04,2.06,2.08,2.1,2.12,2.14,2.16,2.18), 3.426676872737882)); }\n\n";; let cc_code outs iqd = let (b,vs,i) = c_dest_ineq iqd.ineq in let vs = vs @ if (has_penalty iqd) then penalty_var iqd else [] in let branch = cfsqp_branch iqd.tags in let i = move_first branch i in let eps = geteps (iqd.tags) in let casep = if has_penalty iqd then "max(0.0,penalty)" else "0.0" in let nvs = List.length vs in let ni = List.length i in let y = "y_mangle__" in let p = Printf.sprintf in let s = join_lines ([ p"// This code is machine generated "; p"#include <iomanip.h>\n#include <iostream.h>\n#include <math.h>"; p"#include \"../Minimizer.h\"\n#include \"../numerical.h\""; p"#include <assert.h>"; p"class trialdata { public: trialdata(Minimizer M,char* s)"; p"{ M.coutReport(s); };};"; p"int trialcount = %d;\n" (!cfsqp_trialcount); join_lines(map cc_function (!autogen)); p"void c0(int numargs,int whichFn,double* %s, double* ret,void*) {" y; vardecl y vs ; p"switch(whichFn) {"; ] @ map (case casep i) (1-- (-1 + List.length i)) @ [ p"default: *ret = 0; break; }}\n\n"; p"void t0(int numargs,int whichFn,double* %s, double* ret,void*) { " y; vardecl y vs ; p"*ret = (%e) + (%s) + (%s);" eps (List.nth i 0) (penalty_wt iqd); p"}"; p"Minimizer m0() {"; p" double xmin[%d]= {" nvs;(bounds (function (a,b,c) -> a) vs); p "};\n double xmax[%d]= {" nvs; (bounds (function (a,b,c) -> c) vs); p "};\n Minimizer M(trialcount,%d,%d,xmin,xmax);" nvs (ni-1); p" M.func = t0;"; p" M.cFunc = c0;"; p" return M;"; p"}"; p "trialdata d0(m0(),\"%s\");\n\n" iqd.idv; p"int near(double x,double y)"; p" { double eps = 1.0e-8; return (mabs(x-y)<eps); }"; ]) in Printf.fprintf outs "%s %s" s cc_main;; let mk_cc tmpfile iqd = let outs = open_out tmpfile in let _ = cc_code outs iqd in close_out outs ;; let compile = let err = Filename.temp_file "cfsqp_err" ".txt" in fun () -> let e = Sys.command("cd "^flyspeck_dir^"/../cfsqp; make tmp/t.o >& "^err) in let _ = (e=0) or (Sys.command ("cat "^err); failwith "compiler error ") in ();; let execute_cfsqp = let cfsqp_out = Filename.temp_file "tmp_cfsqp" ".out" in let cfsqp_dir = flyspeck_dir^"/../cfsqp" in fun idq -> let _ = mk_cc (cfsqp_dir ^ "/tmp/t.cc") idq in let _ = try (compile()) with Failure s -> failwith (s^idq.idv) in let _ = (0= Sys.command(cfsqp_dir^"/tmp/t.o | tee "^cfsqp_out)) or failwith ("execution error "^idq.idv) in let s = process_to_string ("grep 'NEGATIVE' "^cfsqp_out) in let _ = (s="") or failwith ("NEGATIVE "^idq.idv) in ();; let execute_cfsqp_list xs = let fails = ref [] in let _ = for i=0 to (List.length xs - 1) do try (execute_cfsqp (List.nth xs i); Sys.command("date"); ()) with Failure s -> (fails := s :: (!fails)) done in fails;; (* ======================================== glpk generation ======================================== *) let yy6 = [`y1:real`;`y2:real`;`y3:real`;`y4:real`;`y5:real`;`y6:real`];; let yy9 = yy6 @ [`y7:real`;`y8:real`;`y9:real`];; let glpk_translate =ref [("dih_y","azim[i,j]");("dih2_y","azim2[i,j]");("dih3_y","azim3[i,j]"); ("sol_y","sol[j]"); ("taum","tau[j]");("tauq","tau[j]");("rhazim","rhazim[i,j]"); ("rhazim2","rhazim2[i,j]");("rhazim3","rhazim3[i,j]"); ("sqrt8","sqrt8")];; let reverse = let xs = [("y2","y3");("y5","y6");("rhazim2","rhazim3"); ("dih2_y","dih3_y");] in let f (a,b) = (b,a) in let ys = xs @ map f xs in fun s -> try (List.assoc s ys) with Not_found -> s;; let glpk_lookup rev s xs = let s' = if rev then reverse s else s in if (xs = yy6) or (xs = yy9) then try (List.assoc s' (!glpk_translate)) with Not_found -> failwith ("glpk_lookup translate" ^ s) else if xs = [] then try (List.assoc s' (!glpk_translate)) with Not_found -> (s'^"[i,j]") else failwith ("glpk_lookup unknown arg list:" ^ s);; let rec glpk_form rev t = let soh = glpk_form rev in if is_var t then glpk_lookup rev (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 ifix_swapped i = let [b;a] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in let _ = (is_const f) or failwith ("glpk constant expected: " ^ string_of_term f) in match fst (dest_const f) with | "real_gt" | "real_ge" | "real_sub" -> ifix "-" | "real_lt" | "real_le" -> ifix_swapped "-" | "real_add" -> ifix "+" | "real_mul" -> ifix "*" | "real_div" -> ifix "/" | "real_neg" -> let [a] = xs in paren("-" ^ soh a) | "real_of_num" -> let [a] = xs in soh a | "NUMERAL" -> let [_] = xs in string_of_num' (dest_numeral t) | "DECIMAL" -> string_of_num' (dest_decimal t) | s -> paren(glpk_lookup rev s xs) ;; let (counter,counter_reset) = let ineqcounter = ref 0 in let counter t = let u = !ineqcounter in let _ = ineqcounter := u+1 in u in let counter_reset _ = (ineqcounter := 0) in (counter,counter_reset);; let mk_glpk_ineq rev iqd = let ineq = iqd.ineq in let t = snd(strip_forall (ineq)) in let (vs,i) = dest_comb t in let (_,vs) = dest_comb vs in let (f,xs) = strip_comb vs in let (dart,_) = dest_const f in let i' = hd(disjuncts i) in let _ = (xs = yy6) or (xs = yy9) or (print_qterm vs; failwith "dart_class y1 ... y6 expected") in let p = Printf.sprintf in let s = p"ineq%d 'ID[%s]' \n { (i,j) in %s } : \n %s >= 0.0;\n\n" (counter()) iqd.idv dart (glpk_form rev i') in s;; let mk_glpk_ineq_id rev s = let iqd = Ineq.getexact s in mk_glpk_ineq rev (hd iqd);; let test_domain_symmetry idq = let ineq = idq.ineq in let dart = List.nth (snd(strip_comb (snd(strip_forall ineq)))) 0 in let dom = map(fun (a,(b,c)) -> (a,c)) (map (fun (a,b) -> (a,dest_pair b)) (map dest_pair (dest_list(snd(dest_eq( concl(REWRITE_CONV(!Ineq.dart_classes) dart))))))) in let nth = List.nth in ((nth dom 1 = nth dom 2) & (nth dom 4 = nth dom 5)) or failwith "domain asym";; let lpstring() = let _ = counter_reset() in let _ = map test_domain_symmetry (Ineq.getfield Lpsymmetry) in join_lines (("# File automatically generated from nonlinear inequality list "^ "via lpstring().\n\n") :: (map (mk_glpk_ineq false) (Ineq.getfield Lp)) @ ["# Symmetry section\n\n"] @ (map (mk_glpk_ineq true) (Ineq.getfield Lpsymmetry)));; (* ======================================== Objective Caml generation ======================================== *) let ocaml_string_of_term t = 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 = if is_var f then let fv = fst(dest_var f) in let _ = warn true ("variable function name: "^fv) in fv else if is_const f then fst (dest_const f) else failwith ("var or const expected: " ^ string_of_term f) in match fv with | "real_sub" -> ifix "-. " | "real_add" -> ifix "+." | "real_mul" -> ifix "*." | "real_div" -> ifix "/." | "real_lt" -> ifix "<" | "real_le" -> ifix "<=" | "real_gt" -> ifix ">" | "real_ge" -> ifix ">=" | "real_pow" -> ifix " ** " | "/\\" -> ifix "&&" | "\\/" -> ifix "or" | "real_neg" -> let [a] = xs in paren("-. " ^ soh a) | "acs" -> (try let [a] = xs in "(acos("^soh a^ "))" with Match_failure _ -> let _ = (xs=[]) or failwith "ocaml:acs" in paren "acos") | "real_of_num" -> let [a] = xs in soh a | "NUMERAL" -> let [_] = xs in string_of_num' (dest_numeral t) | "=" -> let [a;b] = xs in soh a ^ " = " ^ soh b | "," -> let [a;b] = xs in paren( soh a ^ "," ^ soh b) | "DECIMAL" -> string_of_num' (dest_decimal t) | "COND" -> let [a;b;c] = xs in paren("if "^( paren(soh a)) ^ " then " ^ (paren (soh b)) ^ " else " ^ (paren(soh c)) ) | "atn2" -> let [ab] = xs in let (a,b) = dest_pair ab in "atan2 " ^ paren(soh b) ^ " " ^ paren(soh a) ^ " " (* note reverse order atan2 in ocaml *) | "domain6" -> let [h;f;g] = xs in domain6 soh h f g | s -> " " ^ s ^ " " ^ join_space(map (paren o soh) xs) ^ " " and domain6 soh h f g = let (hv,hbody) = strip_abs h in let (f1,xs) = strip_comb f in let vs a = join_space (map (fst o dest_var) a) in let hbodys = soh hbody in let fs = fst(dest_const f1) in let gs = soh g in (Printf.sprintf " %s %s = \n let _ = ( %s ) or failwith \"domain6:%s\" in \n ( %s ) %s" fs (vs (xs @ hv)) hbodys fs gs (vs hv)) in try (soh t) with Failure s -> failwith (s^" ....... "^string_of_term t);; let ocaml_function t = "let " ^ ocaml_string_of_term t ^ ";;\n\n";; let ocaml_autogen = map (function b -> snd(strip_forall (concl (strip_let b)))) [sqrt2;sqrt8;delta_x;delta_y;delta_x4;delta_x6;ups_x;eta_x; eta_y;dih_x;dih_y;dih2_y;dih3_y;sol_x;sol_y;interp;ly;const1; rho;rhazim;lnazim;taum;arclength];; let ocaml_code = "(* code automatically generated from Parse_ineq.ocaml_code *)\n\n"^ "module Sphere_math = struct\n\n"^ "let sqrt = Pervasives.sqrt\n\n" ^ "let pi = 4.0 *. atan(1.0);;\n" ^ (join_lines (map ocaml_function ocaml_autogen)) ^ "end;;\n";; let sphere_ml = Filename.temp_file "sphere" ".ml";; output_filestring sphere_ml ocaml_code;; (* ======================================== LaTeX generation ======================================== *) let mk_texstring (tm,idv,s) = match tm with | Section -> "\\section{"^idv^" "^s^"}\n" | Comment -> "\\begin{remark}["^idv^"]\n"^s^"\n\\end{remark}\n" | Ineqdoc -> "\\begin{calculation}["^idv^"]\n"^s^"\n\\end{calculation}\n";; let texstring() = join_lines (map mk_texstring (List.rev (!Ineq.ineqdoc)));; (* output_filestring "/tmp/ineqdoc.tex" (texstring());; *) end;;