(* ========================================================================== *)
(* FLYSPECK - CODE FORMALIZATION                                              *)
(*                                                                            *)
(* Chapter: Linear Programming Inequalities                                          *)
(* Author: Thomas C. Hales                                                    *)
(* Date: 2010-08-01                                                           *)
(* ========================================================================== *)


(* Generate new linear inequalities that are needed for linear
   programs.  This file is part of the scaffolding of the project.  It
   was used extensively to generate new inequalities that have been used
   in the linear programming part of the proof.  These inequalities have
   all been added to ineq.hl.

   This file has served its purpose and is no longer needed.

   Mathematica and Cfsqp both need to be installed before this code can
   be executed.  The mathematica runs are generated with the script found
   in the file whose pathname is given by the string math_initf.

  There is also tight coordinate between this file and the linear programming
   directory glpk/tame_archive/  

   WARNING: For the functions that write external files and reread them into a
   reference, it seems that it is necessary to open this module for it to
   function properly.
*)


(*

  There are several steps required to create an inequality and rerun
  linear programs.  This file automates these steps.

  0/- Analyze output to find a triangle that is bad with
  sorted_azim_weighted_diff darts_of_std_tri amx;; 
  1/- Mathematica.  holineq[Dihedral,{2,2,2,2,2,2},{2.52,2.25,2.52,2.52,2.52,2.52}].
  2/- save, strip "\ " at the end of lines.
  3/- run Parse_ineq.execute_cfsqp new_ineq to check if it seems to be true.
  If not, edit until it is correct.
  4/- change the domain info to something that is recognized by glpk model.
  5/- add new_ineq to put in archive.
  6/- Parse_ineq.lp_string()  to generate model body.mod.
  7/- Save body.mod in directory: glpk/tame_archive.
  8/- Lpproc.make_model() to make the new model.
  9/- Rerun the linear programs.

*)

(* Interaction with inequality generation. Mathematica is needed for
    the next bit.  *)




flyspeck_needs "nonlinear/ineq.hl";;

module Temp_ineq = struct


  let all_forall = Sphere.all_forall;;

let junkval =  { 
 idv = "junk";
 doc="junk";
 tags=[];
 ineq = 
 all_forall `ineq [(&1,y,&2)] (y > &0)`;
 };;

(* ========================================================================== *)
(* Mathematica section. *)
(* ========================================================================== *)

let mathfile = "/Applications/Mathematica\ 5.2.app/Contents/MacOS/MathKernel";;

let math_initf= "/Users/thomashales/Desktop/googlecode/flyspeck/mathematica/auto_mkineq.m";;

let mathtemp = "/tmp/mathtemp4.hl";; (* hardwired into mathematica code *)

let command_string fn lb ub = 
(mathfile^" -run \"<< "^math_initf^ ";\n runQuit["^fn^","^lb^","^ub^"];\"");;

let command_string_p fn p lb ub = 
(mathfile^" -run \"<< "^math_initf^ ";\n runQuitp["^fn^","^p^","^lb^","^ub^"];\"");;

(* ========================================================================== *)
(* cfsqp and ineq creation section.  The mathematica code produces a
   guess of an inequality (that is often inaccurate).  It is run to cfsqp
   to correct the guess, then packaged into an ineq.  *)
(* ========================================================================== *)


 let cfsqp_margin idq = 
  let cfsqp_dir = flyspeck_dir^"/../cfsqp" in
  let _ =  Parse_ineq.mk_cc (cfsqp_dir ^ "/tmp/t.cc") idq in
  let _ = Parse_ineq.compile() in 
  let _ = (0=  Sys.command(cfsqp_dir^"/tmp/t.o > /tmp/cfsqp_out.txt")) or failwith "execution error" in
  let s2 =  process_to_string("grep 'constrained min:' /tmp/cfsqp_out.txt | sed 's/^constrained min://g' | tr -d '\n'") in  float_of_string s2;;

let padded_decimal_of_cfsqp idq = (* add padding to make nonlinear verifications easier *)
   let r =  cfsqp_margin idq in
     let a = if r < 0.001 then 0.001 -. r else 0.0 in
     let b = int_of_float (Pervasives.ceil (10000.0 *. a)) in
     mk_binop `DECIMAL` (mk_numeral (Int b)) (mk_numeral (Int 10000));;

