src/HOL/Library/Sum_Of_Squares/sos_wrapper.ML
changeset 32332 bc5cec7b2be6
parent 32265 d50f0cb67578
child 32362 c0c640d86b4e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/HOL/Library/Sum_Of_Squares/sos_wrapper.ML	Thu Aug 06 19:51:59 2009 +0200
     1.3 @@ -0,0 +1,140 @@
     1.4 +(* Title:      sos_wrapper.ML
     1.5 +   Author:     Philipp Meyer, TU Muenchen
     1.6 +
     1.7 +Added functionality for sums of squares, e.g. calling a remote prover
     1.8 +*)
     1.9 +
    1.10 +signature SOS_WRAPPER =
    1.11 +sig
    1.12 +
    1.13 +  datatype prover_result = Success | Failure | Error
    1.14 +
    1.15 +  val setup: theory -> theory
    1.16 +  val destdir: string ref
    1.17 +end
    1.18 +
    1.19 +structure SosWrapper : SOS_WRAPPER=
    1.20 +struct
    1.21 +
    1.22 +datatype prover_result = Success | Failure | Error
    1.23 +fun str_of_result Success = "Success"
    1.24 +  | str_of_result Failure = "Failure"
    1.25 +  | str_of_result Error = "Error"
    1.26 +
    1.27 +(*** output control ***)
    1.28 +
    1.29 +fun debug s = if ! Sos.debugging then Output.writeln s else ()
    1.30 +val write = Output.priority
    1.31 +
    1.32 +(*** calling provers ***)
    1.33 +
    1.34 +val destdir = ref ""
    1.35 +
    1.36 +fun filename dir name =
    1.37 +  let
    1.38 +    val probfile = Path.basic (name ^ serial_string ())
    1.39 +    val dir_path = Path.explode dir
    1.40 +  in
    1.41 +    if dir = "" then
    1.42 +      File.tmp_path probfile
    1.43 +    else
    1.44 +      if File.exists dir_path then
    1.45 +        Path.append dir_path probfile
    1.46 +      else
    1.47 +        error ("No such directory: " ^ dir)
    1.48 +  end
    1.49 +
    1.50 +fun run_solver name cmd find_failure input =
    1.51 +  let
    1.52 +    val _ = write ("Calling solver: " ^ name)
    1.53 +
    1.54 +    (* create input file *)
    1.55 +    val dir = ! destdir
    1.56 +    val input_file = filename dir "sos_in" 
    1.57 +    val _ = File.write input_file input
    1.58 +
    1.59 +    (* call solver *)
    1.60 +    val output_file = filename dir "sos_out"
    1.61 +    val (output, rv) = system_out (
    1.62 +      if File.exists cmd then space_implode " "
    1.63 +        [File.shell_path cmd, File.platform_path input_file, File.platform_path output_file]
    1.64 +      else error ("Bad executable: " ^ File.shell_path cmd))
    1.65 + 
    1.66 +    (* read and analysize output *)
    1.67 +    val (res, res_msg) = find_failure rv
    1.68 +    val result = if File.exists output_file then File.read output_file else ""
    1.69 +
    1.70 +    (* remove temporary files *)
    1.71 +    val _ = if dir = "" then
    1.72 +        (File.rm input_file ; if File.exists output_file then File.rm output_file else ())
    1.73 +        else ()
    1.74 +
    1.75 +    val _ = debug ("Solver output:\n" ^ output)
    1.76 +
    1.77 +    val _ = write (str_of_result res ^ ": " ^ res_msg)
    1.78 +  in
    1.79 +    case res of
    1.80 +      Success => result
    1.81 +    | Failure => raise Sos.Failure res_msg
    1.82 +    | Error => error ("Prover failed: " ^ res_msg)
    1.83 +  end
    1.84 +
    1.85 +(*** various provers ***)
    1.86 +
    1.87 +(* local csdp client *)
    1.88 +
    1.89 +fun find_csdp_failure rv =
    1.90 +  case rv of
    1.91 +    0 => (Success, "SDP solved")
    1.92 +  | 1 => (Failure, "SDP is primal infeasible")
    1.93 +  | 2 => (Failure, "SDP is dual infeasible")
    1.94 +  | 3 => (Success, "SDP solved with reduced accuracy")
    1.95 +  | 4 => (Failure, "Maximum iterations reached")
    1.96 +  | 5 => (Failure, "Stuck at edge of primal feasibility")
    1.97 +  | 6 => (Failure, "Stuck at edge of dual infeasibility")
    1.98 +  | 7 => (Failure, "Lack of progress")
    1.99 +  | 8 => (Failure, "X, Z, or O was singular")
   1.100 +  | 9 => (Failure, "Detected NaN or Inf values")
   1.101 +  | _ => (Error, "return code is " ^ string_of_int rv)
   1.102 +
   1.103 +val csdp = ("$CSDP_EXE", find_csdp_failure)
   1.104 +
   1.105 +(* remote neos server *)
   1.106 +
   1.107 +fun find_neos_failure rv =
   1.108 +  case rv of
   1.109 +    20 => (Error, "error submitting job")
   1.110 +  | 21 => (Error, "no solution")
   1.111 +  |  _ => find_csdp_failure rv
   1.112 +
   1.113 +val neos_csdp = ("$ISABELLE_SUM_OF_SQUARES/neos_csdp_client", find_neos_failure)
   1.114 +
   1.115 +(* save provers in table *)
   1.116 +
   1.117 +val provers =
   1.118 +     Symtab.make [("remote_csdp", neos_csdp),("csdp", csdp)]
   1.119 +
   1.120 +fun get_prover name =
   1.121 +  case Symtab.lookup provers name of
   1.122 +    SOME prover => prover
   1.123 +  | NONE => error ("unknown prover: " ^ name)
   1.124 +
   1.125 +fun call_solver name =
   1.126 +  let
   1.127 +    val (cmd, find_failure) = get_prover name
   1.128 +  in
   1.129 +    run_solver name (Path.explode cmd) find_failure
   1.130 +  end
   1.131 +
   1.132 +(* setup tactic *)
   1.133 +
   1.134 +val def_solver = "remote_csdp"
   1.135 +
   1.136 +fun sos_solver name = (SIMPLE_METHOD' o (Sos.sos_tac (call_solver name))) 
   1.137 +
   1.138 +val sos_method = Scan.optional (Scan.lift OuterParse.xname) def_solver >> sos_solver
   1.139 +
   1.140 +val setup = Method.setup @{binding sos} sos_method
   1.141 +  "Prove universal problems over the reals using sums of squares"
   1.142 +
   1.143 +end