scs 0.2.3 → 0.3.0

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +11 -6
  4. data/lib/scs/ffi.rb +30 -13
  5. data/lib/scs/solver.rb +32 -9
  6. data/lib/scs/version.rb +1 -1
  7. data/vendor/scs/CITATION.cff +39 -0
  8. data/vendor/scs/CMakeLists.txt +7 -8
  9. data/vendor/scs/Makefile +24 -15
  10. data/vendor/scs/README.md +5 -263
  11. data/vendor/scs/include/aa.h +67 -23
  12. data/vendor/scs/include/cones.h +17 -17
  13. data/vendor/scs/include/glbopts.h +98 -32
  14. data/vendor/scs/include/linalg.h +2 -4
  15. data/vendor/scs/include/linsys.h +58 -44
  16. data/vendor/scs/include/normalize.h +3 -3
  17. data/vendor/scs/include/rw.h +8 -2
  18. data/vendor/scs/include/scs.h +293 -133
  19. data/vendor/scs/include/util.h +3 -15
  20. data/vendor/scs/linsys/cpu/direct/private.c +220 -224
  21. data/vendor/scs/linsys/cpu/direct/private.h +13 -7
  22. data/vendor/scs/linsys/cpu/direct/private.o +0 -0
  23. data/vendor/scs/linsys/cpu/indirect/private.c +177 -110
  24. data/vendor/scs/linsys/cpu/indirect/private.h +8 -4
  25. data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
  26. data/vendor/scs/linsys/csparse.c +87 -0
  27. data/vendor/scs/linsys/csparse.h +34 -0
  28. data/vendor/scs/linsys/csparse.o +0 -0
  29. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +1 -1
  30. data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
  31. data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
  32. data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
  33. data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
  34. data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
  35. data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
  36. data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
  37. data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
  38. data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
  39. data/vendor/scs/linsys/external/amd/amd_internal.h +1 -1
  40. data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
  41. data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
  42. data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
  43. data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
  44. data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
  45. data/vendor/scs/linsys/external/qdldl/changes +2 -0
  46. data/vendor/scs/linsys/external/qdldl/qdldl.c +29 -46
  47. data/vendor/scs/linsys/external/qdldl/qdldl.h +33 -41
  48. data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
  49. data/vendor/scs/linsys/external/qdldl/qdldl_types.h +11 -3
  50. data/vendor/scs/linsys/gpu/gpu.c +31 -33
  51. data/vendor/scs/linsys/gpu/gpu.h +48 -31
  52. data/vendor/scs/linsys/gpu/indirect/private.c +338 -232
  53. data/vendor/scs/linsys/gpu/indirect/private.h +23 -14
  54. data/vendor/scs/linsys/scs_matrix.c +498 -0
  55. data/vendor/scs/linsys/scs_matrix.h +70 -0
  56. data/vendor/scs/linsys/scs_matrix.o +0 -0
  57. data/vendor/scs/scs.mk +13 -9
  58. data/vendor/scs/src/aa.c +384 -109
  59. data/vendor/scs/src/aa.o +0 -0
  60. data/vendor/scs/src/cones.c +440 -353
  61. data/vendor/scs/src/cones.o +0 -0
  62. data/vendor/scs/src/ctrlc.c +15 -5
  63. data/vendor/scs/src/ctrlc.o +0 -0
  64. data/vendor/scs/src/linalg.c +84 -28
  65. data/vendor/scs/src/linalg.o +0 -0
  66. data/vendor/scs/src/normalize.c +22 -64
  67. data/vendor/scs/src/normalize.o +0 -0
  68. data/vendor/scs/src/rw.c +160 -21
  69. data/vendor/scs/src/rw.o +0 -0
  70. data/vendor/scs/src/scs.c +767 -563
  71. data/vendor/scs/src/scs.o +0 -0
  72. data/vendor/scs/src/scs_indir.o +0 -0
  73. data/vendor/scs/src/scs_version.c +9 -3
  74. data/vendor/scs/src/scs_version.o +0 -0
  75. data/vendor/scs/src/util.c +37 -106
  76. data/vendor/scs/src/util.o +0 -0
  77. data/vendor/scs/test/minunit.h +17 -8
  78. data/vendor/scs/test/problem_utils.h +176 -14
  79. data/vendor/scs/test/problems/degenerate.h +130 -0
  80. data/vendor/scs/test/problems/hs21_tiny_qp.h +124 -0
  81. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +116 -0
  82. data/vendor/scs/test/problems/infeasible_tiny_qp.h +100 -0
  83. data/vendor/scs/test/problems/qafiro_tiny_qp.h +199 -0
  84. data/vendor/scs/test/problems/random_prob +0 -0
  85. data/vendor/scs/test/problems/random_prob.h +45 -0
  86. data/vendor/scs/test/problems/rob_gauss_cov_est.h +188 -31
  87. data/vendor/scs/test/problems/small_lp.h +13 -14
  88. data/vendor/scs/test/problems/test_fails.h +43 -0
  89. data/vendor/scs/test/problems/unbounded_tiny_qp.h +82 -0
  90. data/vendor/scs/test/random_socp_prob.c +54 -53
  91. data/vendor/scs/test/rng.h +109 -0
  92. data/vendor/scs/test/run_from_file.c +19 -10
  93. data/vendor/scs/test/run_tests.c +27 -3
  94. metadata +20 -8
  95. data/vendor/scs/linsys/amatrix.c +0 -305
  96. data/vendor/scs/linsys/amatrix.h +0 -36
  97. data/vendor/scs/linsys/amatrix.o +0 -0
  98. data/vendor/scs/test/data/small_random_socp +0 -0
  99. data/vendor/scs/test/problems/small_random_socp.h +0 -33
  100. data/vendor/scs/test/run_tests +0 -2
@@ -1,80 +1,116 @@
1
1
  #include "cones.h"
2
-
3
2
  #include "linalg.h"
4
3
  #include "scs.h"
5
4
  #include "scs_blas.h" /* contains BLAS(X) macros and type info */
6
5
  #include "util.h"
7
6
 
8
- #define CONE_RATE (2)
9
- #define CONE_TOL (1e-8)
10
- #define CONE_THRESH (1e-6)
7
+ #define CONE_TOL (1e-9)
8
+ #define CONE_THRESH (1e-8)
11
9
  #define EXP_CONE_MAX_ITERS (100)
10
+ #define BOX_CONE_MAX_ITERS (25)
12
11
  #define POW_CONE_MAX_ITERS (20)
13
12
 
13
+ /* In the box cone projection we penalize the `t` term additionally by this
14
+ * factor. This encourages the `t` term to stay close to the incoming `t` term,
15
+ * which should provide better convergence since typically the `t` term does
16
+ * not appear in the linear system other than `t = 1`. Setting to 1 is
17
+ * the vanilla projection.
18
+ */
19
+ #define BOX_T_SCALE (1.)
20
+
21
+ /* Box cone limits (+ or -) taken to be INF */
22
+ #define MAX_BOX_VAL (1e15)
23
+
14
24
  #ifdef USE_LAPACK