let add_decimal ineq a =
  let (quant,raw) = strip_forall ineq in
  let (dom,gt) = dest_binop `ineq` raw in
  let (lhs,rhs) = dest_binop `real_gt` gt in
  let lhs' = mk_binop `real_add` lhs a in
  let gt' = mk_binop `real_gt` lhs' rhs in
  let raw' = mk_binop `ineq` dom gt' in
  let ineq' = list_mk_forall (quant,raw') in
   ineq';;

let sqrt8_sqrt2 = 
prove_by_refinement( `sqrt (&8) = &2 * sqrt2`,
(* {{{ proof *) [ SIMP_TAC[Sphere.sqrt2;SQRT_MUL; REAL_ARITH `&8 = &4 * &2 /\ &0 <= &2 /\ &0 <= &4`;]; REWRITE_TAC[REAL_ARITH `&4 = &2 pow 2 /\ abs(&2) = &2`;POW_2_SQRT_ABS]; ]);;
(* }}} *) let constant_fix = [sqrt8_sqrt2;Sphere.h0;Sphere.sqrt2;Sphere.sqrt8; REAL_ARITH `#2 = &2 /\ #2.0 = &2 /\ &2 * #1.26 = #2.52 /\ #2.00 = &2 `];; (* problem: dart_std3 and dart_std3_big have the same "domain". *) let reduced_dart_classes() = search_thml (term_match []) [omit `dart_std3_big`] (map (fun t-> ("",t)) (!Ineq.dart_classes));; let dart_class_rew() = map (REWRITE_RULE constant_fix) (map (GSYM o snd ) (reduced_dart_classes()));; let convert_domain ineq = snd (dest_eq (concl (REWRITE_CONV ( constant_fix @ (dart_class_rew()) ) ineq)));; let adjust = let zero = `&0` in fun s idq -> let a = padded_decimal_of_cfsqp idq in if (a = zero) then idq else { idv = idq.idv; doc = idq.doc ^ s^ "\n The inequality has been fitted to cfsqp margins."; tags = idq.tags; ineq = convert_domain(add_decimal idq.ineq a); };; (* By loading the file mathtemp, the value of the reference tempval is changed to the output of the mathematica run *) let tempval = ref junkval;; let generate_ineq_datum = fun fname slb sub -> let example = command_string fname slb sub in let _ = Sys.command(example) in let _ = loadt mathtemp in adjust ("\n Generated by generate_ineq_datum with input "^ fname ^" "^slb^" "^sub^".") (!tempval);; let generate_ineq_datum_p = fun fname sp slb sub -> let example = command_string_p fname sp slb sub in let _ = Sys.command(example) in let _ = loadt mathtemp in adjust ("\n Generated by generate_ineq_datum_p with input "^ fname ^" "^sp^" "^slb^" "^sub^".") (!tempval);; (* ========================================================================== *) (* Ocaml function section. *) (* ========================================================================== *) (* This is a quick hack that converts an Hol-light inequality (>) into a function that gives the difference between the right and left hand sides of an ineq LHS > RHS for given values y1..y6. It generates the code as a string, writes it to an external file, then reads it back into the reference tempfn. It assumes that the inequality has this particular form (six free variables named y1..y6. *) let ocaml_funstring_of_ineq iqd = let t = snd(strip_forall (Parse_ineq.prep_term (iqd.ineq))) in let (_,tm) = dest_comb t in let (lhs,rhs) = dest_binop `real_gt` tm in let olhs = Parse_ineq.ocaml_string_of_term lhs in let orhs = Parse_ineq.ocaml_string_of_term rhs in "(fun y1 y2 y3 y4 y5 y6 -> " ^ olhs ^ " -. " ^ orhs ^ ");;";; let tempfn = ref (fun (y1:float) (y2:float) (y3:float) (y4:float) (y5:float) (y6:float) -> 0.0);; let ocaml_eval = let tempfile = Filename.temp_file "ocaml_eval_" ".ml" in fun iqd -> let _ = Parse_ineq.output_filestring tempfile ("tempfn := " ^ ocaml_funstring_of_ineq iqd) in let _ = loadt tempfile in !tempfn;; end;;