scs 0.5.1 → 0.5.2
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 +4 -0
- data/lib/scs/ffi.rb +2 -0
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +2 -2
- data/vendor/scs/CMakeLists.txt +136 -6
- data/vendor/scs/Makefile +53 -3
- data/vendor/scs/README.md +1 -1
- data/vendor/scs/include/cones.h +47 -2
- data/vendor/scs/include/glbopts.h +1 -1
- data/vendor/scs/include/scs.h +29 -0
- data/vendor/scs/include/scs_blas.h +4 -0
- data/vendor/scs/include/scs_types.h +3 -1
- data/vendor/scs/include/util_spectral_cones.h +45 -0
- data/vendor/scs/linsys/cpu/direct/private.c +3 -3
- data/vendor/scs/linsys/cpu/direct/private.h +2 -1
- data/vendor/scs/linsys/csparse.c +1 -1
- data/vendor/scs/linsys/cudss/direct/private.c +279 -0
- data/vendor/scs/linsys/cudss/direct/private.h +63 -0
- data/vendor/scs/linsys/external/qdldl/qdldl_types.h +1 -1
- data/vendor/scs/linsys/gpu/indirect/private.c +14 -21
- data/vendor/scs/scs.mk +17 -2
- data/vendor/scs/src/aa.c +8 -12
- data/vendor/scs/src/cones.c +783 -12
- data/vendor/scs/src/rw.c +15 -1
- data/vendor/scs/src/scs.c +4 -0
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +660 -0
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +279 -0
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +205 -0
- data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +143 -0
- data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +221 -0
- data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +99 -0
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +196 -0
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +140 -0
- data/vendor/scs/src/spectral_cones/util_spectral_cones.c +52 -0
- data/vendor/scs/test/problems/complex_PSD.h +83 -0
- data/vendor/scs/test/rng.h +4 -4
- data/vendor/scs/test/run_tests.c +25 -0
- data/vendor/scs/test/spectral_cones_problems/exp_design.h +141 -0
- data/vendor/scs/test/spectral_cones_problems/graph_partitioning.h +275 -0
- data/vendor/scs/test/spectral_cones_problems/robust_pca.h +253 -0
- data/vendor/scs/test/spectral_cones_problems/several_logdet_cones.h +222 -0
- data/vendor/scs/test/spectral_cones_problems/several_nuc_cone.h +285 -0
- data/vendor/scs/test/spectral_cones_problems/several_sum_largest.h +420 -0
- metadata +21 -2
data/vendor/scs/src/cones.c
CHANGED
@@ -3,6 +3,19 @@
|
|
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
|
+
|
8
|
+
// We need these definitions here to avoid including complex.h in scs_types.h.
|
9
|
+
// Including complex.h in scs_types.h causes issues when building with C++
|
10
|
+
// compilers. Reach out to Daniel Cederberg if you have any questions about the
|
11
|
+
// following 7 lines of code.
|
12
|
+
#ifndef SFLOAT
|
13
|
+
#define SCS_BLAS_COMPLEX_CAST(x) ((double _Complex *)(x))
|
14
|
+
#define SCS_BLAS_COMPLEX_TYPE double _Complex
|
15
|
+
#else
|
16
|
+
#define SCS_BLAS_COMPLEX_CAST(x) ((float _Complex *)(x))
|
17
|
+
#define SCS_BLAS_COMPLEX_TYPE float _Complex
|
18
|
+
#endif
|
6
19
|
|
7
20
|
#define BOX_CONE_MAX_ITERS (25)
|
8
21
|
#define POW_CONE_TOL (1e-9)
|
@@ -20,17 +33,51 @@ extern "C" {
|
|
20
33
|
void BLAS(syev)(const char *jobz, const char *uplo, blas_int *n, scs_float *a,
|
21
34
|
blas_int *lda, scs_float *w, scs_float *work, blas_int *lwork,
|
22
35
|
blas_int *info);
|
36
|
+
void BLASC(heevr)(const char *jobz, const char *range, const char *uplo,
|
37
|
+
blas_int *n, SCS_BLAS_COMPLEX_TYPE *a, blas_int *lda,
|
38
|
+
scs_float *vl, scs_float *vu, blas_int *il, blas_int *iu,
|
39
|
+
scs_float *abstol, blas_int *m, scs_float *w,
|
40
|
+
SCS_BLAS_COMPLEX_TYPE *z, blas_int *ldz, blas_int *isuppz,
|
41
|
+
SCS_BLAS_COMPLEX_TYPE *cwork, blas_int *lcwork,
|
42
|
+
scs_float *rwork, blas_int *lrwork, blas_int *iwork,
|
43
|
+
blas_int *liwork, blas_int *info);
|
44
|
+
|
23
45
|
blas_int BLAS(syrk)(const char *uplo, const char *trans, const blas_int *n,
|
24
46
|
const blas_int *k, const scs_float *alpha,
|
25
47
|
const scs_float *a, const blas_int *lda,
|
26
48
|
const scs_float *beta, scs_float *c, const blas_int *ldc);
|
49
|
+
|
50
|
+
blas_int BLASC(herk)(const char *uplo, const char *trans, const blas_int *n,
|
51
|
+
const blas_int *k, const scs_float *alpha,
|
52
|
+
const SCS_BLAS_COMPLEX_TYPE *a, const blas_int *lda,
|
53
|
+
const scs_float *beta, SCS_BLAS_COMPLEX_TYPE *c,
|
54
|
+
const blas_int *ldc);
|
55
|
+
|
27
56
|
void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
|
28
57
|
const blas_int *incx);
|
58
|
+
void BLASC(scal)(const blas_int *n, const SCS_BLAS_COMPLEX_TYPE *sa,
|
59
|
+
SCS_BLAS_COMPLEX_TYPE *sx, const blas_int *incx);
|
60
|
+
|
61
|
+
#ifdef USE_SPECTRAL_CONES
|
62
|
+
void BLAS(gesvd)(const char *jobu, const char *jobvt, const blas_int *m,
|
63
|
+
const blas_int *n, scs_float *a, const blas_int *lda,
|
64
|
+
scs_float *s, scs_float *u, const blas_int *ldu, scs_float *vt,
|
65
|
+
const blas_int *ldvt, scs_float *work, const blas_int *lwork,
|
66
|
+
blas_int *info);
|
67
|
+
|
68
|
+
// Forward declare spectral matrix cone projections
|
69
|
+
scs_int SCS(proj_logdet_cone)(scs_float *tvX, const scs_int n, ScsConeWork *c,
|
70
|
+
scs_int offset, bool *warmstart);
|
71
|
+
scs_int SCS(proj_nuclear_cone)(scs_float *tX, scs_int m, scs_int n,
|
72
|
+
ScsConeWork *c);
|
73
|
+
void SCS(proj_ell_one)(scs_float *tx, scs_int n, ScsConeWork *c);
|
74
|
+
scs_int SCS(proj_sum_largest_evals)(scs_float *tX, scs_int n, scs_int k,
|
75
|
+
ScsConeWork *c);
|
76
|
+
#endif
|
29
77
|
|
30
78
|
#ifdef __cplusplus
|
31
79
|
}
|
32
80
|
#endif
|
33
|
-
|
34
81
|
#endif
|
35
82
|
|
36
83
|
/* Forward declare exponential cone projection routine.
|
@@ -48,8 +95,24 @@ void SCS(free_cone)(ScsCone *k) {
|
|
48
95
|
scs_free(k->q);
|
49
96
|
if (k->s)
|
50
97
|
scs_free(k->s);
|
98
|
+
if (k->cs)
|
99
|
+
scs_free(k->cs);
|
51
100
|
if (k->p)
|
52
101
|
scs_free(k->p);
|
102
|
+
#ifdef USE_SPECTRAL_CONES
|
103
|
+
if (k->d)
|
104
|
+
scs_free(k->d);
|
105
|
+
if (k->nuc_m)
|
106
|
+
scs_free(k->nuc_m);
|
107
|
+
if (k->nuc_n)
|
108
|
+
scs_free(k->nuc_n);
|
109
|
+
if (k->ell1)
|
110
|
+
scs_free(k->ell1);
|
111
|
+
if (k->sl_n)
|
112
|
+
scs_free(k->sl_n);
|
113
|
+
if (k->sl_k)
|
114
|
+
scs_free(k->sl_k);
|
115
|
+
#endif
|
53
116
|
scs_free(k);
|
54
117
|
}
|
55
118
|
}
|
@@ -80,6 +143,13 @@ void SCS(deep_copy_cone)(ScsCone *dest, const ScsCone *src) {
|
|
80
143
|
} else {
|
81
144
|
dest->s = SCS_NULL;
|
82
145
|
}
|
146
|
+
/* copy complex PSD cone */
|
147
|
+
if (src->cssize > 0) {
|
148
|
+
dest->cs = (scs_int *)scs_calloc(src->cssize, sizeof(scs_int));
|
149
|
+
memcpy(dest->cs, src->cs, src->cssize * sizeof(scs_int));
|
150
|
+
} else {
|
151
|
+
dest->cs = SCS_NULL;
|
152
|
+
}
|
83
153
|
/* copy power cone */
|
84
154
|
if (src->psize > 0) {
|
85
155
|
dest->p = (scs_float *)scs_calloc(src->psize, sizeof(scs_float));
|
@@ -87,6 +157,42 @@ void SCS(deep_copy_cone)(ScsCone *dest, const ScsCone *src) {
|
|
87
157
|
} else {
|
88
158
|
dest->p = SCS_NULL;
|
89
159
|
}
|
160
|
+
#ifdef USE_SPECTRAL_CONES
|
161
|
+
/* copy logdet cone */
|
162
|
+
if (src->dsize > 0) {
|
163
|
+
dest->d = (scs_int *)scs_calloc(src->dsize, sizeof(scs_int));
|
164
|
+
memcpy(dest->d, src->d, src->dsize * sizeof(scs_int));
|
165
|
+
} else {
|
166
|
+
dest->d = SCS_NULL;
|
167
|
+
}
|
168
|
+
/* copy nuclear norm cone*/
|
169
|
+
if (src->nucsize > 0) {
|
170
|
+
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
|
+
dest->nuc_n = (scs_int *)scs_calloc(src->nucsize, sizeof(scs_int));
|
173
|
+
memcpy(dest->nuc_n, src->nuc_n, src->nucsize * sizeof(scs_int));
|
174
|
+
} else {
|
175
|
+
dest->nuc_m = SCS_NULL;
|
176
|
+
dest->nuc_n = SCS_NULL;
|
177
|
+
}
|
178
|
+
/* copy ell1-norm cone */
|
179
|
+
if (src->ell1_size > 0) {
|
180
|
+
dest->ell1 = (scs_int *)scs_calloc(src->ell1_size, sizeof(scs_int));
|
181
|
+
memcpy(dest->ell1, src->ell1, src->ell1_size * sizeof(scs_int));
|
182
|
+
} else {
|
183
|
+
dest->ell1 = SCS_NULL;
|
184
|
+
}
|
185
|
+
/* copy sum-of-largest eigenvalues cone */
|
186
|
+
if (src->sl_size > 0) {
|
187
|
+
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
|
+
dest->sl_k = (scs_int *)scs_calloc(src->sl_size, sizeof(scs_int));
|
190
|
+
memcpy(dest->sl_k, src->sl_k, src->sl_size * sizeof(scs_int));
|
191
|
+
} else {
|
192
|
+
dest->sl_n = SCS_NULL;
|
193
|
+
dest->sl_k = SCS_NULL;
|
194
|
+
}
|
195
|
+
#endif
|
90
196
|
}
|
91
197
|
|
92
198
|
/* set the vector of rho y terms, based on scale and cones */
|
@@ -100,6 +206,7 @@ void SCS(set_r_y)(const ScsConeWork *c, scs_float scale, scs_float *r_y) {
|
|
100
206
|
*/
|
101
207
|
r_y[i] = 1.0 / (1000. * scale);
|
102
208
|
}
|
209
|
+
|
103
210
|
/* others */
|
104
211
|
for (i = c->k->z; i < c->m; ++i) {
|
105
212
|
r_y[i] = 1.0 / scale;
|
@@ -126,15 +233,25 @@ static inline scs_int get_sd_cone_size(scs_int s) {
|
|
126
233
|
return (s * (s + 1)) / 2;
|
127
234
|
}
|
128
235
|
|
236
|
+
static inline scs_int get_csd_cone_size(scs_int cs) {
|
237
|
+
return cs * cs;
|
238
|
+
}
|
239
|
+
|
129
240
|
/*
|
130
241
|
* boundaries will contain array of indices of rows of A corresponding to
|
131
242
|
* cone boundaries, boundaries[0] is starting index for cones of size strictly
|
132
243
|
* larger than 1, boundaries malloc-ed here so should be freed.
|
133
244
|
*/
|
134
245
|
void set_cone_boundaries(const ScsCone *k, ScsConeWork *c) {
|
135
|
-
scs_int i, s_cone_sz, count = 0;
|
246
|
+
scs_int i, s_cone_sz, cs_cone_sz, count = 0;
|
247
|
+
#ifdef USE_SPECTRAL_CONES
|
248
|
+
scs_int cone_boundaries_len = 1 + k->qsize + k->ssize + +k->cssize + k->ed +
|
249
|
+
k->ep + k->psize + k->dsize + k->nucsize +
|
250
|
+
k->ell1_size + k->sl_size;
|
251
|
+
#else
|
136
252
|
scs_int cone_boundaries_len =
|
137
|
-
1 + k->qsize + k->ssize + k->ed + k->ep + k->psize;
|
253
|
+
1 + k->qsize + k->ssize + k->cssize + k->ed + k->ep + k->psize;
|
254
|
+
#endif
|
138
255
|
scs_int *b = (scs_int *)scs_calloc(cone_boundaries_len, sizeof(scs_int));
|
139
256
|
/* cones that can be scaled independently */
|
140
257
|
b[count] = k->z + k->l + k->bsize;
|
@@ -143,11 +260,17 @@ void set_cone_boundaries(const ScsCone *k, ScsConeWork *c) {
|
|
143
260
|
b[count + i] = k->q[i];
|
144
261
|
}
|
145
262
|
count += k->qsize;
|
263
|
+
/* semidefinite cones */
|
146
264
|
for (i = 0; i < k->ssize; ++i) {
|
147
265
|
s_cone_sz = get_sd_cone_size(k->s[i]);
|
148
266
|
b[count + i] = s_cone_sz;
|
149
267
|
}
|
150
|
-
count += k->ssize; /*
|
268
|
+
count += k->ssize; /* size here not ssize * (ssize + 1) / 2 */
|
269
|
+
for (i = 0; i < k->cssize; ++i) {
|
270
|
+
cs_cone_sz = get_csd_cone_size(k->cs[i]);
|
271
|
+
b[count + i] = cs_cone_sz;
|
272
|
+
}
|
273
|
+
count += k->cssize;
|
151
274
|
/* exp cones */
|
152
275
|
for (i = 0; i < k->ep + k->ed; ++i) {
|
153
276
|
b[count + i] = 3;
|
@@ -158,6 +281,28 @@ void set_cone_boundaries(const ScsCone *k, ScsConeWork *c) {
|
|
158
281
|
b[count + i] = 3;
|
159
282
|
}
|
160
283
|
count += k->psize;
|
284
|
+
#ifdef USE_SPECTRAL_CONES
|
285
|
+
/* logdet cones */
|
286
|
+
for (i = 0; i < k->dsize; ++i) {
|
287
|
+
b[count + i] = get_sd_cone_size(k->d[i]) + 2;
|
288
|
+
}
|
289
|
+
count += k->dsize;
|
290
|
+
/* nuclear norm cones */
|
291
|
+
for (i = 0; i < k->nucsize; ++i) {
|
292
|
+
b[count + i] = k->nuc_m[i] * k->nuc_n[i] + 1;
|
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
|
+
#endif
|
161
306
|
/* other cones */
|
162
307
|
c->cone_boundaries = b;
|
163
308
|
c->cone_boundaries_len = cone_boundaries_len;
|
@@ -175,6 +320,11 @@ static scs_int get_full_cone_dims(const ScsCone *k) {
|
|
175
320
|
c += get_sd_cone_size(k->s[i]);
|
176
321
|
}
|
177
322
|
}
|
323
|
+
if (k->cssize) {
|
324
|
+
for (i = 0; i < k->cssize; ++i) {
|
325
|
+
c += get_csd_cone_size(k->cs[i]);
|
326
|
+
}
|
327
|
+
}
|
178
328
|
if (k->ed) {
|
179
329
|
c += 3 * k->ed;
|
180
330
|
}
|
@@ -184,6 +334,28 @@ static scs_int get_full_cone_dims(const ScsCone *k) {
|
|
184
334
|
if (k->psize) {
|
185
335
|
c += 3 * k->psize;
|
186
336
|
}
|
337
|
+
#ifdef USE_SPECTRAL_CONES
|
338
|
+
if (k->dsize) {
|
339
|
+
for (i = 0; i < k->dsize; ++i) {
|
340
|
+
c += get_sd_cone_size(k->d[i]) + 2;
|
341
|
+
}
|
342
|
+
}
|
343
|
+
if (k->nucsize) {
|
344
|
+
for (i = 0; i < k->nucsize; ++i) {
|
345
|
+
c += k->nuc_m[i] * k->nuc_n[i] + 1;
|
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
|
+
}
|
358
|
+
#endif
|
187
359
|
return c;
|
188
360
|
}
|
189
361
|
|
@@ -238,6 +410,18 @@ scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
|
|
238
410
|
}
|
239
411
|
}
|
240
412
|
}
|
413
|
+
if (k->cssize && k->cs) {
|
414
|
+
if (k->cssize < 0) {
|
415
|
+
scs_printf("complex psd cone dimension error\n");
|
416
|
+
return -1;
|
417
|
+
}
|
418
|
+
for (i = 0; i < k->cssize; ++i) {
|
419
|
+
if (k->cs[i] < 0) {
|
420
|
+
scs_printf("complex psd cone dimension error\n");
|
421
|
+
return -1;
|
422
|
+
}
|
423
|
+
}
|
424
|
+
}
|
241
425
|
if (k->ed && k->ed < 0) {
|
242
426
|
scs_printf("ep cone dimension error\n");
|
243
427
|
return -1;
|
@@ -258,6 +442,52 @@ scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
|
|
258
442
|
}
|
259
443
|
}
|
260
444
|
}
|
445
|
+
#ifdef USE_SPECTRAL_CONES
|
446
|
+
if (k->dsize && k->d) {
|
447
|
+
if (k->dsize < 0) {
|
448
|
+
scs_printf("logdet cone dimension error\n");
|
449
|
+
return -1;
|
450
|
+
}
|
451
|
+
for (i = 0; i < k->dsize; ++i) {
|
452
|
+
if (k->d[i] < 1) {
|
453
|
+
scs_printf("logdet cone dimension error\n");
|
454
|
+
return -1;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
if (k->nucsize && k->nuc_m && k->nuc_n) {
|
459
|
+
if (k->nucsize < 0) {
|
460
|
+
scs_printf("nuclear cone dimension error\n");
|
461
|
+
return -1;
|
462
|
+
}
|
463
|
+
for (i = 0; i < k->nucsize; ++i) {
|
464
|
+
if (k->nuc_m[i] < 1 || k->nuc_n[i] < 1 || k->nuc_n[i] > k->nuc_m[i]) {
|
465
|
+
scs_printf("nuclear norm cone dimension error\n");
|
466
|
+
return -1;
|
467
|
+
}
|
468
|
+
}
|
469
|
+
}
|
470
|
+
if (k->ell1_size && k->ell1) {
|
471
|
+
if (k->ell1_size < 0) {
|
472
|
+
scs_printf("ell1 cone dimension error\n");
|
473
|
+
return -1;
|
474
|
+
}
|
475
|
+
for (i = 0; i < k->ell1_size; ++i) {
|
476
|
+
if (k->ell1[i] < 1) {
|
477
|
+
scs_printf("ell1 cone dimension error\n");
|
478
|
+
return -1;
|
479
|
+
}
|
480
|
+
}
|
481
|
+
}
|
482
|
+
if (k->sl_size && k->sl_n && k->sl_k) {
|
483
|
+
for (i = 0; i < k->sl_size; ++i) {
|
484
|
+
if ((k->sl_k[i] >= k->sl_n[i]) || k->sl_k[i] <= 0) {
|
485
|
+
scs_printf("sum-of-largest-eigenvalues cone dimension error\n");
|
486
|
+
return -1;
|
487
|
+
}
|
488
|
+
}
|
489
|
+
}
|
490
|
+
#endif
|
261
491
|
return 0;
|
262
492
|
}
|
263
493
|
|
@@ -266,15 +496,33 @@ void SCS(finish_cone)(ScsConeWork *c) {
|
|
266
496
|
if (c->Xs) {
|
267
497
|
scs_free(c->Xs);
|
268
498
|
}
|
499
|
+
if (c->cXs) {
|
500
|
+
scs_free(c->cXs);
|
501
|
+
}
|
269
502
|
if (c->Z) {
|
270
503
|
scs_free(c->Z);
|
271
504
|
}
|
505
|
+
if (c->cZ) {
|
506
|
+
scs_free(c->cZ);
|
507
|
+
}
|
272
508
|
if (c->e) {
|
273
509
|
scs_free(c->e);
|
274
510
|
}
|
511
|
+
if (c->isuppz) {
|
512
|
+
scs_free(c->isuppz);
|
513
|
+
}
|
275
514
|
if (c->work) {
|
276
515
|
scs_free(c->work);
|
277
516
|
}
|
517
|
+
if (c->iwork) {
|
518
|
+
scs_free(c->iwork);
|
519
|
+
}
|
520
|
+
if (c->cwork) {
|
521
|
+
scs_free(c->cwork);
|
522
|
+
}
|
523
|
+
if (c->rwork) {
|
524
|
+
scs_free(c->rwork);
|
525
|
+
}
|
278
526
|
#endif
|
279
527
|
if (c->cone_boundaries) {
|
280
528
|
scs_free(c->cone_boundaries);
|
@@ -282,6 +530,38 @@ void SCS(finish_cone)(ScsConeWork *c) {
|
|
282
530
|
if (c->s) {
|
283
531
|
scs_free(c->s);
|
284
532
|
}
|
533
|
+
#ifdef USE_SPECTRAL_CONES
|
534
|
+
if (c->work_logdet) {
|
535
|
+
scs_free(c->work_logdet);
|
536
|
+
}
|
537
|
+
if (c->saved_log_projs) {
|
538
|
+
scs_free(c->saved_log_projs);
|
539
|
+
}
|
540
|
+
if (c->s_nuc) {
|
541
|
+
scs_free(c->s_nuc);
|
542
|
+
}
|
543
|
+
if (c->u_nuc) {
|
544
|
+
scs_free(c->u_nuc);
|
545
|
+
}
|
546
|
+
if (c->vt_nuc) {
|
547
|
+
scs_free(c->vt_nuc);
|
548
|
+
}
|
549
|
+
if (c->work_nuc) {
|
550
|
+
scs_free(c->work_nuc);
|
551
|
+
}
|
552
|
+
if (c->work_sum_of_largest) {
|
553
|
+
scs_free(c->work_sum_of_largest);
|
554
|
+
}
|
555
|
+
if (c->log_cone_warmstarts) {
|
556
|
+
scs_free(c->log_cone_warmstarts);
|
557
|
+
}
|
558
|
+
if (c->work_ell1) {
|
559
|
+
scs_free(c->work_ell1);
|
560
|
+
}
|
561
|
+
if (c->work_ell1_proj) {
|
562
|
+
scs_free(c->work_ell1_proj);
|
563
|
+
}
|
564
|
+
#endif
|
285
565
|
if (c) {
|
286
566
|
scs_free(c);
|
287
567
|
}
|
@@ -289,7 +569,7 @@ void SCS(finish_cone)(ScsConeWork *c) {
|
|
289
569
|
|
290
570
|
char *SCS(get_cone_header)(const ScsCone *k) {
|
291
571
|
char *tmp = (char *)scs_malloc(512); /* sizeof(char) = 1 */
|
292
|
-
scs_int i, soc_vars, sd_vars;
|
572
|
+
scs_int i, soc_vars, sd_vars, csd_vars;
|
293
573
|
sprintf(tmp, "cones: ");
|
294
574
|
if (k->z) {
|
295
575
|
sprintf(tmp + strlen(tmp), "\t z: primal zero / dual free vars: %li\n",
|
@@ -317,6 +597,14 @@ char *SCS(get_cone_header)(const ScsCone *k) {
|
|
317
597
|
sprintf(tmp + strlen(tmp), "\t s: psd vars: %li, ssize: %li\n",
|
318
598
|
(long)sd_vars, (long)k->ssize);
|
319
599
|
}
|
600
|
+
csd_vars = 0;
|
601
|
+
if (k->cssize && k->cs) {
|
602
|
+
for (i = 0; i < k->cssize; i++) {
|
603
|
+
csd_vars += get_csd_cone_size(k->cs[i]);
|
604
|
+
}
|
605
|
+
sprintf(tmp + strlen(tmp), "\t cs: complex psd vars: %li, ssize: %li\n",
|
606
|
+
(long)csd_vars, (long)k->cssize);
|
607
|
+
}
|
320
608
|
if (k->ep || k->ed) {
|
321
609
|
sprintf(tmp + strlen(tmp), "\t e: exp vars: %li, dual exp vars: %li\n",
|
322
610
|
(long)(3 * k->ep), (long)(3 * k->ed));
|
@@ -325,6 +613,43 @@ char *SCS(get_cone_header)(const ScsCone *k) {
|
|
325
613
|
sprintf(tmp + strlen(tmp), "\t p: primal + dual power vars: %li\n",
|
326
614
|
(long)(3 * k->psize));
|
327
615
|
}
|
616
|
+
#ifdef USE_SPECTRAL_CONES
|
617
|
+
scs_int ell1_vars, log_vars, nuc_vars, sl_vars;
|
618
|
+
log_vars = 0;
|
619
|
+
if (k->dsize && k->d) {
|
620
|
+
for (i = 0; i < k->dsize; i++) {
|
621
|
+
log_vars += get_sd_cone_size(k->d[i]) + 2;
|
622
|
+
}
|
623
|
+
sprintf(tmp + strlen(tmp), "\t d: logdet vars: %li, dsize: %li\n",
|
624
|
+
(long)log_vars, (long)k->dsize);
|
625
|
+
}
|
626
|
+
nuc_vars = 0;
|
627
|
+
if (k->nucsize && k->nuc_m && k->nuc_n) {
|
628
|
+
for (i = 0; i < k->nucsize; i++) {
|
629
|
+
nuc_vars += k->nuc_m[i] * k->nuc_n[i] + 1;
|
630
|
+
}
|
631
|
+
sprintf(tmp + strlen(tmp), "\t nuc: nuclear vars: %li, nucsize: %li\n",
|
632
|
+
(long)nuc_vars, (long)k->nucsize);
|
633
|
+
}
|
634
|
+
ell1_vars = 0;
|
635
|
+
if (k->ell1_size && k->ell1) {
|
636
|
+
for (i = 0; i < k->ell1_size; ++i) {
|
637
|
+
ell1_vars += k->ell1[i];
|
638
|
+
}
|
639
|
+
sprintf(tmp + strlen(tmp), "\t ell1: ell1 vars: %li, ell1_size: %li\n",
|
640
|
+
(long)ell1_vars, (long)k->ell1_size);
|
641
|
+
}
|
642
|
+
|
643
|
+
sl_vars = 0;
|
644
|
+
if (k->sl_size && k->sl_n) {
|
645
|
+
for (i = 0; i < k->sl_size; ++i) {
|
646
|
+
sl_vars += get_sd_cone_size(k->sl_n[i]) + 1;
|
647
|
+
}
|
648
|
+
sprintf(tmp + strlen(tmp), "\t sl: sl vars: %li, sl_size: %li\n",
|
649
|
+
(long)sl_vars, (long)k->sl_size);
|
650
|
+
}
|
651
|
+
#endif
|
652
|
+
|
328
653
|
return tmp;
|
329
654
|
}
|
330
655
|
|
@@ -340,31 +665,133 @@ static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
340
665
|
#define _STR(tok) _STR_EXPAND(tok)
|
341
666
|
scs_printf("BLAS(func) = '%s'\n", _STR(BLAS(func)));
|
342
667
|
#endif
|
343
|
-
|
668
|
+
|
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
|
+
// ----------------------------------------------------------------------
|
344
674
|
for (i = 0; i < k->ssize; ++i) {
|
345
675
|
if (k->s[i] > n_max) {
|
346
676
|
n_max = (blas_int)k->s[i];
|
347
677
|
}
|
348
678
|
}
|
679
|
+
|
680
|
+
#ifdef USE_SPECTRAL_CONES
|
681
|
+
blas_int n_max_logdet = 1;
|
682
|
+
blas_int n_logdet_total = 0;
|
683
|
+
blas_int n_max_sl = 1;
|
684
|
+
c->log_cone_warmstarts = (bool *)scs_calloc(k->dsize, sizeof(bool));
|
685
|
+
|
686
|
+
for (i = 0; i < k->sl_size; ++i) {
|
687
|
+
if (k->sl_n[i] > n_max_sl) {
|
688
|
+
n_max_sl = (blas_int)k->sl_n[i];
|
689
|
+
}
|
690
|
+
}
|
691
|
+
|
692
|
+
for (i = 0; i < k->dsize; ++i) {
|
693
|
+
n_logdet_total += (blas_int)k->d[i];
|
694
|
+
if (k->d[i] > n_max_logdet) {
|
695
|
+
n_max_logdet = (blas_int)k->d[i];
|
696
|
+
}
|
697
|
+
}
|
698
|
+
|
699
|
+
// --------------------------------------------------------------------------
|
700
|
+
// allocate workspace for logdeterminant cones
|
701
|
+
// --------------------------------------------------------------------------
|
702
|
+
if (k->dsize > 0) {
|
703
|
+
c->work_logdet =
|
704
|
+
(scs_float *)scs_calloc(22 * n_max_logdet + 122, sizeof(scs_float));
|
705
|
+
c->saved_log_projs = (scs_float *)scs_calloc(2 * k->dsize + n_logdet_total,
|
706
|
+
sizeof(scs_float));
|
707
|
+
|
708
|
+
if (!c->work_logdet || !c->saved_log_projs) {
|
709
|
+
return -1;
|
710
|
+
}
|
711
|
+
}
|
712
|
+
|
713
|
+
// ---------------------------------------------------------------
|
714
|
+
// allocate workspace for sum-of-largest-eigenvalues cone
|
715
|
+
// ---------------------------------------------------------------
|
716
|
+
if (k->sl_size > 0) {
|
717
|
+
c->work_sum_of_largest =
|
718
|
+
(scs_float *)scs_calloc(n_max_sl * n_max_sl, sizeof(scs_float));
|
719
|
+
if (!c->work_sum_of_largest) {
|
720
|
+
return -1;
|
721
|
+
}
|
722
|
+
}
|
723
|
+
n_max = MAX(n_max, n_max_logdet);
|
724
|
+
n_max = MAX(n_max, n_max_sl);
|
725
|
+
#endif
|
726
|
+
// -----------------------------------------------------------------
|
727
|
+
// allocate eigenvector decomposition workspace
|
728
|
+
// -----------------------------------------------------------------
|
349
729
|
c->Xs = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
|
350
730
|
c->Z = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
|
351
731
|
c->e = (scs_float *)scs_calloc(n_max, sizeof(scs_float));
|
352
732
|
|
353
733
|
/* workspace query */
|
354
|
-
BLAS(syev)
|
355
|
-
|
356
|
-
&info);
|
734
|
+
BLAS(syev)("Vectors", "Lower", &n_max, c->Xs, &n_max, SCS_NULL, &wkopt,
|
735
|
+
&neg_one, &info);
|
357
736
|
|
358
737
|
if (info != 0) {
|
359
738
|
scs_printf("FATAL: syev workspace query failure, info = %li\n", (long)info);
|
360
739
|
return -1;
|
361
740
|
}
|
741
|
+
|
362
742
|
c->lwork = (blas_int)(wkopt + 1); /* +1 for int casting safety */
|
363
743
|
c->work = (scs_float *)scs_calloc(c->lwork, sizeof(scs_float));
|
364
744
|
|
365
745
|
if (!c->Xs || !c->Z || !c->e || !c->work) {
|
366
746
|
return -1;
|
367
747
|
}
|
748
|
+
|
749
|
+
#ifdef USE_SPECTRAL_CONES
|
750
|
+
// ------------------------------------------------------------------
|
751
|
+
// allocate memory for nuclear norm cone
|
752
|
+
// ------------------------------------------------------------------
|
753
|
+
if (k->nucsize > 0) {
|
754
|
+
blas_int m_max_nuc = 1;
|
755
|
+
blas_int n_max_nuc = 1;
|
756
|
+
for (i = 0; i < k->nucsize; ++i) {
|
757
|
+
if (k->nuc_m[i] > m_max_nuc) {
|
758
|
+
m_max_nuc = k->nuc_m[i];
|
759
|
+
}
|
760
|
+
if (k->nuc_n[i] > n_max_nuc) {
|
761
|
+
n_max_nuc = k->nuc_n[i];
|
762
|
+
}
|
763
|
+
}
|
764
|
+
|
765
|
+
c->s_nuc = (scs_float *)scs_calloc(n_max_nuc, sizeof(scs_float));
|
766
|
+
c->u_nuc =
|
767
|
+
(scs_float *)scs_calloc(m_max_nuc * n_max_nuc, sizeof(scs_float));
|
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) {
|
772
|
+
return -1;
|
773
|
+
}
|
774
|
+
|
775
|
+
// workspace query
|
776
|
+
BLAS(gesvd)("S", "A", &m_max_nuc, &n_max_nuc, c->u_nuc, &m_max_nuc,
|
777
|
+
c->s_nuc, c->u_nuc, &m_max_nuc, c->vt_nuc, &n_max_nuc, &wkopt,
|
778
|
+
&neg_one, &info);
|
779
|
+
|
780
|
+
c->lwork_nuc = (blas_int)(wkopt + 1); /* +1 for int casting safety */
|
781
|
+
c->work_nuc = (scs_float *)scs_calloc(c->lwork_nuc, sizeof(scs_float));
|
782
|
+
|
783
|
+
if (!c->lwork_nuc || !c->work_nuc) {
|
784
|
+
return -1;
|
785
|
+
}
|
786
|
+
|
787
|
+
if (info != 0) {
|
788
|
+
scs_printf("FATAL: gesvd workspace query failure, info = %li\n",
|
789
|
+
(long)info);
|
790
|
+
return -1;
|
791
|
+
}
|
792
|
+
}
|
793
|
+
#endif
|
794
|
+
|
368
795
|
return 0;
|
369
796
|
#else
|
370
797
|
for (i = 0; i < k->ssize; i++) {
|
@@ -377,6 +804,38 @@ static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
377
804
|
return -1;
|
378
805
|
}
|
379
806
|
}
|
807
|
+
#ifdef USE_SPECTRAL_CONES
|
808
|
+
bool has_spectral_cones = false;
|
809
|
+
for (i = 0; i < k->dsize; i++) {
|
810
|
+
if (k->d[i] > 1) {
|
811
|
+
has_spectral_cones = true;
|
812
|
+
break;
|
813
|
+
}
|
814
|
+
}
|
815
|
+
|
816
|
+
for (i = 0; i < k->nucsize; i++) {
|
817
|
+
if (k->nuc_m[i] > 1 || k->nuc_n[i] > 1) {
|
818
|
+
has_spectral_cones = true;
|
819
|
+
break;
|
820
|
+
}
|
821
|
+
}
|
822
|
+
|
823
|
+
for (i = 0; i < k->sl_size; i++) {
|
824
|
+
if (k->sl_n[i] > 1) {
|
825
|
+
has_spectral_cones = true;
|
826
|
+
break;
|
827
|
+
}
|
828
|
+
}
|
829
|
+
|
830
|
+
if (has_spectral_cones) {
|
831
|
+
scs_printf("FATAL: Cannot use spectral cones without linked blas+lapack "
|
832
|
+
"libraries\n");
|
833
|
+
scs_printf(
|
834
|
+
"Install blas+lapack and re-compile SCS with blas+lapack library "
|
835
|
+
"locations\n");
|
836
|
+
return -1;
|
837
|
+
}
|
838
|
+
#endif
|
380
839
|
return 0;
|
381
840
|
#endif
|
382
841
|
}
|
@@ -386,6 +845,7 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
386
845
|
ScsConeWork *c) {
|
387
846
|
/* project onto the positive semi-definite cone */
|
388
847
|
#ifdef USE_LAPACK
|
848
|
+
SCS(timer) _timer;
|
389
849
|
scs_int i, first_idx;
|
390
850
|
blas_int nb = (blas_int)n;
|
391
851
|
blas_int ncols_z;
|
@@ -435,6 +895,8 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
435
895
|
}
|
436
896
|
}
|
437
897
|
|
898
|
+
SCS(tic)(&_timer);
|
899
|
+
|
438
900
|
first_idx = -1;
|
439
901
|
/* e is eigvals in ascending order, find first entry > 0 */
|
440
902
|
for (i = 0; i < n; ++i) {
|
@@ -476,7 +938,197 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
476
938
|
#else
|
477
939
|
scs_printf("FAILURE: solving SDP but no blas/lapack libraries were found!\n");
|
478
940
|
scs_printf("SCS will return nonsense!\n");
|
479
|
-
SCS(scale_array)(X, NAN, n);
|
941
|
+
SCS(scale_array)(X, NAN, get_sd_cone_size(n));
|
942
|
+
return -1;
|
943
|
+
#endif
|
944
|
+
}
|
945
|
+
|
946
|
+
static scs_int set_up_csd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
947
|
+
scs_int i;
|
948
|
+
#ifdef USE_LAPACK
|
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) */
|
1016
|
+
static scs_int proj_complex_semi_definite_cone(scs_float *X, const scs_int n,
|
1017
|
+
ScsConeWork *c) {
|
1018
|
+
/* project onto the positive semi-definite cone */
|
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) {
|
1042
|
+
return 0;
|
1043
|
+
}
|
1044
|
+
if (n == 1) {
|
1045
|
+
X[0] = MAX(X[0], 0.);
|
1046
|
+
return 0;
|
1047
|
+
}
|
1048
|
+
|
1049
|
+
#ifdef USE_LAPACK
|
1050
|
+
|
1051
|
+
/* copy lower triangular matrix into full matrix */
|
1052
|
+
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]),
|
1056
|
+
2 * (n - i - 1) * sizeof(scs_float));
|
1057
|
+
}
|
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
|
+
}
|
1082
|
+
|
1083
|
+
first_idx = -1;
|
1084
|
+
/* e is eigvals in ascending order, find first entry > 0 */
|
1085
|
+
for (i = 0; i < n; ++i) {
|
1086
|
+
if (e[i] > 0) {
|
1087
|
+
first_idx = i;
|
1088
|
+
break;
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
if (first_idx == -1) {
|
1093
|
+
/* there are no positive eigenvalues, set X to 0 and return */
|
1094
|
+
memset(X, 0, sizeof(scs_float) * get_csd_cone_size(n));
|
1095
|
+
return 0;
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
/* cZ is matrix of all eigenvectors */
|
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' */
|
1108
|
+
ncols_z = (blas_int)(n - first_idx);
|
1109
|
+
BLASC(herk)
|
1110
|
+
("Lower", "NoTrans", &nb, &ncols_z, &one,
|
1111
|
+
SCS_BLAS_COMPLEX_CAST(&cZ[first_idx * n]), &nb, &zero,
|
1112
|
+
SCS_BLAS_COMPLEX_CAST(cXs), &nb);
|
1113
|
+
|
1114
|
+
/* undo rescaling: scale diags by 1/sqrt(2) */
|
1115
|
+
BLASC(scal)
|
1116
|
+
(&nb, SCS_BLAS_COMPLEX_CAST(&csqrt2_inv), SCS_BLAS_COMPLEX_CAST(cXs),
|
1117
|
+
&nb_plus_one); /* not n_squared */
|
1118
|
+
|
1119
|
+
/* extract just lower triangular matrix */
|
1120
|
+
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]),
|
1123
|
+
2 * (n - i - 1) * sizeof(scs_float));
|
1124
|
+
}
|
1125
|
+
X[n * n - 1] = cXs[n * n - 1][0];
|
1126
|
+
return 0;
|
1127
|
+
|
1128
|
+
#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));
|
480
1132
|
return -1;
|
481
1133
|
#endif
|
482
1134
|
}
|
@@ -509,7 +1161,7 @@ static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
|
|
509
1161
|
* want (t, s) \in K <==> (t', s') \in K'
|
510
1162
|
*
|
511
1163
|
* (t', s') = (d0 * t, D s) (overloading D to mean D[1:])
|
512
|
-
* (up to scalar scaling factor which we can ignore due to conic
|
1164
|
+
* (up to scalar scaling factor which we can ignore due to conic property)
|
513
1165
|
*
|
514
1166
|
* K = { (t, s) | t * l <= s <= t * u, t >= 0 } =>
|
515
1167
|
* { (t, s) | d0 * t * D l / d0 <= D s <= d0 * t D u / d0, t >= 0 } =>
|
@@ -676,6 +1328,9 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
676
1328
|
scs_int i, status;
|
677
1329
|
scs_int count = 0;
|
678
1330
|
scs_float *r_box = SCS_NULL;
|
1331
|
+
#ifdef USE_SPECTRAL_CONES
|
1332
|
+
SPECTRAL_TIMING(SCS(timer) spec_mat_proj_timer;)
|
1333
|
+
#endif
|
679
1334
|
|
680
1335
|
if (k->z) { /* doesn't use r_y */
|
681
1336
|
/* project onto primal zero / dual free cone */
|
@@ -712,7 +1367,14 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
712
1367
|
if (k->ssize && k->s) { /* doesn't use r_y */
|
713
1368
|
/* project onto PSD cones */
|
714
1369
|
for (i = 0; i < k->ssize; ++i) {
|
1370
|
+
#ifdef USE_SPECTRAL_CONES
|
1371
|
+
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
1372
|
+
#endif
|
715
1373
|
status = proj_semi_definite_cone(&(x[count]), k->s[i], c);
|
1374
|
+
#ifdef USE_SPECTRAL_CONES
|
1375
|
+
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
1376
|
+
SCS(tocq)(&spec_mat_proj_timer);)
|
1377
|
+
#endif
|
716
1378
|
if (status < 0) {
|
717
1379
|
return status;
|
718
1380
|
}
|
@@ -720,6 +1382,17 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
720
1382
|
}
|
721
1383
|
}
|
722
1384
|
|
1385
|
+
if (k->cssize && k->cs) { /* doesn't use r_y */
|
1386
|
+
/* project onto complex PSD cones */
|
1387
|
+
for (i = 0; i < k->cssize; ++i) {
|
1388
|
+
status = proj_complex_semi_definite_cone(&(x[count]), k->cs[i], c);
|
1389
|
+
if (status < 0) {
|
1390
|
+
return status;
|
1391
|
+
}
|
1392
|
+
count += get_csd_cone_size(k->cs[i]);
|
1393
|
+
}
|
1394
|
+
}
|
1395
|
+
|
723
1396
|
if (k->ep || k->ed) { /* doesn't use r_y */
|
724
1397
|
#ifdef _OPENMP
|
725
1398
|
#pragma omp parallel for
|
@@ -758,23 +1431,121 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
758
1431
|
}
|
759
1432
|
count += 3 * k->psize;
|
760
1433
|
}
|
1434
|
+
|
1435
|
+
#ifdef USE_SPECTRAL_CONES
|
1436
|
+
scs_int offset_log_cone = 0; /* used for warmstarting log-cone projections */
|
1437
|
+
/* project onto logdet cones */
|
1438
|
+
if (k->dsize && k->d) {
|
1439
|
+
for (i = 0; i < k->dsize; ++i) {
|
1440
|
+
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
1441
|
+
status = SCS(proj_logdet_cone)(&(x[count]), k->d[i], c, offset_log_cone,
|
1442
|
+
c->log_cone_warmstarts + i);
|
1443
|
+
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
1444
|
+
SCS(tocq)(&spec_mat_proj_timer);)
|
1445
|
+
offset_log_cone += k->d[i] + 2;
|
1446
|
+
if (status < 0) {
|
1447
|
+
return status;
|
1448
|
+
}
|
1449
|
+
count += (get_sd_cone_size(k->d[i]) + 2);
|
1450
|
+
}
|
1451
|
+
}
|
1452
|
+
/* project onto nuclear norm cones */
|
1453
|
+
if (k->nucsize && k->nuc_m && k->nuc_n) {
|
1454
|
+
for (i = 0; i < k->nucsize; ++i) {
|
1455
|
+
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
1456
|
+
status = SCS(proj_nuclear_cone)(&(x[count]), k->nuc_m[i], k->nuc_n[i], c);
|
1457
|
+
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
1458
|
+
SCS(tocq)(&spec_mat_proj_timer);)
|
1459
|
+
if (status < 0) {
|
1460
|
+
return status;
|
1461
|
+
}
|
1462
|
+
count += (k->nuc_m[i] * k->nuc_n[i] + 1);
|
1463
|
+
}
|
1464
|
+
}
|
1465
|
+
/* project onto ell1-norm cones */
|
1466
|
+
if (k->ell1_size && k->ell1) {
|
1467
|
+
for (i = 0; i < k->ell1_size; ++i) {
|
1468
|
+
SCS(proj_ell_one)(&(x[count]), k->ell1[i], c);
|
1469
|
+
count += (k->ell1[i] + 1);
|
1470
|
+
}
|
1471
|
+
}
|
1472
|
+
/* project onto sum-of-largest eigenvalues cone */
|
1473
|
+
if (k->sl_size && k->sl_n && k->sl_k) {
|
1474
|
+
for (i = 0; i < k->sl_size; ++i) {
|
1475
|
+
SPECTRAL_TIMING(SCS(tic)(&spec_mat_proj_timer);)
|
1476
|
+
status =
|
1477
|
+
SCS(proj_sum_largest_evals)(&(x[count]), k->sl_n[i], k->sl_k[i], c);
|
1478
|
+
SPECTRAL_TIMING(c->tot_time_mat_cone_proj +=
|
1479
|
+
SCS(tocq)(&spec_mat_proj_timer);)
|
1480
|
+
if (status < 0) {
|
1481
|
+
return status;
|
1482
|
+
}
|
1483
|
+
count += (get_sd_cone_size(k->sl_n[i]) + 1);
|
1484
|
+
}
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
#endif
|
761
1488
|
/* project onto OTHER cones */
|
1489
|
+
|
1490
|
+
return 0;
|
1491
|
+
}
|
1492
|
+
|
1493
|
+
#ifdef USE_SPECTRAL_CONES
|
1494
|
+
static scs_int set_up_ell1_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
1495
|
+
scs_int i;
|
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
|
+
|
762
1510
|
return 0;
|
763
1511
|
}
|
1512
|
+
#endif
|
764
1513
|
|
765
1514
|
ScsConeWork *SCS(init_cone)(ScsCone *k, scs_int m) {
|
766
1515
|
ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
|
767
1516
|
c->k = k;
|
768
1517
|
c->m = m;
|
1518
|
+
|
769
1519
|
c->scaled_cones = 0;
|
770
1520
|
set_cone_boundaries(k, c);
|
771
1521
|
c->s = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
772
|
-
if (k->ssize && k->s)
|
1522
|
+
if ((k->ssize && k->s)
|
1523
|
+
#ifdef USE_SPECTRAL_CONES
|
1524
|
+
|| (k->dsize && k->d) || (k->nucsize && k->nuc_m && k->nuc_n) ||
|
1525
|
+
(k->sl_size && k->sl_k && k->sl_n)
|
1526
|
+
#endif
|
1527
|
+
) {
|
773
1528
|
if (set_up_sd_cone_work_space(c, k) < 0) {
|
774
1529
|
SCS(finish_cone)(c);
|
775
1530
|
return SCS_NULL;
|
776
1531
|
}
|
777
1532
|
}
|
1533
|
+
|
1534
|
+
#ifdef USE_SPECTRAL_CONES
|
1535
|
+
if (k->ell1_size > 0 && k->ell1) {
|
1536
|
+
if (set_up_ell1_cone_work_space(c, k) < 0) {
|
1537
|
+
SCS(finish_cone)(c);
|
1538
|
+
return SCS_NULL;
|
1539
|
+
}
|
1540
|
+
}
|
1541
|
+
#endif
|
1542
|
+
|
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
|
+
}
|
778
1549
|
return c;
|
779
1550
|
}
|
780
1551
|
|