1 (* ========================================================================== *)
2 (* FLYSPECK - BOOK FORMALIZATION *)
4 (* Chapter: nonlinear inequalities *)
5 (* Author: Thomas Hales starting from Roland Zumkeller's ccform function *)
7 (* ========================================================================== *)
11 Use HOL Light specifications of functions and inequalities to
12 automatically generate code in other languages.
15 ** glpk for linear programming
16 ** Objective Caml export of functions
17 ** LaTeX documentation of inequalities.
19 C++ code generation for interval arithmetic is done
20 separately in optimize.hl.
21 (This file is independent from that one.)
24 Executing the cfsqp produces three output files:
26 tmp/t.cc tmp/t.o (in the cfsqp directory)
27 Use macro_add to add new function (that is expanded with rewrites)
28 Use autogen_add to add new function (automatic C code generation)
32 flyspeck_needs "general/flyspeck_lib.hl";;
33 flyspeck_needs "general/sphere.hl";;
34 flyspeck_needs "nonlinear/ineq.hl";;
35 flyspeck_needs "nonlinear/lemma.hl";;
38 module Parse_ineq = struct
41 open Nonlinear_lemma;;
42 open Functional_equation;;
44 let cfsqp_trialcount = ref 500;;
46 let dest_decimal = Flyspeck_lib.dest_decimal;;
48 let string_of_num' = Flyspeck_lib.string_of_num';;
50 let join_comma = Flyspeck_lib.join_comma;;
52 let join_lines = Flyspeck_lib.join_lines;;
54 let join_space = Flyspeck_lib.join_space;;
56 let paren s = "("^ s ^")";;
58 let nub = Flyspeck_lib.nub;;
60 (* moved to lemmas.hl.
61 let strip_let_tm t = snd(dest_eq(concl(REDEPTH_CONV let_CONV t)));;
63 let strip_let t = REWRITE_RULE[REDEPTH_CONV let_CONV (concl t )] t;;
66 (* from HOL Light lib.ml *)
68 let rec (--) = fun m n -> if m > n then [] else m::((m + 1) -- n);;
71 (* renamed from output_string to avoid Pervasives module name clash *)
73 let output_filestring = Flyspeck_lib.output_filestring;;
76 (* ========================================
78 ======================================== *)
80 let c_string_of_term t =
82 if is_var t then fst (dest_var t)
84 let (f,xs) = strip_comb t in
85 let _ = (is_const f) or
86 failwith ("Non-const function name: " ^ string_of_term f) in
88 let [a;b] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in
90 let [b;a] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in
92 match fst (dest_const f) with
93 | "real_gt" | "real_ge" | "real_sub" -> ifix "-"
94 | "real_lt" | "real_le" -> ifix_swapped "-"
95 | "real_add" -> ifix "+"
96 | "real_mul" -> ifix "*"
97 | "real_div" -> ifix "/"
99 | "real_neg" -> let [a] = xs in paren("-" ^ soh a)
100 | "acs" -> let [a] = xs in paren ("acos" ^ (paren (soh a)))
101 | "real_of_num" -> let [a] = xs in soh a
102 | "NUMERAL" -> let [_] = xs in string_of_num' (dest_numeral t)
103 | "<" -> let [a;b] = xs in paren(soh a ^ " < " ^ soh b)
104 | ">" -> let [a;b] = xs in paren(soh a ^ " > " ^ soh b)
105 | "+" -> let [a;b] = xs in paren(soh a ^ " + " ^ soh b)
106 | "*" -> let [a;b] = xs in paren(soh a ^ " * " ^ soh b)
107 | "DECIMAL" -> string_of_num' (dest_decimal t)
110 paren(soh a ^ " ? " ^ soh b ^ " : " ^ soh c)
113 let (a,b) = dest_pair ab in
114 paren("atn2( " ^ soh a ^ "," ^ soh b ^ ")")
115 | s -> paren(s ^ "(" ^ join_comma(map soh xs) ^ ")") in
116 (* c_string_of_term: *)
119 with Failure s -> failwith (s^" ....... "^string_of_term t);;
121 let constant_names i =
122 let rec cn b =function
123 | Const (s,_) -> s::b
124 | Comb (s,t) -> (cn [] s) @ (cn[] t) @ b
125 | Abs(x,t) -> (cn b t)
127 nub (sort (<) (cn [] i ));;
130 (* Rewrite unusual terms to prepare for C++ conversion *)
132 (* function calls are dealt with three different ways:
133 - native_c: use the native C code definition of the function.
134 - autogen: automatically generate a C style function
135 - macro_expand: use rewrites to eliminate the function.
138 (* Native is the default case. There is no need to list them, except
142 ",";"BIT0";"BIT1";"CONS";"DECIMAL"; "NIL"; "NUMERAL"; "_0"; "acs";
143 "ineq"; "pi"; "adodec"; "bdodec";"real_add"; "real_div";"real_pow";"cos";
144 "real_ge"; "real_mul"; "real_of_num"; "real_sub"; "machine_eps";
146 "delta_x";"sol_y";"dih_y";"rhazim";
147 "lmfun";"lnazim";"hminus";
148 "wtcount3_y";"wtcount6_y";"beta_bumpA_y";"matan";"sqp";"sqn";
150 (* "taum_m_diff_quotient";"taum_m_diff_quotient2"; *)
157 let autogen = ref[];;
159 let prep_autogen = (function b -> snd(strip_forall (concl (strip_let b))));;
161 let autogen_remove thm =
162 let thm' = prep_autogen thm in
163 autogen := filter (fun t -> not (t = thm')) !autogen;;
165 let autogen_add thm =
166 let thm' = prep_autogen thm in
167 let _ = autogen_remove thm in (* duplicates create C compile error *)
168 autogen := !autogen @ [thm'];;
170 (* cfsqp autogeneration *)
172 autogen := map prep_autogen
173 [sol0;tau0;hplus;mm1;mm2;vol_x;sqrt8;sqrt2;sqrt3;rho_x;
174 rad2_x;ups_x;eta_x;eta_y;volR;
175 norm2hh;arclength;regular_spherical_polygon_area;
177 a_spine5;b_spine5;beta_bump_lb;marchal_quartic;vol2r;
178 tame_table_d;delta_x4;dih_x_alt;sol_x;delta4_squared_x;x1_delta_x;
179 quad_root_plus_curry;
180 edge_flat_rewrite;const1;taum;flat_term;
181 taum_y1;taum_y2;taum_y1_y2;
182 arclength_y1;arclength_y2;arc_hhn;asn797k;asnFnhk;
183 lfun_y1;arclength_x_123;
185 acs_sqrt_x1_d4;acs_sqrt_x2_d4;
186 tauq;enclosed_rewrite;
187 Nonlin_def.sol_euler_x_div_sqrtdelta;
188 Nonlin_def.dih_x_div_sqrtdelta_posbranch;
190 num1;Nonlin_def.dnum1;
195 Functional_equation.nonf_gamma3_x;
196 Functional_equation.nonf_gamma23_full8_x;
197 Functional_equation.nonf_gamma23_keep135_x;
198 Nonlin_def.gamma2_x_div_azim_v2;
199 Functional_equation.nonf_gamma2_x1_div_a_v2;
200 (* Added 2013-05-20 *)
201 Nonlin_def.mu_y;Nonlin_def.delta_x1;Nonlin_def.taud;
202 Functional_equation.nonf_ups_126;
203 Functional_equation.nonf_gamma3f_x_div_sqrtdelta;
206 (* cfsqp definition macros expansion *)
208 let macros = ref [Sphere.gamma4f];;
210 let macro_remove thm =
211 let _ = macros := filter (fun t -> not (t = thm)) !macros in
215 let _ = macro_remove thm in
216 macros := !macros @ [thm];;
218 let get_macro_expand() = (!macros);;
221 [gamma4f;gamma4fgcy;vol4f;y_of_x_e;vol_y_e;rad2_y_e;
222 vol3f;vol3r;vol2f;delta4_y;delta4_squared_y;x1_delta_y;
223 gamma3f;gamma23f; (* gamma23f_126_w1;gamma23f_red; *)
224 gamma23f_red_03;gamma23f_126_03;
225 GSYM quadratic_root_plus_curry;REAL_MUL_LZERO;
226 REAL_MUL_RZERO;FST;SND;pathL;pathR;node2_y;node3_y;
227 rhazim2;rhazim3;rhazim_x;rhazim2_x;rhazim3_x;
228 (* functional code *)
229 rotate2;rotate3;rotate4;rotate5;rotate6;
230 uni;constant6;promote3_to_6;promote1_to_6;
232 mul6;add6;sub6;scalar6;compose6;I_DEF;
234 functional_proj_x1;functional_proj_y1;
235 functional_proj_x2;functional_proj_y2;
236 functional_proj_x3;functional_proj_y3;
237 functional_proj_x4;functional_proj_y4;
238 functional_proj_x5;functional_proj_y5;
239 functional_proj_x6;functional_proj_y6;
240 Nonlin_def.sol_euler345_x_div_sqrtdelta;
241 Nonlin_def.sol_euler156_x_div_sqrtdelta;
242 Nonlin_def.sol_euler246_x_div_sqrtdelta;
245 Nonlin_def.dih4_x_div_sqrtdelta_posbranch;
246 Nonlin_def.ldih_x_div_sqrtdelta_posbranch;
247 Nonlin_def.ldih2_x_div_sqrtdelta_posbranch;
248 Nonlin_def.ldih2_x_div_sqrtdelta_posbranch;
249 Nonlin_def.ldih3_x_div_sqrtdelta_posbranch;
250 Nonlin_def.ldih5_x_div_sqrtdelta_posbranch;
251 Nonlin_def.ldih6_x_div_sqrtdelta_posbranch;
259 (* may 2011 additions *)
260 Nonlin_def.rhazim_x_div_sqrtdelta_posbranch;
261 Nonlin_def.rhazim2_x_div_sqrtdelta_posbranch;
262 Nonlin_def.rhazim3_x_div_sqrtdelta_posbranch;
263 Nonlin_def.tau_residual_x;
269 (* may 2013 additions *)
270 Nonlin_def.mud_135_x;
271 Nonlin_def.mud_126_x;Nonlin_def.mud_234_x;
272 Nonlin_def.mudLs_234_x;Nonlin_def.mudLs_135_x;Nonlin_def.mudLs_126_x;
273 Nonlin_def.taud_x;Functional_equation.nonfunctional_mu6_x;
274 Functional_equation.nonfunctional_taud_D1;
275 Functional_equation.nonfunctional_taud_D2;
276 Functional_equation.nonfunctional_edge2_126_x;
277 Functional_equation.nonfunctional_edge2_135_x;
278 Functional_equation.nonfunctional_edge2_234_x;
279 Nonlin_def.flat_term2_126_x;
280 Nonlin_def.flat_term2_135_x;Nonlin_def.flat_term2_234_x
281 ] @ (!Ineq.dart_classes));;
284 let t' = REWRITE_CONV (get_macro_expand()) (strip_let_tm t) in
285 let (a,b)= dest_eq (concl t') in
290 let ls = map (fun s -> "double "^s) xs in join_comma ls in
291 let (lhs,rhs) = dest_eq (prep_term t) in
292 let (f,xs) = strip_comb lhs in
293 let ss = map c_string_of_term xs in
294 let p = Printf.sprintf in
296 p"double %s(" (fst (dest_const f)); args ss;
297 p") { \nreturn ( %s ); \n}\n\n" (c_string_of_term rhs);
302 let t = snd(strip_forall (prep_term (ineq))) in
303 let (vs,i) = dest_comb t in
304 let (_,vs) = dest_comb vs in
305 let vs = dest_list vs in
306 let vs = map (fun t -> let (a,b) = dest_pair t in (a,dest_pair b)) vs in
307 let vs = map (fun (a,(b,c)) -> (a, b, c)) vs in
310 let c_dest_ineq ineq =
311 let cs = c_string_of_term in
312 let (b,vs,i) = dest_ineq ineq in
313 (cs b, map (fun (a,b,c) -> (cs a, cs b,cs c)) vs,map cs i);;
315 (* generate c++ code of ineq *)
318 Printf.sprintf "case %d: *ret = (%s) - (%s); break;" j (List.nth i j) p;;
321 let varname = map (fun (a,b,c) -> b) vs in
322 let nvs = List.length vs in
323 let v j = Printf.sprintf "double %s = %s[%d];" (List.nth varname j) y j in
324 join_lines (map v (0-- (nvs-1)));;
327 let lbs = map f vs in
331 let getepsf = function
336 | b::bs -> max(getepsf b) (geteps bs);;
338 let (has_penalty,penalty) =
340 filter (function Penalty _ -> true | _ -> false) iqd.tags in
341 let hasp iqd = (List.length (penalties iqd) >0) in
342 let onep iqd = if (hasp iqd) then hd(penalties iqd) else Penalty (0.0,0.0) in
345 let penalty_var iqd =
346 let penalty_ub = function Penalty(a,_) -> string_of_float a in
347 ["0.0","penalty",penalty_ub (penalty iqd)];;
349 let penalty_wt iqd = if has_penalty iqd then
350 match (penalty iqd) with
351 Penalty(_,b) -> (string_of_float b)^" * penalty"
354 let rec cfsqp_branch = function
356 | Cfsqp_branch i ::_ -> i
357 | _::a -> cfsqp_branch a;;
359 let move_first i ls =
360 let (a,b::xs) = chop_list i ls in
365 //Mathematica generated test data
366 assert(near (pi(),4.0*atan(1.0)));
367 assert(near (sqrt2(),1.41421356237309));
368 assert(near (sqrt8(),2.828427124746190));
369 assert(near (sol0(),0.5512855984325308));
370 assert(near (tau0(),1.54065864570856));
371 assert(near (acos(0.3),1.26610367277949));
372 assert(near(hminus(),1.2317544220903216));
373 assert(near(hplus(),1.3254));
374 assert(near(mm1(),1.012080868420655));
375 assert(near(mm2(),0.0254145072695089));
376 assert(near(real_pow(1.18,2.),1.3924));
377 assert(near(marchal_quartic(1.18),0.228828103048681825));
378 assert(near(lmfun(1.18),0.30769230769230793));
379 assert(near(lmfun(1.27),0.0));
380 assert(near(rad2_x(4.1,4.2,4.3,4.4,4.5,4.6),1.6333363881302794));
381 assert(near(dih_y(2.1,2.2,2.3,2.4,2.5,2.6),1.1884801338917963));
382 assert(near(sol_y(2.1,2.2,2.3,2.4,2.5,2.6), 0.7703577405137815));
383 assert(near(sol_y(2, 2, 2, 2.52, 3.91404, 3.464),4.560740765722419));
384 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) ));
385 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) ));
386 assert(near(taum(2.1,2.2,2.3,2.4,2.5,2.6),0.4913685097602183));
387 assert(near(taum(2, 2, 2, 2.52, 3.91404, 3.464),4.009455167289888));
388 assert(near(ups_x(4.1,4.2,4.3), 52.88));
389 assert(near(eta_y(2.1,2.2,2.3), 1.272816758217772));
390 assert(near(beta_bump_force_y(2.1,2.2,2.3,2.4,2.5,2.6),
391 -0.04734449962124398));
392 assert(near(beta_bump_force_y(2.5,2.05,2.1,2.6,2.15,2.2),
393 beta_bumpA_y(2.5,2.05,2.1,2.6,2.15,2.2)));
394 assert(near(atn2(1.2,1.3),atan(1.3/1.2)));
395 assert(near(edge_flat(2.1,2.2,2.3,2.5,2.6),4.273045018670291));
396 assert(near(flat_term(2.1),-0.4452691371955056));
397 assert(near(enclosed(2.02,2.04,2.06,2.08,2.1,2.12,2.14,2.16,2.18),
401 let cc_code outs iqd =
402 let (b,vs,i) = c_dest_ineq iqd.ineq in
403 let vs = vs @ if (has_penalty iqd) then penalty_var iqd else [] in
404 let branch = cfsqp_branch iqd.tags in
405 let i = move_first branch i in
406 let eps = geteps (iqd.tags) in
407 let casep = if has_penalty iqd then "max(0.0,penalty)" else "0.0" in
408 let nvs = List.length vs in
409 let ni = List.length i in
410 let y = "y_mangle__" in
411 let p = Printf.sprintf in
412 let s = join_lines ([
413 p"// This code is machine generated ";
414 p"#include <iomanip.h>\n#include <iostream.h>\n#include <math.h>";
415 p"#include \"../Minimizer.h\"\n#include \"../numerical.h\"";
416 p"#include <assert.h>";
417 p"class trialdata { public: trialdata(Minimizer M,char* s)";
418 p"{ M.coutReport(s); };};";
419 p"int trialcount = %d;\n" (!cfsqp_trialcount);
420 join_lines(map cc_function (!autogen));
421 p"void c0(int numargs,int whichFn,double* %s, double* ret,void*) {" y;
423 p"switch(whichFn) {";
424 ] @ map (case casep i) (1-- (-1 + List.length i)) @ [
425 p"default: *ret = 0; break; }}\n\n";
426 p"void t0(int numargs,int whichFn,double* %s, double* ret,void*) { " y;
428 p"*ret = (%e) + (%s) + (%s);" eps (List.nth i 0) (penalty_wt iqd);
431 p" double xmin[%d]= {" nvs;(bounds (function (a,b,c) -> a) vs);
432 p "};\n double xmax[%d]= {" nvs; (bounds (function (a,b,c) -> c) vs);
433 p "};\n Minimizer M(trialcount,%d,%d,xmin,xmax);" nvs (ni-1);
438 p "trialdata d0(m0(),\"%s\");\n\n" iqd.idv;
439 p"int near(double x,double y)";
440 p" { double eps = 1.0e-8; return (mabs(x-y)<eps); }";
442 Printf.fprintf outs "%s %s" s cc_main;;
444 let mk_cc tmpfile iqd =
445 let outs = open_out tmpfile in
446 let _ = cc_code outs iqd in
450 let err = Filename.temp_file "cfsqp_err" ".txt" in
452 let e = Sys.command("cd "^flyspeck_dir^"/../cfsqp; make tmp/t.o >& "^err) in
453 let _ = (e=0) or (Sys.command ("cat "^err); failwith "compiler error ") in
457 let cfsqp_out = Filename.temp_file "tmp_cfsqp" ".out" in
458 let cfsqp_dir = flyspeck_dir^"/../cfsqp" in
460 let _ = mk_cc (cfsqp_dir ^ "/tmp/t.cc") idq in
461 let _ = try (compile()) with Failure s -> failwith (s^idq.idv) in
462 let _ = (0= Sys.command(cfsqp_dir^"/tmp/t.o | tee "^cfsqp_out)) or
463 failwith ("execution error "^idq.idv) in
464 let s = process_to_string ("grep 'NEGATIVE' "^cfsqp_out) in
465 let _ = (s="") or failwith ("NEGATIVE "^idq.idv) in
468 let execute_cfsqp_list xs =
469 let fails = ref [] in
470 let _ = for i=0 to (List.length xs - 1)
472 try (execute_cfsqp (List.nth xs i); Sys.command("date"); ())
473 with Failure s -> (fails := s :: (!fails)) done in
477 (* ========================================
480 ======================================== *)
483 let yy6 = [`y1:real`;`y2:real`;`y3:real`;`y4:real`;`y5:real`;`y6:real`];;
484 let yy9 = yy6 @ [`y7:real`;`y8:real`;`y9:real`];;
486 let glpk_translate =ref
487 [("dih_y","azim[i,j]");("dih2_y","azim2[i,j]");("dih3_y","azim3[i,j]");
489 ("taum","tau[j]");("tauq","tau[j]");("rhazim","rhazim[i,j]");
490 ("rhazim2","rhazim2[i,j]");("rhazim3","rhazim3[i,j]");
494 let xs = [("y2","y3");("y5","y6");("rhazim2","rhazim3");
495 ("dih2_y","dih3_y");] in
496 let f (a,b) = (b,a) in
497 let ys = xs @ map f xs in
498 fun s -> try (List.assoc s ys) with Not_found -> s;;
500 let glpk_lookup rev s xs =
501 let s' = if rev then reverse s else s in
502 if (xs = yy6) or (xs = yy9)
505 (List.assoc s' (!glpk_translate))
506 with Not_found -> failwith ("glpk_lookup translate" ^ s)
510 (List.assoc s' (!glpk_translate))
511 with Not_found -> (s'^"[i,j]")
512 else failwith ("glpk_lookup unknown arg list:" ^ s);;
514 let rec glpk_form rev t =
515 let soh = glpk_form rev in
516 if is_var t then glpk_lookup rev (fst (dest_var t)) [] else
517 let (f,xs) = strip_comb t in
518 let ifix i = let [a;b] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in
520 let [b;a] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in
521 let _ = (is_const f) or
522 failwith ("glpk constant expected: " ^ string_of_term f) in
523 match fst (dest_const f) with
524 | "real_gt" | "real_ge" | "real_sub" -> ifix "-"
525 | "real_lt" | "real_le" -> ifix_swapped "-"
526 | "real_add" -> ifix "+"
527 | "real_mul" -> ifix "*"
528 | "real_div" -> ifix "/"
529 | "real_neg" -> let [a] = xs in paren("-" ^ soh a)
530 | "real_of_num" -> let [a] = xs in soh a
531 | "NUMERAL" -> let [_] = xs in string_of_num' (dest_numeral t)
532 | "DECIMAL" -> string_of_num' (dest_decimal t)
533 | s -> paren(glpk_lookup rev s xs) ;;
535 let (counter,counter_reset) =
536 let ineqcounter = ref 0 in
538 let u = !ineqcounter in
539 let _ = ineqcounter := u+1 in
541 let counter_reset _ = (ineqcounter := 0) in
542 (counter,counter_reset);;
544 let mk_glpk_ineq rev iqd =
545 let ineq = iqd.ineq in
546 let t = snd(strip_forall (ineq)) in
547 let (vs,i) = dest_comb t in
548 let (_,vs) = dest_comb vs in
549 let (f,xs) = strip_comb vs in
550 let (dart,_) = dest_const f in
551 let i' = hd(disjuncts i) in
552 let _ = (xs = yy6) or (xs = yy9) or
553 (print_qterm vs; failwith "dart_class y1 ... y6 expected") in
554 let p = Printf.sprintf in
555 let s = p"ineq%d 'ID[%s]' \n { (i,j) in %s } : \n %s >= 0.0;\n\n"
556 (counter()) iqd.idv dart (glpk_form rev i') in
559 let mk_glpk_ineq_id rev s =
560 let iqd = Ineq.getexact s in mk_glpk_ineq rev (hd iqd);;
562 let test_domain_symmetry idq =
563 let ineq = idq.ineq in
564 let dart = List.nth (snd(strip_comb (snd(strip_forall ineq)))) 0 in
565 let dom = map(fun (a,(b,c)) -> (a,c)) (map (fun (a,b) -> (a,dest_pair b))
567 (dest_list(snd(dest_eq(
568 concl(REWRITE_CONV(!Ineq.dart_classes) dart))))))) in
569 let nth = List.nth in
570 ((nth dom 1 = nth dom 2) & (nth dom 4 = nth dom 5)) or
571 failwith "domain asym";;
574 let _ = counter_reset() in
575 let _ = map test_domain_symmetry (Ineq.getfield Lpsymmetry) in
577 (("# File automatically generated from nonlinear inequality list "^
578 "via lpstring().\n\n") ::
579 (map (mk_glpk_ineq false) (Ineq.getfield Lp)) @
580 ["# Symmetry section\n\n"] @
581 (map (mk_glpk_ineq true) (Ineq.getfield Lpsymmetry)));;
585 (* ========================================
587 Objective Caml generation
588 ======================================== *)
591 let ocaml_string_of_term t =
593 if is_var t then fst (dest_var t) else
594 let (f,xs) = strip_comb t in
595 let ifix i = let [a;b] = xs in paren(soh a ^ " " ^ i ^ " " ^ soh b) in
599 let fv = fst(dest_var f) in
600 let _ = warn true ("variable function name: "^fv) in
602 else if is_const f then fst (dest_const f)
604 failwith ("var or const expected: " ^ string_of_term f) in
606 | "real_sub" -> ifix "-. "
607 | "real_add" -> ifix "+."
608 | "real_mul" -> ifix "*."
609 | "real_div" -> ifix "/."
610 | "real_lt" -> ifix "<"
611 | "real_le" -> ifix "<="
612 | "real_gt" -> ifix ">"
613 | "real_ge" -> ifix ">="
614 | "real_pow" -> ifix " ** "
617 | "real_neg" -> let [a] = xs in paren("-. " ^ soh a)
620 let [a] = xs in "(acos("^soh a^ "))"
621 with Match_failure _ ->
622 let _ = (xs=[]) or failwith "ocaml:acs" in
624 | "real_of_num" -> let [a] = xs in soh a
625 | "NUMERAL" -> let [_] = xs in string_of_num' (dest_numeral t)
626 | "=" -> let [a;b] = xs in soh a ^ " = " ^ soh b
627 | "," -> let [a;b] = xs in paren( soh a ^ "," ^ soh b)
628 | "DECIMAL" -> string_of_num' (dest_decimal t)
631 paren("if "^( paren(soh a)) ^
632 " then " ^ (paren (soh b)) ^
633 " else " ^ (paren(soh c)) )
634 | "atn2" -> let [ab] = xs in let (a,b) = dest_pair ab in
635 "atan2 " ^ paren(soh b) ^ " " ^ paren(soh a) ^ " "
636 (* note reverse order atan2 in ocaml *)
637 | "domain6" -> let [h;f;g] = xs in domain6 soh h f g
638 | s -> " " ^ s ^ " " ^ join_space(map (paren o soh) xs) ^ " "
639 and domain6 soh h f g =
640 let (hv,hbody) = strip_abs h in
641 let (f1,xs) = strip_comb f in
642 let vs a = join_space (map (fst o dest_var) a) in
643 let hbodys = soh hbody in
644 let fs = fst(dest_const f1) in
647 " %s %s = \n let _ = ( %s ) or failwith \"domain6:%s\" in \n
648 ( %s ) %s" fs (vs (xs @ hv)) hbodys fs gs (vs hv)) in
651 with Failure s -> failwith (s^" ....... "^string_of_term t);;
653 let ocaml_function t =
654 "let " ^ ocaml_string_of_term t ^ ";;\n\n";;
656 let ocaml_autogen = map
657 (function b -> snd(strip_forall (concl (strip_let b))))
658 [sqrt2;sqrt8;delta_x;delta_y;delta_x4;delta_x6;ups_x;eta_x;
659 eta_y;dih_x;dih_y;dih2_y;dih3_y;sol_x;sol_y;interp;ly;const1;
660 rho;rhazim;lnazim;taum;arclength];;
663 "(* code automatically generated from Parse_ineq.ocaml_code *)\n\n"^
664 "module Sphere_math = struct\n\n"^
665 "let sqrt = Pervasives.sqrt\n\n" ^
666 "let pi = 4.0 *. atan(1.0);;\n" ^
667 (join_lines (map ocaml_function ocaml_autogen)) ^
670 let sphere_ml = Filename.temp_file "sphere" ".ml";;
672 output_filestring sphere_ml ocaml_code;;
674 (* ========================================
677 ======================================== *)
679 let mk_texstring (tm,idv,s) = match tm with
680 | Section -> "\\section{"^idv^" "^s^"}\n"
681 | Comment -> "\\begin{remark}["^idv^"]\n"^s^"\n\\end{remark}\n"
682 | Ineqdoc -> "\\begin{calculation}["^idv^"]\n"^s^"\n\\end{calculation}\n";;
684 let texstring() = join_lines (map mk_texstring (List.rev (!Ineq.ineqdoc)));;
687 output_filestring "/tmp/ineqdoc.tex" (texstring());;