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.
- sdpa_python-0.2.2.dist-info/LICENSE +339 -0
- sdpa_python-0.2.2.dist-info/METADATA +69 -0
- sdpa_python-0.2.2.dist-info/RECORD +24 -0
- sdpa_python-0.2.2.dist-info/WHEEL +5 -0
- sdpa_python-0.2.2.dist-info/top_level.txt +1 -0
- sdpap/__init__.py +28 -0
- sdpap/convert.py +348 -0
- sdpap/fileio.py +836 -0
- sdpap/fvelim/__init__.py +24 -0
- sdpap/fvelim/fvelim.py +256 -0
- sdpap/fvelim/fvelimext.cp313-win_amd64.pyd +0 -0
- sdpap/matdata.py +80 -0
- sdpap/param.py +366 -0
- sdpap/sdpacall/__init__.py +24 -0
- sdpap/sdpacall/sdpa.cp313-win_amd64.pyd +0 -0
- sdpap/sdpacall/sdpacall.py +71 -0
- sdpap/sdpap.py +450 -0
- sdpap/sdpaputils.py +140 -0
- sdpap/spcolo/__init__.py +26 -0
- sdpap/spcolo/asputils.py +182 -0
- sdpap/spcolo/clique.py +68 -0
- sdpap/spcolo/spcolo.py +356 -0
- sdpap/spcolo/spcoloext.cp313-win_amd64.pyd +0 -0
- sdpap/symcone.py +157 -0
sdpap/fileio.py
ADDED
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Routines to read/write files from/to CLP and SDPA sparse format
|
|
4
|
+
This file is a component of SDPAP
|
|
5
|
+
Copyright (C) 2010-2022 SDPA Project
|
|
6
|
+
|
|
7
|
+
This program is free software; you can redistribute it and/or modify
|
|
8
|
+
it under the terms of the GNU General Public License as published by
|
|
9
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
10
|
+
(at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License along
|
|
18
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
19
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20
|
+
|
|
21
|
+
September 2010: Originally written by Kenta Kato
|
|
22
|
+
December 2010: Modified for SciPy
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__all__ = ['readproblem', 'writeproblem', 'fromsdpa', 'tosdpa', 'importsdpa', 'exportsdpa']
|
|
26
|
+
|
|
27
|
+
from . import convert
|
|
28
|
+
from .symcone import SymCone
|
|
29
|
+
from scipy.sparse import csc_matrix, csr_matrix
|
|
30
|
+
from scipy import sparse
|
|
31
|
+
import warnings
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def readproblem(filename):
|
|
35
|
+
"""Read problem file and make CLP
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
filename: A string of file pass for CLP format problem
|
|
39
|
+
Input file format:
|
|
40
|
+
J.f
|
|
41
|
+
J.l
|
|
42
|
+
J.q -> Each numbers are split by " "(white space).
|
|
43
|
+
If J.q = (), write 0.
|
|
44
|
+
J.s -> Each numbers are split by " ". if J.s = (), write 0.
|
|
45
|
+
K.f
|
|
46
|
+
K.l
|
|
47
|
+
K.q -> Each numbers are split by " ". if K.q = (), write 0.
|
|
48
|
+
K.s -> Each numbers are split by " ". if K.s = (), write 0.
|
|
49
|
+
ROW COL row col val -> Each numbers are split by " ".
|
|
50
|
+
ROW COL row col val
|
|
51
|
+
: : : : :
|
|
52
|
+
: : : : :
|
|
53
|
+
|
|
54
|
+
(ROW,COL,row,col,val) means:
|
|
55
|
+
The value of (row,col) element in (ROW,COL) block of A is val
|
|
56
|
+
(ROW,COL,row,col are indexed 1,2,3,...)
|
|
57
|
+
If ROW = 0: the value of col's element in
|
|
58
|
+
COL's block of c is val (row = 0(recommended))
|
|
59
|
+
If COL = 0: the value of row's element in
|
|
60
|
+
ROW's block of b is val (col = 0(recommended))
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
A tuple of CLP problem input (A, b, c, K, J)
|
|
64
|
+
"""
|
|
65
|
+
if not isinstance(filename, str):
|
|
66
|
+
print("readproblem(): filename must be string.")
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
fp = open(filename, "r")
|
|
70
|
+
# Read J
|
|
71
|
+
J_f = int(fp.readline())
|
|
72
|
+
J_l = int(fp.readline())
|
|
73
|
+
line = [int(x) for x in fp.readline().rstrip().split(" ")]
|
|
74
|
+
J_q = tuple(line) if line[0] != 0 else ()
|
|
75
|
+
line = [int(x) for x in fp.readline().rstrip().split(" ")]
|
|
76
|
+
J_s = tuple(line) if line[0] != 0 else ()
|
|
77
|
+
J = SymCone(J_f, J_l, J_q, J_s)
|
|
78
|
+
|
|
79
|
+
# Read K
|
|
80
|
+
K_f = int(fp.readline())
|
|
81
|
+
K_l = int(fp.readline())
|
|
82
|
+
line = [int(x) for x in fp.readline().rstrip().split(" ")]
|
|
83
|
+
K_q = tuple(line) if line[0] != 0 else ()
|
|
84
|
+
line = [int(x) for x in fp.readline().rstrip().split(" ")]
|
|
85
|
+
K_s = tuple(line) if line[0] != 0 else ()
|
|
86
|
+
K = SymCone(K_f, K_l, K_q, K_s)
|
|
87
|
+
|
|
88
|
+
start_row = [0]
|
|
89
|
+
if J.f != 0:
|
|
90
|
+
start_row.append(J.f)
|
|
91
|
+
|
|
92
|
+
if J.l != 0:
|
|
93
|
+
start_row.append(start_row[-1] + J.l)
|
|
94
|
+
|
|
95
|
+
for k in J.q:
|
|
96
|
+
start_row.append(start_row[-1] + k)
|
|
97
|
+
|
|
98
|
+
for k in J.s:
|
|
99
|
+
start_row.append(start_row[-1] + k ** 2)
|
|
100
|
+
|
|
101
|
+
start_col = [0]
|
|
102
|
+
if K.f != 0:
|
|
103
|
+
start_col.append(K.f)
|
|
104
|
+
|
|
105
|
+
if K.l != 0:
|
|
106
|
+
start_col.append(start_col[-1] + K.l)
|
|
107
|
+
|
|
108
|
+
for k in K.q:
|
|
109
|
+
start_col.append(start_col[-1] + k)
|
|
110
|
+
|
|
111
|
+
for k in K.s:
|
|
112
|
+
start_col.append(start_col[-1] + k ** 2)
|
|
113
|
+
|
|
114
|
+
size_row = J.f + J.l + sum(J.q) + sum([k ** 2 for k in J.s])
|
|
115
|
+
size_col = K.f + K.l + sum(K.q) + sum([k ** 2 for k in K.s])
|
|
116
|
+
|
|
117
|
+
# Read I,J,i,j,v
|
|
118
|
+
A_row = []
|
|
119
|
+
A_col = []
|
|
120
|
+
A_val = []
|
|
121
|
+
b_index = []
|
|
122
|
+
b_val = []
|
|
123
|
+
c_index = []
|
|
124
|
+
c_val = []
|
|
125
|
+
|
|
126
|
+
for line in fp.readlines():
|
|
127
|
+
ROW, COL, row, col, val = line.rstrip().split(" ")[0:5]
|
|
128
|
+
if float(val)==0:
|
|
129
|
+
continue
|
|
130
|
+
if int(ROW) == 0:
|
|
131
|
+
c_index.append(start_col[int(COL) - 1] + int(col) - 1)
|
|
132
|
+
c_val.append(float(val))
|
|
133
|
+
elif int(COL) == 0:
|
|
134
|
+
b_index.append(start_row[int(ROW) - 1] + int(row) - 1)
|
|
135
|
+
b_val.append(float(val))
|
|
136
|
+
else:
|
|
137
|
+
A_row.append(start_row[int(ROW) - 1] + int(row) - 1)
|
|
138
|
+
A_col.append(start_col[int(COL) - 1] + int(col) - 1)
|
|
139
|
+
A_val.append(float(val))
|
|
140
|
+
|
|
141
|
+
A = csc_matrix((A_val, (A_row, A_col)), shape=(size_row, size_col))
|
|
142
|
+
b = csc_matrix((b_val, (b_index, [0] * len(b_index))), shape=(size_row, 1))
|
|
143
|
+
c = csc_matrix((c_val, (c_index, [0] * len(c_index))), shape=(size_col, 1))
|
|
144
|
+
|
|
145
|
+
fp.close()
|
|
146
|
+
|
|
147
|
+
return A, b, c, K, J
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def writeproblem(filename, A, b, c, K, J, accuracy="%+8.16e"):
|
|
151
|
+
"""Write CLP to file
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
filename: A string of file pass
|
|
155
|
+
A, b, c: Scipy matrices to denote the CLP
|
|
156
|
+
K, J: Symcone object to denote the CLP
|
|
157
|
+
accuracy: Print format
|
|
158
|
+
"""
|
|
159
|
+
if not isinstance(filename, str):
|
|
160
|
+
raise ValueError("writeproblem(): filename must be string.")
|
|
161
|
+
|
|
162
|
+
if not sparse.isspmatrix_csc(b):
|
|
163
|
+
b = csc_matrix(b)
|
|
164
|
+
|
|
165
|
+
if not sparse.isspmatrix_csc(c):
|
|
166
|
+
c = csc_matrix(c)
|
|
167
|
+
|
|
168
|
+
if not sparse.isspmatrix_csr(A):
|
|
169
|
+
A = csr_matrix(A)
|
|
170
|
+
|
|
171
|
+
fp = open(filename, "w")
|
|
172
|
+
# Write J
|
|
173
|
+
fp.write(str(J.f) + "\n")
|
|
174
|
+
fp.write(str(J.l) + "\n")
|
|
175
|
+
if len(J.q) > 0:
|
|
176
|
+
fp.write(" ".join([str(num) for num in J.q]) + "\n")
|
|
177
|
+
else:
|
|
178
|
+
fp.write("0\n")
|
|
179
|
+
if len(J.s) > 0:
|
|
180
|
+
fp.write(" ".join([str(num) for num in J.s]) + "\n")
|
|
181
|
+
else:
|
|
182
|
+
fp.write("0\n")
|
|
183
|
+
|
|
184
|
+
# Write K
|
|
185
|
+
fp.write(str(K.f) + "\n")
|
|
186
|
+
fp.write(str(K.l) + "\n")
|
|
187
|
+
if len(K.q) > 0:
|
|
188
|
+
fp.write(" ".join([str(num) for num in K.q]) + "\n")
|
|
189
|
+
else:
|
|
190
|
+
fp.write("0\n")
|
|
191
|
+
if len(K.s) > 0:
|
|
192
|
+
fp.write(" ".join([str(num) for num in K.s]) + "\n")
|
|
193
|
+
else:
|
|
194
|
+
fp.write("0\n")
|
|
195
|
+
|
|
196
|
+
start_row = [0]
|
|
197
|
+
if J.f != 0:
|
|
198
|
+
start_row.append(J.f)
|
|
199
|
+
|
|
200
|
+
if J.l != 0:
|
|
201
|
+
start_row.append(start_row[-1] + J.l)
|
|
202
|
+
|
|
203
|
+
for k in J.q:
|
|
204
|
+
start_row.append(start_row[-1] + k)
|
|
205
|
+
|
|
206
|
+
for k in J.s:
|
|
207
|
+
start_row.append(start_row[-1] + k ** 2)
|
|
208
|
+
|
|
209
|
+
start_col = [0]
|
|
210
|
+
if K.f != 0:
|
|
211
|
+
start_col.append(K.f)
|
|
212
|
+
|
|
213
|
+
if K.l != 0:
|
|
214
|
+
start_col.append(start_col[-1] + K.l)
|
|
215
|
+
|
|
216
|
+
for k in K.q:
|
|
217
|
+
start_col.append(start_col[-1] + k)
|
|
218
|
+
|
|
219
|
+
for k in K.s:
|
|
220
|
+
start_col.append(start_col[-1] + k ** 2)
|
|
221
|
+
|
|
222
|
+
size_row = J.f + J.l + sum(J.q) + sum([k ** 2 for k in J.s])
|
|
223
|
+
size_col = K.f + K.l + sum(K.q) + sum([k ** 2 for k in K.s])
|
|
224
|
+
|
|
225
|
+
# Split matrix
|
|
226
|
+
c_block = [c[start_col[i]:start_col[i+1]]
|
|
227
|
+
for i in range(len(start_col) - 1)]
|
|
228
|
+
b_block = [b[start_row[i]:start_row[i+1]]
|
|
229
|
+
for i in range(len(start_row) - 1)]
|
|
230
|
+
tmp_block = [A[start_row[i]:start_row[i+1], :]
|
|
231
|
+
for i in range(len(start_row) - 1)]
|
|
232
|
+
|
|
233
|
+
A_block = []
|
|
234
|
+
for T in tmp_block:
|
|
235
|
+
A_block.append([T[:, start_col[i]:start_col[i+1]]
|
|
236
|
+
for i in range(len(start_col) - 1)])
|
|
237
|
+
|
|
238
|
+
# Write c
|
|
239
|
+
for COL in range(len(start_col) - 1):
|
|
240
|
+
block = c_block[COL]
|
|
241
|
+
list_row = ["0"] * len(list(block.nonzero()[0]))
|
|
242
|
+
list_col = [str(x + 1) for x in list(block.nonzero()[0])]
|
|
243
|
+
list_val = [accuracy % x for x in list(block.data)]
|
|
244
|
+
for (row, col, val) in zip(list_row, list_col, list_val):
|
|
245
|
+
fp.write(" ".join(["0", str(COL + 1), row, col, val]) + "\n")
|
|
246
|
+
|
|
247
|
+
# Write b
|
|
248
|
+
for ROW in range(len(start_row) - 1):
|
|
249
|
+
block = b_block[ROW]
|
|
250
|
+
list_row = [str(x + 1) for x in list(block.nonzero()[0])]
|
|
251
|
+
list_col = ["0"] * len(list(block.nonzero()[0]))
|
|
252
|
+
list_val = [accuracy % x for x in list(block.data)]
|
|
253
|
+
for (row, col, val) in zip(list_row, list_col, list_val):
|
|
254
|
+
fp.write(" ".join([str(ROW + 1), "0", row, col, val]) + "\n")
|
|
255
|
+
|
|
256
|
+
# Write A
|
|
257
|
+
for ROW in range(len(start_row) - 1):
|
|
258
|
+
for COL in range(len(start_col) - 1):
|
|
259
|
+
block = A_block[ROW][COL]
|
|
260
|
+
list_row = [str(x + 1) for x in list(block.nonzero()[0])]
|
|
261
|
+
list_col = [str(x + 1) for x in list(block.nonzero()[1])]
|
|
262
|
+
list_val = [accuracy % x for x in list(block.data)]
|
|
263
|
+
for (row, col, val) in zip(list_row, list_col, list_val):
|
|
264
|
+
fp.write(" ".join([str(ROW + 1), str(COL + 1),
|
|
265
|
+
row, col, val]) + "\n")
|
|
266
|
+
|
|
267
|
+
fp.close()
|
|
268
|
+
return
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def importsdpa(filename, flipsign=True):
|
|
272
|
+
"""Convert from SDPA sparse format to CLP format
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
filename: A string of file pass for SDPA sparse format
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
A tuple of CLP problem input, (A, b, c, K, J)
|
|
279
|
+
"""
|
|
280
|
+
if not isinstance(filename, str):
|
|
281
|
+
print('fromsdpa(): filename must be string')
|
|
282
|
+
return
|
|
283
|
+
|
|
284
|
+
K = SymCone()
|
|
285
|
+
J = SymCone()
|
|
286
|
+
|
|
287
|
+
# skip comment
|
|
288
|
+
fp = open(filename, 'r')
|
|
289
|
+
line = fp.readline()
|
|
290
|
+
while line[0] == '*' or line[0] == '"':
|
|
291
|
+
line = fp.readline()
|
|
292
|
+
|
|
293
|
+
# read mDim
|
|
294
|
+
J.f = int(line.strip().split(' ')[0])
|
|
295
|
+
|
|
296
|
+
# read nBlock
|
|
297
|
+
line = fp.readline()
|
|
298
|
+
nBlock = int(line.strip().split(' ')[0])
|
|
299
|
+
|
|
300
|
+
# read blockStruct
|
|
301
|
+
blockStruct = []
|
|
302
|
+
structSOCP = []
|
|
303
|
+
structSDP = []
|
|
304
|
+
line = fp.readline()
|
|
305
|
+
blockStruct = line.strip().split(' ')
|
|
306
|
+
while blockStruct.count('') > 0:
|
|
307
|
+
blockStruct.remove('')
|
|
308
|
+
|
|
309
|
+
blockSize = []
|
|
310
|
+
blockType = []
|
|
311
|
+
for i in range(nBlock):
|
|
312
|
+
item = blockStruct[i]
|
|
313
|
+
size = abs(int(item[0:-1])) if item[-1] in 'FLQS' else abs(int(item))
|
|
314
|
+
blockSize.append(size)
|
|
315
|
+
|
|
316
|
+
if item[-1] == 'F':
|
|
317
|
+
K.f += size
|
|
318
|
+
blockType.append('F')
|
|
319
|
+
elif item[-1] == 'L':
|
|
320
|
+
K.l += size
|
|
321
|
+
blockType.append('L')
|
|
322
|
+
elif item[-1] == 'Q':
|
|
323
|
+
structSOCP.append(size)
|
|
324
|
+
blockType.append('Q')
|
|
325
|
+
elif item[-1] == 'S':
|
|
326
|
+
structSDP.append(size)
|
|
327
|
+
blockType.append('S')
|
|
328
|
+
else:
|
|
329
|
+
st = int(item)
|
|
330
|
+
if st > 0:
|
|
331
|
+
structSDP.append(st)
|
|
332
|
+
blockType.append('S')
|
|
333
|
+
else:
|
|
334
|
+
K.l -= st
|
|
335
|
+
blockType.append('L')
|
|
336
|
+
|
|
337
|
+
K.q = tuple(structSOCP)
|
|
338
|
+
K.s = tuple(structSDP)
|
|
339
|
+
|
|
340
|
+
# read b
|
|
341
|
+
line = fp.readline()
|
|
342
|
+
line = line.strip()
|
|
343
|
+
line = line.strip('{}()')
|
|
344
|
+
if ',' in line:
|
|
345
|
+
b_str = line.strip().split(',')
|
|
346
|
+
else:
|
|
347
|
+
b_str = line.strip().split()
|
|
348
|
+
while b_str.count('') > 0:
|
|
349
|
+
b_str.remove('')
|
|
350
|
+
|
|
351
|
+
"""
|
|
352
|
+
The documented way to use `csr_matrix` is to provide it an ndarray
|
|
353
|
+
of rank-2. However, directly providing a list seems to work as well.
|
|
354
|
+
If in future this causes a problem, wrap the argument of `csr_matrix`
|
|
355
|
+
with np.array([...])
|
|
356
|
+
"""
|
|
357
|
+
b = csr_matrix(list(map(float, [s for s in b_str]))).T
|
|
358
|
+
|
|
359
|
+
# read c and A
|
|
360
|
+
blockElements_c = [[] for i in range(nBlock)]
|
|
361
|
+
blockElements_A = [[] for i in range(nBlock)]
|
|
362
|
+
lineList = fp.readlines()
|
|
363
|
+
for line in lineList:
|
|
364
|
+
row, block, colI, colJ, val = line.split()[0:5]
|
|
365
|
+
row = int(row.strip(',')) - 1
|
|
366
|
+
# if (row+1) > J.f:
|
|
367
|
+
# break
|
|
368
|
+
block = int(block.strip(',')) - 1
|
|
369
|
+
colI = int(colI.strip(',')) - 1
|
|
370
|
+
colJ = int(colJ.strip(',')) - 1
|
|
371
|
+
val = float(val.strip(','))
|
|
372
|
+
if val==0:
|
|
373
|
+
continue
|
|
374
|
+
col = colI * blockSize[block] + colJ \
|
|
375
|
+
if blockType[block] == 'S' else colI
|
|
376
|
+
col2 = colJ * blockSize[block] + colI \
|
|
377
|
+
if blockType[block] == 'S' else colJ
|
|
378
|
+
|
|
379
|
+
if row == -1:
|
|
380
|
+
blockElements_c[block].append((col, val))
|
|
381
|
+
if blockType[block] == 'S' and colI != colJ:
|
|
382
|
+
blockElements_c[block].append((col2, val))
|
|
383
|
+
else:
|
|
384
|
+
blockElements_A[block].append((row, col, val))
|
|
385
|
+
if blockType[block] == 'S' and colI != colJ:
|
|
386
|
+
blockElements_A[block].append((row, col2, val))
|
|
387
|
+
|
|
388
|
+
for block in range(nBlock):
|
|
389
|
+
blockElements_c[block].sort()
|
|
390
|
+
blockElements_A[block].sort(key = lambda x: x[1])
|
|
391
|
+
|
|
392
|
+
elementsK_c = {'F':[[], []], 'L':[[], []], 'Q':[[], []], 'S':[[], []]}
|
|
393
|
+
elementsK_A = {'F':[[], [], []], 'L':[[], [], []],
|
|
394
|
+
'Q':[[], [], []], 'S':[[], [], []]}
|
|
395
|
+
offsetK = {'F':0, 'L':0, 'Q':0, 'S':0}
|
|
396
|
+
|
|
397
|
+
for block in range(nBlock):
|
|
398
|
+
for item in blockElements_c[block]:
|
|
399
|
+
elementsK_c[blockType[block]][0].append(item[0] +
|
|
400
|
+
offsetK[blockType[block]])
|
|
401
|
+
elementsK_c[blockType[block]][1].append(item[1])
|
|
402
|
+
|
|
403
|
+
for item in blockElements_A[block]:
|
|
404
|
+
elementsK_A[blockType[block]][0].append(item[0])
|
|
405
|
+
elementsK_A[blockType[block]][1].append(item[1] +
|
|
406
|
+
offsetK[blockType[block]])
|
|
407
|
+
elementsK_A[blockType[block]][2].append(item[2])
|
|
408
|
+
|
|
409
|
+
offsetK[blockType[block]] += blockSize[block] ** 2 \
|
|
410
|
+
if blockType[block] == 'S' \
|
|
411
|
+
else blockSize[block]
|
|
412
|
+
|
|
413
|
+
elements_c = [[], []]
|
|
414
|
+
elements_A = [[], [], []]
|
|
415
|
+
offset = 0
|
|
416
|
+
|
|
417
|
+
if K.f > 0:
|
|
418
|
+
elements_c[0].extend(elementsK_c['F'][0])
|
|
419
|
+
elements_c[1].extend(elementsK_c['F'][1])
|
|
420
|
+
elements_A[0].extend(elementsK_A['F'][0])
|
|
421
|
+
elements_A[1].extend(elementsK_A['F'][1])
|
|
422
|
+
elements_A[2].extend(elementsK_A['F'][2])
|
|
423
|
+
offset += K.f
|
|
424
|
+
|
|
425
|
+
if K.l > 0:
|
|
426
|
+
elements_c[0].extend([x + offset for x in elementsK_c['L'][0]])
|
|
427
|
+
elements_c[1].extend(elementsK_c['L'][1])
|
|
428
|
+
elements_A[0].extend(elementsK_A['L'][0])
|
|
429
|
+
elements_A[1].extend([x + offset for x in elementsK_A['L'][1]])
|
|
430
|
+
elements_A[2].extend(elementsK_A['L'][2])
|
|
431
|
+
offset += K.l
|
|
432
|
+
|
|
433
|
+
if True: #K.q > 0:
|
|
434
|
+
elements_c[0].extend([x + offset for x in elementsK_c['Q'][0]])
|
|
435
|
+
elements_c[1].extend(elementsK_c['Q'][1])
|
|
436
|
+
elements_A[0].extend(elementsK_A['Q'][0])
|
|
437
|
+
elements_A[1].extend([x + offset for x in elementsK_A['Q'][1]])
|
|
438
|
+
elements_A[2].extend(elementsK_A['Q'][2])
|
|
439
|
+
offset += sum(K.q)
|
|
440
|
+
|
|
441
|
+
if True: #K.s > 0:
|
|
442
|
+
elements_c[0].extend([x + offset for x in elementsK_c['S'][0]])
|
|
443
|
+
elements_c[1].extend(elementsK_c['S'][1])
|
|
444
|
+
elements_A[0].extend(elementsK_A['S'][0])
|
|
445
|
+
elements_A[1].extend([x + offset for x in elementsK_A['S'][1]])
|
|
446
|
+
elements_A[2].extend(elementsK_A['S'][2])
|
|
447
|
+
offset += sum([x ** 2 for x in K.s])
|
|
448
|
+
|
|
449
|
+
size_K = offset
|
|
450
|
+
|
|
451
|
+
c = csc_matrix((elements_c[1], (elements_c[0], [0] * len(elements_c[0]))),
|
|
452
|
+
shape=(size_K, 1))
|
|
453
|
+
A = csc_matrix((elements_A[2], (elements_A[0], elements_A[1])),
|
|
454
|
+
shape=(J.f, size_K))
|
|
455
|
+
|
|
456
|
+
if flipsign:
|
|
457
|
+
c = -c
|
|
458
|
+
b = -b
|
|
459
|
+
A = -A
|
|
460
|
+
|
|
461
|
+
return A, b, c, K, J
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def exportsdpa(filename, A, b, c, K, J, accuracy="%+8.16e", flipsign=True):
|
|
465
|
+
"""Convert from SeDuMi format to SDPA sparse format
|
|
466
|
+
|
|
467
|
+
If J.l or J.q or J.s are not empty, CLP format will be converted
|
|
468
|
+
to SeDuMi format first.
|
|
469
|
+
|
|
470
|
+
Args:
|
|
471
|
+
filename: A string of file pass
|
|
472
|
+
A, b, c: Scipy matrices to denote the CLP
|
|
473
|
+
K, J: Symcone object to denote the CLP
|
|
474
|
+
accuracy: Print format (e.g. '%8.16e')
|
|
475
|
+
"""
|
|
476
|
+
if accuracy[0] != "%":
|
|
477
|
+
raise ValueError("accuracy must start with %% (e.g. %8.16e) \n")
|
|
478
|
+
|
|
479
|
+
if not isinstance(K, SymCone) or not isinstance(J, SymCone):
|
|
480
|
+
raise ValueError('K and J must be an instance of SymCone.')
|
|
481
|
+
|
|
482
|
+
if not K.check_validity() or not J.check_validity():
|
|
483
|
+
return
|
|
484
|
+
|
|
485
|
+
if J.l > 0 or len(J.q) > 0 or len(J.s) > 0:
|
|
486
|
+
raise ValueError("SymCone J must only have attribute 'f'")
|
|
487
|
+
|
|
488
|
+
if not sparse.isspmatrix_csr(A):
|
|
489
|
+
A = csr_matrix(A)
|
|
490
|
+
if not sparse.isspmatrix_csc(b):
|
|
491
|
+
b = csc_matrix(b)
|
|
492
|
+
if not sparse.isspmatrix_csc(c):
|
|
493
|
+
c = csc_matrix(c)
|
|
494
|
+
|
|
495
|
+
# Note that primal-dual is reverse in SeDuMi.
|
|
496
|
+
# So c2 must be -c2.
|
|
497
|
+
# In addition, A2 should be passed in the transposed style.
|
|
498
|
+
if flipsign:
|
|
499
|
+
c2 = -c
|
|
500
|
+
b2 = -b
|
|
501
|
+
A2 = -A
|
|
502
|
+
else:
|
|
503
|
+
c2 = c
|
|
504
|
+
b2 = b
|
|
505
|
+
A2 = A
|
|
506
|
+
|
|
507
|
+
fp = open(filename, "w")
|
|
508
|
+
|
|
509
|
+
size_row, size_col = A2.shape
|
|
510
|
+
# write mDim
|
|
511
|
+
fp.write(str(size_row) + "\n")
|
|
512
|
+
|
|
513
|
+
# write nBlock
|
|
514
|
+
fp.write(str(int(K.f > 0) + int(K.l > 0) + len(K.q) + len(K.s)) + "\n")
|
|
515
|
+
|
|
516
|
+
print(J)
|
|
517
|
+
print(K)
|
|
518
|
+
|
|
519
|
+
# write blockStruct
|
|
520
|
+
blockStruct = []
|
|
521
|
+
if K.f > 0:
|
|
522
|
+
blockStruct.append(str(K.f) + "F")
|
|
523
|
+
|
|
524
|
+
if K.l > 0:
|
|
525
|
+
blockStruct.append(str(K.l) + "L")
|
|
526
|
+
|
|
527
|
+
if len(K.q) > 0:
|
|
528
|
+
blockStruct.extend([str(x) + "Q" for x in K.q])
|
|
529
|
+
|
|
530
|
+
if len(K.s) > 0:
|
|
531
|
+
blockStruct.extend([str(x) + "S" for x in K.s])
|
|
532
|
+
|
|
533
|
+
fp.write(" ".join(blockStruct) + "\n")
|
|
534
|
+
|
|
535
|
+
# write b
|
|
536
|
+
fp.write(" ".join([accuracy % b2[i,0] for i in range(b2.shape[0])]) + "\n")
|
|
537
|
+
|
|
538
|
+
len_q = sum(K.q)
|
|
539
|
+
len_s = sum([x ** 2 for x in K.s])
|
|
540
|
+
# write c
|
|
541
|
+
if K.f > 0:
|
|
542
|
+
c_f = c2[0:K.f, :]
|
|
543
|
+
if K.l > 0:
|
|
544
|
+
c_l = c2[K.f:(K.f + K.l), :]
|
|
545
|
+
if len_q > 0:
|
|
546
|
+
c_q = c2[(K.f + K.l):(K.f + K.l + len_q), :]
|
|
547
|
+
if len_s > 0:
|
|
548
|
+
c_s = c2[(K.f + K.l + len_q):, :]
|
|
549
|
+
|
|
550
|
+
setBlock = 1
|
|
551
|
+
if K.f > 0:
|
|
552
|
+
list_row = [str(x + 1) for x in list(c_f.nonzero()[0])]
|
|
553
|
+
list_val = [accuracy % x for x in list(c_f.data)]
|
|
554
|
+
length = len(list_row)
|
|
555
|
+
for i in range(length):
|
|
556
|
+
fp.write(" ".join(("0", str(setBlock), list_row[i],
|
|
557
|
+
list_row[i], list_val[i])) + "\n")
|
|
558
|
+
|
|
559
|
+
setBlock += 1
|
|
560
|
+
|
|
561
|
+
if K.l > 0:
|
|
562
|
+
list_row = [str(x + 1) for x in list(c_l.nonzero()[0])]
|
|
563
|
+
list_val = [accuracy % x for x in list(c_l.data)]
|
|
564
|
+
length = len(list_row)
|
|
565
|
+
for i in range(length):
|
|
566
|
+
fp.write(" ".join(("0", str(setBlock), list_row[i],
|
|
567
|
+
list_row[i], list_val[i])) + "\n")
|
|
568
|
+
|
|
569
|
+
setBlock += 1
|
|
570
|
+
|
|
571
|
+
if len_q > 0:
|
|
572
|
+
offset = 0
|
|
573
|
+
for blockSize in K.q:
|
|
574
|
+
list_row = [str(x + 1) for x in
|
|
575
|
+
list(c_q[offset:(offset + blockSize), :].nonzero()[0])]
|
|
576
|
+
list_val = [accuracy % x for x in
|
|
577
|
+
list(c_q[offset:(offset + blockSize), :].data)]
|
|
578
|
+
length = len(list_row)
|
|
579
|
+
for i in range(length):
|
|
580
|
+
fp.write(" ".join(("0", str(setBlock), list_row[i],
|
|
581
|
+
list_row[i], list_val[i])) + "\n")
|
|
582
|
+
|
|
583
|
+
setBlock += 1
|
|
584
|
+
offset += blockSize
|
|
585
|
+
|
|
586
|
+
if len_s > 0:
|
|
587
|
+
offset = 0
|
|
588
|
+
for blockSize in K.s:
|
|
589
|
+
list_row = list(c_s[offset:(offset + blockSize * blockSize),
|
|
590
|
+
:].nonzero()[0])
|
|
591
|
+
list_val = [accuracy % x for x in
|
|
592
|
+
list(c_s[offset:(offset + blockSize * blockSize),
|
|
593
|
+
:].data)]
|
|
594
|
+
length = len(list_row)
|
|
595
|
+
for i in range(length):
|
|
596
|
+
setCol_row = (list_row[i] // blockSize) + 1
|
|
597
|
+
setCol_col = (list_row[i] % blockSize) + 1
|
|
598
|
+
if setCol_row <= setCol_col:
|
|
599
|
+
fp.write(" ".join(("0", str(setBlock), str(setCol_row),
|
|
600
|
+
str(setCol_col), list_val[i])) + "\n")
|
|
601
|
+
|
|
602
|
+
setBlock += 1
|
|
603
|
+
offset += blockSize * blockSize
|
|
604
|
+
|
|
605
|
+
# write A
|
|
606
|
+
if K.f > 0:
|
|
607
|
+
A_f = A2[:, 0:K.f]
|
|
608
|
+
if K.l > 0:
|
|
609
|
+
A_l = A2[:, K.f:(K.f + K.l)]
|
|
610
|
+
if len_q > 0:
|
|
611
|
+
A_q = A2[:, (K.f + K.l):(K.f + K.l + len_q)]
|
|
612
|
+
if len_s > 0:
|
|
613
|
+
A_s = A2[:, (K.f + K.l + len_q):]
|
|
614
|
+
|
|
615
|
+
setBlock = 1
|
|
616
|
+
if K.f > 0:
|
|
617
|
+
list_row = [str(x + 1) for x in list(A_f.nonzero()[0])]
|
|
618
|
+
list_col = [str(x + 1) for x in list(A_f.nonzero()[1])]
|
|
619
|
+
list_val = [accuracy % x for x in list(A_f.data)]
|
|
620
|
+
length = len(list_row)
|
|
621
|
+
for i in range(length):
|
|
622
|
+
fp.write(" ".join((list_row[i], str(setBlock), list_col[i],
|
|
623
|
+
list_col[i], list_val[i])) + "\n")
|
|
624
|
+
|
|
625
|
+
setBlock += 1
|
|
626
|
+
|
|
627
|
+
if K.l > 0:
|
|
628
|
+
list_row = [str(x + 1) for x in list(A_l.nonzero()[0])]
|
|
629
|
+
list_col = [str(x + 1) for x in list(A_l.nonzero()[1])]
|
|
630
|
+
list_val = [accuracy % x for x in list(A_l.data)]
|
|
631
|
+
length = len(list_row)
|
|
632
|
+
for i in range(length):
|
|
633
|
+
fp.write(" ".join((list_row[i], str(setBlock), list_col[i],
|
|
634
|
+
list_col[i], list_val[i])) + "\n")
|
|
635
|
+
|
|
636
|
+
setBlock += 1
|
|
637
|
+
|
|
638
|
+
if len_q > 0:
|
|
639
|
+
offset = 0
|
|
640
|
+
for blockSize in K.q:
|
|
641
|
+
list_row = [str(x + 1) for x in
|
|
642
|
+
list(A_q[:, offset:(offset + blockSize)].nonzero()[0])]
|
|
643
|
+
list_col = [str(x + 1) for x in
|
|
644
|
+
list(A_q[:, offset:(offset + blockSize)].nonzero()[1])]
|
|
645
|
+
list_val = [accuracy % x for x in
|
|
646
|
+
list(A_q[:, offset:(offset + blockSize)].data)]
|
|
647
|
+
length = len(list_row)
|
|
648
|
+
for i in range(length):
|
|
649
|
+
fp.write(" ".join((list_row[i], str(setBlock), list_col[i],
|
|
650
|
+
list_col[i], list_val[i])) + "\n")
|
|
651
|
+
|
|
652
|
+
setBlock += 1
|
|
653
|
+
offset += blockSize
|
|
654
|
+
|
|
655
|
+
if len_s > 0:
|
|
656
|
+
offset = 0
|
|
657
|
+
for blockSize in K.s:
|
|
658
|
+
list_row = [str(x + 1) for x in
|
|
659
|
+
list(A_s[:, offset:(offset + blockSize * blockSize)].
|
|
660
|
+
nonzero()[0])]
|
|
661
|
+
list_col = list(A_s[:, offset:(offset + blockSize * blockSize)].
|
|
662
|
+
nonzero()[1])
|
|
663
|
+
list_val = [accuracy % x for x in
|
|
664
|
+
list(A_s[:, offset:(offset + blockSize * blockSize)].
|
|
665
|
+
data)]
|
|
666
|
+
length = len(list_row)
|
|
667
|
+
for i in range(length):
|
|
668
|
+
setCol_row = (list_col[i] // blockSize) + 1
|
|
669
|
+
setCol_col = (list_col[i] % blockSize) + 1
|
|
670
|
+
if setCol_row <= setCol_col:
|
|
671
|
+
fp.write(" ".join((list_row[i], str(setBlock),
|
|
672
|
+
str(setCol_row), str(setCol_col),
|
|
673
|
+
list_val[i])) + "\n")
|
|
674
|
+
|
|
675
|
+
setBlock += 1
|
|
676
|
+
offset += blockSize * blockSize
|
|
677
|
+
|
|
678
|
+
fp.close()
|
|
679
|
+
return
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
# retaining them for backward compatibility
|
|
683
|
+
|
|
684
|
+
def fromsdpa(filename):
|
|
685
|
+
warnings.warn("fromsdpa will be removed in the future. "
|
|
686
|
+
"Please use importsdpa.", DeprecationWarning, stacklevel=2)
|
|
687
|
+
A, b, c, K, J = importsdpa(filename, flipsign=False)
|
|
688
|
+
return A, b, c, K, J
|
|
689
|
+
|
|
690
|
+
def tosdpa(filename, A, b, c, K, J, accuracy="%+8.16e"):
|
|
691
|
+
warnings.warn("tosdpa will be removed in the future. "
|
|
692
|
+
"Please use exportsdpa.", DeprecationWarning, stacklevel=2)
|
|
693
|
+
|
|
694
|
+
# Note that with flipsign=True, this is identical to the exportsdpa routine
|
|
695
|
+
# that replaces it (i.e. does not require flipping sign of A, b, c).
|
|
696
|
+
exportsdpa(filename, A, b, c, K, J, accuracy="%+8.16e", flipsign=True)
|
|
697
|
+
|
|
698
|
+
# Reason for deprecating this (and the accompanying fromsdpa routine):
|
|
699
|
+
# tosdpa did not require sign flipping (while fromsdpa required manual
|
|
700
|
+
# sign flipping). This was confusing to the user.
|
|
701
|
+
|
|
702
|
+
# The new importsdpa and exportsdpa routines both perform sign
|
|
703
|
+
# flipping by default which is intuitive to most users.
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
# ==================================================
|
|
707
|
+
# Functions to write result file
|
|
708
|
+
# ==================================================
|
|
709
|
+
def write_version(fp):
|
|
710
|
+
"""Write SDPAP title and version to file
|
|
711
|
+
|
|
712
|
+
Args:
|
|
713
|
+
fp: File pointer
|
|
714
|
+
"""
|
|
715
|
+
fp.write("==================================================\n" +
|
|
716
|
+
" SDPAP: SDPA Python Interface\n" +
|
|
717
|
+
" SDPA group 2010-2011\n" +
|
|
718
|
+
"==================================================\n")
|
|
719
|
+
return
|
|
720
|
+
|
|
721
|
+
def write_parameter(fp, option):
|
|
722
|
+
"""Write parameters to file
|
|
723
|
+
|
|
724
|
+
Args:
|
|
725
|
+
fp: File pointer
|
|
726
|
+
option: Parameters
|
|
727
|
+
"""
|
|
728
|
+
fp.write("----- Parameters -----\n" +
|
|
729
|
+
'maxIteration: ' + str(option['maxIteration']) + "\n" +
|
|
730
|
+
' epsilonStar: ' + str(option['epsilonStar']) + "\n" +
|
|
731
|
+
' lambdaStar: ' + str(option['lambdaStar']) + "\n" +
|
|
732
|
+
' omegaStar: ' + str(option['omegaStar']) + "\n" +
|
|
733
|
+
' lowerBound: ' + str(option['lowerBound']) + "\n" +
|
|
734
|
+
' upperBound: ' + str(option['upperBound']) + "\n" +
|
|
735
|
+
' betaStar: ' + str(option['betaStar']) + "\n" +
|
|
736
|
+
' betaBar: ' + str(option['betaBar']) + "\n" +
|
|
737
|
+
' gammaStar: ' + str(option['gammaStar']) + "\n" +
|
|
738
|
+
' epsilonDash: ' + str(option['epsilonDash']) + "\n" +
|
|
739
|
+
' isSymmetric: ' + str(option['isSymmetric']) + "\n" +
|
|
740
|
+
' isDimacs: ' + str(option['isDimacs']) + "\n" +
|
|
741
|
+
' xPrint: ' + str(option['xPrint']) + "\n" +
|
|
742
|
+
' yPrint: ' + str(option['yPrint']) + "\n" +
|
|
743
|
+
' sPrint: ' + str(option['sPrint']) + "\n" +
|
|
744
|
+
' infPrint: ' + str(option['infPrint']) + "\n" +
|
|
745
|
+
' print: ' + str(option['print']) + "\n" +
|
|
746
|
+
' resultFile: ' + str(option['resultFile']) + "\n" +
|
|
747
|
+
' sdpaResult: ' + str(option['sdpaResult']) + "\n" +
|
|
748
|
+
' numThreads: ' + str(option['numThreads']) + "\n" +
|
|
749
|
+
' frvMethod: ' + str(option['frvMethod']) + "\n" +
|
|
750
|
+
' convMethod: ' + str(option['convMethod']) + "\n" +
|
|
751
|
+
'domainMethod: ' + str(option['domainMethod']) + "\n" +
|
|
752
|
+
' rangeMethod: ' + str(option['rangeMethod']) + "\n" +
|
|
753
|
+
' rho: ' + str(option['rho']) + "\n" +
|
|
754
|
+
' zeroPoint: ' + str(option['zeroPoint']) + "\n\n")
|
|
755
|
+
|
|
756
|
+
return
|
|
757
|
+
|
|
758
|
+
def write_symcone(fp, K, J=None):
|
|
759
|
+
"""Write SymCone to file
|
|
760
|
+
|
|
761
|
+
Args:
|
|
762
|
+
fp: File pointer
|
|
763
|
+
K, J: SymCone
|
|
764
|
+
"""
|
|
765
|
+
if J != None:
|
|
766
|
+
fp.write("K =\n" + str(K) + "J =\n" + str(J) + "\n")
|
|
767
|
+
else:
|
|
768
|
+
fp.write("K =\n" + str(K) + "\n")
|
|
769
|
+
|
|
770
|
+
return
|
|
771
|
+
|
|
772
|
+
def write_info(fp, sdpapinfo, sdpainfo, timeinfo):
|
|
773
|
+
"""Write result info to file
|
|
774
|
+
|
|
775
|
+
Args:
|
|
776
|
+
fp: File pointer
|
|
777
|
+
sdpapinfo, sdpainfo, timeinfo: Result information
|
|
778
|
+
"""
|
|
779
|
+
fp.write("----- Result -----\n" +
|
|
780
|
+
" SDPA.phase = %s\n" % sdpainfo['phasevalue'] +
|
|
781
|
+
" iteration = %d\n" % sdpainfo['iteration'] +
|
|
782
|
+
" primalObj = %+10.16e\n" % sdpapinfo['primalObj'] +
|
|
783
|
+
" dualObj = %+10.16e\n" % sdpapinfo['dualObj'] +
|
|
784
|
+
" dualityGap = %+10.16e\n" % sdpapinfo['dualityGap'] +
|
|
785
|
+
" primalError = %+10.16e\n" % sdpapinfo['primalError'] +
|
|
786
|
+
" dualError = %+10.16e\n" % sdpapinfo['dualError'] +
|
|
787
|
+
" convertTime = %f\n" % timeinfo['convert'] +
|
|
788
|
+
" solveTime = %f\n" % timeinfo['sdpa'] +
|
|
789
|
+
"retrievingTime = %f\n" % timeinfo['retrieve'] +
|
|
790
|
+
" totalTime = %f\n" % timeinfo['total'])
|
|
791
|
+
|
|
792
|
+
return
|
|
793
|
+
|
|
794
|
+
def write_result(fp, x, y):
|
|
795
|
+
"""Write result x and y to file
|
|
796
|
+
|
|
797
|
+
Args:
|
|
798
|
+
fp: File pointer
|
|
799
|
+
x, y: results
|
|
800
|
+
"""
|
|
801
|
+
if not sparse.isspmatrix_csc(x):
|
|
802
|
+
x = x.tocsc()
|
|
803
|
+
if not sparse.isspmatrix_csc(y):
|
|
804
|
+
y = y.tocsc()
|
|
805
|
+
|
|
806
|
+
x.sort_indices()
|
|
807
|
+
y.sort_indices()
|
|
808
|
+
|
|
809
|
+
fp.write("\nx(index, value) =\n")
|
|
810
|
+
writeStr = ''
|
|
811
|
+
count = 0
|
|
812
|
+
for (index, value) in zip(x.indices, x.data):
|
|
813
|
+
writeStr += "(%d: %+8.3e), " % (index, value)
|
|
814
|
+
if count == 4:
|
|
815
|
+
writeStr += "\n"
|
|
816
|
+
count = 0
|
|
817
|
+
else:
|
|
818
|
+
count += 1
|
|
819
|
+
|
|
820
|
+
fp.write(writeStr)
|
|
821
|
+
|
|
822
|
+
fp.write("\n\ny(index, value) =\n")
|
|
823
|
+
writeStr = ''
|
|
824
|
+
count = 0
|
|
825
|
+
for (index, value) in zip(y.indices, y.data):
|
|
826
|
+
writeStr += "(%d: %+8.3e), " % (index, value)
|
|
827
|
+
if count == 4:
|
|
828
|
+
writeStr += "\n"
|
|
829
|
+
count = 0
|
|
830
|
+
else:
|
|
831
|
+
count += 1
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
fp.write(writeStr)
|
|
835
|
+
|
|
836
|
+
return
|