scs 0.5.2 → 0.5.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/LICENSE.txt +1 -1
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +1 -1
- data/vendor/scs/CMakeLists.txt +1 -1
- data/vendor/scs/README.md +1 -2
- data/vendor/scs/include/cones.h +2 -2
- data/vendor/scs/include/glbopts.h +9 -15
- data/vendor/scs/include/util.h +1 -0
- data/vendor/scs/linsys/external/amd/amd_1.c +1 -1
- data/vendor/scs/linsys/external/amd/amd_2.c +44 -44
- data/vendor/scs/linsys/external/amd/amd_aat.c +5 -5
- data/vendor/scs/linsys/external/amd/amd_dump.c +12 -12
- data/vendor/scs/linsys/external/amd/amd_post_tree.c +3 -3
- data/vendor/scs/linsys/external/amd/amd_postorder.c +8 -8
- data/vendor/scs/linsys/external/amd/amd_valid.c +5 -5
- data/vendor/scs/scs.mk +1 -1
- data/vendor/scs/src/cones.c +564 -753
- data/vendor/scs/src/exp_cone.c +105 -83
- data/vendor/scs/src/linalg.c +6 -0
- data/vendor/scs/src/scs.c +1 -1
- metadata +2 -2
data/vendor/scs/src/cones.c
CHANGED
|
@@ -3,12 +3,27 @@
|
|
|
3
3
|
#include "scs.h"
|
|
4
4
|
#include "scs_blas.h" /* contains BLAS(X) macros and type info */
|
|
5
5
|
#include "util.h"
|
|
6
|
-
#include <complex.h>
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
/*
|
|
8
|
+
* Cross-platform Complex Type Handling
|
|
9
|
+
* MSVC uses struct layout; GCC/Clang uses C99 _Complex
|
|
10
|
+
*/
|
|
11
|
+
#if defined(_MSC_VER)
|
|
12
|
+
typedef struct {
|
|
13
|
+
double real, imag;
|
|
14
|
+
} scs_blas_cdouble;
|
|
15
|
+
typedef struct {
|
|
16
|
+
float real, imag;
|
|
17
|
+
} scs_blas_cfloat;
|
|
18
|
+
#ifndef SFLOAT
|
|
19
|
+
#define SCS_BLAS_COMPLEX_TYPE scs_blas_cdouble
|
|
20
|
+
#define SCS_BLAS_COMPLEX_CAST(x) ((scs_blas_cdouble *)(x))
|
|
21
|
+
#else
|
|
22
|
+
#define SCS_BLAS_COMPLEX_TYPE scs_blas_cfloat
|
|
23
|
+
#define SCS_BLAS_COMPLEX_CAST(x) ((scs_blas_cfloat *)(x))
|
|
24
|
+
#endif
|
|
25
|
+
#else
|
|
26
|
+
#include <complex.h>
|
|
12
27
|
#ifndef SFLOAT
|
|
13
28
|
#define SCS_BLAS_COMPLEX_CAST(x) ((double _Complex *)(x))
|
|
14
29
|
#define SCS_BLAS_COMPLEX_TYPE double _Complex
|
|
@@ -16,7 +31,9 @@
|
|
|
16
31
|
#define SCS_BLAS_COMPLEX_CAST(x) ((float _Complex *)(x))
|
|
17
32
|
#define SCS_BLAS_COMPLEX_TYPE float _Complex
|
|
18
33
|
#endif
|
|
34
|
+
#endif
|
|
19
35
|
|
|
36
|
+
/* Constants */
|
|
20
37
|
#define BOX_CONE_MAX_ITERS (25)
|
|
21
38
|
#define POW_CONE_TOL (1e-9)
|
|
22
39
|
#define POW_CONE_MAX_ITERS (20)
|
|
@@ -30,9 +47,14 @@
|
|
|
30
47
|
extern "C" {
|
|
31
48
|
#endif
|
|
32
49
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
50
|
+
/* LAPACK / BLAS Function Prototypes */
|
|
51
|
+
void BLAS(syevr)(const char *jobz, const char *range, const char *uplo,
|
|
52
|
+
blas_int *n, scs_float *a, blas_int *lda, scs_float *vl,
|
|
53
|
+
scs_float *vu, blas_int *il, blas_int *iu, scs_float *abstol,
|
|
54
|
+
blas_int *m, scs_float *w, scs_float *z, blas_int *ldz,
|
|
55
|
+
blas_int *isuppz, scs_float *work, blas_int *lwork,
|
|
56
|
+
blas_int *iwork, blas_int *liwork, blas_int *info);
|
|
57
|
+
|
|
36
58
|
void BLASC(heevr)(const char *jobz, const char *range, const char *uplo,
|
|
37
59
|
blas_int *n, SCS_BLAS_COMPLEX_TYPE *a, blas_int *lda,
|
|
38
60
|
scs_float *vl, scs_float *vu, blas_int *il, blas_int *iu,
|
|
@@ -65,7 +87,7 @@ void BLAS(gesvd)(const char *jobu, const char *jobvt, const blas_int *m,
|
|
|
65
87
|
const blas_int *ldvt, scs_float *work, const blas_int *lwork,
|
|
66
88
|
blas_int *info);
|
|
67
89
|
|
|
68
|
-
|
|
90
|
+
/* Forward declare spectral matrix cone projections */
|
|
69
91
|
scs_int SCS(proj_logdet_cone)(scs_float *tvX, const scs_int n, ScsConeWork *c,
|
|
70
92
|
scs_int offset, bool *warmstart);
|
|
71
93
|
scs_int SCS(proj_nuclear_cone)(scs_float *tX, scs_int m, scs_int n,
|
|
@@ -78,13 +100,15 @@ scs_int SCS(proj_sum_largest_evals)(scs_float *tX, scs_int n, scs_int k,
|
|
|
78
100
|
#ifdef __cplusplus
|
|
79
101
|
}
|
|
80
102
|
#endif
|
|
81
|
-
#endif
|
|
103
|
+
#endif /* USE_LAPACK */
|
|
82
104
|
|
|
83
|
-
/* Forward declare exponential cone projection
|
|
84
|
-
* Implemented in exp_cone.c.
|
|
85
|
-
*/
|
|
105
|
+
/* Forward declare exponential cone projection (exp_cone.c) */
|
|
86
106
|
scs_float SCS(proj_pd_exp_cone)(scs_float *v0, scs_int primal);
|
|
87
107
|
|
|
108
|
+
/*
|
|
109
|
+
* Memory Management
|
|
110
|
+
*/
|
|
111
|
+
|
|
88
112
|
void SCS(free_cone)(ScsCone *k) {
|
|
89
113
|
if (k) {
|
|
90
114
|
if (k->bu)
|
|
@@ -119,74 +143,83 @@ void SCS(free_cone)(ScsCone *k) {
|
|
|
119
143
|
|
|
120
144
|
void SCS(deep_copy_cone)(ScsCone *dest, const ScsCone *src) {
|
|
121
145
|
memcpy(dest, src, sizeof(ScsCone));
|
|
122
|
-
|
|
146
|
+
|
|
147
|
+
/* Box cone */
|
|
123
148
|
if (src->bsize > 1) {
|
|
124
149
|
dest->bu = (scs_float *)scs_calloc(src->bsize - 1, sizeof(scs_float));
|
|
125
|
-
memcpy(dest->bu, src->bu, (src->bsize - 1) * sizeof(scs_float));
|
|
126
150
|
dest->bl = (scs_float *)scs_calloc(src->bsize - 1, sizeof(scs_float));
|
|
151
|
+
memcpy(dest->bu, src->bu, (src->bsize - 1) * sizeof(scs_float));
|
|
127
152
|
memcpy(dest->bl, src->bl, (src->bsize - 1) * sizeof(scs_float));
|
|
128
153
|
} else {
|
|
129
154
|
dest->bu = SCS_NULL;
|
|
130
155
|
dest->bl = SCS_NULL;
|
|
131
156
|
}
|
|
132
|
-
|
|
157
|
+
|
|
158
|
+
/* SOC */
|
|
133
159
|
if (src->qsize > 0) {
|
|
134
160
|
dest->q = (scs_int *)scs_calloc(src->qsize, sizeof(scs_int));
|
|
135
161
|
memcpy(dest->q, src->q, src->qsize * sizeof(scs_int));
|
|
136
162
|
} else {
|
|
137
163
|
dest->q = SCS_NULL;
|
|
138
164
|
}
|
|
139
|
-
|
|
165
|
+
|
|
166
|
+
/* PSD */
|
|
140
167
|
if (src->ssize > 0) {
|
|
141
168
|
dest->s = (scs_int *)scs_calloc(src->ssize, sizeof(scs_int));
|
|
142
169
|
memcpy(dest->s, src->s, src->ssize * sizeof(scs_int));
|
|
143
170
|
} else {
|
|
144
171
|
dest->s = SCS_NULL;
|
|
145
172
|
}
|
|
146
|
-
|
|
173
|
+
|
|
174
|
+
/* Complex PSD */
|
|
147
175
|
if (src->cssize > 0) {
|
|
148
176
|
dest->cs = (scs_int *)scs_calloc(src->cssize, sizeof(scs_int));
|
|
149
177
|
memcpy(dest->cs, src->cs, src->cssize * sizeof(scs_int));
|
|
150
178
|
} else {
|
|
151
179
|
dest->cs = SCS_NULL;
|
|
152
180
|
}
|
|
153
|
-
|
|
181
|
+
|
|
182
|
+
/* Power */
|
|
154
183
|
if (src->psize > 0) {
|
|
155
184
|
dest->p = (scs_float *)scs_calloc(src->psize, sizeof(scs_float));
|
|
156
185
|
memcpy(dest->p, src->p, src->psize * sizeof(scs_float));
|
|
157
186
|
} else {
|
|
158
187
|
dest->p = SCS_NULL;
|
|
159
188
|
}
|
|
189
|
+
|
|
160
190
|
#ifdef USE_SPECTRAL_CONES
|
|
161
|
-
/*
|
|
191
|
+
/* Logdet */
|
|
162
192
|
if (src->dsize > 0) {
|
|
163
193
|
dest->d = (scs_int *)scs_calloc(src->dsize, sizeof(scs_int));
|
|
164
194
|
memcpy(dest->d, src->d, src->dsize * sizeof(scs_int));
|
|
165
195
|
} else {
|
|
166
196
|
dest->d = SCS_NULL;
|
|
167
197
|
}
|
|
168
|
-
|
|
198
|
+
|
|
199
|
+
/* Nuclear */
|
|
169
200
|
if (src->nucsize > 0) {
|
|
170
201
|
dest->nuc_m = (scs_int *)scs_calloc(src->nucsize, sizeof(scs_int));
|
|
171
|
-
memcpy(dest->nuc_m, src->nuc_m, src->nucsize * sizeof(scs_int));
|
|
172
202
|
dest->nuc_n = (scs_int *)scs_calloc(src->nucsize, sizeof(scs_int));
|
|
203
|
+
memcpy(dest->nuc_m, src->nuc_m, src->nucsize * sizeof(scs_int));
|
|
173
204
|
memcpy(dest->nuc_n, src->nuc_n, src->nucsize * sizeof(scs_int));
|
|
174
205
|
} else {
|
|
175
206
|
dest->nuc_m = SCS_NULL;
|
|
176
207
|
dest->nuc_n = SCS_NULL;
|
|
177
208
|
}
|
|
178
|
-
|
|
209
|
+
|
|
210
|
+
/* Ell1 */
|
|
179
211
|
if (src->ell1_size > 0) {
|
|
180
212
|
dest->ell1 = (scs_int *)scs_calloc(src->ell1_size, sizeof(scs_int));
|
|
181
213
|
memcpy(dest->ell1, src->ell1, src->ell1_size * sizeof(scs_int));
|
|
182
214
|
} else {
|
|
183
215
|
dest->ell1 = SCS_NULL;
|
|
184
216
|
}
|
|
185
|
-
|
|
217
|
+
|
|
218
|
+
/* Sum Largest Eigenvalues */
|
|
186
219
|
if (src->sl_size > 0) {
|
|
187
220
|
dest->sl_n = (scs_int *)scs_calloc(src->sl_size, sizeof(scs_int));
|
|
188
|
-
memcpy(dest->sl_n, src->sl_n, src->sl_size * sizeof(scs_int));
|
|
189
221
|
dest->sl_k = (scs_int *)scs_calloc(src->sl_size, sizeof(scs_int));
|
|
222
|
+
memcpy(dest->sl_n, src->sl_n, src->sl_size * sizeof(scs_int));
|
|
190
223
|
memcpy(dest->sl_k, src->sl_k, src->sl_size * sizeof(scs_int));
|
|
191
224
|
} else {
|
|
192
225
|
dest->sl_n = SCS_NULL;
|
|
@@ -195,7 +228,17 @@ void SCS(deep_copy_cone)(ScsCone *dest, const ScsCone *src) {
|
|
|
195
228
|
#endif
|
|
196
229
|
}
|
|
197
230
|
|
|
198
|
-
/*
|
|
231
|
+
/*
|
|
232
|
+
* Helper Functions
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
static inline scs_int get_sd_cone_size(scs_int s) {
|
|
236
|
+
return (s * (s + 1)) / 2;
|
|
237
|
+
}
|
|
238
|
+
static inline scs_int get_csd_cone_size(scs_int cs) {
|
|
239
|
+
return cs * cs;
|
|
240
|
+
}
|
|
241
|
+
|
|
199
242
|
void SCS(set_r_y)(const ScsConeWork *c, scs_float scale, scs_float *r_y) {
|
|
200
243
|
scs_int i;
|
|
201
244
|
/* z cone */
|
|
@@ -206,14 +249,13 @@ void SCS(set_r_y)(const ScsConeWork *c, scs_float scale, scs_float *r_y) {
|
|
|
206
249
|
*/
|
|
207
250
|
r_y[i] = 1.0 / (1000. * scale);
|
|
208
251
|
}
|
|
209
|
-
|
|
210
|
-
/* others */
|
|
252
|
+
/* Remaining cones */
|
|
211
253
|
for (i = c->k->z; i < c->m; ++i) {
|
|
212
254
|
r_y[i] = 1.0 / scale;
|
|
213
255
|
}
|
|
214
256
|
}
|
|
215
257
|
|
|
216
|
-
/*
|
|
258
|
+
/* The function f aggregates the entries within each cone */
|
|
217
259
|
void SCS(enforce_cone_boundaries)(const ScsConeWork *c, scs_float *vec,
|
|
218
260
|
scs_float (*f)(const scs_float *, scs_int)) {
|
|
219
261
|
scs_int i, j, delta;
|
|
@@ -229,140 +271,77 @@ void SCS(enforce_cone_boundaries)(const ScsConeWork *c, scs_float *vec,
|
|
|
229
271
|
}
|
|
230
272
|
}
|
|
231
273
|
|
|
232
|
-
static inline scs_int get_sd_cone_size(scs_int s) {
|
|
233
|
-
return (s * (s + 1)) / 2;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
static inline scs_int get_csd_cone_size(scs_int cs) {
|
|
237
|
-
return cs * cs;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
274
|
/*
|
|
241
|
-
*
|
|
275
|
+
* Boundaries will contain array of indices of rows of A corresponding to
|
|
242
276
|
* cone boundaries, boundaries[0] is starting index for cones of size strictly
|
|
243
277
|
* larger than 1, boundaries malloc-ed here so should be freed.
|
|
244
278
|
*/
|
|
245
279
|
void set_cone_boundaries(const ScsCone *k, ScsConeWork *c) {
|
|
246
|
-
scs_int i,
|
|
280
|
+
scs_int i, count = 0;
|
|
247
281
|
#ifdef USE_SPECTRAL_CONES
|
|
248
|
-
scs_int
|
|
249
|
-
|
|
250
|
-
|
|
282
|
+
scs_int total_cones = k->qsize + k->ssize + k->cssize + k->ed + k->ep +
|
|
283
|
+
k->psize + k->dsize + k->nucsize + k->ell1_size +
|
|
284
|
+
k->sl_size;
|
|
251
285
|
#else
|
|
252
|
-
scs_int
|
|
253
|
-
|
|
286
|
+
scs_int total_cones =
|
|
287
|
+
k->qsize + k->ssize + k->cssize + k->ed + k->ep + k->psize;
|
|
254
288
|
#endif
|
|
255
|
-
scs_int *b = (scs_int *)scs_calloc(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
count
|
|
259
|
-
for (i = 0; i < k->qsize; ++i)
|
|
260
|
-
b[count
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
b[count
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
cs_cone_sz = get_csd_cone_size(k->cs[i]);
|
|
271
|
-
b[count + i] = cs_cone_sz;
|
|
272
|
-
}
|
|
273
|
-
count += k->cssize;
|
|
274
|
-
/* exp cones */
|
|
275
|
-
for (i = 0; i < k->ep + k->ed; ++i) {
|
|
276
|
-
b[count + i] = 3;
|
|
277
|
-
}
|
|
278
|
-
count += k->ep + k->ed;
|
|
279
|
-
/* power cones */
|
|
280
|
-
for (i = 0; i < k->psize; ++i) {
|
|
281
|
-
b[count + i] = 3;
|
|
282
|
-
}
|
|
283
|
-
count += k->psize;
|
|
289
|
+
scs_int *b = (scs_int *)scs_calloc(total_cones + 1, sizeof(scs_int));
|
|
290
|
+
|
|
291
|
+
/* Cones that can be scaled independently */
|
|
292
|
+
b[count++] = k->z + k->l + k->bsize;
|
|
293
|
+
for (i = 0; i < k->qsize; ++i)
|
|
294
|
+
b[count++] = k->q[i];
|
|
295
|
+
for (i = 0; i < k->ssize; ++i)
|
|
296
|
+
b[count++] = get_sd_cone_size(k->s[i]);
|
|
297
|
+
for (i = 0; i < k->cssize; ++i)
|
|
298
|
+
b[count++] = get_csd_cone_size(k->cs[i]);
|
|
299
|
+
for (i = 0; i < k->ep + k->ed; ++i)
|
|
300
|
+
b[count++] = 3;
|
|
301
|
+
for (i = 0; i < k->psize; ++i)
|
|
302
|
+
b[count++] = 3;
|
|
303
|
+
|
|
284
304
|
#ifdef USE_SPECTRAL_CONES
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
for (i = 0; i < k->
|
|
292
|
-
b[count
|
|
293
|
-
}
|
|
294
|
-
count += k->nucsize;
|
|
295
|
-
/* ell1-norm cones */
|
|
296
|
-
for (i = 0; i < k->ell1_size; ++i) {
|
|
297
|
-
b[count + i] = k->ell1[i] + 1;
|
|
298
|
-
}
|
|
299
|
-
count += k->ell1_size;
|
|
300
|
-
/* sum-of-largest eigenvalues cones */
|
|
301
|
-
for (i = 0; i < k->sl_size; ++i) {
|
|
302
|
-
b[count + i] = get_sd_cone_size(k->sl_n[i]) + 1;
|
|
303
|
-
}
|
|
304
|
-
count += k->sl_size;
|
|
305
|
+
for (i = 0; i < k->dsize; ++i)
|
|
306
|
+
b[count++] = get_sd_cone_size(k->d[i]) + 2;
|
|
307
|
+
for (i = 0; i < k->nucsize; ++i)
|
|
308
|
+
b[count++] = k->nuc_m[i] * k->nuc_n[i] + 1;
|
|
309
|
+
for (i = 0; i < k->ell1_size; ++i)
|
|
310
|
+
b[count++] = k->ell1[i] + 1;
|
|
311
|
+
for (i = 0; i < k->sl_size; ++i)
|
|
312
|
+
b[count++] = get_sd_cone_size(k->sl_n[i]) + 1;
|
|
305
313
|
#endif
|
|
306
|
-
|
|
314
|
+
|
|
307
315
|
c->cone_boundaries = b;
|
|
308
|
-
c->cone_boundaries_len =
|
|
316
|
+
c->cone_boundaries_len = total_cones + 1;
|
|
309
317
|
}
|
|
310
318
|
|
|
311
319
|
static scs_int get_full_cone_dims(const ScsCone *k) {
|
|
312
|
-
scs_int i,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
c += get_sd_cone_size(k->s[i]);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (k->cssize) {
|
|
324
|
-
for (i = 0; i < k->cssize; ++i) {
|
|
325
|
-
c += get_csd_cone_size(k->cs[i]);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
if (k->ed) {
|
|
329
|
-
c += 3 * k->ed;
|
|
330
|
-
}
|
|
331
|
-
if (k->ep) {
|
|
332
|
-
c += 3 * k->ep;
|
|
333
|
-
}
|
|
334
|
-
if (k->psize) {
|
|
335
|
-
c += 3 * k->psize;
|
|
336
|
-
}
|
|
320
|
+
scs_int i, dims = k->z + k->l + k->bsize;
|
|
321
|
+
for (i = 0; i < k->qsize; ++i)
|
|
322
|
+
dims += k->q[i];
|
|
323
|
+
for (i = 0; i < k->ssize; ++i)
|
|
324
|
+
dims += get_sd_cone_size(k->s[i]);
|
|
325
|
+
for (i = 0; i < k->cssize; ++i)
|
|
326
|
+
dims += get_csd_cone_size(k->cs[i]);
|
|
327
|
+
dims += 3 * (k->ed + k->ep + k->psize);
|
|
337
328
|
#ifdef USE_SPECTRAL_CONES
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
if (k->ell1_size) {
|
|
349
|
-
for (i = 0; i < k->ell1_size; ++i) {
|
|
350
|
-
c += k->ell1[i] + 1;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
if (k->sl_size) {
|
|
354
|
-
for (i = 0; i < k->sl_size; ++i) {
|
|
355
|
-
c += get_sd_cone_size(k->sl_n[i]) + 1;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
329
|
+
for (i = 0; i < k->dsize; ++i)
|
|
330
|
+
dims += get_sd_cone_size(k->d[i]) + 2;
|
|
331
|
+
for (i = 0; i < k->nucsize; ++i)
|
|
332
|
+
dims += k->nuc_m[i] * k->nuc_n[i] + 1;
|
|
333
|
+
for (i = 0; i < k->ell1_size; ++i)
|
|
334
|
+
dims += k->ell1[i] + 1;
|
|
335
|
+
for (i = 0; i < k->sl_size; ++i)
|
|
336
|
+
dims += get_sd_cone_size(k->sl_n[i]) + 1;
|
|
358
337
|
#endif
|
|
359
|
-
return
|
|
338
|
+
return dims;
|
|
360
339
|
}
|
|
361
340
|
|
|
362
341
|
scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
|
|
363
342
|
scs_int i;
|
|
364
343
|
if (get_full_cone_dims(k) != d->m) {
|
|
365
|
-
scs_printf("
|
|
344
|
+
scs_printf("Error: Cone dims %li != rows in A %li\n",
|
|
366
345
|
(long)get_full_cone_dims(k), (long)d->m);
|
|
367
346
|
return -1;
|
|
368
347
|
}
|
|
@@ -492,124 +471,98 @@ scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
|
|
|
492
471
|
}
|
|
493
472
|
|
|
494
473
|
void SCS(finish_cone)(ScsConeWork *c) {
|
|
474
|
+
if (!c)
|
|
475
|
+
return;
|
|
495
476
|
#ifdef USE_LAPACK
|
|
496
|
-
if (c->Xs)
|
|
477
|
+
if (c->Xs)
|
|
497
478
|
scs_free(c->Xs);
|
|
498
|
-
|
|
499
|
-
if (c->cXs) {
|
|
479
|
+
if (c->cXs)
|
|
500
480
|
scs_free(c->cXs);
|
|
501
|
-
|
|
502
|
-
if (c->Z) {
|
|
481
|
+
if (c->Z)
|
|
503
482
|
scs_free(c->Z);
|
|
504
|
-
|
|
505
|
-
if (c->cZ) {
|
|
483
|
+
if (c->cZ)
|
|
506
484
|
scs_free(c->cZ);
|
|
507
|
-
|
|
508
|
-
if (c->e) {
|
|
485
|
+
if (c->e)
|
|
509
486
|
scs_free(c->e);
|
|
510
|
-
|
|
511
|
-
if (c->isuppz) {
|
|
487
|
+
if (c->isuppz)
|
|
512
488
|
scs_free(c->isuppz);
|
|
513
|
-
|
|
514
|
-
if (c->work) {
|
|
489
|
+
if (c->work)
|
|
515
490
|
scs_free(c->work);
|
|
516
|
-
|
|
517
|
-
if (c->iwork) {
|
|
491
|
+
if (c->iwork)
|
|
518
492
|
scs_free(c->iwork);
|
|
519
|
-
|
|
520
|
-
if (c->cwork) {
|
|
493
|
+
if (c->cwork)
|
|
521
494
|
scs_free(c->cwork);
|
|
522
|
-
|
|
523
|
-
if (c->rwork) {
|
|
524
|
-
scs_free(c->rwork);
|
|
525
|
-
}
|
|
495
|
+
/* c->rwork is aliased to c->work in setup, no free needed */
|
|
526
496
|
#endif
|
|
527
|
-
if (c->cone_boundaries)
|
|
497
|
+
if (c->cone_boundaries)
|
|
528
498
|
scs_free(c->cone_boundaries);
|
|
529
|
-
|
|
530
|
-
if (c->s) {
|
|
499
|
+
if (c->s)
|
|
531
500
|
scs_free(c->s);
|
|
532
|
-
|
|
501
|
+
|
|
533
502
|
#ifdef USE_SPECTRAL_CONES
|
|
534
|
-
if (c->work_logdet)
|
|
503
|
+
if (c->work_logdet)
|
|
535
504
|
scs_free(c->work_logdet);
|
|
536
|
-
|
|
537
|
-
if (c->saved_log_projs) {
|
|
505
|
+
if (c->saved_log_projs)
|
|
538
506
|
scs_free(c->saved_log_projs);
|
|
539
|
-
|
|
540
|
-
if (c->s_nuc) {
|
|
507
|
+
if (c->s_nuc)
|
|
541
508
|
scs_free(c->s_nuc);
|
|
542
|
-
|
|
543
|
-
if (c->u_nuc) {
|
|
509
|
+
if (c->u_nuc)
|
|
544
510
|
scs_free(c->u_nuc);
|
|
545
|
-
|
|
546
|
-
if (c->vt_nuc) {
|
|
511
|
+
if (c->vt_nuc)
|
|
547
512
|
scs_free(c->vt_nuc);
|
|
548
|
-
|
|
549
|
-
if (c->work_nuc) {
|
|
513
|
+
if (c->work_nuc)
|
|
550
514
|
scs_free(c->work_nuc);
|
|
551
|
-
|
|
552
|
-
if (c->work_sum_of_largest) {
|
|
515
|
+
if (c->work_sum_of_largest)
|
|
553
516
|
scs_free(c->work_sum_of_largest);
|
|
554
|
-
|
|
555
|
-
if (c->log_cone_warmstarts) {
|
|
517
|
+
if (c->log_cone_warmstarts)
|
|
556
518
|
scs_free(c->log_cone_warmstarts);
|
|
557
|
-
|
|
558
|
-
if (c->work_ell1) {
|
|
519
|
+
if (c->work_ell1)
|
|
559
520
|
scs_free(c->work_ell1);
|
|
560
|
-
|
|
561
|
-
if (c->work_ell1_proj) {
|
|
521
|
+
if (c->work_ell1_proj)
|
|
562
522
|
scs_free(c->work_ell1_proj);
|
|
563
|
-
}
|
|
564
523
|
#endif
|
|
565
|
-
|
|
566
|
-
scs_free(c);
|
|
567
|
-
}
|
|
524
|
+
scs_free(c);
|
|
568
525
|
}
|
|
569
526
|
|
|
570
527
|
char *SCS(get_cone_header)(const ScsCone *k) {
|
|
571
|
-
char *tmp = (char *)scs_malloc(512);
|
|
572
|
-
scs_int i,
|
|
528
|
+
char *tmp = (char *)scs_malloc(512);
|
|
529
|
+
scs_int i, count;
|
|
530
|
+
|
|
573
531
|
sprintf(tmp, "cones: ");
|
|
574
|
-
if (k->z)
|
|
532
|
+
if (k->z)
|
|
575
533
|
sprintf(tmp + strlen(tmp), "\t z: primal zero / dual free vars: %li\n",
|
|
576
534
|
(long)k->z);
|
|
577
|
-
|
|
578
|
-
if (k->l) {
|
|
535
|
+
if (k->l)
|
|
579
536
|
sprintf(tmp + strlen(tmp), "\t l: linear vars: %li\n", (long)k->l);
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
soc_vars += k->q[i];
|
|
588
|
-
}
|
|
537
|
+
if (k->bsize)
|
|
538
|
+
sprintf(tmp + strlen(tmp), "\t b: box cone vars: %li\n", (long)k->bsize);
|
|
539
|
+
|
|
540
|
+
if (k->qsize) {
|
|
541
|
+
count = 0;
|
|
542
|
+
for (i = 0; i < k->qsize; ++i)
|
|
543
|
+
count += k->q[i];
|
|
589
544
|
sprintf(tmp + strlen(tmp), "\t q: soc vars: %li, qsize: %li\n",
|
|
590
|
-
(long)
|
|
545
|
+
(long)count, (long)k->qsize);
|
|
591
546
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
for (i = 0; i < k->ssize; i
|
|
595
|
-
|
|
596
|
-
}
|
|
547
|
+
if (k->ssize) {
|
|
548
|
+
count = 0;
|
|
549
|
+
for (i = 0; i < k->ssize; ++i)
|
|
550
|
+
count += get_sd_cone_size(k->s[i]);
|
|
597
551
|
sprintf(tmp + strlen(tmp), "\t s: psd vars: %li, ssize: %li\n",
|
|
598
|
-
(long)
|
|
552
|
+
(long)count, (long)k->ssize);
|
|
599
553
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
for (i = 0; i < k->cssize; i
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
(long)csd_vars, (long)k->cssize);
|
|
554
|
+
if (k->cssize) {
|
|
555
|
+
count = 0;
|
|
556
|
+
for (i = 0; i < k->cssize; ++i)
|
|
557
|
+
count += get_csd_cone_size(k->cs[i]);
|
|
558
|
+
sprintf(tmp + strlen(tmp), "\t cs: complex psd vars: %li, cssize: %li\n",
|
|
559
|
+
(long)count, (long)k->cssize);
|
|
607
560
|
}
|
|
608
561
|
if (k->ep || k->ed) {
|
|
609
562
|
sprintf(tmp + strlen(tmp), "\t e: exp vars: %li, dual exp vars: %li\n",
|
|
610
563
|
(long)(3 * k->ep), (long)(3 * k->ed));
|
|
611
564
|
}
|
|
612
|
-
if (k->psize
|
|
565
|
+
if (k->psize) {
|
|
613
566
|
sprintf(tmp + strlen(tmp), "\t p: primal + dual power vars: %li\n",
|
|
614
567
|
(long)(3 * k->psize));
|
|
615
568
|
}
|
|
@@ -649,190 +602,215 @@ char *SCS(get_cone_header)(const ScsCone *k) {
|
|
|
649
602
|
(long)sl_vars, (long)k->sl_size);
|
|
650
603
|
}
|
|
651
604
|
#endif
|
|
652
|
-
|
|
653
605
|
return tmp;
|
|
654
606
|
}
|
|
655
607
|
|
|
656
|
-
|
|
608
|
+
/*
|
|
609
|
+
* Workspace Setup
|
|
610
|
+
* Consolidated setup for Real PSD, Complex PSD, and Spectral cones.
|
|
611
|
+
*/
|
|
612
|
+
static scs_int set_up_cone_work_spaces(ScsConeWork *c, const ScsCone *k) {
|
|
657
613
|
scs_int i;
|
|
658
614
|
#ifdef USE_LAPACK
|
|
615
|
+
/* Max dim for eigenvalues (e) and integer work (isuppz) */
|
|
659
616
|
blas_int n_max = 1;
|
|
660
|
-
blas_int
|
|
661
|
-
blas_int
|
|
617
|
+
blas_int n_max_real = 1; /* Max dim for Real PSD matrix (Xs) */
|
|
618
|
+
blas_int n_max_csd = 1; /* Max dim for Complex PSD matrix (cXs) */
|
|
619
|
+
|
|
620
|
+
/* LAPACK Query Variables */
|
|
621
|
+
blas_int neg_one = -1, info = 0, m = 0;
|
|
622
|
+
blas_int d_i = 0;
|
|
623
|
+
scs_float d_f = 0.0, abstol = -1.0;
|
|
662
624
|
scs_float wkopt = 0.0;
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
625
|
+
blas_int iwkopt = 0;
|
|
626
|
+
scs_complex_float lcwork_opt = {0.0};
|
|
627
|
+
scs_float lrwork_opt = 0.0;
|
|
628
|
+
blas_int liwork_opt_c = 0;
|
|
629
|
+
|
|
630
|
+
/* Max workspace sizes across all cone types */
|
|
631
|
+
blas_int lwork_max = 0;
|
|
632
|
+
blas_int liwork_max = 0;
|
|
668
633
|
|
|
669
|
-
|
|
670
|
-
// compute max dimension needed for eigenvalue decomposition workspace
|
|
671
|
-
// (all cones appearing in the next section of code require eigenvalue
|
|
672
|
-
// decompositions)
|
|
673
|
-
// ----------------------------------------------------------------------
|
|
634
|
+
/* Calculate Dimensions */
|
|
674
635
|
for (i = 0; i < k->ssize; ++i) {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
636
|
+
n_max = MAX(n_max, (blas_int)k->s[i]);
|
|
637
|
+
n_max_real = MAX(n_max_real, (blas_int)k->s[i]);
|
|
638
|
+
}
|
|
639
|
+
for (i = 0; i < k->cssize; ++i) {
|
|
640
|
+
n_max = MAX(n_max, (blas_int)k->cs[i]);
|
|
641
|
+
n_max_csd = MAX(n_max_csd, (blas_int)k->cs[i]);
|
|
678
642
|
}
|
|
679
643
|
|
|
680
644
|
#ifdef USE_SPECTRAL_CONES
|
|
681
645
|
blas_int n_max_logdet = 1;
|
|
682
646
|
blas_int n_logdet_total = 0;
|
|
683
647
|
blas_int n_max_sl = 1;
|
|
684
|
-
c->log_cone_warmstarts = (bool *)scs_calloc(k->dsize, sizeof(bool));
|
|
685
648
|
|
|
686
|
-
|
|
687
|
-
if (k->sl_n[i] > n_max_sl) {
|
|
688
|
-
n_max_sl = (blas_int)k->sl_n[i];
|
|
689
|
-
}
|
|
690
|
-
}
|
|
649
|
+
c->log_cone_warmstarts = (bool *)scs_calloc(k->dsize, sizeof(bool));
|
|
691
650
|
|
|
651
|
+
/* Spectral Dimensions */
|
|
652
|
+
for (i = 0; i < k->sl_size; ++i)
|
|
653
|
+
n_max_sl = MAX(n_max_sl, (blas_int)k->sl_n[i]);
|
|
692
654
|
for (i = 0; i < k->dsize; ++i) {
|
|
693
655
|
n_logdet_total += (blas_int)k->d[i];
|
|
694
|
-
|
|
695
|
-
n_max_logdet = (blas_int)k->d[i];
|
|
696
|
-
}
|
|
656
|
+
n_max_logdet = MAX(n_max_logdet, (blas_int)k->d[i]);
|
|
697
657
|
}
|
|
698
658
|
|
|
699
|
-
|
|
700
|
-
// allocate workspace for logdeterminant cones
|
|
701
|
-
// --------------------------------------------------------------------------
|
|
659
|
+
/* Logdet Allocation */
|
|
702
660
|
if (k->dsize > 0) {
|
|
703
661
|
c->work_logdet =
|
|
704
662
|
(scs_float *)scs_calloc(22 * n_max_logdet + 122, sizeof(scs_float));
|
|
705
663
|
c->saved_log_projs = (scs_float *)scs_calloc(2 * k->dsize + n_logdet_total,
|
|
706
664
|
sizeof(scs_float));
|
|
707
|
-
|
|
708
|
-
if (!c->work_logdet || !c->saved_log_projs) {
|
|
665
|
+
if (!c->work_logdet || !c->saved_log_projs)
|
|
709
666
|
return -1;
|
|
710
|
-
}
|
|
711
667
|
}
|
|
712
|
-
|
|
713
|
-
// ---------------------------------------------------------------
|
|
714
|
-
// allocate workspace for sum-of-largest-eigenvalues cone
|
|
715
|
-
// ---------------------------------------------------------------
|
|
668
|
+
/* Sum Largest Allocation */
|
|
716
669
|
if (k->sl_size > 0) {
|
|
717
670
|
c->work_sum_of_largest =
|
|
718
671
|
(scs_float *)scs_calloc(n_max_sl * n_max_sl, sizeof(scs_float));
|
|
719
|
-
if (!c->work_sum_of_largest)
|
|
672
|
+
if (!c->work_sum_of_largest)
|
|
720
673
|
return -1;
|
|
721
|
-
}
|
|
722
674
|
}
|
|
675
|
+
|
|
676
|
+
/* Update Max Real Dims based on Spectral needs */
|
|
723
677
|
n_max = MAX(n_max, n_max_logdet);
|
|
724
678
|
n_max = MAX(n_max, n_max_sl);
|
|
679
|
+
n_max_real = MAX(n_max_real, n_max_logdet);
|
|
680
|
+
n_max_real = MAX(n_max_real, n_max_sl);
|
|
725
681
|
#endif
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
c->Z = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
|
|
682
|
+
|
|
683
|
+
/* Allocate standard eigenvalue buffers
|
|
684
|
+
* 'e' stores eigenvalues, 'isuppz' supports them. Shared by Real/Complex.
|
|
685
|
+
*/
|
|
731
686
|
c->e = (scs_float *)scs_calloc(n_max, sizeof(scs_float));
|
|
687
|
+
c->isuppz = (blas_int *)scs_calloc(MAX(2, 2 * n_max), sizeof(blas_int));
|
|
688
|
+
if (!c->e || !c->isuppz)
|
|
689
|
+
return -1;
|
|
732
690
|
|
|
733
|
-
/*
|
|
734
|
-
|
|
735
|
-
|
|
691
|
+
/* 1. Real PSD Workspace Query (syevr) */
|
|
692
|
+
if (k->ssize > 0
|
|
693
|
+
#ifdef USE_SPECTRAL_CONES
|
|
694
|
+
|| k->dsize > 0 || k->sl_size > 0
|
|
695
|
+
#endif
|
|
696
|
+
) {
|
|
697
|
+
c->Xs = (scs_float *)scs_calloc(n_max_real * n_max_real, sizeof(scs_float));
|
|
698
|
+
c->Z = (scs_float *)scs_calloc(n_max_real * n_max_real, sizeof(scs_float));
|
|
699
|
+
if (!c->Xs || !c->Z)
|
|
700
|
+
return -1;
|
|
736
701
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
702
|
+
BLAS(syevr)("V", "A", "L", &n_max_real, c->Xs, &n_max_real, &d_f, &d_f,
|
|
703
|
+
&d_i, &d_i, &abstol, &m, c->e, c->Z, &n_max_real, c->isuppz,
|
|
704
|
+
&wkopt, &neg_one, &iwkopt, &neg_one, &info);
|
|
705
|
+
|
|
706
|
+
if (info != 0) {
|
|
707
|
+
scs_printf("FATAL: syevr workspace query failure, info = %li\n",
|
|
708
|
+
(long)info);
|
|
709
|
+
return -1;
|
|
710
|
+
}
|
|
711
|
+
lwork_max = MAX(lwork_max, (blas_int)(wkopt + 1));
|
|
712
|
+
liwork_max = MAX(liwork_max, iwkopt);
|
|
740
713
|
}
|
|
741
714
|
|
|
742
|
-
|
|
743
|
-
|
|
715
|
+
/* 2. Complex PSD Workspace Query (heevr) */
|
|
716
|
+
if (k->cssize > 0) {
|
|
717
|
+
c->cXs = (scs_complex_float *)scs_calloc(n_max_csd * n_max_csd,
|
|
718
|
+
sizeof(scs_complex_float));
|
|
719
|
+
c->cZ = (scs_complex_float *)scs_calloc(n_max_csd * n_max_csd,
|
|
720
|
+
sizeof(scs_complex_float));
|
|
721
|
+
if (!c->cXs || !c->cZ)
|
|
722
|
+
return -1;
|
|
744
723
|
|
|
745
|
-
|
|
746
|
-
|
|
724
|
+
BLASC(heevr)("V", "A", "L", &n_max_csd, SCS_BLAS_COMPLEX_CAST(c->cXs),
|
|
725
|
+
&n_max_csd, &d_f, &d_f, &d_i, &d_i, &abstol, &m, c->e,
|
|
726
|
+
SCS_BLAS_COMPLEX_CAST(c->cZ), &n_max_csd, c->isuppz,
|
|
727
|
+
SCS_BLAS_COMPLEX_CAST(&lcwork_opt), &neg_one, &lrwork_opt,
|
|
728
|
+
&neg_one, &liwork_opt_c, &neg_one, &info);
|
|
729
|
+
|
|
730
|
+
if (info != 0) {
|
|
731
|
+
scs_printf("FATAL: heevr workspace query failure, info = %li\n",
|
|
732
|
+
(long)info);
|
|
733
|
+
return -1;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
c->lcwork = (blas_int)(lcwork_opt[0]);
|
|
737
|
+
c->cwork =
|
|
738
|
+
(scs_complex_float *)scs_calloc(c->lcwork, sizeof(scs_complex_float));
|
|
739
|
+
if (!c->cwork)
|
|
740
|
+
return -1;
|
|
741
|
+
|
|
742
|
+
/* heevr uses a real 'rwork' array. We alias this to the shared real 'work'
|
|
743
|
+
* array */
|
|
744
|
+
lwork_max = MAX(lwork_max, (blas_int)lrwork_opt);
|
|
745
|
+
liwork_max = MAX(liwork_max, liwork_opt_c);
|
|
747
746
|
}
|
|
748
747
|
|
|
749
748
|
#ifdef USE_SPECTRAL_CONES
|
|
750
|
-
|
|
751
|
-
// allocate memory for nuclear norm cone
|
|
752
|
-
// ------------------------------------------------------------------
|
|
749
|
+
/* 3. Nuclear Norm Workspace (gesvd) */
|
|
753
750
|
if (k->nucsize > 0) {
|
|
754
|
-
blas_int
|
|
755
|
-
blas_int n_max_nuc = 1;
|
|
751
|
+
blas_int m_max = 1, n_max_n = 1;
|
|
756
752
|
for (i = 0; i < k->nucsize; ++i) {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
}
|
|
760
|
-
if (k->nuc_n[i] > n_max_nuc) {
|
|
761
|
-
n_max_nuc = k->nuc_n[i];
|
|
762
|
-
}
|
|
753
|
+
m_max = MAX(m_max, (blas_int)k->nuc_m[i]);
|
|
754
|
+
n_max_n = MAX(n_max_n, (blas_int)k->nuc_n[i]);
|
|
763
755
|
}
|
|
764
756
|
|
|
765
|
-
c->s_nuc = (scs_float *)scs_calloc(
|
|
766
|
-
c->u_nuc =
|
|
767
|
-
|
|
768
|
-
c->vt_nuc
|
|
769
|
-
(scs_float *)scs_calloc(n_max_nuc * n_max_nuc, sizeof(scs_float));
|
|
770
|
-
|
|
771
|
-
if (!c->s_nuc || !c->u_nuc || !c->vt_nuc) {
|
|
757
|
+
c->s_nuc = (scs_float *)scs_calloc(n_max_n, sizeof(scs_float));
|
|
758
|
+
c->u_nuc = (scs_float *)scs_calloc(m_max * n_max_n, sizeof(scs_float));
|
|
759
|
+
c->vt_nuc = (scs_float *)scs_calloc(n_max_n * n_max_n, sizeof(scs_float));
|
|
760
|
+
if (!c->s_nuc || !c->u_nuc || !c->vt_nuc)
|
|
772
761
|
return -1;
|
|
773
|
-
}
|
|
774
762
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
c->s_nuc, c->u_nuc, &m_max_nuc, c->vt_nuc, &n_max_nuc, &wkopt,
|
|
778
|
-
&neg_one, &info);
|
|
763
|
+
BLAS(gesvd)("S", "A", &m_max, &n_max_n, c->u_nuc, &m_max, c->s_nuc,
|
|
764
|
+
c->u_nuc, &m_max, c->vt_nuc, &n_max_n, &wkopt, &neg_one, &info);
|
|
779
765
|
|
|
780
|
-
|
|
781
|
-
c->work_nuc = (scs_float *)scs_calloc(c->lwork_nuc, sizeof(scs_float));
|
|
782
|
-
|
|
783
|
-
if (!c->lwork_nuc || !c->work_nuc) {
|
|
766
|
+
if (info != 0)
|
|
784
767
|
return -1;
|
|
785
|
-
}
|
|
786
768
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
769
|
+
/* We allocate work_nuc separately to avoid aliasing risks during SVD
|
|
770
|
+
* perations */
|
|
771
|
+
c->lwork_nuc = (blas_int)(wkopt + 1);
|
|
772
|
+
c->work_nuc = (scs_float *)scs_calloc(c->lwork_nuc, sizeof(scs_float));
|
|
773
|
+
if (!c->work_nuc)
|
|
790
774
|
return -1;
|
|
791
|
-
}
|
|
792
775
|
}
|
|
793
776
|
#endif
|
|
794
777
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
"Install blas+lapack and re-compile SCS with blas+lapack library "
|
|
803
|
-
"locations\n");
|
|
778
|
+
/* Final Consolidated Allocation
|
|
779
|
+
* c->work aliases 'work' for syevr and 'rwork' for heevr
|
|
780
|
+
*/
|
|
781
|
+
if (lwork_max > 0) {
|
|
782
|
+
c->lwork = lwork_max;
|
|
783
|
+
c->work = (scs_float *)scs_calloc(c->lwork, sizeof(scs_float));
|
|
784
|
+
if (!c->work)
|
|
804
785
|
return -1;
|
|
805
|
-
}
|
|
806
786
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
if (
|
|
811
|
-
|
|
812
|
-
break;
|
|
813
|
-
}
|
|
787
|
+
if (liwork_max > 0) {
|
|
788
|
+
c->liwork = liwork_max;
|
|
789
|
+
c->iwork = (blas_int *)scs_calloc(c->liwork, sizeof(blas_int));
|
|
790
|
+
if (!c->iwork)
|
|
791
|
+
return -1;
|
|
814
792
|
}
|
|
815
793
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
794
|
+
return 0;
|
|
795
|
+
#else
|
|
796
|
+
/* Non-LAPACK fallback check */
|
|
797
|
+
if (k->ssize > 0 || k->cssize > 0) {
|
|
798
|
+
for (i = 0; i < k->ssize; i++) {
|
|
799
|
+
if (k->s[i] > 1) {
|
|
800
|
+
scs_printf("FATAL: SDP/Complex SDP requires BLAS/LAPACK.\n");
|
|
801
|
+
return -1;
|
|
802
|
+
}
|
|
820
803
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
break;
|
|
804
|
+
for (i = 0; i < k->cssize; i++) {
|
|
805
|
+
if (k->cs[i] > 1) {
|
|
806
|
+
scs_printf("FATAL: SDP/Complex SDP requires BLAS/LAPACK.\n");
|
|
807
|
+
return -1;
|
|
808
|
+
}
|
|
827
809
|
}
|
|
828
810
|
}
|
|
829
|
-
|
|
830
|
-
if (
|
|
831
|
-
scs_printf("FATAL:
|
|
832
|
-
"libraries\n");
|
|
833
|
-
scs_printf(
|
|
834
|
-
"Install blas+lapack and re-compile SCS with blas+lapack library "
|
|
835
|
-
"locations\n");
|
|
811
|
+
#ifdef USE_SPECTRAL_CONES
|
|
812
|
+
if (k->dsize > 0 || k->nucsize > 0 || k->sl_size > 0) {
|
|
813
|
+
scs_printf("FATAL: Spectral cones require BLAS/LAPACK.\n");
|
|
836
814
|
return -1;
|
|
837
815
|
}
|
|
838
816
|
#endif
|
|
@@ -840,347 +818,201 @@ static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
|
840
818
|
#endif
|
|
841
819
|
}
|
|
842
820
|
|
|
843
|
-
|
|
844
|
-
static scs_int
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
scs_float sqrt2_inv = 1.0 / sqrt2;
|
|
857
|
-
scs_float *Xs = c->Xs;
|
|
858
|
-
scs_float *Z = c->Z;
|
|
859
|
-
scs_float *e = c->e;
|
|
860
|
-
scs_float *work = c->work;
|
|
861
|
-
blas_int lwork = c->lwork;
|
|
862
|
-
blas_int info = 0;
|
|
863
|
-
scs_float sq_eig_pos;
|
|
864
|
-
|
|
821
|
+
#ifdef USE_SPECTRAL_CONES
|
|
822
|
+
static scs_int set_up_ell1_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
823
|
+
scs_int i, n_max = 0;
|
|
824
|
+
if (k->ell1_size > 0) {
|
|
825
|
+
for (i = 0; i < k->ell1_size; ++i)
|
|
826
|
+
n_max = MAX(k->ell1[i], n_max);
|
|
827
|
+
c->work_ell1 = (Value_index *)scs_calloc(n_max, sizeof(Value_index));
|
|
828
|
+
c->work_ell1_proj = (scs_float *)scs_calloc(n_max + 1, sizeof(scs_float));
|
|
829
|
+
if (!c->work_ell1 || !c->work_ell1_proj)
|
|
830
|
+
return -1;
|
|
831
|
+
}
|
|
832
|
+
return 0;
|
|
833
|
+
}
|
|
865
834
|
#endif
|
|
866
835
|
|
|
867
|
-
|
|
836
|
+
/*
|
|
837
|
+
* Projection: Real Semi-Definite Cone
|
|
838
|
+
*/
|
|
839
|
+
static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
840
|
+
ScsConeWork *c) {
|
|
841
|
+
if (n == 0)
|
|
868
842
|
return 0;
|
|
869
|
-
}
|
|
870
843
|
if (n == 1) {
|
|
871
844
|
X[0] = MAX(X[0], 0.);
|
|
872
845
|
return 0;
|
|
873
846
|
}
|
|
874
847
|
|
|
875
848
|
#ifdef USE_LAPACK
|
|
876
|
-
|
|
877
|
-
|
|
849
|
+
scs_int i;
|
|
850
|
+
blas_int nb = (blas_int)n;
|
|
851
|
+
blas_int nb_p1 = (blas_int)(n + 1);
|
|
852
|
+
blas_int info = 0, one_int = 1, ncols_z = 0;
|
|
853
|
+
scs_float zero = 0., one = 1., sqrt2 = SQRTF(2.0), sqrt2_inv = 1.0 / sqrt2;
|
|
854
|
+
scs_float abstol = -1.0, d_f = 0.0, sq_eig;
|
|
855
|
+
blas_int m = 0, d_i = 0;
|
|
856
|
+
scs_int first_idx = -1;
|
|
857
|
+
|
|
858
|
+
/* Copy lower triangular part to full matrix buffer Xs */
|
|
878
859
|
for (i = 0; i < n; ++i) {
|
|
879
|
-
memcpy(&(Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
|
|
860
|
+
memcpy(&(c->Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
|
|
880
861
|
(n - i) * sizeof(scs_float));
|
|
881
862
|
}
|
|
882
|
-
/*
|
|
883
|
-
rescale so projection works, and matrix norm preserved
|
|
884
|
-
see http://www.seas.ucla.edu/~vandenbe/publications/mlbook.pdf pg 3
|
|
885
|
-
*/
|
|
886
|
-
/* scale diags by sqrt(2) */
|
|
887
|
-
BLAS(scal)(&nb, &sqrt2, Xs, &nb_plus_one); /* not n_squared */
|
|
888
|
-
|
|
889
|
-
/* Solve eigenproblem, reuse workspaces */
|
|
890
|
-
BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
|
|
891
|
-
if (info != 0) {
|
|
892
|
-
scs_printf("WARN: LAPACK syev error, info = %i\n", (int)info);
|
|
893
|
-
if (info < 0) {
|
|
894
|
-
return info;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
863
|
|
|
898
|
-
|
|
864
|
+
/* Scale diagonals by sqrt(2) */
|
|
865
|
+
BLAS(scal)(&nb, &sqrt2, c->Xs, &nb_p1);
|
|
866
|
+
|
|
867
|
+
/* Solve Eigenproblem: Xs = Z * diag(e) * Z' */
|
|
868
|
+
BLAS(syevr)("V", "A", "L", &nb, c->Xs, &nb, &d_f, &d_f, &d_i, &d_i, &abstol,
|
|
869
|
+
&m, c->e, c->Z, &nb, c->isuppz, c->work, &c->lwork, c->iwork,
|
|
870
|
+
&c->liwork, &info);
|
|
871
|
+
if (info != 0)
|
|
872
|
+
return (int)info;
|
|
899
873
|
|
|
900
|
-
|
|
901
|
-
/* e is
|
|
874
|
+
/* Filter negative eigenvalues and scale eigenvectors */
|
|
875
|
+
/* Note: e is in ascending order */
|
|
902
876
|
for (i = 0; i < n; ++i) {
|
|
903
|
-
if (e[i] > 0) {
|
|
904
|
-
first_idx
|
|
905
|
-
|
|
877
|
+
if (c->e[i] > 0) {
|
|
878
|
+
if (first_idx == -1) {
|
|
879
|
+
first_idx = i;
|
|
880
|
+
}
|
|
881
|
+
sq_eig = SQRTF(c->e[i]);
|
|
882
|
+
BLAS(scal)(&nb, &sq_eig, &c->Z[i * n], &one_int);
|
|
906
883
|
}
|
|
907
884
|
}
|
|
908
|
-
|
|
909
885
|
if (first_idx == -1) {
|
|
910
886
|
/* there are no positive eigenvalues, set X to 0 and return */
|
|
911
887
|
memset(X, 0, sizeof(scs_float) * get_sd_cone_size(n));
|
|
912
888
|
return 0;
|
|
913
889
|
}
|
|
914
|
-
|
|
915
|
-
/* Z is matrix of eigenvectors with positive eigenvalues */
|
|
916
|
-
memcpy(Z, &Xs[first_idx * n], sizeof(scs_float) * n * (n - first_idx));
|
|
917
|
-
|
|
918
|
-
/* scale Z by sqrt(eig) */
|
|
919
|
-
for (i = first_idx; i < n; ++i) {
|
|
920
|
-
sq_eig_pos = SQRTF(e[i]);
|
|
921
|
-
BLAS(scal)(&nb, &sq_eig_pos, &Z[(i - first_idx) * n], &one_int);
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
/* Xs = Z Z' = V E V' */
|
|
890
|
+
/* Reconstruct Xs = Z * Z' */
|
|
925
891
|
ncols_z = (blas_int)(n - first_idx);
|
|
926
|
-
BLAS(syrk)("Lower", "NoTrans", &nb, &ncols_z, &one, Z
|
|
892
|
+
BLAS(syrk)("Lower", "NoTrans", &nb, &ncols_z, &one, &c->Z[first_idx * n], &nb,
|
|
893
|
+
&zero, c->Xs, &nb);
|
|
927
894
|
|
|
928
|
-
/*
|
|
929
|
-
BLAS(scal)(&nb, &sqrt2_inv, Xs, &
|
|
895
|
+
/* Rescale diagonals by 1/sqrt(2) */
|
|
896
|
+
BLAS(scal)(&nb, &sqrt2_inv, c->Xs, &nb_p1);
|
|
930
897
|
|
|
931
|
-
/*
|
|
898
|
+
/* Extract lower triangular matrix back to X */
|
|
932
899
|
for (i = 0; i < n; ++i) {
|
|
933
|
-
memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(Xs[i * (n + 1)]),
|
|
900
|
+
memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(c->Xs[i * (n + 1)]),
|
|
934
901
|
(n - i) * sizeof(scs_float));
|
|
935
902
|
}
|
|
936
903
|
return 0;
|
|
937
|
-
|
|
938
904
|
#else
|
|
939
|
-
scs_printf("FAILURE: solving SDP but no blas/lapack libraries were found!\n");
|
|
940
|
-
scs_printf("SCS will return nonsense!\n");
|
|
941
|
-
SCS(scale_array)(X, NAN, get_sd_cone_size(n));
|
|
942
905
|
return -1;
|
|
943
906
|
#endif
|
|
944
907
|
}
|
|
945
908
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
blas_int n_max = 1;
|
|
950
|
-
blas_int neg_one = -1;
|
|
951
|
-
blas_int info = 0;
|
|
952
|
-
scs_float abstol = -1.0;
|
|
953
|
-
blas_int m = 0;
|
|
954
|
-
scs_complex_float lcwork = {0.0};
|
|
955
|
-
scs_float lrwork = 0.0;
|
|
956
|
-
blas_int liwork = 0;
|
|
957
|
-
#if VERBOSITY > 0
|
|
958
|
-
#define _STR_EXPAND(tok) #tok
|
|
959
|
-
#define _STR(tok) _STR_EXPAND(tok)
|
|
960
|
-
scs_printf("BLAS(func) = '%s'\n", _STR(BLASC(func)));
|
|
961
|
-
#endif
|
|
962
|
-
/* eigenvector decomp workspace */
|
|
963
|
-
for (i = 0; i < k->cssize; ++i) {
|
|
964
|
-
if (k->cs[i] > n_max) {
|
|
965
|
-
n_max = (blas_int)k->cs[i];
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
c->cXs =
|
|
969
|
-
(scs_complex_float *)scs_calloc(n_max * n_max, sizeof(scs_complex_float));
|
|
970
|
-
c->cZ =
|
|
971
|
-
(scs_complex_float *)scs_calloc(n_max * n_max, sizeof(scs_complex_float));
|
|
972
|
-
c->e = (scs_float *)scs_calloc(n_max, sizeof(scs_float));
|
|
973
|
-
c->isuppz = (blas_int *)scs_calloc(MAX(2, 2 * n_max), sizeof(blas_int));
|
|
974
|
-
|
|
975
|
-
/* workspace query */
|
|
976
|
-
BLASC(heevr)
|
|
977
|
-
("V", "A", "L", &n_max, SCS_BLAS_COMPLEX_CAST(c->cXs), &n_max, SCS_NULL,
|
|
978
|
-
SCS_NULL, SCS_NULL, SCS_NULL, &abstol, &m, c->e,
|
|
979
|
-
SCS_BLAS_COMPLEX_CAST(c->cZ), &n_max, c->isuppz,
|
|
980
|
-
SCS_BLAS_COMPLEX_CAST(&lcwork), &neg_one, &lrwork, &neg_one, &liwork,
|
|
981
|
-
&neg_one, &info);
|
|
982
|
-
|
|
983
|
-
if (info != 0) {
|
|
984
|
-
scs_printf("FATAL: heev workspace query failure, info = %li\n", (long)info);
|
|
985
|
-
return -1;
|
|
986
|
-
}
|
|
987
|
-
c->lcwork = (blas_int)(lcwork[0]);
|
|
988
|
-
c->lrwork = (blas_int)(lrwork);
|
|
989
|
-
c->liwork = liwork;
|
|
990
|
-
c->cwork =
|
|
991
|
-
(scs_complex_float *)scs_calloc(c->lcwork, sizeof(scs_complex_float));
|
|
992
|
-
c->rwork = (scs_float *)scs_calloc(c->lrwork, sizeof(scs_float));
|
|
993
|
-
c->iwork = (blas_int *)scs_calloc(c->liwork, sizeof(blas_int));
|
|
994
|
-
|
|
995
|
-
if (!c->cXs || !c->cZ || !c->e || !c->isuppz || !c->cwork || !c->rwork ||
|
|
996
|
-
!c->iwork) {
|
|
997
|
-
return -1;
|
|
998
|
-
}
|
|
999
|
-
return 0;
|
|
1000
|
-
#else
|
|
1001
|
-
for (i = 0; i < k->cssize; i++) {
|
|
1002
|
-
if (k->cs[i] > 1) {
|
|
1003
|
-
scs_printf(
|
|
1004
|
-
"FATAL: Cannot solve SDPs without linked blas+lapack libraries\n");
|
|
1005
|
-
scs_printf(
|
|
1006
|
-
"Install blas+lapack and re-compile SCS with blas+lapack library "
|
|
1007
|
-
"locations\n");
|
|
1008
|
-
return -1;
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
return 0;
|
|
1012
|
-
#endif
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
/* size of X is get_csd_cone_size(n) */
|
|
909
|
+
/*
|
|
910
|
+
* Projection: Complex Semi-Definite Cone
|
|
911
|
+
*/
|
|
1016
912
|
static scs_int proj_complex_semi_definite_cone(scs_float *X, const scs_int n,
|
|
1017
913
|
ScsConeWork *c) {
|
|
1018
|
-
|
|
1019
|
-
#ifdef USE_LAPACK
|
|
1020
|
-
scs_int i, first_idx;
|
|
1021
|
-
blas_int nb = (blas_int)n;
|
|
1022
|
-
blas_int ncols_z;
|
|
1023
|
-
blas_int nb_plus_one = (blas_int)(n + 1);
|
|
1024
|
-
blas_int one_int = 1;
|
|
1025
|
-
scs_float zero = 0., one = 1.;
|
|
1026
|
-
scs_complex_float csqrt2 = {0.0};
|
|
1027
|
-
csqrt2[0] = SQRTF(2.0);
|
|
1028
|
-
scs_complex_float csqrt2_inv = {0.0};
|
|
1029
|
-
csqrt2_inv[0] = 1.0 / csqrt2[0];
|
|
1030
|
-
;
|
|
1031
|
-
scs_complex_float *cXs = c->cXs;
|
|
1032
|
-
scs_complex_float *cZ = c->cZ;
|
|
1033
|
-
scs_float *e = c->e;
|
|
1034
|
-
scs_float abstol = -1.0;
|
|
1035
|
-
blas_int m = 0;
|
|
1036
|
-
blas_int info = 0;
|
|
1037
|
-
scs_complex_float csq_eig_pos = {0.0};
|
|
1038
|
-
|
|
1039
|
-
#endif
|
|
1040
|
-
|
|
1041
|
-
if (n == 0) {
|
|
914
|
+
if (n == 0)
|
|
1042
915
|
return 0;
|
|
1043
|
-
}
|
|
1044
916
|
if (n == 1) {
|
|
1045
917
|
X[0] = MAX(X[0], 0.);
|
|
1046
918
|
return 0;
|
|
1047
919
|
}
|
|
1048
920
|
|
|
1049
921
|
#ifdef USE_LAPACK
|
|
922
|
+
scs_int i;
|
|
923
|
+
blas_int nb = (blas_int)n;
|
|
924
|
+
blas_int nb_p1 = (blas_int)(n + 1);
|
|
925
|
+
blas_int info = 0, one_int = 1, d_i = 0, ncols_z = 0;
|
|
926
|
+
scs_float zero = 0., one = 1., abstol = -1.0, d_f = 0.0;
|
|
927
|
+
blas_int m = 0;
|
|
928
|
+
scs_int first_idx = -1;
|
|
929
|
+
|
|
930
|
+
/* Complex constants */
|
|
931
|
+
scs_complex_float csqrt2 = {0.0}, csqrt2_inv = {0.0}, csq_eig = {0.0};
|
|
932
|
+
csqrt2[0] = SQRTF(2.0);
|
|
933
|
+
csqrt2_inv[0] = 1.0 / csqrt2[0];
|
|
1050
934
|
|
|
1051
|
-
/*
|
|
935
|
+
/* Unpack X (real array) into cXs (complex matrix) */
|
|
1052
936
|
for (i = 0; i < n - 1; ++i) {
|
|
1053
|
-
cXs[i * (n + 1)][0] = X[i * (2 * n - i)];
|
|
1054
|
-
cXs[i * (n + 1)][1] = 0.0;
|
|
1055
|
-
memcpy(&(cXs[i * (n + 1) + 1]), &(X[i * (2 * n - i) + 1]),
|
|
937
|
+
c->cXs[i * (n + 1)][0] = X[i * (2 * n - i)]; /* Diagonal (Real) */
|
|
938
|
+
c->cXs[i * (n + 1)][1] = 0.0;
|
|
939
|
+
memcpy(&(c->cXs[i * (n + 1) + 1]), &(X[i * (2 * n - i) + 1]),
|
|
1056
940
|
2 * (n - i - 1) * sizeof(scs_float));
|
|
1057
941
|
}
|
|
1058
|
-
cXs[n * n - 1][0] = X[n * n - 1];
|
|
1059
|
-
cXs[n * n - 1][1] = 0.0;
|
|
1060
|
-
/*
|
|
1061
|
-
rescale so projection works, and matrix norm preserved
|
|
1062
|
-
see http://www.seas.ucla.edu/~vandenbe/publications/mlbook.pdf pg 3
|
|
1063
|
-
*/
|
|
1064
|
-
/* scale diags by sqrt(2) */
|
|
1065
|
-
BLASC(scal)
|
|
1066
|
-
(&nb, SCS_BLAS_COMPLEX_CAST(&csqrt2), SCS_BLAS_COMPLEX_CAST(cXs),
|
|
1067
|
-
&nb_plus_one); /* not n_squared */
|
|
1068
|
-
|
|
1069
|
-
/* Solve eigenproblem, reuse workspaces */
|
|
1070
|
-
BLASC(heevr)
|
|
1071
|
-
("V", "A", "L", &nb, SCS_BLAS_COMPLEX_CAST(cXs), &nb, SCS_NULL, SCS_NULL,
|
|
1072
|
-
SCS_NULL, SCS_NULL, &abstol, &m, e, SCS_BLAS_COMPLEX_CAST(cZ), &nb,
|
|
1073
|
-
c->isuppz, SCS_BLAS_COMPLEX_CAST(c->cwork), &c->lcwork, c->rwork, &c->lrwork,
|
|
1074
|
-
c->iwork, &c->liwork, &info);
|
|
1075
|
-
|
|
1076
|
-
if (info != 0) {
|
|
1077
|
-
scs_printf("WARN: LAPACK heev error, info = %i\n", (int)info);
|
|
1078
|
-
if (info < 0) {
|
|
1079
|
-
return info;
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
942
|
+
c->cXs[n * n - 1][0] = X[n * n - 1]; /* Last element */
|
|
943
|
+
c->cXs[n * n - 1][1] = 0.0;
|
|
1082
944
|
|
|
1083
|
-
|
|
1084
|
-
|
|
945
|
+
/* Scale diagonals by sqrt*/
|
|
946
|
+
BLASC(scal)(&nb, SCS_BLAS_COMPLEX_CAST(&csqrt2),
|
|
947
|
+
SCS_BLAS_COMPLEX_CAST(c->cXs), &nb_p1);
|
|
948
|
+
|
|
949
|
+
/* Solve Eigenproblem. Note: c->work acts as rwork here. */
|
|
950
|
+
BLASC(heevr)("V", "A", "L", &nb, SCS_BLAS_COMPLEX_CAST(c->cXs), &nb, &d_f,
|
|
951
|
+
&d_f, &d_i, &d_i, &abstol, &m, c->e,
|
|
952
|
+
SCS_BLAS_COMPLEX_CAST(c->cZ), &nb, c->isuppz,
|
|
953
|
+
SCS_BLAS_COMPLEX_CAST(c->cwork), &c->lcwork, c->work, &c->lwork,
|
|
954
|
+
c->iwork, &c->liwork, &info);
|
|
955
|
+
if (info != 0)
|
|
956
|
+
return (int)info;
|
|
957
|
+
|
|
958
|
+
/* Reconstruct */
|
|
1085
959
|
for (i = 0; i < n; ++i) {
|
|
1086
|
-
if (e[i] > 0) {
|
|
1087
|
-
first_idx
|
|
1088
|
-
|
|
960
|
+
if (c->e[i] > 0) {
|
|
961
|
+
if (first_idx == -1) {
|
|
962
|
+
first_idx = i;
|
|
963
|
+
}
|
|
964
|
+
csq_eig[0] = SQRTF(c->e[i]);
|
|
965
|
+
BLASC(scal)(&nb, SCS_BLAS_COMPLEX_CAST(&csq_eig),
|
|
966
|
+
SCS_BLAS_COMPLEX_CAST(&c->cZ[i * n]), &one_int);
|
|
1089
967
|
}
|
|
1090
968
|
}
|
|
1091
|
-
|
|
1092
969
|
if (first_idx == -1) {
|
|
1093
970
|
/* there are no positive eigenvalues, set X to 0 and return */
|
|
1094
971
|
memset(X, 0, sizeof(scs_float) * get_csd_cone_size(n));
|
|
1095
972
|
return 0;
|
|
1096
973
|
}
|
|
1097
974
|
|
|
1098
|
-
/*
|
|
1099
|
-
/* scale cZ by sqrt(eig) */
|
|
1100
|
-
for (i = first_idx; i < n; ++i) {
|
|
1101
|
-
csq_eig_pos[0] = SQRTF(e[i]);
|
|
1102
|
-
BLASC(scal)
|
|
1103
|
-
(&nb, SCS_BLAS_COMPLEX_CAST(&csq_eig_pos),
|
|
1104
|
-
SCS_BLAS_COMPLEX_CAST(&cZ[i * n]), &one_int);
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
/* Xs = cZ cZ' = V E V' */
|
|
975
|
+
/* cXs = cZ * cZ' */
|
|
1108
976
|
ncols_z = (blas_int)(n - first_idx);
|
|
1109
|
-
BLASC(herk)
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
SCS_BLAS_COMPLEX_CAST(cXs), &nb);
|
|
977
|
+
BLASC(herk)("Lower", "NoTrans", &nb, &ncols_z, &one,
|
|
978
|
+
SCS_BLAS_COMPLEX_CAST(&c->cZ[first_idx * n]), &nb, &zero,
|
|
979
|
+
SCS_BLAS_COMPLEX_CAST(c->cXs), &nb);
|
|
1113
980
|
|
|
1114
|
-
/*
|
|
1115
|
-
BLASC(scal)
|
|
1116
|
-
|
|
1117
|
-
&nb_plus_one); /* not n_squared */
|
|
981
|
+
/* Rescale diagonals */
|
|
982
|
+
BLASC(scal)(&nb, SCS_BLAS_COMPLEX_CAST(&csqrt2_inv),
|
|
983
|
+
SCS_BLAS_COMPLEX_CAST(c->cXs), &nb_p1);
|
|
1118
984
|
|
|
1119
|
-
/*
|
|
985
|
+
/* Repack into X */
|
|
1120
986
|
for (i = 0; i < n - 1; ++i) {
|
|
1121
|
-
X[i * (2 * n - i)] = cXs[i * (n + 1)][0];
|
|
1122
|
-
memcpy(&(X[i * (2 * n - i) + 1]), &(cXs[i * (n + 1) + 1]),
|
|
987
|
+
X[i * (2 * n - i)] = c->cXs[i * (n + 1)][0];
|
|
988
|
+
memcpy(&(X[i * (2 * n - i) + 1]), &(c->cXs[i * (n + 1) + 1]),
|
|
1123
989
|
2 * (n - i - 1) * sizeof(scs_float));
|
|
1124
990
|
}
|
|
1125
|
-
X[n * n - 1] = cXs[n * n - 1][0];
|
|
991
|
+
X[n * n - 1] = c->cXs[n * n - 1][0];
|
|
1126
992
|
return 0;
|
|
1127
|
-
|
|
1128
993
|
#else
|
|
1129
|
-
scs_printf("FAILURE: solving SDP but no blas/lapack libraries were found!\n");
|
|
1130
|
-
scs_printf("SCS will return nonsense!\n");
|
|
1131
|
-
SCS(scale_array)(X, NAN, get_csd_cone_size(n));
|
|
1132
994
|
return -1;
|
|
1133
995
|
#endif
|
|
1134
996
|
}
|
|
1135
997
|
|
|
1136
|
-
static scs_float pow_calc_x(scs_float r, scs_float xh, scs_float rh,
|
|
1137
|
-
scs_float a) {
|
|
1138
|
-
scs_float x = 0.5 * (xh + SQRTF(xh * xh + 4 * a * (rh - r) * r));
|
|
1139
|
-
return MAX(x, 1e-12);
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
static scs_float pow_calcdxdr(scs_float x, scs_float xh, scs_float rh,
|
|
1143
|
-
scs_float r, scs_float a) {
|
|
1144
|
-
return a * (rh - 2 * r) / (2 * x - xh);
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
static scs_float pow_calc_f(scs_float x, scs_float y, scs_float r,
|
|
1148
|
-
scs_float a) {
|
|
1149
|
-
return POWF(x, a) * POWF(y, (1 - a)) - r;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
|
|
1153
|
-
scs_float dydr, scs_float a) {
|
|
1154
|
-
return POWF(x, a) * POWF(y, (1 - a)) * (a * dxdr / x + (1 - a) * dydr / y) -
|
|
1155
|
-
1;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
998
|
/*
|
|
1159
|
-
*
|
|
1160
|
-
*
|
|
1161
|
-
* want (t, s) \in K <==> (t', s') \in K'
|
|
1162
|
-
*
|
|
1163
|
-
* (t', s') = (d0 * t, D s) (overloading D to mean D[1:])
|
|
1164
|
-
* (up to scalar scaling factor which we can ignore due to conic property)
|
|
1165
|
-
*
|
|
1166
|
-
* K = { (t, s) | t * l <= s <= t * u, t >= 0 } =>
|
|
1167
|
-
* { (t, s) | d0 * t * D l / d0 <= D s <= d0 * t D u / d0, t >= 0 } =>
|
|
1168
|
-
* { (t', s') | t' * l' <= s' <= t' u', t >= 0 } = K'
|
|
1169
|
-
* where l' = D l / d0, u' = D u / d0.
|
|
999
|
+
* Projection: Box Cone
|
|
1170
1000
|
*/
|
|
1171
1001
|
static void normalize_box_cone(ScsCone *k, scs_float *D, scs_int bsize) {
|
|
1172
1002
|
scs_int j;
|
|
1003
|
+
scs_float factor;
|
|
1173
1004
|
for (j = 0; j < bsize - 1; j++) {
|
|
1174
|
-
|
|
1005
|
+
factor = D ? D[j + 1] / D[0] : 1.0;
|
|
1006
|
+
|
|
1007
|
+
if (k->bu[j] >= MAX_BOX_VAL)
|
|
1175
1008
|
k->bu[j] = INFINITY;
|
|
1176
|
-
|
|
1177
|
-
k->bu[j]
|
|
1178
|
-
|
|
1179
|
-
if (k->bl[j] <= -MAX_BOX_VAL)
|
|
1009
|
+
else
|
|
1010
|
+
k->bu[j] *= factor;
|
|
1011
|
+
|
|
1012
|
+
if (k->bl[j] <= -MAX_BOX_VAL)
|
|
1180
1013
|
k->bl[j] = -INFINITY;
|
|
1181
|
-
|
|
1182
|
-
k->bl[j]
|
|
1183
|
-
}
|
|
1014
|
+
else
|
|
1015
|
+
k->bl[j] *= factor;
|
|
1184
1016
|
}
|
|
1185
1017
|
}
|
|
1186
1018
|
|
|
@@ -1189,106 +1021,113 @@ static void normalize_box_cone(ScsCone *k, scs_float *D, scs_int bsize) {
|
|
|
1189
1021
|
*/
|
|
1190
1022
|
static scs_float proj_box_cone(scs_float *tx, const scs_float *bl,
|
|
1191
1023
|
const scs_float *bu, scs_int bsize,
|
|
1192
|
-
scs_float
|
|
1193
|
-
scs_float *x
|
|
1194
|
-
scs_float
|
|
1024
|
+
scs_float t_wm, scs_float *r_box) {
|
|
1025
|
+
scs_float *x = &(tx[1]);
|
|
1026
|
+
scs_float gt, ht, t = t_wm, t_prev, r;
|
|
1027
|
+
scs_float rho_t = 1.0;
|
|
1028
|
+
scs_float *rho = SCS_NULL;
|
|
1195
1029
|
scs_int iter, j;
|
|
1196
1030
|
|
|
1197
|
-
if (bsize == 1) {
|
|
1031
|
+
if (bsize == 1) {
|
|
1198
1032
|
tx[0] = MAX(tx[0], 0.0);
|
|
1199
1033
|
return tx[0];
|
|
1200
1034
|
}
|
|
1201
|
-
x = &(tx[1]);
|
|
1202
|
-
|
|
1203
1035
|
if (r_box) {
|
|
1204
1036
|
rho_t = 1.0 / r_box[0];
|
|
1205
1037
|
rho = &(r_box[1]);
|
|
1206
1038
|
}
|
|
1207
1039
|
|
|
1208
|
-
/*
|
|
1040
|
+
/* Newton's method for t */
|
|
1209
1041
|
for (iter = 0; iter < BOX_CONE_MAX_ITERS; iter++) {
|
|
1210
1042
|
t_prev = t;
|
|
1211
|
-
gt = rho_t * (t - tx[0]);
|
|
1212
|
-
ht = rho_t;
|
|
1043
|
+
gt = rho_t * (t - tx[0]);
|
|
1044
|
+
ht = rho_t;
|
|
1045
|
+
|
|
1213
1046
|
for (j = 0; j < bsize - 1; j++) {
|
|
1214
|
-
r = rho ? 1.0 / rho[j] : 1
|
|
1047
|
+
r = rho ? 1.0 / rho[j] : 1.0;
|
|
1215
1048
|
if (x[j] > t * bu[j]) {
|
|
1216
|
-
gt += r * (t * bu[j] - x[j]) * bu[j];
|
|
1217
|
-
ht += r * bu[j] * bu[j];
|
|
1049
|
+
gt += r * (t * bu[j] - x[j]) * bu[j];
|
|
1050
|
+
ht += r * bu[j] * bu[j];
|
|
1218
1051
|
} else if (x[j] < t * bl[j]) {
|
|
1219
|
-
gt += r * (t * bl[j] - x[j]) * bl[j];
|
|
1220
|
-
ht += r * bl[j] * bl[j];
|
|
1052
|
+
gt += r * (t * bl[j] - x[j]) * bl[j];
|
|
1053
|
+
ht += r * bl[j] * bl[j];
|
|
1221
1054
|
}
|
|
1222
1055
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
ABS(gt / (ht + 1e-6)), ABS(t - t_prev));
|
|
1229
|
-
#endif
|
|
1230
|
-
/* TODO: sometimes this check can fail (ie, declare convergence before it
|
|
1056
|
+
|
|
1057
|
+
t = MAX(t - gt / MAX(ht, 1e-8), 0.0);
|
|
1058
|
+
|
|
1059
|
+
/*
|
|
1060
|
+
* TODO: sometimes this check can fail (ie, declare convergence before it
|
|
1231
1061
|
* should) if ht is very large, which can happen with some pathological
|
|
1232
1062
|
* problems.
|
|
1233
1063
|
*/
|
|
1234
1064
|
if (ABS(gt / MAX(ht, 1e-6)) < 1e-12 * MAX(t, 1.) ||
|
|
1235
|
-
ABS(t - t_prev) < 1e-11 * MAX(t, 1.))
|
|
1065
|
+
ABS(t - t_prev) < 1e-11 * MAX(t, 1.))
|
|
1236
1066
|
break;
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
if (iter == BOX_CONE_MAX_ITERS) {
|
|
1240
|
-
scs_printf("warning: box cone proj hit maximum %i iters\n", (int)iter);
|
|
1241
1067
|
}
|
|
1068
|
+
|
|
1069
|
+
/* Apply calculated t to x */
|
|
1242
1070
|
for (j = 0; j < bsize - 1; j++) {
|
|
1243
|
-
if (x[j] > t * bu[j])
|
|
1071
|
+
if (x[j] > t * bu[j])
|
|
1244
1072
|
x[j] = t * bu[j];
|
|
1245
|
-
|
|
1073
|
+
else if (x[j] < t * bl[j])
|
|
1246
1074
|
x[j] = t * bl[j];
|
|
1247
|
-
}
|
|
1248
|
-
/* x[j] unchanged otherwise */
|
|
1249
1075
|
}
|
|
1250
1076
|
tx[0] = t;
|
|
1251
|
-
|
|
1252
|
-
#if VERBOSITY > 3
|
|
1253
|
-
scs_printf("box cone iters %i\n", (int)iter + 1);
|
|
1254
|
-
#endif
|
|
1255
1077
|
return t;
|
|
1256
1078
|
}
|
|
1257
1079
|
|
|
1258
|
-
/*
|
|
1080
|
+
/*
|
|
1081
|
+
* Projection: Second Order Cone
|
|
1082
|
+
*/
|
|
1259
1083
|
static void proj_soc(scs_float *x, scs_int q) {
|
|
1260
|
-
if (q
|
|
1084
|
+
if (q <= 0)
|
|
1261
1085
|
return;
|
|
1262
|
-
}
|
|
1263
1086
|
if (q == 1) {
|
|
1264
1087
|
x[0] = MAX(x[0], 0.);
|
|
1265
1088
|
return;
|
|
1266
1089
|
}
|
|
1090
|
+
|
|
1267
1091
|
scs_float v1 = x[0];
|
|
1268
1092
|
scs_float s = SCS(norm_2)(&(x[1]), q - 1);
|
|
1269
1093
|
scs_float alpha = (s + v1) / 2.0;
|
|
1270
1094
|
|
|
1271
|
-
if (s <= v1)
|
|
1272
|
-
return;
|
|
1273
|
-
|
|
1274
|
-
memset(
|
|
1275
|
-
} else {
|
|
1095
|
+
if (s <= v1)
|
|
1096
|
+
return; /* Inside cone */
|
|
1097
|
+
if (s <= -v1) { /* Below dual cone */
|
|
1098
|
+
memset(x, 0, q * sizeof(scs_float));
|
|
1099
|
+
} else { /* Projection */
|
|
1276
1100
|
x[0] = alpha;
|
|
1277
1101
|
SCS(scale_array)(&(x[1]), alpha / s, q - 1);
|
|
1278
1102
|
}
|
|
1279
1103
|
}
|
|
1280
1104
|
|
|
1105
|
+
/*
|
|
1106
|
+
* Projection: Power Cone
|
|
1107
|
+
*/
|
|
1108
|
+
static scs_float pow_calc_x(scs_float r, scs_float xh, scs_float rh,
|
|
1109
|
+
scs_float a) {
|
|
1110
|
+
scs_float x = 0.5 * (xh + SQRTF(xh * xh + 4 * a * (rh - r) * r));
|
|
1111
|
+
return MAX(x, 1e-12);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
|
|
1115
|
+
scs_float dydr, scs_float a) {
|
|
1116
|
+
return POWF(x, a) * POWF(y, (1 - a)) * (a * dxdr / x + (1 - a) * dydr / y) -
|
|
1117
|
+
1;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1281
1120
|
static void proj_power_cone(scs_float *v, scs_float a) {
|
|
1282
1121
|
scs_float xh = v[0], yh = v[1], rh = ABS(v[2]);
|
|
1283
1122
|
scs_float x = 0.0, y = 0.0, r;
|
|
1284
1123
|
scs_int i;
|
|
1285
|
-
|
|
1124
|
+
|
|
1125
|
+
/* Check v membership in K_a */
|
|
1286
1126
|
if (xh >= 0 && yh >= 0 &&
|
|
1287
|
-
POW_CONE_TOL + POWF(xh, a) * POWF(yh, (1 - a)) >= rh)
|
|
1127
|
+
POW_CONE_TOL + POWF(xh, a) * POWF(yh, (1 - a)) >= rh)
|
|
1288
1128
|
return;
|
|
1289
|
-
}
|
|
1290
1129
|
|
|
1291
|
-
/* -v in K_a^* */
|
|
1130
|
+
/* Check -v membership in Polar K_a^* */
|
|
1292
1131
|
if (xh <= 0 && yh <= 0 &&
|
|
1293
1132
|
POW_CONE_TOL + POWF(-xh, a) * POWF(-yh, 1 - a) >=
|
|
1294
1133
|
rh * POWF(a, a) * POWF(1 - a, 1 - a)) {
|
|
@@ -1302,13 +1141,12 @@ static void proj_power_cone(scs_float *v, scs_float a) {
|
|
|
1302
1141
|
x = pow_calc_x(r, xh, rh, a);
|
|
1303
1142
|
y = pow_calc_x(r, yh, rh, 1 - a);
|
|
1304
1143
|
|
|
1305
|
-
f =
|
|
1306
|
-
if (ABS(f) < POW_CONE_TOL)
|
|
1144
|
+
f = POWF(x, a) * POWF(y, (1 - a)) - r;
|
|
1145
|
+
if (ABS(f) < POW_CONE_TOL)
|
|
1307
1146
|
break;
|
|
1308
|
-
}
|
|
1309
1147
|
|
|
1310
|
-
dxdr =
|
|
1311
|
-
dydr =
|
|
1148
|
+
dxdr = a * (rh - 2 * r) / (2 * x - xh);
|
|
1149
|
+
dydr = (1 - a) * (rh - 2 * r) / (2 * y - yh);
|
|
1312
1150
|
fp = pow_calc_fp(x, y, dxdr, dydr, a);
|
|
1313
1151
|
|
|
1314
1152
|
r = MAX(r - f / fp, 0);
|
|
@@ -1316,56 +1154,53 @@ static void proj_power_cone(scs_float *v, scs_float a) {
|
|
|
1316
1154
|
}
|
|
1317
1155
|
v[0] = x;
|
|
1318
1156
|
v[1] = y;
|
|
1319
|
-
v[2] = (v[2] < 0) ? -
|
|
1157
|
+
v[2] = (v[2] < 0) ? -r : r;
|
|
1320
1158
|
}
|
|
1321
1159
|
|
|
1322
|
-
/*
|
|
1323
|
-
/*
|
|
1160
|
+
/* Project onto the primal K cone in the paper */
|
|
1161
|
+
/* The r_y vector determines the INVERSE metric, ie, project under the
|
|
1324
1162
|
* diag(r_y)^-1 norm.
|
|
1325
1163
|
*/
|
|
1326
1164
|
static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
1327
1165
|
scs_int normalize, scs_float *r_y) {
|
|
1328
|
-
scs_int i, status;
|
|
1329
|
-
scs_int count = 0;
|
|
1166
|
+
scs_int i, count = 0, status = 0;
|
|
1330
1167
|
scs_float *r_box = SCS_NULL;
|
|
1331
1168
|
#ifdef USE_SPECTRAL_CONES
|
|
1332
1169
|
SPECTRAL_TIMING(SCS(timer) spec_mat_proj_timer;)
|
|
1333
1170
|
#endif
|
|
1334
1171
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1172
|
+
/* 1. Zero Cone */
|
|
1173
|
+
if (k->z) {
|
|
1337
1174
|
memset(x, 0, k->z * sizeof(scs_float));
|
|
1338
1175
|
count += k->z;
|
|
1339
1176
|
}
|
|
1340
1177
|
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
for (i = count; i < count + k->l; ++i)
|
|
1178
|
+
/* 2. Linear Cone (Non-negative orthant) */
|
|
1179
|
+
if (k->l) {
|
|
1180
|
+
for (i = count; i < count + k->l; ++i)
|
|
1344
1181
|
x[i] = MAX(x[i], 0.0);
|
|
1345
|
-
}
|
|
1346
1182
|
count += k->l;
|
|
1347
1183
|
}
|
|
1348
1184
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1185
|
+
/* 3. Box Cone */
|
|
1186
|
+
if (k->bsize) {
|
|
1187
|
+
if (r_y)
|
|
1351
1188
|
r_box = &(r_y[count]);
|
|
1352
|
-
}
|
|
1353
|
-
/* project onto box cone */
|
|
1354
1189
|
c->box_t_warm_start = proj_box_cone(&(x[count]), k->bl, k->bu, k->bsize,
|
|
1355
1190
|
c->box_t_warm_start, r_box);
|
|
1356
|
-
count += k->bsize;
|
|
1191
|
+
count += k->bsize;
|
|
1357
1192
|
}
|
|
1358
1193
|
|
|
1359
|
-
|
|
1360
|
-
|
|
1194
|
+
/* 4. SOC */
|
|
1195
|
+
if (k->qsize) {
|
|
1361
1196
|
for (i = 0; i < k->qsize; ++i) {
|
|
1362
1197
|
proj_soc(&(x[count]), k->q[i]);
|
|
1363
1198
|
count += k->q[i];
|
|
1364
1199
|
}
|
|
1365
1200
|
}
|
|
1366
1201
|
|
|
1367
|
-
|
|
1368
|
-
|
|
1202
|
+
/* 5. PSD Cone */
|
|
1203
|
+
if (k->ssize) {
|
|
1369
1204
|
for (i = 0; i < k->ssize; ++i) {
|
|
1370
1205
|
#ifdef USE_SPECTRAL_CONES
|
|
1371
1206
|
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
|
@@ -1375,20 +1210,18 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
1375
1210
|
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
|
1376
1211
|
SCS(tocq)(&spec_mat_proj_timer);)
|
|
1377
1212
|
#endif
|
|
1378
|
-
if (status < 0)
|
|
1213
|
+
if (status < 0)
|
|
1379
1214
|
return status;
|
|
1380
|
-
}
|
|
1381
1215
|
count += get_sd_cone_size(k->s[i]);
|
|
1382
1216
|
}
|
|
1383
1217
|
}
|
|
1384
1218
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1219
|
+
/* 6. Complex PSD Cone */
|
|
1220
|
+
if (k->cssize) {
|
|
1387
1221
|
for (i = 0; i < k->cssize; ++i) {
|
|
1388
1222
|
status = proj_complex_semi_definite_cone(&(x[count]), k->cs[i], c);
|
|
1389
|
-
if (status < 0)
|
|
1223
|
+
if (status < 0)
|
|
1390
1224
|
return status;
|
|
1391
|
-
}
|
|
1392
1225
|
count += get_csd_cone_size(k->cs[i]);
|
|
1393
1226
|
}
|
|
1394
1227
|
}
|
|
@@ -1398,15 +1231,17 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
1398
1231
|
#pragma omp parallel for
|
|
1399
1232
|
#endif
|
|
1400
1233
|
for (i = 0; i < k->ep + k->ed; ++i) {
|
|
1401
|
-
/* provided in exp_cone.c */
|
|
1402
1234
|
SCS(proj_pd_exp_cone)(&(x[count + 3 * i]), i < k->ep);
|
|
1403
1235
|
}
|
|
1404
1236
|
count += 3 * (k->ep + k->ed);
|
|
1405
1237
|
}
|
|
1406
|
-
|
|
1238
|
+
|
|
1239
|
+
/* 8. Power Cone */
|
|
1240
|
+
if (k->psize) {
|
|
1407
1241
|
scs_float v[3];
|
|
1408
1242
|
scs_int idx;
|
|
1409
|
-
/*
|
|
1243
|
+
/* TODO: openmp not working well for power cone. */
|
|
1244
|
+
/*
|
|
1410
1245
|
ifdef _OPENMP
|
|
1411
1246
|
pragma omp parallel for private(v, idx)
|
|
1412
1247
|
endif
|
|
@@ -1414,16 +1249,14 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
1414
1249
|
for (i = 0; i < k->psize; ++i) { /* doesn't use r_y */
|
|
1415
1250
|
idx = count + 3 * i;
|
|
1416
1251
|
if (k->p[i] >= 0) {
|
|
1417
|
-
/*
|
|
1252
|
+
/* Primal power cone */
|
|
1418
1253
|
proj_power_cone(&(x[idx]), k->p[i]);
|
|
1419
1254
|
} else {
|
|
1420
|
-
/*
|
|
1255
|
+
/* Dual power cone via Moreau */
|
|
1421
1256
|
v[0] = -x[idx];
|
|
1422
1257
|
v[1] = -x[idx + 1];
|
|
1423
1258
|
v[2] = -x[idx + 2];
|
|
1424
|
-
|
|
1425
1259
|
proj_power_cone(v, -k->p[i]);
|
|
1426
|
-
|
|
1427
1260
|
x[idx] += v[0];
|
|
1428
1261
|
x[idx + 1] += v[1];
|
|
1429
1262
|
x[idx + 2] += v[2];
|
|
@@ -1433,99 +1266,79 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
1433
1266
|
}
|
|
1434
1267
|
|
|
1435
1268
|
#ifdef USE_SPECTRAL_CONES
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1269
|
+
/* Spectral Cones (Logdet, Nuclear, Ell1, Sum Largest) */
|
|
1270
|
+
scs_int offset_log = 0;
|
|
1271
|
+
|
|
1272
|
+
if (k->dsize) {
|
|
1439
1273
|
for (i = 0; i < k->dsize; ++i) {
|
|
1440
1274
|
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
|
1441
|
-
status = SCS(proj_logdet_cone)(&(x[count]), k->d[i], c,
|
|
1275
|
+
status = SCS(proj_logdet_cone)(&(x[count]), k->d[i], c, offset_log,
|
|
1442
1276
|
c->log_cone_warmstarts + i);
|
|
1443
1277
|
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
|
1444
1278
|
SCS(tocq)(&spec_mat_proj_timer);)
|
|
1445
|
-
|
|
1446
|
-
if (status < 0) {
|
|
1279
|
+
if (status < 0)
|
|
1447
1280
|
return status;
|
|
1448
|
-
|
|
1449
|
-
count +=
|
|
1281
|
+
offset_log += k->d[i] + 2;
|
|
1282
|
+
count += get_sd_cone_size(k->d[i]) + 2;
|
|
1450
1283
|
}
|
|
1451
1284
|
}
|
|
1452
|
-
|
|
1453
|
-
if (k->nucsize && k->nuc_m && k->nuc_n) {
|
|
1285
|
+
if (k->nucsize) {
|
|
1454
1286
|
for (i = 0; i < k->nucsize; ++i) {
|
|
1455
1287
|
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
|
1456
1288
|
status = SCS(proj_nuclear_cone)(&(x[count]), k->nuc_m[i], k->nuc_n[i], c);
|
|
1457
1289
|
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
|
1458
1290
|
SCS(tocq)(&spec_mat_proj_timer);)
|
|
1459
|
-
if (status < 0)
|
|
1291
|
+
if (status < 0)
|
|
1460
1292
|
return status;
|
|
1461
|
-
|
|
1462
|
-
count += (k->nuc_m[i] * k->nuc_n[i] + 1);
|
|
1293
|
+
count += k->nuc_m[i] * k->nuc_n[i] + 1;
|
|
1463
1294
|
}
|
|
1464
1295
|
}
|
|
1465
|
-
|
|
1466
|
-
if (k->ell1_size && k->ell1) {
|
|
1296
|
+
if (k->ell1_size) {
|
|
1467
1297
|
for (i = 0; i < k->ell1_size; ++i) {
|
|
1468
1298
|
SCS(proj_ell_one)(&(x[count]), k->ell1[i], c);
|
|
1469
|
-
count +=
|
|
1299
|
+
count += k->ell1[i] + 1;
|
|
1470
1300
|
}
|
|
1471
1301
|
}
|
|
1472
|
-
|
|
1473
|
-
if (k->sl_size && k->sl_n && k->sl_k) {
|
|
1302
|
+
if (k->sl_size) {
|
|
1474
1303
|
for (i = 0; i < k->sl_size; ++i) {
|
|
1475
1304
|
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
|
1476
1305
|
status =
|
|
1477
1306
|
SCS(proj_sum_largest_evals)(&(x[count]), k->sl_n[i], k->sl_k[i], c);
|
|
1478
1307
|
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
|
1479
1308
|
SCS(tocq)(&spec_mat_proj_timer);)
|
|
1480
|
-
if (status < 0)
|
|
1309
|
+
if (status < 0)
|
|
1481
1310
|
return status;
|
|
1482
|
-
|
|
1483
|
-
count += (get_sd_cone_size(k->sl_n[i]) + 1);
|
|
1311
|
+
count += get_sd_cone_size(k->sl_n[i]) + 1;
|
|
1484
1312
|
}
|
|
1485
1313
|
}
|
|
1486
|
-
|
|
1487
1314
|
#endif
|
|
1488
|
-
/* project onto OTHER cones */
|
|
1489
1315
|
|
|
1490
1316
|
return 0;
|
|
1491
1317
|
}
|
|
1492
1318
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
scs_int n_max = 0;
|
|
1497
|
-
|
|
1498
|
-
if (k->ell1_size > 0) {
|
|
1499
|
-
for (i = 0; i < k->ell1_size; ++i) {
|
|
1500
|
-
n_max = MAX(k->ell1[i], n_max);
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
c->work_ell1 = (Value_index *)scs_calloc(n_max, sizeof(Value_index));
|
|
1504
|
-
c->work_ell1_proj = (scs_float *)scs_calloc(n_max + 1, sizeof(scs_float));
|
|
1505
|
-
if (!c->work_ell1 || !c->work_ell1_proj) {
|
|
1506
|
-
return -1;
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
return 0;
|
|
1511
|
-
}
|
|
1512
|
-
#endif
|
|
1319
|
+
/*
|
|
1320
|
+
* Public API
|
|
1321
|
+
*/
|
|
1513
1322
|
|
|
1514
1323
|
ScsConeWork *SCS(init_cone)(ScsCone *k, scs_int m) {
|
|
1515
1324
|
ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
|
|
1325
|
+
if (!c)
|
|
1326
|
+
return SCS_NULL;
|
|
1327
|
+
|
|
1516
1328
|
c->k = k;
|
|
1517
1329
|
c->m = m;
|
|
1518
|
-
|
|
1519
1330
|
c->scaled_cones = 0;
|
|
1331
|
+
|
|
1520
1332
|
set_cone_boundaries(k, c);
|
|
1521
1333
|
c->s = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
|
1522
|
-
|
|
1334
|
+
|
|
1335
|
+
/* Set up workspaces if matrix cones are present */
|
|
1336
|
+
if ((k->ssize && k->s) || (k->cssize && k->cs)
|
|
1523
1337
|
#ifdef USE_SPECTRAL_CONES
|
|
1524
|
-
|| (k->dsize
|
|
1525
|
-
(k->sl_size && k->sl_k && k->sl_n)
|
|
1338
|
+
|| (k->dsize) || (k->nucsize) || (k->sl_size)
|
|
1526
1339
|
#endif
|
|
1527
1340
|
) {
|
|
1528
|
-
if (
|
|
1341
|
+
if (set_up_cone_work_spaces(c, k) < 0) {
|
|
1529
1342
|
SCS(finish_cone)(c);
|
|
1530
1343
|
return SCS_NULL;
|
|
1531
1344
|
}
|
|
@@ -1540,16 +1353,10 @@ ScsConeWork *SCS(init_cone)(ScsCone *k, scs_int m) {
|
|
|
1540
1353
|
}
|
|
1541
1354
|
#endif
|
|
1542
1355
|
|
|
1543
|
-
if (k->cssize && k->cs) {
|
|
1544
|
-
if (set_up_csd_cone_work_space(c, k) < 0) {
|
|
1545
|
-
SCS(finish_cone)(c);
|
|
1546
|
-
return SCS_NULL;
|
|
1547
|
-
}
|
|
1548
|
-
}
|
|
1549
1356
|
return c;
|
|
1550
1357
|
}
|
|
1551
1358
|
|
|
1552
|
-
void scale_box_cone(ScsCone *k, ScsConeWork *c, ScsScaling *scal) {
|
|
1359
|
+
void scale_box_cone(ScsCone *k, ScsConeWork *c, const ScsScaling *scal) {
|
|
1553
1360
|
if (k->bsize && k->bu && k->bl) {
|
|
1554
1361
|
c->box_t_warm_start = 1.;
|
|
1555
1362
|
if (scal) {
|
|
@@ -1571,34 +1378,38 @@ void scale_box_cone(ScsCone *k, ScsConeWork *c, ScsScaling *scal) {
|
|
|
1571
1378
|
`||x||_R = \sqrt{x ' R x}`.
|
|
1572
1379
|
|
|
1573
1380
|
*/
|
|
1574
|
-
scs_int SCS(proj_dual_cone)(scs_float *x, ScsConeWork *c,
|
|
1575
|
-
scs_float *r_y) {
|
|
1381
|
+
scs_int SCS(proj_dual_cone)(scs_float *x, ScsConeWork *c,
|
|
1382
|
+
const ScsScaling *scal, scs_float *r_y) {
|
|
1576
1383
|
scs_int status, i;
|
|
1577
1384
|
ScsCone *k = c->k;
|
|
1578
1385
|
|
|
1579
1386
|
if (!c->scaled_cones) {
|
|
1580
|
-
|
|
1387
|
+
/* Normalize box cone if applicable */
|
|
1388
|
+
if (k->bsize && k->bu && k->bl) {
|
|
1389
|
+
c->box_t_warm_start = 1.;
|
|
1390
|
+
if (scal)
|
|
1391
|
+
normalize_box_cone(k, &(scal->D[k->z + k->l]), k->bsize);
|
|
1392
|
+
}
|
|
1581
1393
|
c->scaled_cones = 1;
|
|
1582
1394
|
}
|
|
1583
1395
|
|
|
1584
|
-
/*
|
|
1396
|
+
/* Copy s = x */
|
|
1585
1397
|
memcpy(c->s, x, c->m * sizeof(scs_float));
|
|
1586
1398
|
|
|
1587
1399
|
/* x -> - Rx */
|
|
1588
1400
|
for (i = 0; i < c->m; ++i) {
|
|
1589
|
-
x[i] *= r_y ? -r_y[i] : -1;
|
|
1401
|
+
x[i] *= r_y ? -r_y[i] : -1.0;
|
|
1590
1402
|
}
|
|
1591
1403
|
|
|
1592
|
-
/*
|
|
1404
|
+
/* Project -x onto cone, x -> \Pi_{C^*}^{R^{-1}}(-x) under r_y metric */
|
|
1593
1405
|
status = proj_cone(x, k, c, scal ? 1 : 0, r_y);
|
|
1594
1406
|
|
|
1595
|
-
/*
|
|
1407
|
+
/* Return x + R^{-1} \Pi_{C^*}^{R^{-1}} ( -x ) */
|
|
1596
1408
|
for (i = 0; i < c->m; ++i) {
|
|
1597
|
-
if (r_y)
|
|
1409
|
+
if (r_y)
|
|
1598
1410
|
x[i] = x[i] / r_y[i] + c->s[i];
|
|
1599
|
-
|
|
1411
|
+
else
|
|
1600
1412
|
x[i] += c->s[i];
|
|
1601
|
-
}
|
|
1602
1413
|
}
|
|
1603
1414
|
|
|
1604
1415
|
return status;
|