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