author | wenzelm |
Tue, 11 May 2021 20:19:07 +0200 | |
changeset 73675 | 6c56f2ebe157 |
parent 59058 | a78612c67ec0 |
permissions | -rw-r--r-- |
47455 | 1 |
(* Title: HOL/Matrix_LP/FloatSparseMatrixBuilder.ML |
16784 | 2 |
Author: Steven Obua |
3 |
*) |
|
4 |
||
46532 | 5 |
signature FLOAT_SPARSE_MATRIX_BUILDER = |
16784 | 6 |
sig |
22964 | 7 |
include MATRIX_BUILDER |
16784 | 8 |
|
22964 | 9 |
structure cplex : CPLEX |
16784 | 10 |
|
22964 | 11 |
type float = Float.float |
12 |
val approx_value : int -> (float -> float) -> string -> term * term |
|
13 |
val approx_vector : int -> (float -> float) -> vector -> term * term |
|
14 |
val approx_matrix : int -> (float -> float) -> matrix -> term * term |
|
16784 | 15 |
|
24630
351a308ab58d
simplified type int (eliminated IntInf.int, integer);
wenzelm
parents:
24302
diff
changeset
|
16 |
val mk_spvec_entry : int -> float -> term |
351a308ab58d
simplified type int (eliminated IntInf.int, integer);
wenzelm
parents:
24302
diff
changeset
|
17 |
val mk_spvec_entry' : int -> term -> term |
351a308ab58d
simplified type int (eliminated IntInf.int, integer);
wenzelm
parents:
24302
diff
changeset
|
18 |
val mk_spmat_entry : int -> term -> term |
22964 | 19 |
val spvecT: typ |
20 |
val spmatT: typ |
|
21 |
||
22 |
val v_elem_at : vector -> int -> string option |
|
23 |
val m_elem_at : matrix -> int -> vector option |
|
24 |
val v_only_elem : vector -> int option |
|
25 |
val v_fold : (int * string -> 'a -> 'a) -> vector -> 'a -> 'a |
|
26 |
val m_fold : (int * vector -> 'a -> 'a) -> matrix -> 'a -> 'a |
|
20485 | 27 |
|
22964 | 28 |
val transpose_matrix : matrix -> matrix |
16784 | 29 |
|
22964 | 30 |
val cut_vector : int -> vector -> vector |
31 |
val cut_matrix : vector -> int option -> matrix -> matrix |
|
22951 | 32 |
|
23883 | 33 |
val delete_matrix : int list -> matrix -> matrix |
34 |
val cut_matrix' : int list -> matrix -> matrix |
|
35 |
val delete_vector : int list -> vector -> vector |
|
36 |
val cut_vector' : int list -> vector -> vector |
|
37 |
||
38 |
val indices_of_matrix : matrix -> int list |
|
39 |
val indices_of_vector : vector -> int list |
|
40 |
||
22964 | 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 |
end; |
|
16784 | 46 |
|
46532 | 47 |
structure FloatSparseMatrixBuilder : FLOAT_SPARSE_MATRIX_BUILDER = |
16784 | 48 |
struct |
49 |
||
22964 | 50 |
type float = Float.float |
31971
8c1b845ed105
renamed functor TableFun to Table, and GraphFun to Graph;
wenzelm
parents:
24630
diff
changeset
|
51 |
structure Inttab = Table(type key = int val ord = rev_order o int_ord); |
16784 | 52 |
|
53 |
type vector = string Inttab.table |
|
54 |
type matrix = vector Inttab.table |
|
20485 | 55 |
|
22964 | 56 |
val spvec_elemT = HOLogic.mk_prodT (HOLogic.natT, HOLogic.realT); |
57 |
val spvecT = HOLogic.listT spvec_elemT; |
|
58 |
val spmat_elemT = HOLogic.mk_prodT (HOLogic.natT, spvecT); |
|
59 |
val spmatT = HOLogic.listT spmat_elemT; |
|
16784 | 60 |
|
22964 | 61 |
fun approx_value prec f = |
62 |
FloatArith.approx_float prec (fn (x, y) => (f x, f y)); |
|
16784 | 63 |
|
22951 | 64 |
fun mk_spvec_entry i f = |
22964 | 65 |
HOLogic.mk_prod (HOLogic.mk_number HOLogic.natT i, FloatArith.mk_float f); |
16784 | 66 |
|
24302 | 67 |
fun mk_spvec_entry' i x = |
68 |
HOLogic.mk_prod (HOLogic.mk_number HOLogic.natT i, x); |
|
69 |
||
22951 | 70 |
fun mk_spmat_entry i e = |
22964 | 71 |
HOLogic.mk_prod (HOLogic.mk_number HOLogic.natT i, e); |
16784 | 72 |
|
73 |
fun approx_vector prec pprt vector = |
|
22964 | 74 |
let |
75 |
fun app (index, s) (lower, upper) = |
|
76 |
let |
|
77 |
val (flower, fupper) = approx_value prec pprt s |
|
24630
351a308ab58d
simplified type int (eliminated IntInf.int, integer);
wenzelm
parents:
24302
diff
changeset
|
78 |
val index = HOLogic.mk_number HOLogic.natT index |
22964 | 79 |
val elower = HOLogic.mk_prod (index, flower) |
80 |
val eupper = HOLogic.mk_prod (index, fupper) |
|
81 |
in (elower :: lower, eupper :: upper) end; |
|
82 |
in |
|
59058
a78612c67ec0
renamed "pairself" to "apply2", in accordance to @{apply 2};
wenzelm
parents:
52049
diff
changeset
|
83 |
apply2 (HOLogic.mk_list spvec_elemT) (Inttab.fold app vector ([], [])) |
22964 | 84 |
end; |
16784 | 85 |
|
22964 | 86 |
fun approx_matrix prec pprt vector = |
87 |
let |
|
88 |
fun app (index, v) (lower, upper) = |
|
89 |
let |
|
90 |
val (flower, fupper) = approx_vector prec pprt v |
|
24630
351a308ab58d
simplified type int (eliminated IntInf.int, integer);
wenzelm
parents:
24302
diff
changeset
|
91 |
val index = HOLogic.mk_number HOLogic.natT index |
22964 | 92 |
val elower = HOLogic.mk_prod (index, flower) |
93 |
val eupper = HOLogic.mk_prod (index, fupper) |
|
94 |
in (elower :: lower, eupper :: upper) end; |
|
95 |
in |
|
59058
a78612c67ec0
renamed "pairself" to "apply2", in accordance to @{apply 2};
wenzelm
parents:
52049
diff
changeset
|
96 |
apply2 (HOLogic.mk_list spmat_elemT) (Inttab.fold app vector ([], [])) |
22964 | 97 |
end; |
16784 | 98 |
|
99 |
exception Nat_expected of int; |
|
100 |
||
22964 | 101 |
val zero_interval = approx_value 1 I "0" |
16784 | 102 |
|
22951 | 103 |
fun set_elem vector index str = |
104 |
if index < 0 then |
|
105 |
raise (Nat_expected index) |
|
22964 | 106 |
else if (approx_value 1 I str) = zero_interval then |
22951 | 107 |
vector |
108 |
else |
|
109 |
Inttab.update (index, str) vector |
|
16784 | 110 |
|
22951 | 111 |
fun set_vector matrix index vector = |
16784 | 112 |
if index < 0 then |
22951 | 113 |
raise (Nat_expected index) |
16784 | 114 |
else if Inttab.is_empty vector then |
22951 | 115 |
matrix |
16784 | 116 |
else |
22951 | 117 |
Inttab.update (index, vector) matrix |
16784 | 118 |
|
119 |
val empty_matrix = Inttab.empty |
|
120 |
val empty_vector = Inttab.empty |
|
121 |
||
122 |
(* dual stuff *) |
|
123 |
||
124 |
structure cplex = Cplex |
|
125 |
||
22951 | 126 |
fun transpose_matrix matrix = |
21056 | 127 |
let |
128 |
fun upd j (i, s) = |
|
129 |
Inttab.map_default (i, Inttab.empty) (Inttab.update (j, s)); |
|
130 |
fun updm (j, v) = Inttab.fold (upd j) v; |
|
131 |
in Inttab.fold updm matrix empty_matrix end; |
|
16784 | 132 |
|
133 |
exception No_name of string; |
|
134 |
||
135 |
exception Superfluous_constr_right_hand_sides |
|
136 |
||
22951 | 137 |
fun cplexProg c A b = |
16784 | 138 |
let |
32740 | 139 |
val ytable = Unsynchronized.ref Inttab.empty |
22951 | 140 |
fun indexof s = |
141 |
if String.size s = 0 then raise (No_name s) |
|
142 |
else case Int.fromString (String.extract(s, 1, NONE)) of |
|
143 |
SOME i => i | NONE => raise (No_name s) |
|
16784 | 144 |
|
22951 | 145 |
fun nameof i = |
146 |
let |
|
41491 | 147 |
val s = "x" ^ string_of_int i |
32740 | 148 |
val _ = Unsynchronized.change ytable (Inttab.update (i, s)) |
22951 | 149 |
in |
150 |
s |
|
151 |
end |
|
152 |
||
153 |
fun split_numstr s = |
|
154 |
if String.isPrefix "-" s then (false,String.extract(s, 1, NONE)) |
|
155 |
else if String.isPrefix "+" s then (true, String.extract(s, 1, NONE)) |
|
156 |
else (true, s) |
|
157 |
||
158 |
fun mk_term index s = |
|
159 |
let |
|
160 |
val (p, s) = split_numstr s |
|
161 |
val prod = cplex.cplexProd (cplex.cplexNum s, cplex.cplexVar (nameof index)) |
|
162 |
in |
|
163 |
if p then prod else cplex.cplexNeg prod |
|
164 |
end |
|
16784 | 165 |
|
22951 | 166 |
fun vec2sum vector = |
167 |
cplex.cplexSum (Inttab.fold (fn (index, s) => fn list => (mk_term index s) :: list) vector []) |
|
16784 | 168 |
|
22951 | 169 |
fun mk_constr index vector c = |
170 |
let |
|
171 |
val s = case Inttab.lookup c index of SOME s => s | NONE => "0" |
|
172 |
val (p, s) = split_numstr s |
|
173 |
val num = if p then cplex.cplexNum s else cplex.cplexNeg (cplex.cplexNum s) |
|
174 |
in |
|
175 |
(NONE, cplex.cplexConstr (cplex.cplexLeq, (vec2sum vector, num))) |
|
176 |
end |
|
177 |
||
178 |
fun delete index c = Inttab.delete index c handle Inttab.UNDEF _ => c |
|
16784 | 179 |
|
22951 | 180 |
val (list, b) = Inttab.fold |
181 |
(fn (index, v) => fn (list, c) => ((mk_constr index v c)::list, delete index c)) |
|
182 |
A ([], b) |
|
183 |
val _ = if Inttab.is_empty b then () else raise Superfluous_constr_right_hand_sides |
|
16784 | 184 |
|
22951 | 185 |
fun mk_free y = cplex.cplexBounds (cplex.cplexNeg cplex.cplexInf, cplex.cplexLeq, |
186 |
cplex.cplexVar y, cplex.cplexLeq, |
|
187 |
cplex.cplexInf) |
|
16784 | 188 |
|
46531 | 189 |
val yvars = Inttab.fold (fn (_, y) => fn l => (mk_free y)::l) (!ytable) [] |
16784 | 190 |
|
22951 | 191 |
val prog = cplex.cplexProg ("original", cplex.cplexMaximize (vec2sum c), list, yvars) |
16784 | 192 |
in |
22951 | 193 |
(prog, indexof) |
16784 | 194 |
end |
195 |
||
196 |
||
22951 | 197 |
fun dual_cplexProg c A b = |
16784 | 198 |
let |
22951 | 199 |
fun indexof s = |
200 |
if String.size s = 0 then raise (No_name s) |
|
201 |
else case Int.fromString (String.extract(s, 1, NONE)) of |
|
202 |
SOME i => i | NONE => raise (No_name s) |
|
203 |
||
41491 | 204 |
fun nameof i = "y" ^ string_of_int i |
16784 | 205 |
|
22951 | 206 |
fun split_numstr s = |
207 |
if String.isPrefix "-" s then (false,String.extract(s, 1, NONE)) |
|
208 |
else if String.isPrefix "+" s then (true, String.extract(s, 1, NONE)) |
|
209 |
else (true, s) |
|
210 |
||
211 |
fun mk_term index s = |
|
212 |
let |
|
213 |
val (p, s) = split_numstr s |
|
214 |
val prod = cplex.cplexProd (cplex.cplexNum s, cplex.cplexVar (nameof index)) |
|
215 |
in |
|
216 |
if p then prod else cplex.cplexNeg prod |
|
217 |
end |
|
16784 | 218 |
|
22951 | 219 |
fun vec2sum vector = |
220 |
cplex.cplexSum (Inttab.fold (fn (index, s) => fn list => (mk_term index s)::list) vector []) |
|
16784 | 221 |
|
22951 | 222 |
fun mk_constr index vector c = |
223 |
let |
|
224 |
val s = case Inttab.lookup c index of SOME s => s | NONE => "0" |
|
225 |
val (p, s) = split_numstr s |
|
226 |
val num = if p then cplex.cplexNum s else cplex.cplexNeg (cplex.cplexNum s) |
|
227 |
in |
|
228 |
(NONE, cplex.cplexConstr (cplex.cplexEq, (vec2sum vector, num))) |
|
229 |
end |
|
16784 | 230 |
|
22951 | 231 |
fun delete index c = Inttab.delete index c handle Inttab.UNDEF _ => c |
16784 | 232 |
|
22951 | 233 |
val (list, c) = Inttab.fold |
234 |
(fn (index, v) => fn (list, c) => ((mk_constr index v c)::list, delete index c)) |
|
235 |
(transpose_matrix A) ([], c) |
|
236 |
val _ = if Inttab.is_empty c then () else raise Superfluous_constr_right_hand_sides |
|
237 |
||
238 |
val prog = cplex.cplexProg ("dual", cplex.cplexMinimize (vec2sum b), list, []) |
|
16784 | 239 |
in |
22951 | 240 |
(prog, indexof) |
16784 | 241 |
end |
242 |
||
22951 | 243 |
fun cut_vector size v = |
21056 | 244 |
let |
32740 | 245 |
val count = Unsynchronized.ref 0; |
21056 | 246 |
fun app (i, s) = if (!count < size) then |
247 |
(count := !count +1 ; Inttab.update (i, s)) |
|
248 |
else I |
|
249 |
in |
|
250 |
Inttab.fold app v empty_vector |
|
251 |
end |
|
16784 | 252 |
|
22951 | 253 |
fun cut_matrix vfilter vsize m = |
21056 | 254 |
let |
22951 | 255 |
fun app (i, v) = |
21056 | 256 |
if is_none (Inttab.lookup vfilter i) then I |
257 |
else case vsize |
|
258 |
of NONE => Inttab.update (i, v) |
|
259 |
| SOME s => Inttab.update (i, cut_vector s v) |
|
260 |
in Inttab.fold app m empty_matrix end |
|
261 |
||
17412 | 262 |
fun v_elem_at v i = Inttab.lookup v i |
263 |
fun m_elem_at m i = Inttab.lookup m i |
|
16784 | 264 |
|
22951 | 265 |
fun v_only_elem v = |
52049 | 266 |
case Inttab.min v of |
22951 | 267 |
NONE => NONE |
52049 | 268 |
| SOME (vmin, _) => (case Inttab.max v of |
22951 | 269 |
NONE => SOME vmin |
52049 | 270 |
| SOME (vmax, _) => if vmin = vmax then SOME vmin else NONE) |
16784 | 271 |
|
21056 | 272 |
fun v_fold f = Inttab.fold f; |
273 |
fun m_fold f = Inttab.fold f; |
|
16784 | 274 |
|
23883 | 275 |
fun indices_of_vector v = Inttab.keys v |
276 |
fun indices_of_matrix m = Inttab.keys m |
|
277 |
fun delete_vector indices v = fold Inttab.delete indices v |
|
278 |
fun delete_matrix indices m = fold Inttab.delete indices m |
|
46531 | 279 |
fun cut_matrix' indices _ = fold (fn i => fn m => (case Inttab.lookup m i of NONE => m | SOME v => Inttab.update (i, v) m)) indices Inttab.empty |
280 |
fun cut_vector' indices _ = fold (fn i => fn v => (case Inttab.lookup v i of NONE => v | SOME x => Inttab.update (i, x) v)) indices Inttab.empty |
|
23883 | 281 |
|
282 |
||
283 |
||
16784 | 284 |
end; |