15
- void BLAS(syevr)(const char *jobz, const char *range, const char *uplo,
16
- blas_int *n, scs_float *a, blas_int *lda, scs_float *vl,
17
- scs_float *vu, blas_int *il, blas_int *iu, scs_float *abstol,
18
- blas_int *m, scs_float *w, scs_float *z, blas_int *ldz,
19
- blas_int *isuppz, scs_float *work, blas_int *lwork,
20
- blas_int *iwork, blas_int *liwork, blas_int *info);
21
- void BLAS(syr)(const char *uplo, const blas_int *n, const scs_float *alpha,
22
- const scs_float *x, const blas_int *incx, scs_float *a,
23
- const blas_int *lda);
25
+ void BLAS(syev)(const char *jobz, const char *uplo, blas_int *n, scs_float *a,
26
+ blas_int *lda, scs_float *w, scs_float *work, blas_int *lwork,
27
+ blas_int *info);
28
+ blas_int BLAS(syrk)(const char *uplo, const char *trans, const blas_int *n,
29
+ const blas_int *k, const scs_float *alpha,
30
+ const scs_float *a, const blas_int *lda,
31
+ const scs_float *beta, scs_float *c, const blas_int *ldc);
24
32
  void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
25
33
  const blas_int *incx);
26
- scs_float BLAS(nrm2)(const blas_int *n, scs_float *x, const blas_int *incx);
27
34
  #endif
28
35
 
29
- static scs_int get_sd_cone_size(scs_int s) { return (s * (s + 1)) / 2; }
36
+ /* set the vector of rho y terms, based on scale and cones */
37
+ void SCS(set_rho_y_vec)(const ScsCone *k, scs_float scale, scs_float *rho_y_vec,
38
+ scs_int m) {
39
+ scs_int i, count = 0;
40
+ /* f cone */
41
+ for (i = 0; i < k->z; ++i) {
42
+ /* set rho_y small for z, similar to rho_x term, since z corresponds to
43
+ * dual free cone, this effectively decreases penalty on those entries
44
+ * and lets them be determined almost entirely by the linear system solve
45
+ */
46
+ rho_y_vec[i] = 1.0 / (1000. * scale);
47
+ }
48
+ count += k->z;
49
+ /* others */
50
+ for (i = count; i < m; ++i) {
51
+ rho_y_vec[i] = 1.0 / scale;
52
+ }
53
+
54
+ /* Note, if updating this to use different scales for other cones (e.g. box)
55
+ * then you must be careful to also include the effect of the rho_y_vec
56
+ * in the cone projection operator.
57
+ */
58
+
59
+ /* Increase rho_y_vec for the t term in the box cone */
60
+ if (k->bsize) {
61
+ rho_y_vec[k->z + k->l] *= BOX_T_SCALE;
62
+ }
63
+ }
64
+
65
+ static inline scs_int get_sd_cone_size(scs_int s) {
66
+ return (s * (s + 1)) / 2;
67
+ }
30
68
 
31
69
  /*
32
70
  * boundaries will contain array of indices of rows of A corresponding to
33
71
  * cone boundaries, boundaries[0] is starting index for cones of size strictly
34
- * larger than 1
35
- * returns length of boundaries array, boundaries malloc-ed here so should be
36
- * freed
72
+ * larger than 1, boundaries malloc-ed here so should be freed.
37
73
  */
