scs 0.5.0 → 0.5.2

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