sdpa-python 0.2.2__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sdpap/convert.py ADDED
@@ -0,0 +1,348 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Convert CLP format to SeDuMi format
4
+
5
+ These routines were originally implemented in SparseCoLO (MATLAB) [1] and are
6
+ Copyright (C) 2009 Masakazu Kojima Group
7
+ Department of Mathematical and Computing Sciences, Tokyo Institute of Technology
8
+
9
+ SparseCoLO [1] implements sparsity exploitation algorithms in [2]
10
+
11
+ Python translations of routines written for SDPAP and are
12
+ Copyright (C) 2010-2022 SDPA Project
13
+
14
+ [1] http://www.opt.c.titech.ac.jp/kojima/SparseCoLO/SparseCoLO.htm
15
+ [2] Sunyoung Kim, Masakazu Kojima, Martin Mevissen and Makoto Yamashita, "Exploiting sparsity in linear and nonlinear matrix inequalities via positive semidefinite matrix completion," Mathematical Programming, 129(1), 33–68. https://doi.org/10.1007/s10107-010-0402-6
16
+
17
+ This program is free software; you can redistribute it and/or modify
18
+ it under the terms of the GNU General Public License as published by
19
+ the Free Software Foundation; either version 2 of the License, or
20
+ (at your option) any later version.
21
+
22
+ This program is distributed in the hope that it will be useful,
23
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
24
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
+ GNU General Public License for more details.
26
+
27
+ You should have received a copy of the GNU General Public License along
28
+ with this program; if not, write to the Free Software Foundation, Inc.,
29
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30
+
31
+ September 2010: `clp_toLMI` and `result_fromLMI` written by Kenta Kato
32
+ """
33
+
34
+ from .symcone import SymCone
35
+ from scipy.sparse import csc_matrix, bmat, eye
36
+ from scipy import sparse
37
+
38
+
39
+ def clp_toLMI(A, b, c, K, J):
40
+ """Convert from CLP format to LMI standard form (SeDuMi dual format).
41
+
42
+ Args:
43
+ A, b, c, K, J: CLP format
44
+
45
+ Returns:
46
+ A tuple (A2, b2, c2, K2, J2, map_sdpIndex). Each members are:
47
+ LMI standard form in SeDuMi dual format, (A2, b2, c2, K2, J2)
48
+ J2 has only an attribute 'f'
49
+ Index mapping from converted matrix to original matrix map_sdpIndex
50
+ """
51
+ # Type check
52
+ if not sparse.isspmatrix_csc(A):
53
+ A = A.tocsc()
54
+ if not sparse.isspmatrix_csc(b):
55
+ b = b.tocsc()
56
+ if not sparse.isspmatrix_csc(c):
57
+ c = c.tocsc()
58
+ if not K.check_validity() or not J.check_validity():
59
+ print('clp_toLMI(): K or J is invalid.')
60
+ return
61
+
62
+ # Get size
63
+ size_m, size_n = A.shape
64
+
65
+ K_f = K.f
66
+ K_l = K.l
67
+ K_q = sum(K.q)
68
+ K_s = sum([i ** 2 for i in K.s])
69
+
70
+ J_f = J.f
71
+ J_l = J.l
72
+ J_q = sum(J.q)
73
+ J_s = sum([i ** 2 for i in J.s])
74
+
75
+ # ----------------------------------------
76
+ # Make converted K.s part
77
+ # ----------------------------------------
78
+ if len(K.s) > 0:
79
+ # Make index mapping from converted index to original index
80
+ map_sdpIndex = [0] * sum([k * (k + 1) / 2 for k in K.s])
81
+ offset = 0
82
+ for k in K.s:
83
+ for i in range(k):
84
+ for j in range(i):
85
+ idx1 = i * k + j
86
+ idx2 = j * k + i
87
+ map_sdpIndex[i * (i + 1) / 2 + j + offset] = (idx1, idx2)
88
+ # i == j case
89
+ idx = i * k + i
90
+ map_sdpIndex[i * (i + 1) / 2 + i + offset] = (idx, idx)
91
+ offset += k * (k + 1) / 2
92
+
93
+ # Split matrix
94
+ c_flq = c[0:(K_f + K_l + K_q), :]
95
+ c_s = c[(K_f + K_l + K_q):, :]
96
+ A_flq = A[:, 0:(K_f + K_l + K_q)]
97
+ A_s = A[:, (K_f + K_l + K_q):]
98
+
99
+ # To make converted matrix
100
+ convcs_row = []
101
+ convcs_val = []
102
+ convAs_row = []
103
+ convAs_col = []
104
+ convAs_val = []
105
+ addAs_row = []
106
+ addAs_col = []
107
+ col_ptr = 0
108
+ offset_row = 0
109
+ offset_col = 0
110
+ else:
111
+ map_sdpIndex = None
112
+
113
+ for sDim in K.s:
114
+ A_block = A_s[:, col_ptr:(col_ptr + sDim ** 2)]
115
+ c_block = c_s[col_ptr:(col_ptr + sDim ** 2)]
116
+
117
+ # Make conv_cs
118
+ for (row, val) in zip(c_block.nonzero()[0], c_block.data):
119
+ i = row // sDim
120
+ j = row % sDim
121
+ if i >= j:
122
+ convcs_row.append(i * (i + 1) / 2 + j + offset_col)
123
+ convcs_val.append(val * 2 if i > j else val)
124
+
125
+ # Make conv_As
126
+ for (row, col, val) in zip(A_block.nonzero()[0], A_block.nonzero()[1],
127
+ A_block.data):
128
+ i = col // sDim
129
+ j = col % sDim
130
+ if i >= j:
131
+ convAs_row.append(row)
132
+ convAs_col.append(i * (i + 1) / 2 + j + offset_col)
133
+ convAs_val.append(val * 2 if i > j else val)
134
+
135
+ # Make add_As
136
+ for i in range(sDim):
137
+ for j in range(i):
138
+ addAs_row.extend([i * sDim + j + offset_row,
139
+ j * sDim + i + offset_row])
140
+ idx = i * (i + 1) / 2 + j + offset_col
141
+ addAs_col.extend([idx, idx])
142
+ # i == j case
143
+ addAs_row.append(i * sDim + i + offset_row)
144
+ addAs_col.append(i * (i + 1) / 2 + i + offset_col)
145
+
146
+ col_ptr += sDim ** 2
147
+ offset_row += sDim ** 2
148
+ offset_col += sDim * (sDim + 1) / 2
149
+
150
+ # ----------------------------------------
151
+ # Make converted matrix
152
+ # ----------------------------------------
153
+ # A2
154
+ if K_s > 0:
155
+ newJ_s = offset_row
156
+ newK_s = offset_col
157
+ sub_A = csc_matrix((convAs_val, (convAs_row, convAs_col)),
158
+ shape=(size_m, newK_s))
159
+ sub_As = csc_matrix(([1.0] * len(addAs_row), (addAs_row, addAs_col)),
160
+ shape=(newJ_s, newK_s))
161
+ new_A = bmat([[A_flq, sub_A]])
162
+ else:
163
+ newJ_s = 0
164
+ newK_s = 0
165
+ new_A = A
166
+
167
+ if not sparse.isspmatrix_csc(new_A):
168
+ new_A = new_A.tocsc()
169
+
170
+ list_A2 = []
171
+ list_c2 = []
172
+ if J_f > 0:
173
+ A_f = new_A[0:(J_f), :]
174
+ list_A2.append(-A_f.T)
175
+ b_f = b[0:(J_f), :]
176
+ list_c2.append([-b_f])
177
+
178
+ if J_l > 0:
179
+ A_l = new_A[(J_f):(J_f + J_l), :]
180
+ list_A2.append(-A_l.T)
181
+ b_l = b[(J_f):(J_f + J_l), :]
182
+ list_c2.append([-b_l])
183
+
184
+ if K_l > 0:
185
+ list_subAl = []
186
+ if K_f > 0:
187
+ list_subAl.append([csc_matrix((K_f, K_l))])
188
+ list_subAl.append([eye(K_l, K_l, format='csc')])
189
+ if K_q + newK_s > 0:
190
+ list_subAl.append([csc_matrix((K_q + newK_s, K_l))])
191
+ sub_Al = bmat(list_subAl)
192
+ list_A2.append(-sub_Al)
193
+ list_c2.append([csc_matrix((K_l, 1))])
194
+
195
+ if J_q > 0:
196
+ A_q = new_A[(J_f + J_l):(J_f + J_l + J_q), :]
197
+ list_A2.append(-A_q.T)
198
+ b_q = b[(J_f + J_l):(J_f + J_l + J_q), :]
199
+ list_c2.append([-b_q])
200
+
201
+ if K_q > 0:
202
+ list_subAq = []
203
+ if K_f + K_l > 0:
204
+ list_subAq.append([csc_matrix((K_f + K_l, K_q))])
205
+ list_subAq.append([eye(K_q, K_q, format='csc')])
206
+ if K_s > 0:
207
+ list_subAq.append([csc_matrix((newK_s, K_q))])
208
+ sub_Aq = bmat(list_subAq)
209
+ list_A2.append(-sub_Aq)
210
+ list_c2.append([csc_matrix((K_q, 1))])
211
+
212
+ if J_s > 0:
213
+ A_s = new_A[(J_f + J_l + J_q):, :]
214
+ list_A2.append(-A_s.T)
215
+ b_s = b[(J_f + J_l + J_q):, :]
216
+ list_c2.append([-b_s])
217
+
218
+ if K_s > 0:
219
+ list_subAs = []
220
+ if K_f + K_l + K_q > 0:
221
+ list_subAs.append([csc_matrix((K_f + K_l + K_q, K_s))])
222
+ list_subAs.append([sub_As.T])
223
+ sub_As = bmat(list_subAs)
224
+ list_A2.append(-sub_As)
225
+ list_c2.append([csc_matrix((K_s, 1))])
226
+
227
+ A2 = bmat([list_A2])
228
+ c2 = bmat(list_c2)
229
+
230
+ if newK_s > 0:
231
+ conv_cs = csc_matrix((convcs_val, (convcs_row, [0] * len(convcs_row))),
232
+ shape=(newK_s, 1))
233
+ b2 = -bmat([[c_flq],
234
+ [conv_cs]])
235
+ else:
236
+ b2 = -c
237
+
238
+ K2 = SymCone()
239
+ K2.f = J.f
240
+ K2.l = J.l + K.l
241
+ K2.q = J.q + K.q
242
+ K2.s = J.s + K.s
243
+
244
+ J2 = SymCone()
245
+ J2.f = A2.shape[0]
246
+
247
+ return A2, b2, c2, K2, J2, map_sdpIndex
248
+
249
+
250
+ def clp_toEQ(A, b, c, K, J):
251
+ """Convert from CLP format to Equality standard form (Sedumi primal format)
252
+
253
+ THIS FUNCTION HAS NOT IMPLEMENTED YET.
254
+
255
+ Args:
256
+ A, b, c, K, J: CLP format
257
+
258
+ Returns:
259
+ Equality standard form in SeDuMi primal format, (A2, b2, c2, K2, J2)
260
+ """
261
+ ##################################################
262
+ # Under construction
263
+ ##################################################
264
+ print('THIS FUNCTION HAS NOT IMPLEMENTED YET.')
265
+ return A2, b2, c2, K2, J2
266
+
267
+
268
+ def result_fromLMI(x2, y2, K, J, map_sdpIndex):
269
+ """Get result of CLP from result of converted problem by clp_toLMI().
270
+
271
+ Args:
272
+ x2, y2: Result of converted problem by clp_toLMI()
273
+ K, J : SymCone of CLP
274
+ map_sdpIndex: Index mapping from converted matrix to original matrix
275
+
276
+ Returns:
277
+ Result of CLP, (x, y)
278
+ """
279
+ # Type check
280
+ if not sparse.isspmatrix_csc(x2):
281
+ x2 = x2.tocsc()
282
+ if not sparse.isspmatrix_csc(y2):
283
+ y2 = y2.tocsc()
284
+
285
+ if len(K.s) > 0:
286
+ K_f = K.f
287
+ K_l = K.l
288
+ K_q = sum(K.q)
289
+ K_s = sum([i ** 2 for i in K.s])
290
+
291
+ x_flq = y2[:(K.f + K.l + K_q)]
292
+ x_s = y2[(K.f + K.l + K_q):]
293
+ x_row = []
294
+ x_val = []
295
+ for (row, val) in zip(x_s.nonzero()[0], x_s.data):
296
+ (idx1, idx2) = map_sdpIndex[row]
297
+ if idx1 != idx2:
298
+ x_row.extend([idx1, idx2])
299
+ x_val.extend([val, val])
300
+ else:
301
+ x_row.append(idx1)
302
+ x_val.append(val)
303
+
304
+ x = bmat([[x_flq],
305
+ [csc_matrix((x_val, (x_row, [0] * len(x_row))),
306
+ shape=(K_s, 1))]])
307
+ else:
308
+ x = y2
309
+
310
+ size_Jq = sum(J.q)
311
+ size_Js = sum([z ** 2 for z in J.s])
312
+ size_Kq = sum(K.q)
313
+
314
+ y_list = []
315
+ if J.f + J.l > 0:
316
+ yfl = x2[:(J.f + J.l)]
317
+ y_list.append([yfl])
318
+
319
+ if size_Jq > 0:
320
+ yq = x2[(J.f + J.l + K.l):(J.f + J.l + K.l + size_Jq)]
321
+ y_list.append([yq])
322
+
323
+ if size_Js > 0:
324
+ ys = x2[(J.f + J.l + K.l + size_Jq + size_Kq):
325
+ (J.f + J.l + K.l + size_Jq + size_Kq + size_Js)]
326
+ y_list.append([ys])
327
+
328
+ y = bmat(y_list)
329
+ return x, y
330
+
331
+ def result_fromEQ(x2, y2, K, J):
332
+ """Get result of CLP from result of converted problem by clp_toEQ().
333
+
334
+ THIS FUNCTION HAS NOT IMPLEMENTED YET.
335
+
336
+ Args:
337
+ x2, y2: Result of converted problem by clp_toEQ()
338
+ K, J : SymCone of CLP
339
+
340
+ Returns:
341
+ x, y : Result of CLP, (x, y)
342
+ """
343
+ ##################################################
344
+ # Under construction
345
+ ##################################################
346
+ print('THIS FUNCTION HAS NOT IMPLEMENTED YET.')
347
+ return x, y
348
+