38
- scs_int SCS(get_cone_boundaries)(const ScsCone *k, scs_int **boundaries) {
39
- scs_int i, count = 0;
40
- scs_int len = 1 + k->qsize + k->ssize + k->ed + k->ep + k->psize;
41
- scs_int *b = (scs_int *)scs_calloc(len, sizeof(scs_int));
42
- b[count] = k->f + k->l;
43
- count += 1;
44
- if (k->qsize > 0) {
45
- memcpy(&b[count], k->q, k->qsize * sizeof(scs_int));
74
+ scs_int SCS(set_cone_boundaries)(const ScsCone *k, scs_int **cone_boundaries) {
75
+ scs_int i, s_cone_sz, count = 0;
76
+ scs_int cone_boundaries_len =
77
+ 1 + k->qsize + k->ssize + k->ed + k->ep + k->psize;
78
+ scs_int *b = (scs_int *)scs_calloc(cone_boundaries_len, sizeof(scs_int));
79
+ /* cones that can be scaled independently */
80
+ b[count] = k->z + k->l + k->bsize;
81
+ count += 1; /* started at 0 now move to first entry */
82
+ for (i = 0; i < k->qsize; ++i) {
83
+ b[count + i] = k->q[i];
46
84
  }
47
85
  count += k->qsize;
48
86
  for (i = 0; i < k->ssize; ++i) {
49
- b[count + i] = get_sd_cone_size(k->s[i]);
87
+ s_cone_sz = get_sd_cone_size(k->s[i]);
88
+ b[count + i] = s_cone_sz;
50
89
  }
51
- count += k->ssize;
90
+ count += k->ssize; /* add ssize here not ssize * (ssize + 1) / 2 */
91
+ /* exp cones */
52
92
  for (i = 0; i < k->ep + k->ed; ++i) {
53
93
  b[count + i] = 3;
54
94
  }
55
95
  count += k->ep + k->ed;
96
+ /* power cones */
56
97
  for (i = 0; i < k->psize; ++i) {
57
98
  b[count + i] = 3;
58
99
  }
59
100
  count += k->psize;
60
- *boundaries = b;
61
- return len;
101
+ /* other cones */
102
+ *cone_boundaries = b;
103
+ return cone_boundaries_len;
62
104
  }
63
105
 
64
106
  static scs_int get_full_cone_dims(const ScsCone *k) {
65
- scs_int i, c = 0;
66
- if (k->f) {
67
- c += k->f;
68
- }
69
- if (k->l) {
70
- c += k->l;
71
- }
72
- if (k->qsize && k->q) {
107
+ scs_int i, c = k->z + k->l + k->bsize;
108
+ if (k->qsize) {
73
109
  for (i = 0; i < k->qsize; ++i) {
74
110
  c += k->q[i];
75
111
  }
76
112
  }
77
- if (k->ssize && k->s) {
113
+ if (k->ssize) {
78
114
  for (i = 0; i < k->ssize; ++i) {
79
115
  c += get_sd_cone_size(k->s[i]);
80
116
  }
@@ -98,49 +134,61 @@ scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
98
134
  (long)get_full_cone_dims(k), (long)d->m);
99
135
  return -1;
100
136
  }
101
- if (k->f && k->f < 0) {
102
- scs_printf("free cone error\n");
137
+ if (k->z && k->z < 0) {
138
+ scs_printf("free cone dimension error\n");
103
139
  return -1;
104
140
  }
105
141
  if (k->l && k->l < 0) {
106
- scs_printf("lp cone error\n");
142
+ scs_printf("lp cone dimension error\n");
107
143
  return -1;
108
144
  }
145
+ if (k->bsize) {
146
+ if (k->bsize < 0) {
147
+ scs_printf("box cone dimension error\n");
148
+ return -1;
149
+ }
150
+ for (i = 0; i < k->bsize - 1; ++i) {
151
+ if (k->bl[i] > k->bu[i]) {
152
+ scs_printf("infeasible: box lower bound larger than upper bound\n");
153
+ return -1;
154
+ }
155
+ }
156
+ }
109
157
  if (k->qsize && k->q) {
110
158
  if (k->qsize < 0) {
111
- scs_printf("soc cone error\n");
159
+ scs_printf("soc cone dimension error\n");
112
160
  return -1;
113
161
  }
114
162
  for (i = 0; i < k->qsize; ++i) {
115
163
  if (k->q[i] < 0) {
116
- scs_printf("soc cone error\n");
164
+ scs_printf("soc cone dimension error\n");
117
165
  return -1;
118
166
  }
119
167
  }
120
168
  }
121
169
  if (k->ssize && k->s) {
122
170
  if (k->ssize < 0) {
123
- scs_printf("sd cone error\n");
171
+ scs_printf("sd cone dimension error\n");
124
172
  return -1;
125
173
  }
126
174
  for (i = 0; i < k->ssize; ++i) {
127
175
  if (k->s[i] < 0) {
128
- scs_printf("sd cone error\n");
176
+ scs_printf("sd cone dimension error\n");
129
177
  return -1;
130
178
  }
131
179
  }
132
180
  }
133
181
  if (k->ed && k->ed < 0) {
134
- scs_printf("ep cone error\n");
182
+ scs_printf("ep cone dimension error\n");
135
183
  return -1;
136
184
  }
137
185
  if (k->ep && k->ep < 0) {
138
- scs_printf("ed cone error\n");
186
+ scs_printf("ed cone dimension error\n");
139
187
  return -1;
140
188
  }
141
189
  if (k->psize && k->p) {
142
190
  if (k->psize < 0) {
143
- scs_printf("power cone error\n");
191
+ scs_printf("power cone dimension error\n");
144
192
  return -1;
145
193
  }
146
194
  for (i = 0; i < k->psize; ++i) {
@@ -153,14 +201,6 @@ scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
153
201
  return 0;
154
202
  }
155
203
 
156
- char *SCS(get_cone_summary)(const ScsInfo *info, ScsConeWork *c) {
157
- char *str = (char *)scs_malloc(sizeof(char) * 64);
158
- sprintf(str, "\tCones: avg projection time: %1.2es\n",
159
- c->total_cone_time / (info->iter + 1) / 1e3);
160
- c->total_cone_time = 0.0;
161
- return str;
162
- }
163
-
164
204
  void SCS(finish_cone)(ScsConeWork *c) {
165
205
  #ifdef USE_LAPACK
166
206
  if (c->Xs) {
@@ -175,10 +215,16 @@ void SCS(finish_cone)(ScsConeWork *c) {
175
215
  if (c->work) {
176
216
  scs_free(c->work);
177
217
  }
178
- if (c->iwork) {
179
- scs_free(c->iwork);
180
- }
181
218
  #endif
219
+ if (c->s) {
220
+ scs_free(c->s);
221
+ }
222
+ if (c->bu) {
223
+ scs_free(c->bu);
224
+ }
225
+ if (c->bl) {
226
+ scs_free(c->bl);
227
+ }
182
228
  if (c) {
183
229
  scs_free(c);
184
230
  }
@@ -186,98 +232,99 @@ void SCS(finish_cone)(ScsConeWork *c) {
186
232
 
187
233
  char *SCS(get_cone_header)(const ScsCone *k) {
188
234
  char *tmp = (char *)scs_malloc(sizeof(char) * 512);
189
- scs_int i, soc_vars, soc_blks, sd_vars, sd_blks;
190
- sprintf(tmp, "Cones:");
191
- if (k->f) {
192
- sprintf(tmp + strlen(tmp), "\tprimal zero / dual free vars: %li\n",
193
- (long)k->f);
235
+ scs_int i, soc_vars, sd_vars;
236
+ sprintf(tmp, "cones: ");
237
+ if (k->z) {
238
+ sprintf(tmp + strlen(tmp), "\t z: primal zero / dual free vars: %li\n",
239
+ (long)k->z);
194
240
  }
195
241
  if (k->l) {
196
- sprintf(tmp + strlen(tmp), "\tlinear vars: %li\n", (long)k->l);
242
+ sprintf(tmp + strlen(tmp), "\t l: linear vars: %li\n", (long)k->l);
243
+ }
244
+ if (k->bsize) {
245
+ sprintf(tmp + strlen(tmp), "\t b: box cone vars: %li\n", (long)(k->bsize));
197
246
  }
198
247
  soc_vars = 0;
199
- soc_blks = 0;
200
248
  if (k->qsize && k->q) {
201
- soc_blks = k->qsize;
202
249
  for (i = 0; i < k->qsize; i++) {
203
250
  soc_vars += k->q[i];
204
251
  }
205
- sprintf(tmp + strlen(tmp), "\tsoc vars: %li, soc blks: %li\n",
206
- (long)soc_vars, (long)soc_blks);
252
+ sprintf(tmp + strlen(tmp), "\t q: soc vars: %li, qsize: %li\n",
253
+ (long)soc_vars, (long)k->qsize);
207
254
  }
208
255
  sd_vars = 0;
209
- sd_blks = 0;
210
256
  if (k->ssize && k->s) {
211
- sd_blks = k->ssize;
212
257
  for (i = 0; i < k->ssize; i++) {
213
258
  sd_vars += get_sd_cone_size(k->s[i]);
214
259
  }
215
- sprintf(tmp + strlen(tmp), "\tsd vars: %li, sd blks: %li\n", (long)sd_vars,
216
- (long)sd_blks);
260
+ sprintf(tmp + strlen(tmp), "\t s: psd vars: %li, ssize: %li\n",
261
+ (long)sd_vars, (long)k->ssize);
217
262
  }
218
263
  if (k->ep || k->ed) {
219
- sprintf(tmp + strlen(tmp), "\texp vars: %li, dual exp vars: %li\n",
264
+ sprintf(tmp + strlen(tmp), "\t e: exp vars: %li, dual exp vars: %li\n",
220
265
  (long)(3 * k->ep), (long)(3 * k->ed));
221
266
  }
222
267
  if (k->psize && k->p) {
223
- sprintf(tmp + strlen(tmp), "\tprimal + dual power vars: %li\n",
268
+ sprintf(tmp + strlen(tmp), "\t p: primal + dual power vars: %li\n",
224
269
  (long)(3 * k->psize));
225
270
  }
226
271
  return tmp;
227
272
  }
228
273
 
229
- static scs_int is_simple_semi_definite_cone(scs_int *s, scs_int ssize) {
230
- scs_int i;
231
- for (i = 0; i < ssize; i++) {
232
- if (s[i] > 2) {
233
- return 0; /* false */
234
- }
235
- }
236
- return 1; /* true */
237
- }
238
-
239
274
  static scs_float exp_newton_one_d(scs_float rho, scs_float y_hat,
240
- scs_float z_hat) {
241
- scs_float t = MAX(-z_hat, 1e-6);
242
- scs_float f, fp;
275
+ scs_float z_hat, scs_float w) {
276
+ scs_float t_prev, t = MAX(w - z_hat, MAX(-z_hat, 1e-9));
277
+ scs_float f = 1., fp = 1.;
243
278
  scs_int i;
244
279
  for (i = 0; i < EXP_CONE_MAX_ITERS; ++i) {
280
+ t_prev = t;
245
281
  f = t * (t + z_hat) / rho / rho - y_hat / rho + log(t / rho) + 1;
246
282
  fp = (2 * t + z_hat) / rho / rho + 1 / t;
247
283
 
248
284
  t = t - f / fp;
249
285
 
250
286
  if (t <= -z_hat) {
251
- return 0;
287
+ t = -z_hat;
288
+ break;
252
289
  } else if (t <= 0) {
253
- return z_hat;
254
- } else if (ABS(f) < CONE_TOL) {
290
+ t = 0;
291
+ break;
292
+ } else if (ABS(t - t_prev) < CONE_TOL) {
293
+ break;
294
+ } else if (SQRTF(f * f / fp) < CONE_TOL) {
255
295
  break;
256
296
  }
257
297
  }
298
+ if (i == EXP_CONE_MAX_ITERS) {
299
+ scs_printf("warning: exp cone newton step hit maximum %i iters\n", (int)i);
300
+ scs_printf("rho=%1.5e; y_hat=%1.5e; z_hat=%1.5e; w=%1.5e; f=%1.5e, "
301
+ "fp=%1.5e, t=%1.5e, t_prev= %1.5e\n",
302
+ rho, y_hat, z_hat, w, f, fp, t, t_prev);
303
+ }
258
304
  return t + z_hat;
259
305
  }
260
306
 
261
- static void exp_solve_for_x_with_rho(scs_float *v, scs_float *x,
262
- scs_float rho) {
263
- x[2] = exp_newton_one_d(rho, v[1], v[2]);
307
+ static void exp_solve_for_x_with_rho(const scs_float *v, scs_float *x,
308
+ scs_float rho, scs_float w) {
309
+ x[2] = exp_newton_one_d(rho, v[1], v[2], w);
264
310
  x[1] = (x[2] - v[2]) * x[2] / rho;
265
311
  x[0] = v[0] - rho;
266
312
  }
267
313
 
268
- static scs_float exp_calc_grad(scs_float *v, scs_float *x, scs_float rho) {
269
- exp_solve_for_x_with_rho(v, x, rho);
314
+ static scs_float exp_calc_grad(const scs_float *v, scs_float *x, scs_float rho,
315
+ scs_float w) {
316
+ exp_solve_for_x_with_rho(v, x, rho, w);
270
317
  if (x[1] <= 1e-12) {
271
318
  return x[0];
272
319
  }
273
320
  return x[0] + x[1] * log(x[1] / x[2]);
274
321
  }
275
322
 
276
- static void exp_get_rho_ub(scs_float *v, scs_float *x, scs_float *ub,
323
+ static void exp_get_rho_ub(const scs_float *v, scs_float *x, scs_float *ub,
277
324
  scs_float *lb) {
278
325
  *lb = 0;
279
326
  *ub = 0.125;
280
- while (exp_calc_grad(v, x, *ub) > 0) {
327
+ while (exp_calc_grad(v, x, *ub, v[1]) > 0) {
281
328
  *lb = *ub;
282
329
  (*ub) *= 2;
283
330
  }
@@ -288,8 +335,6 @@ static scs_int proj_exp_cone(scs_float *v) {
288
335
  scs_int i;
289
336
  scs_float ub, lb, rho, g, x[3];
290
337
  scs_float r = v[0], s = v[1], t = v[2];
291
- scs_float tol = CONE_TOL; /* iter < 0 ? CONE_TOL : MAX(CONE_TOL, 1 /
292
- POWF((iter + 1), CONE_RATE)); */
293
338
 
294
339
  /* v in cl(Kexp) */
295
340
  if ((s * exp(r / s) - t <= CONE_THRESH && s > 0) ||
@@ -298,8 +343,8 @@ static scs_int proj_exp_cone(scs_float *v) {
298
343
  }
299
344
 
300
345
  /* -v in Kexp^* */
301
- if ((-r < 0 && r * exp(s / r) + exp(1) * t <= CONE_THRESH) ||
302
- (-r == 0 && -s >= 0 && -t >= 0)) {
346
+ if ((r > 0 && r * exp(s / r) + exp(1) * t <= CONE_THRESH) ||
347
+ (r == 0 && s <= 0 && t <= 0)) {
303
348
  memset(v, 0, 3 * sizeof(scs_float));
304
349
  return 0;
305
350
  }
@@ -314,22 +359,24 @@ static scs_int proj_exp_cone(scs_float *v) {
314
359
  /* iterative procedure to find projection, bisects on dual variable: */
315
360
  exp_get_rho_ub(v, x, &ub, &lb); /* get starting upper and lower bounds */
316
361
  for (i = 0; i < EXP_CONE_MAX_ITERS; ++i) {
317
- rho = (ub + lb) / 2; /* halfway between upper and lower bounds */
318
- g = exp_calc_grad(v, x, rho); /* calculates gradient wrt dual var */
362
+ rho = (ub + lb) / 2; /* halfway between upper and lower bounds */
363
+ g = exp_calc_grad(v, x, rho, x[1]); /* calculates gradient wrt dual var */
319
364
  if (g > 0) {
320
365
  lb = rho;
321
366
  } else {
322
367
  ub = rho;
323
368
  }
324
- if (ub - lb < tol) {
369
+ if (ub - lb < CONE_TOL) {
325
370
  break;
326
371
  }
327
372
  }
328
- /*
329
- #if EXTRA_VERBOSE > 0
330
- scs_printf("exponential cone proj iters %i\n", i);
373
+ #if VERBOSITY > 10
374
+ scs_printf("exponential cone proj iters %i\n", (int)i);
331
375
  #endif
332
- */
376
+ if (i == EXP_CONE_MAX_ITERS) {
377
+ scs_printf("warning: exp cone outer step hit maximum %i iters\n", (int)i);
378
+ scs_printf("r=%1.5e; s=%1.5e; t=%1.5e\n", r, s, t);
379
+ }
333
380
  v[0] = x[0];
334
381
  v[1] = x[1];
335
382
  v[2] = x[2];
@@ -337,15 +384,13 @@ static scs_int proj_exp_cone(scs_float *v) {
337
384
  }
338
385
 
339
386
  static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
340
- #ifdef USE_LAPACK
341
387
  scs_int i;
388
+ #ifdef USE_LAPACK
342
389
  blas_int n_max = 0;
343
- scs_float eig_tol = 1e-8;
344
390
  blas_int neg_one = -1;
345
- blas_int m = 0;
346
391
  blas_int info = 0;
347
392
  scs_float wkopt = 0.0;
348
- #if EXTRA_VERBOSE > 0
393
+ #if VERBOSITY > 0
349
394
  #define _STR_EXPAND(tok) #tok
350
395
  #define _STR(tok) _STR_EXPAND(tok)
351
396
  scs_printf("BLAS(func) = '%s'\n", _STR(BLAS(func)));
@@ -359,102 +404,36 @@ static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
359
404
  c->Xs = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
360
405
  c->Z = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
361
406
  c->e = (scs_float *)scs_calloc(n_max, sizeof(scs_float));
362
- c->liwork = 0;
363
407
 
364
- BLAS(syevr)
365
- ("Vectors", "All", "Lower", &n_max, c->Xs, &n_max, SCS_NULL, SCS_NULL,
366
- SCS_NULL, SCS_NULL, &eig_tol, &m, c->e, c->Z, &n_max, SCS_NULL, &wkopt,
367
- &neg_one, &(c->liwork), &neg_one, &info);
408
+ /* workspace query */
409
+ BLAS(syev)
410
+ ("Vectors", "Lower", &n_max, c->Xs, &n_max, SCS_NULL, &wkopt, &neg_one,
411
+ &info);
368
412
 
369
413
  if (info != 0) {
370
- scs_printf("FATAL: syevr failure, info = %li\n", (long)info);
414
+ scs_printf("FATAL: syev failure, info = %li\n", (long)info);
371
415
  return -1;
372
416
  }
373
- c->lwork = (blas_int)(wkopt + 0.01); /* 0.01 for int casting safety */
417
+ c->lwork = (blas_int)(wkopt + 1); /* +1 for int casting safety */
374
418
  c->work = (scs_float *)scs_calloc(c->lwork, sizeof(scs_float));
375
- c->iwork = (blas_int *)scs_calloc(c->liwork, sizeof(blas_int));
376
419
 
377
- if (!c->Xs || !c->Z || !c->e || !c->work || !c->iwork) {
420
+ if (!c->Xs || !c->Z || !c->e || !c->work) {
378
421
  return -1;
379
422
  }
380
423
  return 0;
381
424
  #else
382
- scs_printf(
383
- "FATAL: Cannot solve SDPs with > 2x2 matrices without linked "
384
- "blas+lapack libraries\n");
385
- scs_printf(
386
- "Install blas+lapack and re-compile SCS with blas+lapack library "
387
- "locations\n");
388
- return -1;
389
- #endif
390
- }
391
-
392
- ScsConeWork *SCS(init_cone)(const ScsCone *k) {
393
- ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
394
- #if EXTRA_VERBOSE > 0
395
- scs_printf("init_cone\n");
396
- #endif
397
- c->total_cone_time = 0.0;
398
- if (k->ssize && k->s) {
399
- if (!is_simple_semi_definite_cone(k->s, k->ssize) &&
400
- set_up_sd_cone_work_space(c, k) < 0) {
401
- SCS(finish_cone)(c);
402
- return SCS_NULL;
425
+ for (i = 0; i < k->ssize; i++) {
426
+ if (k->s[i] > 1) {
427
+ scs_printf(
428
+ "FATAL: Cannot solve SDPs without linked blas+lapack libraries\n");
429
+ scs_printf(
430
+ "Install blas+lapack and re-compile SCS with blas+lapack library "
431
+ "locations\n");
432
+ return -1;
403
433
  }
404
434
  }
405
- #if EXTRA_VERBOSE > 0
406
- scs_printf("init_cone complete\n");
407
- #ifdef MATLAB_MEX_FILE
408
- mexEvalString("drawnow;");
409
- #endif
410
- #endif
411
- return c;
412
- }
413
-
414
- static scs_int project_2x2_sdc(scs_float *X) {
415
- scs_float a, b, d, l1, l2, x1, x2, rad;
416
- scs_float sqrt2 = SQRTF(2.0);
417
- a = X[0];
418
- b = X[1] / sqrt2;
419
- d = X[2];
420
-
421
- if (ABS(b) < 1e-6) { /* diagonal matrix */
422
- X[0] = MAX(a, 0);
423
- X[1] = 0;
424
- X[2] = MAX(d, 0);
425
- return 0;
426
- }
427
-
428
- rad = SQRTF((a - d) * (a - d) + 4 * b * b);
429
- /* l1 >= l2 always, since rad >= 0 */
430
- l1 = 0.5 * (a + d + rad);
431
- l2 = 0.5 * (a + d - rad);
432
-
433
- #if EXTRA_VERBOSE > 0
434
- scs_printf(
435
- "2x2 SD: a = %4f, b = %4f, (X[1] = %4f, X[2] = %4f), d = %4f, "
436
- "rad = %4f, l1 = %4f, l2 = %4f\n",
437
- a, b, X[1], X[2], d, rad, l1, l2);
438
- #endif
439
-
440
- if (l2 >= 0) { /* both eigs positive already */
441
- return 0;
442
- }
443
- if (l1 <= 0) { /* both eigs negative, set to 0 */
444
- X[0] = 0;
445
- X[1] = 0;
446
- X[2] = 0;
447
- return 0;
448
- }
449
-
450
- /* l1 pos, l2 neg */
451
- x1 = 1 / SQRTF(1 + (l1 - a) * (l1 - a) / b / b);
452
- x2 = x1 * (l1 - a) / b;
453
-
454
- X[0] = l1 * x1 * x1;
455
- X[1] = (l1 * x1 * x2) * sqrt2;
456
- X[2] = l1 * x2 * x2;
457
435
  return 0;
436
+ #endif
458
437
  }
459
438
 
460
439
  /* size of X is get_sd_cone_size(n) */
@@ -462,45 +441,35 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
462
441
  ScsConeWork *c) {
463
442
  /* project onto the positive semi-definite cone */
464
443
  #ifdef USE_LAPACK
465
- scs_int i;
466
- blas_int one = 1;
467
- blas_int m = 0;
444
+ scs_int i, first_idx;
468
445
  blas_int nb = (blas_int)n;
446
+ blas_int ncols_z;
469
447
  blas_int nb_plus_one = (blas_int)(n + 1);
470
- blas_int cone_sz = (blas_int)(get_sd_cone_size(n));
471
-
448
+ blas_int one_int = 1;
449
+ scs_float zero = 0., one = 1.;
472
450
  scs_float sqrt2 = SQRTF(2.0);
473
- scs_float sqrt2Inv = 1.0 / sqrt2;
451
+ scs_float sqrt2_inv = 1.0 / sqrt2;
474
452
  scs_float *Xs = c->Xs;
475
453
  scs_float *Z = c->Z;
476
454
  scs_float *e = c->e;
477
455
  scs_float *work = c->work;
478
- blas_int *iwork = c->iwork;
479
456
  blas_int lwork = c->lwork;
480
- blas_int liwork = c->liwork;
481
-
482
- scs_float eig_tol = CONE_TOL; /* iter < 0 ? CONE_TOL : MAX(CONE_TOL, 1 /
483
- POWF(iter + 1, CONE_RATE)); */
484
- scs_float zero = 0.0;
485
457
  blas_int info = 0;
486
- scs_float vupper = 0.0;
458
+ scs_float sq_eig_pos;
459
+
487
460
  #endif
461
+
488
462
  if (n == 0) {
489
463
  return 0;
490
464
  }
491
465
  if (n == 1) {
492
- if (X[0] < 0.0) {
493
- X[0] = 0.0;
494
- }
466
+ X[0] = MAX(X[0], 0.);
495
467
  return 0;
496
468
  }
497
- if (n == 2) {
498
- return project_2x2_sdc(X);
499
- }
469
+
500
470
  #ifdef USE_LAPACK
501
471
 
502
- memset(Xs, 0, n * n * sizeof(scs_float));
503
- /* expand lower triangular matrix to full matrix */
472
+ /* copy lower triangular matrix into full matrix */
504
473
  for (i = 0; i < n; ++i) {
505
474
  memcpy(&(Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
506
475
  (n - i) * sizeof(scs_float));
@@ -512,64 +481,59 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
512
481
  /* scale diags by sqrt(2) */
513
482
  BLAS(scal)(&nb, &sqrt2, Xs, &nb_plus_one); /* not n_squared */
514
483
 
515
- /* max-eig upper bounded by frobenius norm */
516
- vupper = 1.1 * sqrt2 *
517
- BLAS(nrm2)(&cone_sz, X,
518
- &one); /* mult by factor to make sure is upper bound */
519
- vupper = MAX(vupper, 0.01);
520
- #if EXTRA_VERBOSE > 0
521
- SCS(print_array)(Xs, n * n, "Xs");
522
- SCS(print_array)(X, get_sd_cone_size(n), "X");
523
- #endif
524
484
  /* Solve eigenproblem, reuse workspaces */
525
- BLAS(syevr)
526
- ("Vectors", "VInterval", "Lower", &nb, Xs, &nb, &zero, &vupper, SCS_NULL,
527
- SCS_NULL, &eig_tol, &m, e, Z, &nb, SCS_NULL, work, &lwork, iwork, &liwork,
528
- &info);
529
- #if EXTRA_VERBOSE > 0
485
+ BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
530
486
  if (info != 0) {
531
- scs_printf("WARN: LAPACK syevr error, info = %i\n", info);
532
- }
533
- scs_printf("syevr input parameter dump:\n");
534
- scs_printf("nb = %li\n", (long)nb);
535
- scs_printf("lwork = %li\n", (long)lwork);
536
- scs_printf("liwork = %li\n", (long)liwork);
537
- scs_printf("vupper = %f\n", vupper);
538
- scs_printf("eig_tol = %e\n", eig_tol);
539
- SCS(print_array)(e, m, "e");
540
- SCS(print_array)(Z, m * n, "Z");
541
- #endif
542
- if (info < 0) {
543
- return -1;
487
+ scs_printf("WARN: LAPACK syev error, info = %i\n", info);
488
+ if (info < 0) {
489
+ return info;
490
+ }
544
491
  }
545
492
 
546
- memset(Xs, 0, n * n * sizeof(scs_float));
547
- for (i = 0; i < m; ++i) {
548
- scs_float a = e[i];
549
- BLAS(syr)("Lower", &nb, &a, &(Z[i * n]), &one, Xs, &nb);
493
+ first_idx = -1;
494
+ /* e is eigvals in ascending order, find first entry > 0 */
495
+ for (i = 0; i < n; ++i) {
496
+ if (e[i] > 0) {
497
+ first_idx = i;
498
+ break;
499
+ }
550
500
  }
551
- /* scale diags by 1/sqrt(2) */
552
- BLAS(scal)(&nb, &sqrt2Inv, Xs, &nb_plus_one); /* not n_squared */
501
+
502
+ if (first_idx == -1) {
503
+ /* there are no positive eigenvalues, set X to 0 and return */
504
+ memset(X, 0, sizeof(scs_float) * get_sd_cone_size(n));
505
+ return 0;
506
+ }
507
+
508
+ /* Z is matrix of eigenvectors with positive eigenvalues */
509
+ memcpy(Z, &Xs[first_idx * n], sizeof(scs_float) * n * (n - first_idx));
510
+
511
+ /* scale Z by sqrt(eig) */
512
+ for (i = first_idx; i < n; ++i) {
513
+ sq_eig_pos = SQRTF(e[i]);
514
+ BLAS(scal)(&nb, &sq_eig_pos, &Z[(i - first_idx) * n], &one_int);
515
+ }
516
+
517
+ /* Xs = Z Z' = V E V' */
518
+ ncols_z = (blas_int)(n - first_idx);
519
+ BLAS(syrk)("Lower", "NoTrans", &nb, &ncols_z, &one, Z, &nb, &zero, Xs, &nb);
520
+
521
+ /* undo rescaling: scale diags by 1/sqrt(2) */
522
+ BLAS(scal)(&nb, &sqrt2_inv, Xs, &nb_plus_one); /* not n_squared */
523
+
553
524
  /* extract just lower triangular matrix */
554
525
  for (i = 0; i < n; ++i) {
555
526
  memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(Xs[i * (n + 1)]),
556
527
  (n - i) * sizeof(scs_float));
557
528
  }
558
-
559
- #if EXTRA_VERBOSE > 0
560
- SCS(print_array)(Xs, n * n, "Xs");
561
- SCS(print_array)(X, get_sd_cone_size(n), "X");
562
- #endif
529
+ return 0;
563
530
 
564
531
  #else
565
- scs_printf(
566
- "FAILURE: solving SDP with > 2x2 matrices, but no blas/lapack "
567
- "libraries were linked!\n");
532
+ scs_printf("FAILURE: solving SDP but no blas/lapack libraries were found!\n");
568
533
  scs_printf("SCS will return nonsense!\n");
569
534
  SCS(scale_array)(X, NAN, n);
570
535
  return -1;
571
536
  #endif
572
- return 0;
573
537
  }
574
538
 
575
539
  static scs_float pow_calc_x(scs_float r, scs_float xh, scs_float rh,
@@ -594,6 +558,124 @@ static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
594
558
  1;
595
559
  }
596
560
 
561
+ /*
562
+ * Routine to scale the limits of the box cone by the scaling diagonal mat D > 0
563
+ *
564
+ * want (t, s) \in K <==> (t', s') \in K'
565
+ *
566
+ * (t', s') = (d0 * t, D s) (overloading D to mean D[1:])
567
+ * (up to scalar scaling factor which we can ignore due to conic prooperty)
568
+ *
569
+ * K = { (t, s) | t * l <= s <= t * u, t >= 0 } =>
570
+ * { (t, s) | d0 * t * D l / d0 <= D s <= d0 * t D u / d0, t >= 0 } =>
571
+ * { (t', s') | t' * l' <= s' <= t' u', t >= 0 } = K'
572
+ * where l' = D l / d0, u' = D u / d0.
573
+ */
574
+ static void normalize_box_cone(ScsConeWork *c, scs_float *D, scs_int bsize) {
575
+ scs_int j;
576
+ for (j = 0; j < bsize - 1; j++) {
577
+ if (c->bu[j] >= MAX_BOX_VAL) {
578
+ c->bu[j] = INFINITY;
579
+ } else {
580
+ c->bu[j] = D ? D[j + 1] * c->bu[j] / D[0] : c->bu[j];
581
+ }
582
+ if (c->bl[j] <= -MAX_BOX_VAL) {
583
+ c->bl[j] = -INFINITY;
584
+ } else {
585
+ c->bl[j] = D ? D[j + 1] * c->bl[j] / D[0] : c->bl[j];
586
+ }
587
+ }
588
+ }
589
+
590
+ /* project onto { (t, s) | t * l <= s <= t * u, t >= 0 }, Newton's method on t
591
+ tx = [t; s], total length = bsize
592
+ uses Moreau since \Pi_K*(tx) = \Pi_K(-tx) + tx
593
+ */
594
+ static scs_float proj_box_cone(scs_float *tx, const scs_float *bl,
595
+ const scs_float *bu, scs_int bsize,
596
+ scs_float t_warm_start) {
597
+ scs_float *x, gt, ht, t_prev, t = t_warm_start;
598
+ scs_int iter, j;
599
+
600
+ if (bsize == 1) { /* special case */
601
+ tx[0] = MAX(tx[0], 0.0);
602
+ return tx[0];
603
+ }
604
+
605
+ x = &(tx[1]);
606
+
607
+ /* should only require about 5 or so iterations, 1 or 2 if warm-started */
608
+ for (iter = 0; iter < BOX_CONE_MAX_ITERS; iter++) {
609
+ t_prev = t;
610
+ /* incorporate the additional BOX_T_SCALE factor into the projection */
611
+ gt = BOX_T_SCALE * (t - tx[0]); /* gradient */
612
+ ht = BOX_T_SCALE; /* hessian */
613
+ for (j = 0; j < bsize - 1; j++) {
614
+ if (x[j] > t * bu[j]) {
615
+ gt += (t * bu[j] - x[j]) * bu[j]; /* gradient */
616
+ ht += bu[j] * bu[j]; /* hessian */
617
+ } else if (x[j] < t * bl[j]) {
618
+ gt += (t * bl[j] - x[j]) * bl[j]; /* gradient */
619
+ ht += bl[j] * bl[j]; /* hessian */
620
+ }
621
+ }
622
+ t = MAX(t - gt / MAX(ht, 1e-8), 0.); /* newton step */
623
+ #if VERBOSITY > 3
624
+ scs_printf("iter %i, t_new %1.3e, t_prev %1.3e, gt %1.3e, ht %1.3e\n", iter,
625
+ t, t_prev, gt, ht);
626
+ scs_printf("ABS(gt / (ht + 1e-6)) %.4e, ABS(t - t_prev) %.4e\n",
627
+ ABS(gt / (ht + 1e-6)), ABS(t - t_prev));
628
+ #endif
629
+ /* TODO: sometimes this check can fail (ie, declare convergence before it
630
+ * should) if ht is very large, which can happen with some pathological
631
+ * problems.
632
+ */
633
+ if (ABS(gt / MAX(ht, 1e-6)) < 1e-12 * MAX(t, 1.) ||
634
+ ABS(t - t_prev) < 1e-11 * MAX(t, 1.)) {
635
+ break;
636
+ }
637
+ }
638
+ if (iter == BOX_CONE_MAX_ITERS) {
639
+ scs_printf("warning: box cone proj hit maximum %i iters\n", (int)iter);
640
+ }
641
+ for (j = 0; j < bsize - 1; j++) {
642
+ if (x[j] > t * bu[j]) {
643
+ x[j] = t * bu[j];
644
+ } else if (x[j] < t * bl[j]) {
645
+ x[j] = t * bl[j];
646
+ }
647
+ /* x[j] unchanged otherwise */
648
+ }
649
+ tx[0] = t;
650
+ #if VERBOSITY > 3
651
+ scs_printf("box cone iters %i\n", (int)iter + 1);
652
+ #endif
653
+ return t;
654
+ }
655
+
656
+ /* project onto SOC of size q*/
657
+ static void proj_soc(scs_float *x, scs_int q) {
658
+ if (q == 0) {
659
+ return;
660
+ }
661
+ if (q == 1) {
662
+ x[0] = MAX(x[0], 0.);
663
+ return;
664
+ }
665
+ scs_float v1 = x[0];
666
+ scs_float s = SCS(norm_2)(&(x[1]), q - 1);
667
+ scs_float alpha = (s + v1) / 2.0;
668
+
669
+ if (s <= v1) {
670
+ return;
671
+ } else if (s <= -v1) {
672
+ memset(&(x[0]), 0, q * sizeof(scs_float));
673
+ } else {
674
+ x[0] = alpha;
675
+ SCS(scale_array)(&(x[1]), alpha / s, q - 1);
676
+ }
677
+ }
678
+
597
679
  static void proj_power_cone(scs_float *v, scs_float a) {
598
680
  scs_float xh = v[0], yh = v[1], rh = ABS(v[2]);
599
681
  scs_float x = 0.0, y = 0.0, r;
@@ -635,100 +717,87 @@ static void proj_power_cone(scs_float *v, scs_float a) {
635
717
  v[2] = (v[2] < 0) ? -(r) : (r);
636
718
  }
637
719
 
638
- /* outward facing cone projection routine, iter is outer algorithm iteration, if
639
- iter < 0 then iter is ignored
640
- warm_start contains guess of projection (can be set to SCS_NULL) */
641
- scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
642
- const scs_float *warm_start, scs_int iter) {
643
- scs_int i;
644
- scs_int count = (k->f ? k->f : 0);
645
- SCS(timer) cone_timer;
646
- #if EXTRA_VERBOSE > 0
647
- SCS(timer) proj_timer;
648
- SCS(tic)(&proj_timer);
649
- #endif
650
- SCS(tic)(&cone_timer);
720
+ /* project onto the primal K cone in the paper */
721
+ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
722
+ scs_int normalize) {
723
+ scs_int i, status;
724
+ scs_int count = 0;
725
+
726
+ if (k->z) {
727
+ /* project onto primal zero / dual free cone */
728
+ memset(x, 0, k->z * sizeof(scs_float));
729
+ count += k->z;
730
+ }
651
731
 
652
732
  if (k->l) {
653
733
  /* project onto positive orthant */
654
734
  for (i = count; i < count + k->l; ++i) {
655
- if (x[i] < 0.0) {
656
- x[i] = 0.0;
657
- }
658
- /* x[i] = (x[i] < 0.0) ? 0.0 : x[i]; */
735
+ x[i] = MAX(x[i], 0.0);
659
736
  }
660
737
  count += k->l;
661
- #if EXTRA_VERBOSE > 0
662
- scs_printf("pos orthant proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
663
- SCS(tic)(&proj_timer);
664
- #endif
738
+ }
739
+
740
+ if (k->bsize) {
741
+ /* project onto box cone */
742
+ if (normalize) {
743
+ c->box_t_warm_start = proj_box_cone(&(x[count]), c->bl, c->bu, k->bsize,
744
+ c->box_t_warm_start);
745
+ } else {
746
+ c->box_t_warm_start = proj_box_cone(&(x[count]), k->bl, k->bu, k->bsize,
747
+ c->box_t_warm_start);
748
+ }
749
+ count += k->bsize; /* since b = (t,s), len(s) = bsize - 1 */
665
750
  }
666
751
 
667
752
  if (k->qsize && k->q) {
668
- /* project onto SOC */
753
+ /* project onto second-order cones */
669
754
  for (i = 0; i < k->qsize; ++i) {
670
- if (k->q[i] == 0) {
671
- continue;
672
- }
673
- if (k->q[i] == 1) {
674
- if (x[count] < 0.0) {
675
- x[count] = 0.0;
676
- }
677
- } else {
678
- scs_float v1 = x[count];
679
- scs_float s = SCS(norm)(&(x[count + 1]), k->q[i] - 1);
680
- scs_float alpha = (s + v1) / 2.0;
681
-
682
- if (s <= v1) { /* do nothing */
683
- } else if (s <= -v1) {
684
- memset(&(x[count]), 0, k->q[i] * sizeof(scs_float));
685
- } else {
686
- x[count] = alpha;
687
- SCS(scale_array)(&(x[count + 1]), alpha / s, k->q[i] - 1);
688
- }
689
- }
755
+ proj_soc(&(x[count]), k->q[i]);
690
756
  count += k->q[i];
691
757
  }
692
- #if EXTRA_VERBOSE > 0
693
- scs_printf("SOC proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
694
- SCS(tic)(&proj_timer);
695
- #endif
696
758
  }
697
759
 
698
760
  if (k->ssize && k->s) {
699
- /* project onto PSD cone */
761
+ /* project onto PSD cones */
700
762
  for (i = 0; i < k->ssize; ++i) {
701
- #if EXTRA_VERBOSE > 0
702
- scs_printf("SD proj size %li\n", (long)k->s[i]);
703
- #endif
704
- if (k->s[i] == 0) {
705
- continue;
706
- }
707
- if (proj_semi_definite_cone(&(x[count]), k->s[i], c) < 0) {
708
- return -1;
763
+ status = proj_semi_definite_cone(&(x[count]), k->s[i], c);
764
+ if (status < 0) {
765
+ return status;
709
766
  }
710
767
  count += get_sd_cone_size(k->s[i]);
711
768
  }
712
- #if EXTRA_VERBOSE > 0
713
- scs_printf("SD proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
714
- SCS(tic)(&proj_timer);
715
- #endif
716
769
  }
717
770
 
718
771
  if (k->ep) {
719
- scs_float r, s, t;
720
- scs_int idx;
721
772
  /*
722
773
  * exponential cone is not self dual, if s \in K
723
774
  * then y \in K^* and so if K is the primal cone
724
775
  * here we project onto K^*, via Moreau
725
776
  * \Pi_C^*(y) = y + \Pi_C(-y)
726
777
  */
727
- SCS(scale_array)(&(x[count]), -1, 3 * k->ep); /* x = -x; */
728
778
  #ifdef _OPENMP
729
- #pragma omp parallel for private(r, s, t, idx)
779
+ #pragma omp parallel for
730
780
  #endif
731
781
  for (i = 0; i < k->ep; ++i) {
782
+ proj_exp_cone(&(x[count + 3 * i]));
783
+ }
784
+ count += 3 * k->ep;
785
+ }
786
+
787
+ if (k->ed) { /* dual exponential cone */
788
+ /*
789
+ * exponential cone is not self dual, if s \in K
790
+ * then y \in K^* and so if K is the primal cone
791
+ * here we project onto K^*, via Moreau
792
+ * \Pi_C^*(y) = y + \Pi_C(-y)
793
+ */
794
+ scs_int idx;
795
+ scs_float r, s, t;
796
+ SCS(scale_array)(&(x[count]), -1, 3 * k->ed); /* x = -x; */
797
+ #ifdef _OPENMP
798
+ #pragma omp parallel for private(r, s, t, idx)
799
+ #endif
800
+ for (i = 0; i < k->ed; ++i) {
732
801
  idx = count + 3 * i;
733
802
  r = x[idx];
734
803
  s = x[idx + 1];
@@ -740,26 +809,7 @@ scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
740
809
  x[idx + 1] -= s;
741
810
  x[idx + 2] -= t;
742
811
  }
743
- count += 3 * k->ep;
744
- #if EXTRA_VERBOSE > 0
745
- scs_printf("EP proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
746
- SCS(tic)(&proj_timer);
747
- #endif
748
- }
749
-
750
- if (k->ed) {
751
- /* exponential cone: */
752
- #ifdef _OPENMP
753
- #pragma omp parallel for
754
- #endif
755
- for (i = 0; i < k->ed; ++i) {
756
- proj_exp_cone(&(x[count + 3 * i]));
757
- }
758
812
  count += 3 * k->ed;
759
- #if EXTRA_VERBOSE > 0
760
- scs_printf("ED proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
761
- SCS(tic)(&proj_timer);
762
- #endif
763
813
  }
764
814
 
765
815
  if (k->psize && k->p) {
@@ -772,16 +822,16 @@ scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
772
822
  */
773
823
  for (i = 0; i < k->psize; ++i) {
774
824
  idx = count + 3 * i;
775
- if (k->p[i] <= 0) {
776
- /* dual power cone */
777
- proj_power_cone(&(x[idx]), -k->p[i]);
825
+ if (k->p[i] >= 0) {
826
+ /* primal power cone */
827
+ proj_power_cone(&(x[idx]), k->p[i]);
778
828
  } else {
779
- /* primal power cone, using Moreau */
829
+ /* dual power cone, using Moreau */
780
830
  v[0] = -x[idx];
781
831
  v[1] = -x[idx + 1];
782
832
  v[2] = -x[idx + 2];
783
833
 
784
- proj_power_cone(v, k->p[i]);
834
+ proj_power_cone(v, -k->p[i]);
785
835
 
786
836
  x[idx] += v[0];
787
837
  x[idx + 1] += v[1];
@@ -789,14 +839,51 @@ scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
789
839
  }
790
840
  }
791
841
  count += 3 * k->psize;
792
- #if EXTRA_VERBOSE > 0
793
- scs_printf("Power cone proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
794
- SCS(tic)(&proj_timer);
795
- #endif
796
842
  }
797
843
  /* project onto OTHER cones */
798
- if (c) {
799
- c->total_cone_time += SCS(tocq)(&cone_timer);
800
- }
801
844
  return 0;
802
845
  }
846
+
847
+ ScsConeWork *SCS(init_cone)(const ScsCone *k, const ScsScaling *scal,
848
+ scs_int cone_len) {
849
+ ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
850
+ c->cone_len = cone_len;
851
+ c->s = (scs_float *)scs_calloc(cone_len, sizeof(scs_float));
852
+ if (k->bsize && k->bu && k->bl) {
853
+ c->box_t_warm_start = 1.;
854
+ if (scal) {
855
+ c->bu = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
856
+ c->bl = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
857
+ memcpy(c->bu, k->bu, (k->bsize - 1) * sizeof(scs_float));
858
+ memcpy(c->bl, k->bl, (k->bsize - 1) * sizeof(scs_float));
859
+ /* also does some sanitizing */
860
+ normalize_box_cone(c, scal ? &(scal->D[k->z + k->l]) : SCS_NULL,
861
+ k->bsize);
862
+ }
863
+ }
864
+ if (k->ssize && k->s) {
865
+ if (set_up_sd_cone_work_space(c, k) < 0) {
866
+ SCS(finish_cone)(c);
867
+ return SCS_NULL;
868
+ }
869
+ }
870
+ return c;
871
+ }
872
+
873
+ /* outward facing cone projection routine
874
+ performs projection in-place
875
+ if normalize > 0 then will use normalized (equilibrated) cones if applicable.
876
+ */
877
+ scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
878
+ scs_int normalize) {
879
+ scs_int status;
880
+ /* copy x, s = x */
881
+ memcpy(c->s, x, c->cone_len * sizeof(scs_float));
882
+ /* negate x -> -x */
883
+ SCS(scale_array)(x, -1., c->cone_len);
884
+ /* project -x onto cone, x -> Pi_K(-x) */
885
+ status = proj_cone(x, k, c, normalize);
886
+ /* return Pi_K*(x) = s + Pi_K(-x) */
887
+ SCS(add_scaled_array)(x, c->s, c->cone_len, 1.);
888
+ return status;
889
+ }