16784
|
1 |
(* Title: HOL/Matrix/cplex/FloatSparseMatrixBuilder.ML
|
|
2 |
ID: $Id$
|
|
3 |
Author: Steven Obua
|
|
4 |
*)
|
|
5 |
|
|
6 |
structure FloatSparseMatrixBuilder :
|
|
7 |
sig
|
|
8 |
include MATRIX_BUILDER
|
|
9 |
|
|
10 |
structure cplex : CPLEX
|
|
11 |
|
|
12 |
type float = IntInf.int*IntInf.int
|
|
13 |
type floatfunc = float -> float
|
|
14 |
|
|
15 |
|
|
16 |
val float2cterm : IntInf.int * IntInf.int -> cterm
|
|
17 |
|
|
18 |
val approx_value : int -> floatfunc -> string -> cterm * cterm
|
|
19 |
val approx_vector : int -> floatfunc -> vector -> cterm * cterm
|
|
20 |
val approx_matrix : int -> floatfunc -> matrix -> cterm * cterm
|
|
21 |
|
|
22 |
val mk_spvec_entry : int -> float -> term
|
|
23 |
val empty_spvec : term
|
|
24 |
val cons_spvec : term -> term -> term
|
|
25 |
val empty_spmat : term
|
|
26 |
val mk_spmat_entry : int -> term -> term
|
|
27 |
val cons_spmat : term -> term -> term
|
|
28 |
val sign_term : term -> cterm
|
|
29 |
|
|
30 |
val v_elem_at : vector -> int -> string option
|
|
31 |
val m_elem_at : matrix -> int -> vector option
|
|
32 |
val v_only_elem : vector -> int option
|
|
33 |
val v_fold : ('a * (int * string) -> 'a) -> 'a -> vector -> 'a
|
|
34 |
val m_fold : ('a * (int * vector) -> 'a) -> 'a -> matrix -> 'a
|
|
35 |
|
|
36 |
val transpose_matrix : matrix -> matrix
|
|
37 |
|
|
38 |
val cut_vector : int -> vector -> vector
|
|
39 |
val cut_matrix : vector -> (int option) -> matrix -> matrix
|
|
40 |
|
|
41 |
(* cplexProg c A b *)
|
|
42 |
val cplexProg : vector -> matrix -> vector -> (cplex.cplexProg * (string -> int))
|
|
43 |
(* dual_cplexProg c A b *)
|
|
44 |
val dual_cplexProg : vector -> matrix -> vector -> (cplex.cplexProg * (string -> int))
|
|
45 |
|
|
46 |
val real_spmatT : typ
|
|
47 |
val real_spvecT : typ
|
|
48 |
end
|
|
49 |
=
|
|
50 |
struct
|
|
51 |
|
|
52 |
|
|
53 |
structure Inttab = TableFun(type key = int val ord = (rev_order o int_ord));
|
|
54 |
|
|
55 |
type vector = string Inttab.table
|
|
56 |
type matrix = vector Inttab.table
|
|
57 |
type float = IntInf.int*IntInf.int
|
|
58 |
type floatfunc = float -> float
|
|
59 |
|
|
60 |
val th = theory "FloatSparseMatrix"
|
|
61 |
val sg = sign_of th
|
|
62 |
|
|
63 |
fun readtype s = Sign.intern_type sg s
|
|
64 |
fun readterm s = Sign.intern_const sg s
|
|
65 |
|
|
66 |
val ty_list = readtype "list"
|
|
67 |
val term_Nil = readterm "Nil"
|
|
68 |
val term_Cons = readterm "Cons"
|
|
69 |
|
|
70 |
val spvec_elemT = HOLogic.mk_prodT (HOLogic.natT, HOLogic.realT)
|
|
71 |
val spvecT = Type (ty_list, [spvec_elemT])
|
|
72 |
val spmat_elemT = HOLogic.mk_prodT (HOLogic.natT, spvecT)
|
|
73 |
val spmatT = Type (ty_list, [spmat_elemT])
|
|
74 |
|
|
75 |
val real_spmatT = spmatT
|
|
76 |
val real_spvecT = spvecT
|
|
77 |
|
|
78 |
val empty_matrix_const = Const (term_Nil, spmatT)
|
|
79 |
val empty_vector_const = Const (term_Nil, spvecT)
|
|
80 |
|
|
81 |
val Cons_spvec_const = Const (term_Cons, spvec_elemT --> spvecT --> spvecT)
|
|
82 |
val Cons_spmat_const = Const (term_Cons, spmat_elemT --> spmatT --> spmatT)
|
|
83 |
|
16873
|
84 |
val float_const = Float.float_const
|
|
85 |
|
|
86 |
(*val float_const = Const (readterm "float", HOLogic.mk_prodT (HOLogic.intT, HOLogic.intT) --> HOLogic.realT)*)
|
16784
|
87 |
|
|
88 |
val zero = IntInf.fromInt 0
|
|
89 |
val minus_one = IntInf.fromInt ~1
|
|
90 |
val two = IntInf.fromInt 2
|
|
91 |
|
16873
|
92 |
val mk_intinf = Float.mk_intinf
|
|
93 |
(* let
|
16784
|
94 |
fun mk_bit n = if n = zero then HOLogic.false_const else HOLogic.true_const
|
|
95 |
|
|
96 |
fun bin_of n =
|
|
97 |
if n = zero then HOLogic.pls_const
|
|
98 |
else if n = minus_one then HOLogic.min_const
|
|
99 |
else
|
|
100 |
let
|
|
101 |
(*val (q,r) = IntInf.divMod (n, two): doesn't work in SML 10.0.7, but in newer versions!!!*)
|
|
102 |
val q = IntInf.div (n, two)
|
|
103 |
val r = IntInf.mod (n, two)
|
|
104 |
in
|
|
105 |
HOLogic.bit_const $ bin_of q $ mk_bit r
|
|
106 |
end
|
|
107 |
in
|
|
108 |
HOLogic.number_of_const ty $ (bin_of n)
|
16873
|
109 |
end*)
|
16784
|
110 |
|
16873
|
111 |
val mk_float = Float.mk_float
|
|
112 |
(* float_const $ (HOLogic.mk_prod ((mk_intinf HOLogic.intT a), (mk_intinf HOLogic.intT b)))*)
|
16784
|
113 |
|
|
114 |
fun float2cterm (a,b) = cterm_of sg (mk_float (a,b))
|
|
115 |
|
16873
|
116 |
fun approx_value_term prec f = Float.approx_float prec (fn (x, y) => (f x, f y))
|
|
117 |
(* let
|
16784
|
118 |
val (flower, fupper) = ExactFloatingPoint.approx_decstr_by_bin prec value
|
|
119 |
val (flower, fupper) = (f flower, f fupper)
|
|
120 |
in
|
|
121 |
(mk_float flower, mk_float fupper)
|
16873
|
122 |
end*)
|
16784
|
123 |
|
|
124 |
fun approx_value prec pprt value =
|
|
125 |
let
|
|
126 |
val (flower, fupper) = approx_value_term prec pprt value
|
|
127 |
in
|
|
128 |
(cterm_of sg flower, cterm_of sg fupper)
|
|
129 |
end
|
|
130 |
|
|
131 |
fun sign_term t = cterm_of sg t
|
|
132 |
|
|
133 |
val empty_spvec = empty_vector_const
|
|
134 |
|
|
135 |
val empty_spmat = empty_matrix_const
|
|
136 |
|
|
137 |
fun mk_spvec_entry i f =
|
|
138 |
let
|
|
139 |
val term_i = mk_intinf HOLogic.natT (IntInf.fromInt i)
|
|
140 |
val term_f = mk_float f
|
|
141 |
in
|
|
142 |
HOLogic.mk_prod (term_i, term_f)
|
|
143 |
end
|
|
144 |
|
|
145 |
fun mk_spmat_entry i e =
|
|
146 |
let
|
|
147 |
val term_i = mk_intinf HOLogic.natT (IntInf.fromInt i)
|
|
148 |
in
|
|
149 |
HOLogic.mk_prod (term_i, e)
|
|
150 |
end
|
|
151 |
|
|
152 |
fun cons_spvec h t = Cons_spvec_const $ h $ t
|
|
153 |
|
|
154 |
fun cons_spmat h t = Cons_spmat_const $ h $ t
|
|
155 |
|
|
156 |
fun approx_vector_term prec pprt vector =
|
|
157 |
let
|
|
158 |
fun app ((vlower, vupper), (index, s)) =
|
|
159 |
let
|
|
160 |
val (flower, fupper) = approx_value_term prec pprt s
|
|
161 |
val index = mk_intinf HOLogic.natT (IntInf.fromInt index)
|
|
162 |
val elower = HOLogic.mk_prod (index, flower)
|
|
163 |
val eupper = HOLogic.mk_prod (index, fupper)
|
|
164 |
in
|
|
165 |
(Cons_spvec_const $ elower $ vlower,
|
|
166 |
Cons_spvec_const $ eupper $ vupper)
|
|
167 |
end
|
|
168 |
in
|
|
169 |
Inttab.foldl app ((empty_vector_const, empty_vector_const), vector)
|
|
170 |
end
|
|
171 |
|
|
172 |
fun approx_matrix_term prec pprt matrix =
|
|
173 |
let
|
|
174 |
fun app ((mlower, mupper), (index, vector)) =
|
|
175 |
let
|
|
176 |
val (vlower, vupper) = approx_vector_term prec pprt vector
|
|
177 |
val index = mk_intinf HOLogic.natT (IntInf.fromInt index)
|
|
178 |
val elower = HOLogic.mk_prod (index, vlower)
|
|
179 |
val eupper = HOLogic.mk_prod (index, vupper)
|
|
180 |
in
|
|
181 |
(Cons_spmat_const $ elower $ mlower,
|
|
182 |
Cons_spmat_const $ eupper $ mupper)
|
|
183 |
end
|
|
184 |
|
|
185 |
val (mlower, mupper) = Inttab.foldl app ((empty_matrix_const, empty_matrix_const), matrix)
|
|
186 |
in
|
|
187 |
Inttab.foldl app ((empty_matrix_const, empty_matrix_const), matrix)
|
|
188 |
end
|
|
189 |
|
|
190 |
fun approx_vector prec pprt vector =
|
|
191 |
let
|
|
192 |
val (l, u) = approx_vector_term prec pprt vector
|
|
193 |
in
|
|
194 |
(cterm_of sg l, cterm_of sg u)
|
|
195 |
end
|
|
196 |
|
|
197 |
fun approx_matrix prec pprt matrix =
|
|
198 |
let
|
|
199 |
val (l, u) = approx_matrix_term prec pprt matrix
|
|
200 |
in
|
|
201 |
(cterm_of sg l, cterm_of sg u)
|
|
202 |
end
|
|
203 |
|
|
204 |
|
|
205 |
exception Nat_expected of int;
|
|
206 |
|
|
207 |
val zero_interval = approx_value_term 1 I "0"
|
|
208 |
|
|
209 |
fun set_elem vector index str =
|
|
210 |
if index < 0 then
|
|
211 |
raise (Nat_expected index)
|
|
212 |
else if (approx_value_term 1 I str) = zero_interval then
|
|
213 |
vector
|
|
214 |
else
|
|
215 |
Inttab.update ((index, str), vector)
|
|
216 |
|
|
217 |
fun set_vector matrix index vector =
|
|
218 |
if index < 0 then
|
|
219 |
raise (Nat_expected index)
|
|
220 |
else if Inttab.is_empty vector then
|
|
221 |
matrix
|
|
222 |
else
|
|
223 |
Inttab.update ((index, vector), matrix)
|
|
224 |
|
|
225 |
val empty_matrix = Inttab.empty
|
|
226 |
val empty_vector = Inttab.empty
|
|
227 |
|
|
228 |
(* dual stuff *)
|
|
229 |
|
|
230 |
structure cplex = Cplex
|
|
231 |
|
|
232 |
fun transpose_matrix matrix =
|
|
233 |
let
|
|
234 |
fun upd m j i x =
|
|
235 |
case Inttab.lookup (m, j) of
|
|
236 |
SOME v => Inttab.update ((j, Inttab.update ((i, x), v)), m)
|
|
237 |
| NONE => Inttab.update ((j, Inttab.update ((i, x), Inttab.empty)), m)
|
|
238 |
|
|
239 |
fun updv j (m, (i, s)) = upd m i j s
|
|
240 |
|
|
241 |
fun updm (m, (j, v)) = Inttab.foldl (updv j) (m, v)
|
|
242 |
in
|
|
243 |
Inttab.foldl updm (empty_matrix, matrix)
|
|
244 |
end
|
|
245 |
|
|
246 |
exception No_name of string;
|
|
247 |
|
|
248 |
exception Superfluous_constr_right_hand_sides
|
|
249 |
|
|
250 |
fun cplexProg c A b =
|
|
251 |
let
|
|
252 |
val ytable = ref Inttab.empty
|
|
253 |
fun indexof s =
|
|
254 |
if String.size s = 0 then raise (No_name s)
|
|
255 |
else case Int.fromString (String.extract(s, 1, NONE)) of
|
|
256 |
SOME i => i | NONE => raise (No_name s)
|
|
257 |
|
|
258 |
fun nameof i =
|
|
259 |
let
|
|
260 |
val s = "x"^(Int.toString i)
|
|
261 |
val _ = ytable := (Inttab.update ((i, s), !ytable))
|
|
262 |
in
|
|
263 |
s
|
|
264 |
end
|
|
265 |
|
|
266 |
fun split_numstr s =
|
|
267 |
if String.isPrefix "-" s then (false,String.extract(s, 1, NONE))
|
|
268 |
else if String.isPrefix "+" s then (true, String.extract(s, 1, NONE))
|
|
269 |
else (true, s)
|
|
270 |
|
|
271 |
fun mk_term index s =
|
|
272 |
let
|
|
273 |
val (p, s) = split_numstr s
|
|
274 |
val prod = cplex.cplexProd (cplex.cplexNum s, cplex.cplexVar (nameof index))
|
|
275 |
in
|
|
276 |
if p then prod else cplex.cplexNeg prod
|
|
277 |
end
|
|
278 |
|
|
279 |
fun vec2sum vector =
|
|
280 |
cplex.cplexSum (Inttab.foldl (fn (list, (index, s)) => (mk_term index s)::list) ([], vector))
|
|
281 |
|
|
282 |
fun mk_constr index vector c =
|
|
283 |
let
|
|
284 |
val s = case Inttab.lookup (c, index) of SOME s => s | NONE => "0"
|
|
285 |
val (p, s) = split_numstr s
|
|
286 |
val num = if p then cplex.cplexNum s else cplex.cplexNeg (cplex.cplexNum s)
|
|
287 |
in
|
|
288 |
(NONE, cplex.cplexConstr (cplex.cplexLeq, (vec2sum vector, num)))
|
|
289 |
end
|
|
290 |
|
|
291 |
fun delete index c = Inttab.delete index c handle Inttab.UNDEF _ => c
|
|
292 |
|
|
293 |
val (list, b) = Inttab.foldl
|
|
294 |
(fn ((list, c), (index, v)) => ((mk_constr index v c)::list, delete index c))
|
|
295 |
(([], b), A)
|
|
296 |
val _ = if Inttab.is_empty b then () else raise Superfluous_constr_right_hand_sides
|
|
297 |
|
|
298 |
fun mk_free y = cplex.cplexBounds (cplex.cplexNeg cplex.cplexInf, cplex.cplexLeq,
|
|
299 |
cplex.cplexVar y, cplex.cplexLeq,
|
|
300 |
cplex.cplexInf)
|
|
301 |
|
|
302 |
val yvars = Inttab.foldl (fn (l, (i, y)) => (mk_free y)::l) ([], !ytable)
|
|
303 |
|
|
304 |
val prog = cplex.cplexProg ("original", cplex.cplexMaximize (vec2sum c), list, yvars)
|
|
305 |
in
|
|
306 |
(prog, indexof)
|
|
307 |
end
|
|
308 |
|
|
309 |
|
|
310 |
fun dual_cplexProg c A b =
|
|
311 |
let
|
|
312 |
fun indexof s =
|
|
313 |
if String.size s = 0 then raise (No_name s)
|
|
314 |
else case Int.fromString (String.extract(s, 1, NONE)) of
|
|
315 |
SOME i => i | NONE => raise (No_name s)
|
|
316 |
|
|
317 |
fun nameof i = "y"^(Int.toString i)
|
|
318 |
|
|
319 |
fun split_numstr s =
|
|
320 |
if String.isPrefix "-" s then (false,String.extract(s, 1, NONE))
|
|
321 |
else if String.isPrefix "+" s then (true, String.extract(s, 1, NONE))
|
|
322 |
else (true, s)
|
|
323 |
|
|
324 |
fun mk_term index s =
|
|
325 |
let
|
|
326 |
val (p, s) = split_numstr s
|
|
327 |
val prod = cplex.cplexProd (cplex.cplexNum s, cplex.cplexVar (nameof index))
|
|
328 |
in
|
|
329 |
if p then prod else cplex.cplexNeg prod
|
|
330 |
end
|
|
331 |
|
|
332 |
fun vec2sum vector =
|
|
333 |
cplex.cplexSum (Inttab.foldl (fn (list, (index, s)) => (mk_term index s)::list) ([], vector))
|
|
334 |
|
|
335 |
fun mk_constr index vector c =
|
|
336 |
let
|
|
337 |
val s = case Inttab.lookup (c, index) of SOME s => s | NONE => "0"
|
|
338 |
val (p, s) = split_numstr s
|
|
339 |
val num = if p then cplex.cplexNum s else cplex.cplexNeg (cplex.cplexNum s)
|
|
340 |
in
|
|
341 |
(NONE, cplex.cplexConstr (cplex.cplexEq, (vec2sum vector, num)))
|
|
342 |
end
|
|
343 |
|
|
344 |
fun delete index c = Inttab.delete index c handle Inttab.UNDEF _ => c
|
|
345 |
|
|
346 |
val (list, c) = Inttab.foldl
|
|
347 |
(fn ((list, c), (index, v)) => ((mk_constr index v c)::list, delete index c))
|
|
348 |
(([], c), transpose_matrix A)
|
|
349 |
val _ = if Inttab.is_empty c then () else raise Superfluous_constr_right_hand_sides
|
|
350 |
|
|
351 |
val prog = cplex.cplexProg ("dual", cplex.cplexMinimize (vec2sum b), list, [])
|
|
352 |
in
|
|
353 |
(prog, indexof)
|
|
354 |
end
|
|
355 |
|
|
356 |
fun cut_vector size v =
|
|
357 |
let
|
|
358 |
val count = ref 0
|
|
359 |
fun app (v, (i, s)) =
|
|
360 |
if (!count < size) then
|
|
361 |
(count := !count +1 ; Inttab.update ((i,s),v))
|
|
362 |
else
|
|
363 |
v
|
|
364 |
in
|
|
365 |
Inttab.foldl app (empty_vector, v)
|
|
366 |
end
|
|
367 |
|
|
368 |
fun cut_matrix vfilter vsize m =
|
|
369 |
let
|
|
370 |
fun app (m, (i, v)) =
|
|
371 |
if (Inttab.lookup (vfilter, i) = NONE) then
|
|
372 |
m
|
|
373 |
else
|
|
374 |
case vsize of
|
|
375 |
NONE => Inttab.update ((i,v), m)
|
|
376 |
| SOME s => Inttab.update((i, cut_vector s v),m)
|
|
377 |
in
|
|
378 |
Inttab.foldl app (empty_matrix, m)
|
|
379 |
end
|
|
380 |
|
|
381 |
fun v_elem_at v i = Inttab.lookup (v,i)
|
|
382 |
fun m_elem_at m i = Inttab.lookup (m,i)
|
|
383 |
|
|
384 |
fun v_only_elem v =
|
|
385 |
case Inttab.min_key v of
|
|
386 |
NONE => NONE
|
|
387 |
| SOME vmin => (case Inttab.max_key v of
|
|
388 |
NONE => SOME vmin
|
|
389 |
| SOME vmax => if vmin = vmax then SOME vmin else NONE)
|
|
390 |
|
|
391 |
fun v_fold f a v = Inttab.foldl f (a,v)
|
|
392 |
|
|
393 |
fun m_fold f a m = Inttab.foldl f (a,m)
|
|
394 |
|
|
395 |
end;
|