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.
@@ -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
- /* MSVC: no C99 <complex.h> */
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
- #include <complex.h>
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
- /* GCC/Clang: keep using C99 _Complex */
29
- #ifndef SFLOAT
30
- #define SCS_BLAS_COMPLEX_CAST(x) ((double _Complex *)(x))
31
- #define SCS_BLAS_COMPLEX_TYPE double _Complex
32
- #else
33
- #define SCS_BLAS_COMPLEX_CAST(x) ((float _Complex *)(x))
34
- #define SCS_BLAS_COMPLEX_TYPE float _Complex
35
- #endif
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
- void BLAS(syev)(const char *jobz, const char *uplo, blas_int *n, scs_float *a,
52
- blas_int *lda, scs_float *w, scs_float *work, blas_int *lwork,
53
- blas_int *info);
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
- // Forward declare spectral matrix cone projections
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 routine.
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
- /* copy bu, bl */
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
- /* copy SOC */
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
- /* copy PSD cone */
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
- /* copy complex PSD cone */
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
- /* copy power cone */
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
- /* copy logdet cone */
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
- /* copy nuclear norm cone*/
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
- /* copy ell1-norm cone */
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
- /* copy sum-of-largest eigenvalues cone */
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
- /* set the vector of rho y terms, based on scale and cones */
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
- /* the function f aggregates the entries within each cone */
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
- * boundaries will contain array of indices of rows of A corresponding to
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, s_cone_sz, cs_cone_sz, count = 0;
280
+ scs_int i, count = 0;
265
281
  #ifdef USE_SPECTRAL_CONES
