src/HOL/Matrix/cplex/fspmlp.ML
changeset 22951 dfafcd6223ad
parent 21056 2cfe839e8d58
child 22964 2284e0d02e7f
equal deleted inserted replaced
22950:8b6d28fc6532 22951:dfafcd6223ad
     1 (*  Title:      HOL/Matrix/cplex/fspmlp.ML
     1 (*  Title:      HOL/Matrix/cplex/fspmlp.ML
     2     ID:         $Id$
     2     ID:         $Id$
     3     Author:     Steven Obua
     3     Author:     Steven Obua
     4 *)
     4 *)
     5 
     5 
     6 signature FSPMLP = 
     6 signature FSPMLP =
     7 sig
     7 sig
     8     type linprog
     8     type linprog
     9     type vector = FloatSparseMatrixBuilder.vector
     9     type vector = FloatSparseMatrixBuilder.vector
    10     type matrix = FloatSparseMatrixBuilder.matrix
    10     type matrix = FloatSparseMatrixBuilder.matrix
    11 
    11 
    15     val c : linprog -> cterm * cterm
    15     val c : linprog -> cterm * cterm
    16     val r : linprog -> cterm
    16     val r : linprog -> cterm
    17     val r12 : linprog -> cterm * cterm
    17     val r12 : linprog -> cterm * cterm
    18 
    18 
    19     exception Load of string
    19     exception Load of string
    20 		       
    20 
    21     val load : string -> int -> bool -> linprog
    21     val load : string -> int -> bool -> linprog
    22 end
    22 end
    23 
    23 
    24 structure fspmlp : FSPMLP = 
    24 structure fspmlp : FSPMLP =
    25 struct
    25 struct
    26 
    26 
    27 type vector = FloatSparseMatrixBuilder.vector
    27 type vector = FloatSparseMatrixBuilder.vector
    28 type matrix = FloatSparseMatrixBuilder.matrix
    28 type matrix = FloatSparseMatrixBuilder.matrix
    29 
    29 
    34 fun b (c1, c2, c3, c4, c5, _) = c3
    34 fun b (c1, c2, c3, c4, c5, _) = c3
    35 fun c (c1, c2, c3, c4, c5, _) = c4
    35 fun c (c1, c2, c3, c4, c5, _) = c4
    36 fun r (c1, c2, c3, c4, c5, _) = c5
    36 fun r (c1, c2, c3, c4, c5, _) = c5
    37 fun r12 (c1, c2, c3, c4, c5, c6) = c6
    37 fun r12 (c1, c2, c3, c4, c5, c6) = c6
    38 
    38 
    39 structure CplexFloatSparseMatrixConverter = 
    39 structure CplexFloatSparseMatrixConverter =
    40 MAKE_CPLEX_MATRIX_CONVERTER(structure cplex = Cplex and matrix_builder = FloatSparseMatrixBuilder);
    40 MAKE_CPLEX_MATRIX_CONVERTER(structure cplex = Cplex and matrix_builder = FloatSparseMatrixBuilder);
    41 
    41 
    42 datatype bound_type = LOWER | UPPER
    42 datatype bound_type = LOWER | UPPER
    43 
    43 
    44 fun intbound_ord ((i1, b1),(i2,b2)) = 
    44 fun intbound_ord ((i1, b1),(i2,b2)) =
    45     if i1 < i2 then LESS
    45     if i1 < i2 then LESS
    46     else if i1 = i2 then 
    46     else if i1 = i2 then
    47 	(if b1 = b2 then EQUAL else if b1=LOWER then LESS else GREATER)
    47         (if b1 = b2 then EQUAL else if b1=LOWER then LESS else GREATER)
    48     else GREATER
    48     else GREATER
    49 
    49 
    50 structure Inttab = TableFun(type key = int val ord = (rev_order o int_ord));
    50 structure Inttab = TableFun(type key = int val ord = (rev_order o int_ord));
    51 
    51 
    52 structure VarGraph = TableFun(type key = int*bound_type val ord = intbound_ord);
    52 structure VarGraph = TableFun(type key = int*bound_type val ord = intbound_ord);
    53 (* key -> (float option) * (int -> (float * (((float * float) * key) list)))) *)
    53 (* key -> (float option) * (int -> (float * (((float * float) * key) list)))) *)
    54 (* dest_key -> (sure_bound * (row_index -> (row_bound * (((coeff_lower * coeff_upper) * src_key) list)))) *)
    54 (* dest_key -> (sure_bound * (row_index -> (row_bound * (((coeff_lower * coeff_upper) * src_key) list)))) *)
    55 
    55 
    56 exception Internal of string;
    56 exception Internal of string;
    57 
    57 
    58 fun add_row_bound g dest_key row_index row_bound = 
    58 fun add_row_bound g dest_key row_index row_bound =
    59     let 
    59     let
    60 	val x = 
    60         val x =
    61 	    case VarGraph.lookup g dest_key of
    61             case VarGraph.lookup g dest_key of
    62 		NONE => (NONE, Inttab.update (row_index, (row_bound, [])) Inttab.empty)
    62                 NONE => (NONE, Inttab.update (row_index, (row_bound, [])) Inttab.empty)
    63 	      | SOME (sure_bound, f) =>
    63               | SOME (sure_bound, f) =>
    64 		(sure_bound,
    64                 (sure_bound,
    65 		 case Inttab.lookup f row_index of
    65                  case Inttab.lookup f row_index of
    66 		     NONE => Inttab.update (row_index, (row_bound, [])) f
    66                      NONE => Inttab.update (row_index, (row_bound, [])) f
    67 		   | SOME _ => raise (Internal "add_row_bound"))				     
    67                    | SOME _ => raise (Internal "add_row_bound"))
    68     in
    68     in
    69 	VarGraph.update (dest_key, x) g
    69         VarGraph.update (dest_key, x) g
    70     end    
       
    71 
       
    72 fun update_sure_bound g (key as (_, btype)) bound = 
       
    73     let
       
    74 	val x = 
       
    75 	    case VarGraph.lookup g key of
       
    76 		NONE => (SOME bound, Inttab.empty)
       
    77 	      | SOME (NONE, f) => (SOME bound, f)
       
    78 	      | SOME (SOME old_bound, f) => 
       
    79 		(SOME ((case btype of 
       
    80 			    UPPER => FloatArith.min 
       
    81 			  | LOWER => FloatArith.max) 
       
    82 			   old_bound bound), f)
       
    83     in
       
    84 	VarGraph.update (key, x) g
       
    85     end
    70     end
    86 
    71 
    87 fun get_sure_bound g key = 
    72 fun update_sure_bound g (key as (_, btype)) bound =
    88     case VarGraph.lookup g key of 
    73     let
    89 	NONE => NONE
    74         val x =
       
    75             case VarGraph.lookup g key of
       
    76                 NONE => (SOME bound, Inttab.empty)
       
    77               | SOME (NONE, f) => (SOME bound, f)
       
    78               | SOME (SOME old_bound, f) =>
       
    79                 (SOME ((case btype of
       
    80                             UPPER => FloatArith.min
       
    81                           | LOWER => FloatArith.max)
       
    82                            old_bound bound), f)
       
    83     in
       
    84         VarGraph.update (key, x) g
       
    85     end
       
    86 
       
    87 fun get_sure_bound g key =
       
    88     case VarGraph.lookup g key of
       
    89         NONE => NONE
    90       | SOME (sure_bound, _) => sure_bound
    90       | SOME (sure_bound, _) => sure_bound
    91 
    91 
    92 (*fun get_row_bound g key row_index = 
    92 (*fun get_row_bound g key row_index =
    93     case VarGraph.lookup g key of
    93     case VarGraph.lookup g key of
    94 	NONE => NONE
    94         NONE => NONE
    95       | SOME (sure_bound, f) =>
    95       | SOME (sure_bound, f) =>
    96 	(case Inttab.lookup f row_index of 
    96         (case Inttab.lookup f row_index of
    97 	     NONE => NONE
    97              NONE => NONE
    98 	   | SOME (row_bound, _) => (sure_bound, row_bound))*)
    98            | SOME (row_bound, _) => (sure_bound, row_bound))*)
    99     
    99 
   100 fun add_edge g src_key dest_key row_index coeff = 
   100 fun add_edge g src_key dest_key row_index coeff =
   101     case VarGraph.lookup g dest_key of
   101     case VarGraph.lookup g dest_key of
   102 	NONE => raise (Internal "add_edge: dest_key not found")
   102         NONE => raise (Internal "add_edge: dest_key not found")
   103       | SOME (sure_bound, f) =>
   103       | SOME (sure_bound, f) =>
   104 	(case Inttab.lookup f row_index of
   104         (case Inttab.lookup f row_index of
   105 	     NONE => raise (Internal "add_edge: row_index not found")
   105              NONE => raise (Internal "add_edge: row_index not found")
   106 	   | SOME (row_bound, sources) => 
   106            | SOME (row_bound, sources) =>
   107 	     VarGraph.update (dest_key, (sure_bound, Inttab.update (row_index, (row_bound, (coeff, src_key) :: sources)) f)) g)
   107              VarGraph.update (dest_key, (sure_bound, Inttab.update (row_index, (row_bound, (coeff, src_key) :: sources)) f)) g)
   108 
   108 
   109 fun split_graph g = 
   109 fun split_graph g =
   110   let
   110   let
   111     fun split (key, (sure_bound, _)) (r1, r2) = case sure_bound
   111     fun split (key, (sure_bound, _)) (r1, r2) = case sure_bound
   112      of NONE => (r1, r2)
   112      of NONE => (r1, r2)
   113       | SOME bound =>  (case key
   113       | SOME bound =>  (case key
   114          of (u, UPPER) => (r1, Inttab.update (u, bound) r2)
   114          of (u, UPPER) => (r1, Inttab.update (u, bound) r2)
   117 
   117 
   118 fun it2list t = Inttab.fold cons t [];
   118 fun it2list t = Inttab.fold cons t [];
   119 
   119 
   120 (* If safe is true, termination is guaranteed, but the sure bounds may be not optimal (relative to the algorithm).
   120 (* If safe is true, termination is guaranteed, but the sure bounds may be not optimal (relative to the algorithm).
   121    If safe is false, termination is not guaranteed, but on termination the sure bounds are optimal (relative to the algorithm) *)
   121    If safe is false, termination is not guaranteed, but on termination the sure bounds are optimal (relative to the algorithm) *)
   122 fun propagate_sure_bounds safe names g = 
   122 fun propagate_sure_bounds safe names g =
   123     let		 	    	
   123     let
   124 	(* returns NONE if no new sure bound could be calculated, otherwise the new sure bound is returned *)
   124         (* returns NONE if no new sure bound could be calculated, otherwise the new sure bound is returned *)
   125 	fun calc_sure_bound_from_sources g (key as (_, btype)) = 
   125         fun calc_sure_bound_from_sources g (key as (_, btype)) =
   126 	    let		
   126             let
   127 		fun mult_upper x (lower, upper) = 
   127                 fun mult_upper x (lower, upper) =
   128 		    if FloatArith.is_negative x then
   128                     if FloatArith.is_negative x then
   129 			FloatArith.mul x lower
   129                         FloatArith.mul x lower
   130 		    else
   130                     else
   131 			FloatArith.mul x upper
   131                         FloatArith.mul x upper
   132 			
   132 
   133 		fun mult_lower x (lower, upper) = 
   133                 fun mult_lower x (lower, upper) =
   134 		    if FloatArith.is_negative x then
   134                     if FloatArith.is_negative x then
   135 			FloatArith.mul x upper
   135                         FloatArith.mul x upper
   136 		    else
   136                     else
   137 			FloatArith.mul x lower
   137                         FloatArith.mul x lower
   138 
   138 
   139 		val mult_btype = case btype of UPPER => mult_upper | LOWER => mult_lower
   139                 val mult_btype = case btype of UPPER => mult_upper | LOWER => mult_lower
   140 
   140 
   141 		fun calc_sure_bound (row_index, (row_bound, sources)) sure_bound = 
   141                 fun calc_sure_bound (row_index, (row_bound, sources)) sure_bound =
   142 		    let
   142                     let
   143 			fun add_src_bound (coeff, src_key) sum = 
   143                         fun add_src_bound (coeff, src_key) sum =
   144 			    case sum of 
   144                             case sum of
   145 				NONE => NONE
   145                                 NONE => NONE
   146 			      | SOME x => 
   146                               | SOME x =>
   147 				(case get_sure_bound g src_key of
   147                                 (case get_sure_bound g src_key of
   148 				     NONE => NONE
   148                                      NONE => NONE
   149 				   | SOME src_sure_bound => SOME (FloatArith.add x (mult_btype src_sure_bound coeff)))
   149                                    | SOME src_sure_bound => SOME (FloatArith.add x (mult_btype src_sure_bound coeff)))
   150 		    in
   150                     in
   151 			case fold add_src_bound sources (SOME row_bound) of
   151                         case fold add_src_bound sources (SOME row_bound) of
   152 			    NONE => sure_bound
   152                             NONE => sure_bound
   153 			  | new_sure_bound as (SOME new_bound) => 
   153                           | new_sure_bound as (SOME new_bound) =>
   154 			    (case sure_bound of 
   154                             (case sure_bound of
   155 				 NONE => new_sure_bound
   155                                  NONE => new_sure_bound
   156 			       | SOME old_bound => 
   156                                | SOME old_bound =>
   157 				 SOME (case btype of 
   157                                  SOME (case btype of
   158 					   UPPER => FloatArith.min old_bound new_bound
   158                                            UPPER => FloatArith.min old_bound new_bound
   159 					 | LOWER => FloatArith.max old_bound new_bound))				 
   159                                          | LOWER => FloatArith.max old_bound new_bound))
   160 		    end		
   160                     end
   161 	    in
   161             in
   162 		case VarGraph.lookup g key of
   162                 case VarGraph.lookup g key of
   163 		    NONE => NONE
   163                     NONE => NONE
   164 		  | SOME (sure_bound, f) =>
   164                   | SOME (sure_bound, f) =>
   165 		    let
   165                     let
   166 			val x = Inttab.fold calc_sure_bound f sure_bound
   166                         val x = Inttab.fold calc_sure_bound f sure_bound
   167 		    in
   167                     in
   168 			if x = sure_bound then NONE else x
   168                         if x = sure_bound then NONE else x
   169 		    end		
   169                     end
   170     	    end
   170                 end
   171 
   171 
   172 	fun propagate (key, _) (g, b) = 
   172         fun propagate (key, _) (g, b) =
   173 	    case calc_sure_bound_from_sources g key of 
   173             case calc_sure_bound_from_sources g key of
   174 		NONE => (g,b)
   174                 NONE => (g,b)
   175 	      | SOME bound => (update_sure_bound g key bound, 
   175               | SOME bound => (update_sure_bound g key bound,
   176 			       if safe then 
   176                                if safe then
   177 				   case get_sure_bound g key of
   177                                    case get_sure_bound g key of
   178 				       NONE => true
   178                                        NONE => true
   179 				     | _ => b
   179                                      | _ => b
   180 			       else
   180                                else
   181 				   true)
   181                                    true)
   182 
   182 
   183 	val (g, b) = VarGraph.fold propagate g (g, false)
   183         val (g, b) = VarGraph.fold propagate g (g, false)
   184     in
   184     in
   185 	if b then propagate_sure_bounds safe names g else g	
   185         if b then propagate_sure_bounds safe names g else g
   186     end	    
   186     end
   187     		
   187 
   188 exception Load of string;
   188 exception Load of string;
   189 
   189 
   190 fun calcr safe_propagation xlen names prec A b = 
   190 fun calcr safe_propagation xlen names prec A b =
   191     let
   191     let
   192 	val empty = Inttab.empty
   192         val empty = Inttab.empty
   193 
   193 
   194 	fun instab t i x = Inttab.update (i, x) t
   194         fun instab t i x = Inttab.update (i, x) t
   195 
   195 
   196 	fun isnegstr x = String.isPrefix "-" x
   196         fun isnegstr x = String.isPrefix "-" x
   197 	fun negstr x = if isnegstr x then String.extract (x, 1, NONE) else "-"^x
   197         fun negstr x = if isnegstr x then String.extract (x, 1, NONE) else "-"^x
   198 
   198 
   199 	fun test_1 (lower, upper) = 
   199         fun test_1 (lower, upper) =
   200 	    if lower = upper then
   200             if lower = upper then
   201 		(if FloatArith.is_equal lower (IntInf.fromInt ~1, FloatArith.izero) then ~1 
   201                 (if FloatArith.is_equal lower (IntInf.fromInt ~1, FloatArith.izero) then ~1
   202 		 else if FloatArith.is_equal lower (IntInf.fromInt 1, FloatArith.izero) then 1
   202                  else if FloatArith.is_equal lower (IntInf.fromInt 1, FloatArith.izero) then 1
   203 		 else 0)
   203                  else 0)
   204 	    else 0	
   204             else 0
   205 
   205 
   206 	fun calcr (row_index, a) g = 
   206         fun calcr (row_index, a) g =
   207 	    let
   207             let
   208 		val b =  FloatSparseMatrixBuilder.v_elem_at b row_index
   208                 val b =  FloatSparseMatrixBuilder.v_elem_at b row_index
   209 		val (_, b2) = ExactFloatingPoint.approx_decstr_by_bin prec (case b of NONE => "0" | SOME b => b)
   209                 val (_, b2) = ExactFloatingPoint.approx_decstr_by_bin prec (case b of NONE => "0" | SOME b => b)
   210 		val approx_a = FloatSparseMatrixBuilder.v_fold (fn (i, s) => fn l => 
   210                 val approx_a = FloatSparseMatrixBuilder.v_fold (fn (i, s) => fn l =>
   211 								   (i, ExactFloatingPoint.approx_decstr_by_bin prec s)::l) a []
   211                                                                    (i, ExactFloatingPoint.approx_decstr_by_bin prec s)::l) a []
   212 			       
   212 
   213 		fun fold_dest_nodes (dest_index, dest_value) g = 
   213                 fun fold_dest_nodes (dest_index, dest_value) g =
   214 		    let
   214                     let
   215 			val dest_test = test_1 dest_value
   215                         val dest_test = test_1 dest_value
   216 		    in
   216                     in
   217 			if dest_test = 0 then
   217                         if dest_test = 0 then
   218 			    g
   218                             g
   219 			else let
   219                         else let
   220 				val (dest_key as (_, dest_btype), row_bound) = 
   220                                 val (dest_key as (_, dest_btype), row_bound) =
   221 				    if dest_test = ~1 then 
   221                                     if dest_test = ~1 then
   222 					((dest_index, LOWER), FloatArith.neg b2)
   222                                         ((dest_index, LOWER), FloatArith.neg b2)
   223 				    else
   223                                     else
   224 					((dest_index, UPPER), b2)
   224                                         ((dest_index, UPPER), b2)
   225 					
   225 
   226 				fun fold_src_nodes (src_index, src_value as (src_lower, src_upper)) g = 
   226                                 fun fold_src_nodes (src_index, src_value as (src_lower, src_upper)) g =
   227 				    if src_index = dest_index then g
   227                                     if src_index = dest_index then g
   228 				    else
   228                                     else
   229 					let
   229                                         let
   230 					    val coeff = case dest_btype of 
   230                                             val coeff = case dest_btype of
   231 							    UPPER => (FloatArith.neg src_upper, FloatArith.neg src_lower)
   231                                                             UPPER => (FloatArith.neg src_upper, FloatArith.neg src_lower)
   232 							  | LOWER => src_value
   232                                                           | LOWER => src_value
   233 					in
   233                                         in
   234 					    if FloatArith.is_negative src_lower then
   234                                             if FloatArith.is_negative src_lower then
   235 						add_edge g (src_index, UPPER) dest_key row_index coeff
   235                                                 add_edge g (src_index, UPPER) dest_key row_index coeff
   236 					    else
   236                                             else
   237 						add_edge g (src_index, LOWER) dest_key row_index coeff
   237                                                 add_edge g (src_index, LOWER) dest_key row_index coeff
   238 					end
   238                                         end
   239 			    in	    
   239                             in
   240 				fold fold_src_nodes approx_a (add_row_bound g dest_key row_index row_bound)
   240                                 fold fold_src_nodes approx_a (add_row_bound g dest_key row_index row_bound)
   241 			    end
   241                             end
   242 		    end
   242                     end
   243 	    in
   243             in
   244 		case approx_a of
   244                 case approx_a of
   245 		    [] => g
   245                     [] => g
   246 		  | [(u, a)] => 
   246                   | [(u, a)] =>
   247 		    let
   247                     let
   248 			val atest = test_1 a
   248                         val atest = test_1 a
   249 		    in
   249                     in
   250 			if atest = ~1 then 			  
   250                         if atest = ~1 then
   251 			    update_sure_bound g (u, LOWER) (FloatArith.neg b2)
   251                             update_sure_bound g (u, LOWER) (FloatArith.neg b2)
   252 			else if atest = 1 then
   252                         else if atest = 1 then
   253 			    update_sure_bound g (u, UPPER) b2
   253                             update_sure_bound g (u, UPPER) b2
   254 			else
   254                         else
   255 			    g
   255                             g
   256 		    end
   256                     end
   257 		  | _ => fold fold_dest_nodes approx_a g
   257                   | _ => fold fold_dest_nodes approx_a g
   258 	    end
   258             end
   259 	
   259 
   260 	val g = FloatSparseMatrixBuilder.m_fold calcr A VarGraph.empty
   260         val g = FloatSparseMatrixBuilder.m_fold calcr A VarGraph.empty
   261 	val g = propagate_sure_bounds safe_propagation names g
   261         val g = propagate_sure_bounds safe_propagation names g
   262 
   262 
   263 	val (r1, r2) = split_graph g
   263         val (r1, r2) = split_graph g
   264 
   264 
   265 	fun add_row_entry m index value = 
   265         fun add_row_entry m index value =
   266 	    let
   266             let
   267 		val vec = FloatSparseMatrixBuilder.cons_spvec (FloatSparseMatrixBuilder.mk_spvec_entry 0 value) FloatSparseMatrixBuilder.empty_spvec
   267                 val vec = FloatSparseMatrixBuilder.cons_spvec (FloatSparseMatrixBuilder.mk_spvec_entry 0 value) FloatSparseMatrixBuilder.empty_spvec
   268 	    in
   268             in
   269 		FloatSparseMatrixBuilder.cons_spmat (FloatSparseMatrixBuilder.mk_spmat_entry index vec) m	
   269                 FloatSparseMatrixBuilder.cons_spmat (FloatSparseMatrixBuilder.mk_spmat_entry index vec) m
   270 	    end
   270             end
   271 	
   271 
   272 	fun abs_estimate i r1 r2 = 
   272         fun abs_estimate i r1 r2 =
   273 	    if i = 0 then 
   273             if i = 0 then
   274 		let val e = FloatSparseMatrixBuilder.empty_spmat in (e, (e, e)) end
   274                 let val e = FloatSparseMatrixBuilder.empty_spmat in (e, (e, e)) end
   275 	    else
   275             else
   276 		let
   276                 let
   277 		    val index = xlen-i
   277                     val index = xlen-i
   278 		    val (r, (r12_1, r12_2)) = abs_estimate (i-1) r1 r2 
   278                     val (r, (r12_1, r12_2)) = abs_estimate (i-1) r1 r2
   279 		    val b1 = case Inttab.lookup r1 index of NONE => raise (Load ("x-value not bounded from below: "^(names index))) | SOME x => x
   279                     val b1 = case Inttab.lookup r1 index of NONE => raise (Load ("x-value not bounded from below: "^(names index))) | SOME x => x
   280 		    val b2 = case Inttab.lookup r2 index of NONE => raise (Load ("x-value not bounded from above: "^(names index))) | SOME x => x
   280                     val b2 = case Inttab.lookup r2 index of NONE => raise (Load ("x-value not bounded from above: "^(names index))) | SOME x => x
   281 		    val abs_max = FloatArith.max (FloatArith.neg (FloatArith.negative_part b1)) (FloatArith.positive_part b2)    
   281                     val abs_max = FloatArith.max (FloatArith.neg (FloatArith.negative_part b1)) (FloatArith.positive_part b2)
   282 		in
   282                 in
   283 		    (add_row_entry r index abs_max, (add_row_entry r12_1 index b1, add_row_entry r12_2 index b2))
   283                     (add_row_entry r index abs_max, (add_row_entry r12_1 index b1, add_row_entry r12_2 index b2))
   284 		end		    		   
   284                 end
   285 	val sign = FloatSparseMatrixBuilder.sign_term
   285         val sign = FloatSparseMatrixBuilder.sign_term
   286 	val (r, (r1, r2)) = abs_estimate xlen r1 r2
   286         val (r, (r1, r2)) = abs_estimate xlen r1 r2
   287     in
   287     in
   288 	(sign r, (sign r1, sign r2))
   288         (sign r, (sign r1, sign r2))
   289     end
   289     end
   290 	    
   290 
   291 fun load filename prec safe_propagation =
   291 fun load filename prec safe_propagation =
   292     let
   292     let
   293 	val prog = Cplex.load_cplexFile filename
   293         val prog = Cplex.load_cplexFile filename
   294 	val prog = Cplex.elim_nonfree_bounds prog
   294         val prog = Cplex.elim_nonfree_bounds prog
   295 	val prog = Cplex.relax_strict_ineqs prog
   295         val prog = Cplex.relax_strict_ineqs prog
   296 	val (maximize, c, A, b, (xlen, names, _)) = CplexFloatSparseMatrixConverter.convert_prog prog
   296         val (maximize, c, A, b, (xlen, names, _)) = CplexFloatSparseMatrixConverter.convert_prog prog
   297 	val (r, (r1, r2)) = calcr safe_propagation xlen names prec A b
   297         val (r, (r1, r2)) = calcr safe_propagation xlen names prec A b
   298 	val _ = if maximize then () else raise Load "sorry, cannot handle minimization problems"			
   298         val _ = if maximize then () else raise Load "sorry, cannot handle minimization problems"
   299 	val (dualprog, indexof) = FloatSparseMatrixBuilder.dual_cplexProg c A b
   299         val (dualprog, indexof) = FloatSparseMatrixBuilder.dual_cplexProg c A b
   300 	val results = Cplex.solve dualprog
   300         val results = Cplex.solve dualprog
   301 	val (optimal,v) = CplexFloatSparseMatrixConverter.convert_results results indexof
   301         val (optimal,v) = CplexFloatSparseMatrixConverter.convert_results results indexof
   302 	val A = FloatSparseMatrixBuilder.cut_matrix v NONE A
   302         val A = FloatSparseMatrixBuilder.cut_matrix v NONE A
   303 	fun id x = x
   303         fun id x = x
   304 	val v = FloatSparseMatrixBuilder.set_vector FloatSparseMatrixBuilder.empty_matrix 0 v
   304         val v = FloatSparseMatrixBuilder.set_vector FloatSparseMatrixBuilder.empty_matrix 0 v
   305 	val b = FloatSparseMatrixBuilder.transpose_matrix (FloatSparseMatrixBuilder.set_vector FloatSparseMatrixBuilder.empty_matrix 0 b)
   305         val b = FloatSparseMatrixBuilder.transpose_matrix (FloatSparseMatrixBuilder.set_vector FloatSparseMatrixBuilder.empty_matrix 0 b)
   306 	val c = FloatSparseMatrixBuilder.set_vector FloatSparseMatrixBuilder.empty_matrix 0 c
   306         val c = FloatSparseMatrixBuilder.set_vector FloatSparseMatrixBuilder.empty_matrix 0 c
   307 	val (y1, _) = FloatSparseMatrixBuilder.approx_matrix prec FloatArith.positive_part v
   307         val (y1, _) = FloatSparseMatrixBuilder.approx_matrix prec FloatArith.positive_part v
   308 	val A = FloatSparseMatrixBuilder.approx_matrix prec id A
   308         val A = FloatSparseMatrixBuilder.approx_matrix prec id A
   309 	val (_,b2) = FloatSparseMatrixBuilder.approx_matrix prec id b
   309         val (_,b2) = FloatSparseMatrixBuilder.approx_matrix prec id b
   310 	val c = FloatSparseMatrixBuilder.approx_matrix prec id c
   310         val c = FloatSparseMatrixBuilder.approx_matrix prec id c
   311     in
   311     in
   312 	(y1, A, b2, c, r, (r1, r2))
   312         (y1, A, b2, c, r, (r1, r2))
   313     end handle CplexFloatSparseMatrixConverter.Converter s => (raise (Load ("Converter: "^s)))	
   313     end handle CplexFloatSparseMatrixConverter.Converter s => (raise (Load ("Converter: "^s)))
   314 
       
   315 
   314 
   316 end
   315 end