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