266
- scs_int cone_boundaries_len = 1 + k->qsize + k->ssize + k->cssize + k->ed +
267
- k->ep + k->psize + k->dsize + k->nucsize +
268
- k->ell1_size + k->sl_size;
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 cone_boundaries_len =
271
- 1 + k->qsize + k->ssize + k->cssize + k->ed + k->ep + k->psize;
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(cone_boundaries_len, sizeof(scs_int));
274
- /* cones that can be scaled independently */
275
- b[count] = k->z + k->l + k->bsize;
276
- count += 1; /* started at 0 now move to first entry */
277
- for (i = 0; i < k->qsize; ++i) {
278
- b[count + i] = k->q[i];
279
- }
280
- count += k->qsize;
281
- /* semidefinite cones */
282
- for (i = 0; i < k->ssize; ++i) {
283
- s_cone_sz = get_sd_cone_size(k->s[i]);
284
- b[count + i] = s_cone_sz;
285
- }
286
- count += k->ssize; /* size here not ssize * (ssize + 1) / 2 */
287
- for (i = 0; i < k->cssize; ++i) {
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
- /* logdet cones */
304
- for (i = 0; i < k->dsize; ++i) {
305
- b[count + i] = get_sd_cone_size(k->d[i]) + 2;
306
- }
307
- count += k->dsize;
308
- /* nuclear norm cones */
309
- for (i = 0; i < k->nucsize; ++i) {
310
- b[count + i] = k->nuc_m[i] * k->nuc_n[i] + 1;
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
- /* other cones */
314
+
325
315
  c->cone_boundaries = b;
326
- c->cone_boundaries_len = 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, c = k->z + k->l + k->bsize;
331
- if (k->qsize) {
332
- for (i = 0; i < k->qsize; ++i) {
333
- c += k->q[i];
334
- }
335
- }
336
- if (k->ssize) {
337
- for (i = 0; i < k->ssize; ++i) {
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
- if (k->dsize) {
357
- for (i = 0; i < k->dsize; ++i) {
358
- c += get_sd_cone_size(k->d[i]) + 2;
359
- }
360
- }
361
- if (k->nucsize) {
362
- for (i = 0; i < k->nucsize; ++i) {
363
- c += k->nuc_m[i] * k->nuc_n[i] + 1;
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 c;
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("cone dimensions %li not equal to num rows in A = m = %li\n",
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
- if (c) {
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); /* sizeof(char) = 1 */
590
- scs_int i, soc_vars, sd_vars, csd_vars;
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
- if (k->bsize) {
600
- sprintf(tmp + strlen(tmp), "\t b: box cone vars: %li\n", (long)(k->bsize));
601
- }
602
- soc_vars = 0;
603
- if (k->qsize && k->q) {
604
- for (i = 0; i < k->qsize; i++) {
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)soc_vars, (long)k->qsize);
545
+ (long)count, (long)k->qsize);
609
546
  }
610
- sd_vars = 0;
611
- if (k->ssize && k->s) {
612
- for (i = 0; i < k->ssize; i++) {
613
- sd_vars += get_sd_cone_size(k->s[i]);
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)sd_vars, (long)k->ssize);
552
+ (long)count, (long)k->ssize);
617
553
  }
618
- csd_vars = 0;
619
- if (k->cssize && k->cs) {
620
- for (i = 0; i < k->cssize; i++) {
621
- csd_vars += get_csd_cone_size(k->cs[i]);
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)csd_vars, (long)k->cssize);
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 && k->p) {
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
- static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
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 neg_one = -1;
679
- blas_int info = 0;
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
- #if VERBOSITY > 0
682
- #define _STR_EXPAND(tok) #tok
683
- #define _STR(tok) _STR_EXPAND(tok)
684
- scs_printf("BLAS(func) = '%s'\n", _STR(BLAS(func)));
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
- // compute max dimension needed for eigenvalue decomposition workspace
689
- // (all cones appearing in the next section of code require eigenvalue
690
- // decompositions)
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
- if (k->s[i] > n_max) {
694
- n_max = (blas_int)k->s[i];
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
- for (i = 0; i < k->sl_size; ++i) {
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
- if (k->d[i] > n_max_logdet) {
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
- // allocate eigenvector decomposition workspace
746
- // -----------------------------------------------------------------
747
- c->Xs = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
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
- /* workspace query */
752
- BLAS(syev)("Vectors", "Lower", &n_max, c->Xs, &n_max, SCS_NULL, &wkopt,
753
- &neg_one, &info);
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
- if (info != 0) {
756
- scs_printf("FATAL: syev workspace query failure, info = %li\n", (long)info);
757
- return -1;
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
- c->lwork = (blas_int)(wkopt + 1); /* +1 for int casting safety */
761
- c->work = (scs_float *)scs_calloc(c->lwork, sizeof(scs_float));
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
- if (!c->Xs || !c->Z || !c->e || !c->work) {
764
- return -1;
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 m_max_nuc = 1;
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
- if (k->nuc_m[i] > m_max_nuc) {
776
- m_max_nuc = k->nuc_m[i];
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(n_max_nuc, sizeof(scs_float));
784
- c->u_nuc =
785
- (scs_float *)scs_calloc(m_max_nuc * n_max_nuc, sizeof(scs_float));
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
- c->lwork_nuc = (blas_int)(wkopt + 1); /* +1 for int casting safety */
799
- c->work_nuc = (scs_float *)scs_calloc(c->lwork_nuc, sizeof(scs_float));
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 (!c->lwork_nuc || !c->work_nuc) {
766
+ if (info != 0)
802
767
  return -1;
803
- }
804
768
 
805
- if (info != 0) {
806
- scs_printf("FATAL: gesvd workspace query failure, info = %li\n",
807
- (long)info);
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
- return 0;
814
- #else
815
- for (i = 0; i < k->ssize; i++) {
816
- if (k->s[i] > 1) {
817
- scs_printf(
818
- "FATAL: Cannot solve SDPs without linked blas+lapack libraries\n");
819
- scs_printf(
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
- #ifdef USE_SPECTRAL_CONES
826
- bool has_spectral_cones = false;
827
- for (i = 0; i < k->dsize; i++) {
828
- if (k->d[i] > 1) {
829
- has_spectral_cones = true;
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
- for (i = 0; i < k->nucsize; i++) {
835
- if (k->nuc_m[i] > 1 || k->nuc_n[i] > 1) {
836
- has_spectral_cones = true;
837
- break;
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
- for (i = 0; i < k->sl_size; i++) {
842
- if (k->sl_n[i] > 1) {
843
- has_spectral_cones = true;
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 (has_spectral_cones) {
849
- scs_printf("FATAL: Cannot use spectral cones without linked blas+lapack "
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
- /* size of X is get_sd_cone_size(n) */
862
- static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
863
- ScsConeWork *c) {
864
- /* project onto the positive semi-definite cone */
865
- #ifdef USE_LAPACK
866
- SCS(timer) _timer;
867
- scs_int i, first_idx;
868
- blas_int nb = (blas_int)n;
869
- blas_int ncols_z;
870
- blas_int nb_plus_one = (blas_int)(n + 1);
871
- blas_int one_int = 1;
872
- scs_float zero = 0., one = 1.;
873
- scs_float sqrt2 = SQRTF(2.0);
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
- if (n == 0) {
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
- /* copy lower triangular matrix into full matrix */
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
- SCS(tic)(&_timer);
864
+ /* Scale diagonals by sqrt(2) */
865
+ BLAS(scal)(&nb, &sqrt2, c->Xs, &nb_p1);
917
866
 
918
- first_idx = -1;
919
- /* e is eigvals in ascending order, find first entry > 0 */
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 = i;
923
- break;
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, &nb, &zero, Xs, &nb);
892
+ BLAS(syrk)("Lower", "NoTrans", &nb, &ncols_z, &one, &c->Z[first_idx * n], &nb,
893
+ &zero, c->Xs, &nb);
945
894
 
946
- /* undo rescaling: scale diags by 1/sqrt(2) */
947
- BLAS(scal)(&nb, &sqrt2_inv, Xs, &nb_plus_one); /* not n_squared */
895
+ /* Rescale diagonals by 1/sqrt(2) */
896
+ BLAS(scal)(&nb, &sqrt2_inv, c->Xs, &nb_p1);
948
897
 
949
- /* extract just lower triangular matrix */
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
- static scs_int set_up_csd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
965
- scs_int i;
966
- #ifdef USE_LAPACK
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
- /* project onto the positive semi-definite cone */
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
- /* copy lower triangular matrix into full matrix */
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
- first_idx = -1;
1102
- /* e is eigvals in ascending order, find first entry > 0 */
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 = i;
1106
- break;
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
- /* cZ is matrix of all eigenvectors */
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
- ("Lower", "NoTrans", &nb, &ncols_z, &one,
1129
- SCS_BLAS_COMPLEX_CAST(&cZ[first_idx * n]), &nb, &zero,
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
- /* undo rescaling: scale diags by 1/sqrt(2) */
1133
- BLASC(scal)
1134
- (&nb, SCS_BLAS_COMPLEX_CAST(&csqrt2_inv), SCS_BLAS_COMPLEX_CAST(cXs),
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
- /* extract just lower triangular matrix */
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
- * Routine to scale the limits of the box cone by the scaling diagonal mat D > 0
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
- if (k->bu[j] >= MAX_BOX_VAL) {
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
- } else {
1195
- k->bu[j] = D ? D[j + 1] * k->bu[j] / D[0] : 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
- } else {
1200
- k->bl[j] = D ? D[j + 1] * k->bl[j] / D[0] : 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 t_warm_start, scs_float *r_box) {
1211
- scs_float *x, gt, ht, t_prev, t = t_warm_start;
1212
- scs_float rho_t = 1, *rho = SCS_NULL, r;
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) { /* special case */
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
- /* should only require about 5 or so iterations, 1 or 2 if warm-started */
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]); /* gradient */
1230
- ht = rho_t; /* hessian */
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]; /* gradient */
1235
- ht += r * bu[j] * bu[j]; /* hessian */
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]; /* gradient */
1238
- ht += r * bl[j] * bl[j]; /* hessian */
1052
+ gt += r * (t * bl[j] - x[j]) * bl[j];
1053
+ ht += r * bl[j] * bl[j];
1239
1054
  }
1240
1055
  }
1241
- t = MAX(t - gt / MAX(ht, 1e-8), 0.); /* newton step */
1242
- #if VERBOSITY > 3
1243
- scs_printf("iter %i, t_new %1.3e, t_prev %1.3e, gt %1.3e, ht %1.3e\n", iter,
1244
- t, t_prev, gt, ht);
1245
- scs_printf("ABS(gt / (ht + 1e-6)) %.4e, ABS(t - t_prev) %.4e\n",
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
- } else if (x[j] < t * bl[j]) {
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
- /* project onto SOC of size q*/
1080
+ /*
1081
+ * Projection: Second Order Cone
1082
+ */
1277
1083
  static void proj_soc(scs_float *x, scs_int q) {
1278
- if (q == 0) {
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
- } else if (s <= -v1) {
1292
- memset(&(x[0]), 0, q * sizeof(scs_float));
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
- /* v in K_a */
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 = pow_calc_f(x, y, r, a);
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 = pow_calcdxdr(x, xh, rh, r, a);
1329
- dydr = pow_calcdxdr(y, yh, rh, r, (1 - a));
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) ? -(r) : (r);
1157
+ v[2] = (v[2] < 0) ? -r : r;
1338
1158
  }
1339
1159
 
1340
- /* project onto the primal K cone in the paper */
1341
- /* the r_y vector determines the INVERSE metric, ie, project under the
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
- if (k->z) { /* doesn't use r_y */
1354
- /* project onto primal zero / dual free cone */
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
- if (k->l) { /* doesn't use r_y */
1360
- /* project onto positive orthant */
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
- if (k->bsize) { /* DOES use r_y */
1368
- if (r_y) {
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; /* since b = (t,s), len(s) = bsize - 1 */
1191
+ count += k->bsize;
1375
1192
  }
1376
1193
 
1377
- if (k->qsize && k->q) { /* doesn't use r_y */
1378
- /* project onto second-order cones */
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
- if (k->ssize && k->s) { /* doesn't use r_y */
1386
- /* project onto PSD cones */
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
- if (k->cssize && k->cs) { /* doesn't use r_y */
1404
- /* project onto complex PSD cones */
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
- if (k->psize && k->p) { /* doesn't use r_y */
1238
+
1239
+ /* 8. Power Cone */
1240
+ if (k->psize) {
1425
1241
  scs_float v[3];
1426
1242
  scs_int idx;
1427
- /* don't use openmp for power cone
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
- /* primal power cone */
1252
+ /* Primal power cone */
1436
1253
  proj_power_cone(&(x[idx]), k->p[i]);
1437
1254
  } else {
1438
- /* dual power cone, using Moreau */
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
- scs_int offset_log_cone = 0; /* used for warmstarting log-cone projections */
1455
- /* project onto logdet cones */
1456
- if (k->dsize && k->d) {
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, offset_log_cone,
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
- offset_log_cone += k->d[i] + 2;
1464
- if (status < 0) {
1279
+ if (status < 0)
1465
1280
  return status;
1466
- }
1467
- count += (get_sd_cone_size(k->d[i]) + 2);
1281
+ offset_log += k->d[i] + 2;
1282
+ count += get_sd_cone_size(k->d[i]) + 2;
1468
1283
  }
1469
1284
  }
1470
- /* project onto nuclear norm cones */
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
- /* project onto ell1-norm cones */
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 += (k->ell1[i] + 1);
1299
+ count += k->ell1[i] + 1;
1488
1300
  }
1489
1301
  }
1490
- /* project onto sum-of-largest eigenvalues cone */
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
- #ifdef USE_SPECTRAL_CONES
1512
- static scs_int set_up_ell1_cone_work_space(ScsConeWork *c, const ScsCone *k) {
1513
- scs_int i;
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
- if ((k->ssize && k->s)
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 && k->d) || (k->nucsize && k->nuc_m && k->nuc_n) ||
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 (set_up_sd_cone_work_space(c, k) < 0) {
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, ScsScaling *scal,
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
- scale_box_cone(k, c, scal);
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
- /* copy s = x */
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
- /* project -x onto cone, x -> \Pi_{C^*}^{R^{-1}}(-x) under r_y metric */
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
- /* return x + R^{-1} \Pi_{C^*}^{R^{-1}} ( -x ) */
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
- } else {
1411
+ else
1618
1412
  x[i] += c->s[i];
1619
- }
1620
1413
  }
1621
1414
 
1622
1415
  return status;