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/spcolo/asputils.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
SparseCoLO [1] implements sparsity exploitation algorithms in [2]
|
|
5
|
+
These routines were originally implemented as subprograms of SparseCoLO (MATLAB) and are
|
|
6
|
+
Copyright (C) 2009 Masakazu Kojima Group
|
|
7
|
+
Department of Mathematical and Computing Sciences, Tokyo Institute of Technology
|
|
8
|
+
|
|
9
|
+
Python translations written for SDPAP and are
|
|
10
|
+
Copyright (C) 2010-2022 SDPA Project
|
|
11
|
+
|
|
12
|
+
[1] http://www.opt.c.titech.ac.jp/kojima/SparseCoLO/SparseCoLO.htm
|
|
13
|
+
[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
|
|
14
|
+
|
|
15
|
+
This program is free software; you can redistribute it and/or modify
|
|
16
|
+
it under the terms of the GNU General Public License as published by
|
|
17
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
18
|
+
(at your option) any later version.
|
|
19
|
+
|
|
20
|
+
This program is distributed in the hope that it will be useful,
|
|
21
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
22
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
23
|
+
GNU General Public License for more details.
|
|
24
|
+
|
|
25
|
+
You should have received a copy of the GNU General Public License along
|
|
26
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
27
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
28
|
+
|
|
29
|
+
September 2010: `getASP`, `symb_cholesky`, `cliques_fromASP` written by Kenta Kato
|
|
30
|
+
December 2010: Modified for SciPy
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
__all__ = ['getASP', 'cliques_fromASP']
|
|
34
|
+
|
|
35
|
+
from sdpap.matdata import MatData
|
|
36
|
+
from . import spcoloext
|
|
37
|
+
from .clique import CliqueSet
|
|
38
|
+
from scipy.sparse import csc_matrix, tril
|
|
39
|
+
from scipy import sparse
|
|
40
|
+
# from numpy import array
|
|
41
|
+
|
|
42
|
+
def getASP(A, c, K_s):
|
|
43
|
+
"""Get Aggregate Sparsity Pattern
|
|
44
|
+
|
|
45
|
+
Args;
|
|
46
|
+
A, c: submatrix or subvector of CoLO
|
|
47
|
+
K_s: A tuple of block struct of A or c
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Aggregate Sparsity Pattern Matrix
|
|
51
|
+
"""
|
|
52
|
+
if not isinstance(K_s, tuple):
|
|
53
|
+
raise TypeError('K_s must be tuple.')
|
|
54
|
+
|
|
55
|
+
if len(K_s) == 0:
|
|
56
|
+
print("getASP(): K_s is not assigned.")
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
size_asp = sum(K_s)
|
|
60
|
+
sDim = sum([x ** 2 for x in K_s])
|
|
61
|
+
size_m, size_n = A.shape
|
|
62
|
+
|
|
63
|
+
asp_I = set(c.nonzero()[0])
|
|
64
|
+
asp_I.update(set(A.nonzero()[1]))
|
|
65
|
+
|
|
66
|
+
list_I = sorted(list(asp_I))
|
|
67
|
+
mat_offset = 0
|
|
68
|
+
vec_offset = 0
|
|
69
|
+
asp_row = []
|
|
70
|
+
asp_col = []
|
|
71
|
+
for k in K_s:
|
|
72
|
+
block_I = list_I[vec_offset:(vec_offset + k ** 2)]
|
|
73
|
+
asp_row.extend([((i - vec_offset) // k) + mat_offset
|
|
74
|
+
for i in block_I])
|
|
75
|
+
asp_col.extend([((i - vec_offset) % k) + mat_offset
|
|
76
|
+
for i in block_I])
|
|
77
|
+
mat_offset += k
|
|
78
|
+
vec_offset += k ** 2
|
|
79
|
+
|
|
80
|
+
ret_mat = csc_matrix(([1] * len(asp_row), (asp_row, asp_col)),
|
|
81
|
+
shape=(size_asp, size_asp))
|
|
82
|
+
|
|
83
|
+
return ret_mat
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def symb_cholesky(asp):
|
|
87
|
+
"""Symbolic Cholesky Factorization
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
asp: Aggregated Sparsity Pattern Matrix
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Indices and indptr of Lower triangular matrix L (indL, ptrL)
|
|
94
|
+
"""
|
|
95
|
+
A = tril(asp, k=-1, format='csc')
|
|
96
|
+
A.sort_indices()
|
|
97
|
+
parent = dict()
|
|
98
|
+
indA = A.indices
|
|
99
|
+
ptrA = A.indptr
|
|
100
|
+
setL = []
|
|
101
|
+
for i in range(A.shape[0]):
|
|
102
|
+
setL.append(set(indA[ptrA[i]:ptrA[i+1]]))
|
|
103
|
+
for j in parent.keys():
|
|
104
|
+
if parent[j] == i:
|
|
105
|
+
setL[i].update(setL[j])
|
|
106
|
+
|
|
107
|
+
setL[i] -= set(range(i+1))
|
|
108
|
+
if setL[i]:
|
|
109
|
+
parent[i] = min(setL[i])
|
|
110
|
+
|
|
111
|
+
indL = []
|
|
112
|
+
ptrL = [0] * (A.shape[0] + 1)
|
|
113
|
+
for i in range(A.shape[0]):
|
|
114
|
+
indL.append(i)
|
|
115
|
+
indL.extend(sorted(list(setL[i])))
|
|
116
|
+
ptrL[i+1] = len(indL)
|
|
117
|
+
|
|
118
|
+
#L = csc_matrix((array([1.0] * len(indL)),
|
|
119
|
+
# array(indL),
|
|
120
|
+
# array(ptrL)),
|
|
121
|
+
# shape=A.shape)
|
|
122
|
+
return indL, ptrL
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def cliques_fromASP(asp):
|
|
126
|
+
"""Get cliques from Aggregate Sparsity Pattern Matrix
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
asp: Aggregate Sparsity Pattern Matrix
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
orig_cliques: A list of list. Each list has indexes of clique.
|
|
133
|
+
"""
|
|
134
|
+
from scipy import ix_
|
|
135
|
+
|
|
136
|
+
size_n = asp.shape[0]
|
|
137
|
+
A = asp + sparse.eye(size_n, size_n, format='csc')
|
|
138
|
+
#A = asp + (2 * size_n + 1) * sparse.eye(size_n, size_n, format='csc')
|
|
139
|
+
data_A = MatData(mat=A.tocsc().sorted_indices())
|
|
140
|
+
|
|
141
|
+
# Minimum degree ordering
|
|
142
|
+
# using spooles
|
|
143
|
+
ordering = spcoloext.ordering_mmd(data_A)
|
|
144
|
+
if len(ordering) == 0:
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
if A.shape != (1, 1):
|
|
148
|
+
#data_A = MatData(mat=A.tocsc()[ix_(ordering, ordering)])
|
|
149
|
+
A = A.tocsc()[ix_(ordering, ordering)]
|
|
150
|
+
else:
|
|
151
|
+
#data_A = MatData(mat=A.tocsc())
|
|
152
|
+
A = A.tocsc()
|
|
153
|
+
|
|
154
|
+
# Cholesky factorization
|
|
155
|
+
#L = symb_cholesky(A)
|
|
156
|
+
indL, ptrL = symb_cholesky(A)
|
|
157
|
+
#values, rowind, colptr = spcoloext.cholesky(data_A)
|
|
158
|
+
#data_R = MatData(values=values, rowind=rowind, colptr=colptr,
|
|
159
|
+
# size=(size_n,size_n))
|
|
160
|
+
|
|
161
|
+
#R = data_R.tomatrix()
|
|
162
|
+
#L = R.T
|
|
163
|
+
|
|
164
|
+
# Finding the maximal cliques
|
|
165
|
+
#clique_set = [set(L[:,col].nonzero()[0]) for col in range(size_n)]
|
|
166
|
+
clique_set = [set(indL[ptrL[col]:ptrL[col+1]]) for col in range(size_n)]
|
|
167
|
+
maxclique_idx = [0]
|
|
168
|
+
for i in range(1, size_n):
|
|
169
|
+
for j in range(i):
|
|
170
|
+
if clique_set[i] <= clique_set[j]:
|
|
171
|
+
break
|
|
172
|
+
else:
|
|
173
|
+
maxclique_idx.append(i)
|
|
174
|
+
|
|
175
|
+
cliqueSet = CliqueSet(size_n)
|
|
176
|
+
for i in maxclique_idx:
|
|
177
|
+
clq = sorted([ordering[j] for j in clique_set[i]])
|
|
178
|
+
cliqueSet.append_clique(clq)
|
|
179
|
+
|
|
180
|
+
# print cliqueSet.cliques
|
|
181
|
+
|
|
182
|
+
return cliqueSet
|
sdpap/spcolo/clique.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Class definition of `CliqueSet`
|
|
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
|
+
October 2010: Originally written by Kenta Kato
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
__all__ = ['CliqueSet']
|
|
25
|
+
|
|
26
|
+
class CliqueSet(object):
|
|
27
|
+
"""Maximal clique set of Aggregate sparsity pattern
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
cliques: A list of clique. Each clique is described as list of integer.
|
|
31
|
+
map_convIndex: A dictionary of mapping list from index of ASP (i,j)
|
|
32
|
+
to converted index.
|
|
33
|
+
i.e. map_convIndex[(i,j)] = converted_index
|
|
34
|
+
map_origIndex: A dictionary of mapping list from converted index
|
|
35
|
+
to original index.
|
|
36
|
+
i.e. map_index[converted_index] = original_index
|
|
37
|
+
"""
|
|
38
|
+
def __init__(self, size_n):
|
|
39
|
+
"""Constructor"""
|
|
40
|
+
self.cliques = []
|
|
41
|
+
self.map_convIndex = {}
|
|
42
|
+
self.map_origIndex = {}
|
|
43
|
+
self.num_element = 0
|
|
44
|
+
self.size_n = size_n
|
|
45
|
+
|
|
46
|
+
def __len__(self):
|
|
47
|
+
"""Return number of cliques"""
|
|
48
|
+
return len(self.cliques)
|
|
49
|
+
|
|
50
|
+
def append_clique(self, clq):
|
|
51
|
+
"""Append one clique to cliques and make index mapping
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
clq: A list of integer.
|
|
55
|
+
"""
|
|
56
|
+
self.cliques.append(clq)
|
|
57
|
+
for i in clq:
|
|
58
|
+
for j in clq:
|
|
59
|
+
if i >= j:
|
|
60
|
+
origIndex1 = i * self.size_n + j
|
|
61
|
+
origIndex2 = j * self.size_n + i
|
|
62
|
+
if origIndex1 not in self.map_convIndex:
|
|
63
|
+
self.map_origIndex[self.num_element] = \
|
|
64
|
+
(origIndex1, origIndex2)
|
|
65
|
+
self.map_convIndex[origIndex1] = self.num_element
|
|
66
|
+
self.map_convIndex[origIndex2] = self.num_element
|
|
67
|
+
self.num_element += 1
|
|
68
|
+
return
|
sdpap/spcolo/spcolo.py
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Exploit sparsity in SDPs using techniques from [1]
|
|
4
|
+
|
|
5
|
+
These routines were originally implemented in SparseCoLO (MATLAB) [2] and are
|
|
6
|
+
Copyright (C) 2009 Masakazu Kojima Group
|
|
7
|
+
Department of Mathematical and Computing Sciences, Tokyo Institute of Technology
|
|
8
|
+
|
|
9
|
+
Python translations written for SDPAP and are
|
|
10
|
+
Copyright (C) 2010-2022 SDPA Project
|
|
11
|
+
|
|
12
|
+
[1] 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
|
|
13
|
+
[2] http://www.opt.c.titech.ac.jp/kojima/SparseCoLO/SparseCoLO.htm
|
|
14
|
+
|
|
15
|
+
This program is free software; you can redistribute it and/or modify
|
|
16
|
+
it under the terms of the GNU General Public License as published by
|
|
17
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
18
|
+
(at your option) any later version.
|
|
19
|
+
|
|
20
|
+
This program is distributed in the hope that it will be useful,
|
|
21
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
22
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
23
|
+
GNU General Public License for more details.
|
|
24
|
+
|
|
25
|
+
You should have received a copy of the GNU General Public License along
|
|
26
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
27
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
28
|
+
|
|
29
|
+
August 2010: `dconv_basisrep`, `rconv_matdecomp`, `dconv_basisresult`, `rconv_decompresult` written by Kenta Kato
|
|
30
|
+
December 2010: Modified for SciPy
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
__all__ = ['dconv_basisrep', 'rconv_matdecomp',
|
|
34
|
+
'dconv_basisresult', 'rconv_decompresult']
|
|
35
|
+
|
|
36
|
+
from . import asputils
|
|
37
|
+
from .clique import CliqueSet
|
|
38
|
+
from sdpap.symcone import SymCone
|
|
39
|
+
from scipy.sparse import csc_matrix, bmat, eye
|
|
40
|
+
from scipy import sparse
|
|
41
|
+
|
|
42
|
+
#from cvxopt import matrix, spmatrix, sparse
|
|
43
|
+
#import cvxopt
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def dconv_basisrep(A, b, c, K, J):
|
|
47
|
+
"""The d-space conversion method using basis representation
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
A, b, c, K, J: CLP format
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
A converted problem in CLP format and list of CliqueSet,
|
|
54
|
+
(A2, b2, c2, K2, J2, list_cliqueSet)
|
|
55
|
+
"""
|
|
56
|
+
if len(K.s) == 0:
|
|
57
|
+
print('No conversion becsuse K.s is empty.')
|
|
58
|
+
import copy
|
|
59
|
+
A2 = copy.deepcopy(A)
|
|
60
|
+
b2 = copy.deepcopy(b)
|
|
61
|
+
c2 = copy.deepcopy(c)
|
|
62
|
+
K2 = K.SymCone()
|
|
63
|
+
J2 = J.SymCone()
|
|
64
|
+
return A2, b2, c2, K2, J2, None
|
|
65
|
+
|
|
66
|
+
sDimTotal = sum([x ** 2 for x in K.s])
|
|
67
|
+
size_m, size_n = A.shape
|
|
68
|
+
numSDPcones = len(K.s)
|
|
69
|
+
|
|
70
|
+
list_cliqueSet = []
|
|
71
|
+
|
|
72
|
+
# When a block is not converted
|
|
73
|
+
list_addcs = []
|
|
74
|
+
list_addAs = []
|
|
75
|
+
list_addKs = []
|
|
76
|
+
|
|
77
|
+
# Additional J.s part
|
|
78
|
+
list_addAclq = []
|
|
79
|
+
list_addJs = []
|
|
80
|
+
|
|
81
|
+
# --------------------------------------------------
|
|
82
|
+
# Type check
|
|
83
|
+
# --------------------------------------------------
|
|
84
|
+
if not sparse.isspmatrix_csc(A):
|
|
85
|
+
A = A.tocsc()
|
|
86
|
+
|
|
87
|
+
if not sparse.isspmatrix_csc(b):
|
|
88
|
+
b = b.tocsc()
|
|
89
|
+
|
|
90
|
+
if not sparse.isspmatrix_csc(c):
|
|
91
|
+
c = c.tocsc()
|
|
92
|
+
|
|
93
|
+
# --------------------------------------------------
|
|
94
|
+
# Get maximal cliques and make additional submatrix
|
|
95
|
+
# --------------------------------------------------
|
|
96
|
+
col_ptr = K.f + K.l + sum(K.q)
|
|
97
|
+
offset_row = 0
|
|
98
|
+
offset_col = 0
|
|
99
|
+
# Additional c_f
|
|
100
|
+
addcf_row = []
|
|
101
|
+
addcf_val = []
|
|
102
|
+
# Additional A_f
|
|
103
|
+
addAf_row = []
|
|
104
|
+
addAf_col = []
|
|
105
|
+
addAf_val = []
|
|
106
|
+
# Additional J.s part of A_f
|
|
107
|
+
addAclq_row = []
|
|
108
|
+
addAclq_col = []
|
|
109
|
+
|
|
110
|
+
for sDim in K.s:
|
|
111
|
+
A_block = A[:, col_ptr:(col_ptr + sDim ** 2)]
|
|
112
|
+
c_block = c[col_ptr:(col_ptr + sDim ** 2)]
|
|
113
|
+
|
|
114
|
+
# Get Aggregate Sparsity Pattern
|
|
115
|
+
asp = asputils.getASP(A_block, c_block, (sDim,))
|
|
116
|
+
# print asp
|
|
117
|
+
|
|
118
|
+
# Get maximal clique and add to clique list
|
|
119
|
+
cliqueSet = asputils.cliques_fromASP(asp)
|
|
120
|
+
if cliqueSet == None:
|
|
121
|
+
# Doesn't need to convert this block
|
|
122
|
+
list_addcs.append([c_block])
|
|
123
|
+
list_addAs.append(A_block)
|
|
124
|
+
list_addKs.append(sDim)
|
|
125
|
+
list_cliqueSet.append(None)
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
list_cliqueSet.append(cliqueSet)
|
|
129
|
+
# print cliqueSet.map_convIndex
|
|
130
|
+
|
|
131
|
+
# ----------------------------------------
|
|
132
|
+
# Make additional submatrix
|
|
133
|
+
# ----------------------------------------
|
|
134
|
+
|
|
135
|
+
# Make addAclq
|
|
136
|
+
add_Js = [len(clq) for clq in cliqueSet.cliques]
|
|
137
|
+
addJs_size = sum([x ** 2 for x in add_Js])
|
|
138
|
+
addAclq_row.extend([i + offset_row for i in range(addJs_size)])
|
|
139
|
+
for clq in cliqueSet.cliques:
|
|
140
|
+
addAclq_col.extend([cliqueSet.map_convIndex[i*sDim+j] + offset_col
|
|
141
|
+
for i in clq for j in clq])
|
|
142
|
+
|
|
143
|
+
# Make addcf
|
|
144
|
+
for (row, val) in zip(c_block.nonzero()[0], c_block.data):
|
|
145
|
+
i = row // sDim
|
|
146
|
+
j = row % sDim
|
|
147
|
+
if i >= j:
|
|
148
|
+
addcf_row.append(cliqueSet.map_convIndex[row] + offset_col)
|
|
149
|
+
addcf_val.append(val * 2 if i > j else val)
|
|
150
|
+
|
|
151
|
+
#print addcf_row
|
|
152
|
+
|
|
153
|
+
# Make addAf
|
|
154
|
+
for (row, col, val) in zip(A_block.nonzero()[0], A_block.nonzero()[1],
|
|
155
|
+
A_block.data):
|
|
156
|
+
i = col // sDim
|
|
157
|
+
j = col % sDim
|
|
158
|
+
if i >= j:
|
|
159
|
+
addAf_row.append(row)
|
|
160
|
+
addAf_col.append(cliqueSet.map_convIndex[col] + offset_col)
|
|
161
|
+
addAf_val.append(val * 2 if i > j else val)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
list_addJs.extend(add_Js)
|
|
165
|
+
|
|
166
|
+
col_ptr += sDim ** 2
|
|
167
|
+
offset_row += addJs_size
|
|
168
|
+
offset_col += cliqueSet.num_element
|
|
169
|
+
|
|
170
|
+
# --------------------------------------------------
|
|
171
|
+
# Make converted matrix
|
|
172
|
+
# --------------------------------------------------
|
|
173
|
+
size_addJs = offset_row
|
|
174
|
+
size_addKf = offset_col
|
|
175
|
+
size_addKs = sum(list_addKs)
|
|
176
|
+
|
|
177
|
+
list_A = []
|
|
178
|
+
list_c = []
|
|
179
|
+
|
|
180
|
+
# J.f, J.l, J.q, J.s part
|
|
181
|
+
# K.f part
|
|
182
|
+
if K.f > 0:
|
|
183
|
+
A_f = A[:, 0:K.f]
|
|
184
|
+
list_A.append(A_f)
|
|
185
|
+
c_f = c[0:K.f]
|
|
186
|
+
list_c.append([c_f])
|
|
187
|
+
|
|
188
|
+
# Additional K.f part
|
|
189
|
+
if len(addAf_val) > 0:
|
|
190
|
+
add_Af = csc_matrix((addAf_val, (addAf_row, addAf_col)),
|
|
191
|
+
shape=(size_m, size_addKf))
|
|
192
|
+
add_cf = csc_matrix((addcf_val, (addcf_row, [0] * len(addcf_row))),
|
|
193
|
+
shape=(size_addKf, 1))
|
|
194
|
+
list_A.append(add_Af)
|
|
195
|
+
list_c.append([add_cf])
|
|
196
|
+
|
|
197
|
+
# K.l, K.q part
|
|
198
|
+
if K.l > 0 or len(K.q) > 0:
|
|
199
|
+
A_lq = A[:, K.f:(K.f + K.l + sum(K.q))]
|
|
200
|
+
list_A.append(A_lq)
|
|
201
|
+
c_lq = c[K.f:(K.f + K.l + sum(K.q))]
|
|
202
|
+
list_c.append([c_lq])
|
|
203
|
+
|
|
204
|
+
# Additional K.s part
|
|
205
|
+
if len(addAf_val) > 0:
|
|
206
|
+
list_A.extend(list_addAs)
|
|
207
|
+
list_c.extend(list_addcs)
|
|
208
|
+
|
|
209
|
+
# Concatenate matrix
|
|
210
|
+
A2 = bmat([list_A])
|
|
211
|
+
c2 = bmat(list_c)
|
|
212
|
+
|
|
213
|
+
# Additional J.s part
|
|
214
|
+
if len(addAf_val) > 0:
|
|
215
|
+
list_A = []
|
|
216
|
+
add_Aclq = csc_matrix(([1.0] * len(addAclq_row),
|
|
217
|
+
(addAclq_row, addAclq_col)),
|
|
218
|
+
shape=(size_addJs, size_addKf))
|
|
219
|
+
if K.f > 0:
|
|
220
|
+
list_A.append(csc_matrix((size_addJs, K.f)))
|
|
221
|
+
|
|
222
|
+
list_A.append(add_Aclq)
|
|
223
|
+
|
|
224
|
+
if K.l > 0 or len(K.q) > 0:
|
|
225
|
+
list_A.append(csc_matrix((size_addJs, K.l + sum(K.q))))
|
|
226
|
+
|
|
227
|
+
if len(list_addAs) > 0:
|
|
228
|
+
list_A.append(csc_matrix((size_addJs, size_addKs)))
|
|
229
|
+
|
|
230
|
+
add_A = bmat([list_A])
|
|
231
|
+
A2 = bmat([[A2], [add_A]])
|
|
232
|
+
b2 = bmat([[b], [csc_matrix((size_addJs, 1))]])
|
|
233
|
+
else:
|
|
234
|
+
b2 = b
|
|
235
|
+
|
|
236
|
+
# --------------------------------------------------
|
|
237
|
+
# Make converted SymCone
|
|
238
|
+
# --------------------------------------------------
|
|
239
|
+
K2 = SymCone(f=K.f+size_addKf, l=K.l, q=K.q, s=tuple(list_addKs))
|
|
240
|
+
J2 = SymCone(f=J.f, l=J.l, q=J.q, s=tuple(list(J.s)+list_addJs))
|
|
241
|
+
|
|
242
|
+
return A2, b2, c2, K2, J2, list_cliqueSet
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def rconv_matdecomp(A, b, c, K, J):
|
|
246
|
+
"""The r-space conversion method using matrix decomposition.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
A, b, c, K, J: CoLO format
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
A converted problem in CoLO format and list of CliqueSet,
|
|
253
|
+
(A2, b2, c2, K2, J2, list_cliqueSet)
|
|
254
|
+
"""
|
|
255
|
+
dom_A, dom_b, dom_c, dom_K, dom_J, list_cliqueSet = \
|
|
256
|
+
dconv_basisrep(-A.T, -c, -b, J, K)
|
|
257
|
+
A2 = -dom_A.T
|
|
258
|
+
c2 = -dom_b
|
|
259
|
+
b2 = -dom_c
|
|
260
|
+
J2 = dom_K
|
|
261
|
+
K2 = dom_J
|
|
262
|
+
|
|
263
|
+
return A2, b2, c2, K2, J2, list_cliqueSet
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def dconv_basisresult(x, y, K, J, dom_K, cliqueD):
|
|
267
|
+
"""Retrieve an optimal solution which solved by dconv_basisrep()
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
x, y: Results of the converted problem
|
|
271
|
+
K, J: A SymCone of the original problem
|
|
272
|
+
dom_K: A SymCone of the converted problem
|
|
273
|
+
cliqueD: A list of CliqueSet
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
x0, y0: Results of the original problem
|
|
277
|
+
"""
|
|
278
|
+
# --------------------------------------------------
|
|
279
|
+
# Type check
|
|
280
|
+
# --------------------------------------------------
|
|
281
|
+
if not sparse.isspmatrix_csc(x):
|
|
282
|
+
x = x.tocsc()
|
|
283
|
+
if not sparse.isspmatrix_csc(y):
|
|
284
|
+
y = y.tocsc()
|
|
285
|
+
|
|
286
|
+
x0_row = []
|
|
287
|
+
x0_val = []
|
|
288
|
+
if K.f > 0:
|
|
289
|
+
x_f = x[:K.f]
|
|
290
|
+
x0_row.extend(list(x_f.nonzero()[0]))
|
|
291
|
+
x0_val.extend(list(x_f.data))
|
|
292
|
+
|
|
293
|
+
add_xf = x[K.f:dom_K.f]
|
|
294
|
+
|
|
295
|
+
if K.l > 0 or len(K.q) > 0:
|
|
296
|
+
x_lq = x[dom_K.f:(dom_K.f + dom_K.l + sum(dom_K.q))]
|
|
297
|
+
x0_row.extend(list(x_lq.nonzero()[0]))
|
|
298
|
+
x0_val.extend(list(x_lq.data))
|
|
299
|
+
|
|
300
|
+
if len(dom_K.s) > 0:
|
|
301
|
+
add_xs = x[(dom_K.f + dom_K.l + sum(dom_K.q)):]
|
|
302
|
+
|
|
303
|
+
offset_x0 = K.f + K.l + sum(K.q)
|
|
304
|
+
offset_addxf = 0
|
|
305
|
+
offset_addxs = 0
|
|
306
|
+
index_addKs = 0
|
|
307
|
+
for cliqueSet in cliqueD:
|
|
308
|
+
if cliqueSet != None:
|
|
309
|
+
size_clique = cliqueSet.num_element
|
|
310
|
+
addxf_block = add_xf[offset_addxf:(offset_addxf + size_clique)]
|
|
311
|
+
for (row, val) in zip(addxf_block.nonzero()[0], addxf_block.data):
|
|
312
|
+
orig_idx = cliqueSet.map_origIndex[row]
|
|
313
|
+
if orig_idx[0] != orig_idx[1]:
|
|
314
|
+
x0_row.extend([offset_x0 + orig_idx[0],
|
|
315
|
+
offset_x0 + orig_idx[1]])
|
|
316
|
+
x0_val.extend([val, val])
|
|
317
|
+
else:
|
|
318
|
+
x0_row.append(offset_x0 + orig_idx[0])
|
|
319
|
+
x0_val.append(val)
|
|
320
|
+
|
|
321
|
+
offset_addxf += size_clique
|
|
322
|
+
offset_x0 += size_clique
|
|
323
|
+
else:
|
|
324
|
+
size_Ks = dom_K.s[index_addKs] ** 2
|
|
325
|
+
addxs_block = add_xs[offset_addxs:(offset_addxs + size_Ks)]
|
|
326
|
+
addxs_row = list(addxs_block.I)
|
|
327
|
+
for row in addxs_row:
|
|
328
|
+
x0_row.append(offset_x0 + row)
|
|
329
|
+
|
|
330
|
+
x0_val.extend(list(addxs_block.V))
|
|
331
|
+
offset_addxs += size_Ks
|
|
332
|
+
offset_x0 += size_Ks
|
|
333
|
+
|
|
334
|
+
totalsize_x = K.f + K.l + sum(K.q) + sum([i ** 2 for i in K.s])
|
|
335
|
+
totalsize_y = J.f + J.l + sum(J.q) + sum([i ** 2 for i in J.s])
|
|
336
|
+
x0 = csc_matrix((x0_val, (x0_row, [0] * len(x0_row))),
|
|
337
|
+
shape=(totalsize_x, 1))
|
|
338
|
+
y0 = y[:totalsize_y]
|
|
339
|
+
|
|
340
|
+
return x0, y0
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def rconv_decompresult(x, y, K, J, ran_J, cliqueR):
|
|
344
|
+
"""Retrieve an optimal solution which solved by rconv_matdecomp()
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
x, y: Results of the converted problem
|
|
348
|
+
K, J: A SymCone of the original problem
|
|
349
|
+
ran_J: A SymCone of the converted problem
|
|
350
|
+
cliqueR: A list of CliqueSet
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
x0, y0: Results of the original problem
|
|
354
|
+
"""
|
|
355
|
+
y0, x0 = dconv_basisresult(y, x, J, K, ran_J, cliqueR)
|
|
356
|
+
return x0, y0
|
|
Binary file
|