scs 0.5.2 → 0.5.4

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