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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +11 -6
- data/lib/scs/ffi.rb +30 -13
- data/lib/scs/solver.rb +32 -9
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +39 -0
- data/vendor/scs/CMakeLists.txt +7 -8
- data/vendor/scs/Makefile +24 -15
- data/vendor/scs/README.md +5 -263
- data/vendor/scs/include/aa.h +67 -23
- data/vendor/scs/include/cones.h +17 -17
- data/vendor/scs/include/glbopts.h +98 -32
- data/vendor/scs/include/linalg.h +2 -4
- data/vendor/scs/include/linsys.h +58 -44
- data/vendor/scs/include/normalize.h +3 -3
- data/vendor/scs/include/rw.h +8 -2
- data/vendor/scs/include/scs.h +293 -133
- data/vendor/scs/include/util.h +3 -15
- data/vendor/scs/linsys/cpu/direct/private.c +220 -224
- data/vendor/scs/linsys/cpu/direct/private.h +13 -7
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.c +177 -110
- data/vendor/scs/linsys/cpu/indirect/private.h +8 -4
- data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
- data/vendor/scs/linsys/csparse.c +87 -0
- data/vendor/scs/linsys/csparse.h +34 -0
- data/vendor/scs/linsys/csparse.o +0 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +1 -1
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_internal.h +1 -1
- data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
- data/vendor/scs/linsys/external/qdldl/changes +2 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.c +29 -46
- data/vendor/scs/linsys/external/qdldl/qdldl.h +33 -41
- data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
- data/vendor/scs/linsys/external/qdldl/qdldl_types.h +11 -3
- data/vendor/scs/linsys/gpu/gpu.c +31 -33
- data/vendor/scs/linsys/gpu/gpu.h +48 -31
- data/vendor/scs/linsys/gpu/indirect/private.c +338 -232
- data/vendor/scs/linsys/gpu/indirect/private.h +23 -14
- data/vendor/scs/linsys/scs_matrix.c +498 -0
- data/vendor/scs/linsys/scs_matrix.h +70 -0
- data/vendor/scs/linsys/scs_matrix.o +0 -0
- data/vendor/scs/scs.mk +13 -9
- data/vendor/scs/src/aa.c +384 -109
- data/vendor/scs/src/aa.o +0 -0
- data/vendor/scs/src/cones.c +440 -353
- data/vendor/scs/src/cones.o +0 -0
- data/vendor/scs/src/ctrlc.c +15 -5
- data/vendor/scs/src/ctrlc.o +0 -0
- data/vendor/scs/src/linalg.c +84 -28
- data/vendor/scs/src/linalg.o +0 -0
- data/vendor/scs/src/normalize.c +22 -64
- data/vendor/scs/src/normalize.o +0 -0
- data/vendor/scs/src/rw.c +160 -21
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.c +767 -563
- data/vendor/scs/src/scs.o +0 -0
- data/vendor/scs/src/scs_indir.o +0 -0
- data/vendor/scs/src/scs_version.c +9 -3
- data/vendor/scs/src/scs_version.o +0 -0
- data/vendor/scs/src/util.c +37 -106
- data/vendor/scs/src/util.o +0 -0
- data/vendor/scs/test/minunit.h +17 -8
- data/vendor/scs/test/problem_utils.h +176 -14
- data/vendor/scs/test/problems/degenerate.h +130 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +124 -0
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +116 -0
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +100 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +199 -0
- data/vendor/scs/test/problems/random_prob +0 -0
- data/vendor/scs/test/problems/random_prob.h +45 -0
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +188 -31
- data/vendor/scs/test/problems/small_lp.h +13 -14
- data/vendor/scs/test/problems/test_fails.h +43 -0
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +82 -0
- data/vendor/scs/test/random_socp_prob.c +54 -53
- data/vendor/scs/test/rng.h +109 -0
- data/vendor/scs/test/run_from_file.c +19 -10
- data/vendor/scs/test/run_tests.c +27 -3
- metadata +20 -8
- data/vendor/scs/linsys/amatrix.c +0 -305
- data/vendor/scs/linsys/amatrix.h +0 -36
- data/vendor/scs/linsys/amatrix.o +0 -0
- data/vendor/scs/test/data/small_random_socp +0 -0
- data/vendor/scs/test/problems/small_random_socp.h +0 -33
- data/vendor/scs/test/run_tests +0 -2
data/vendor/scs/src/cones.c
CHANGED
@@ -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
|
9
|
-
#define
|
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(
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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(
|
39
|
-
scs_int i, count = 0;
|
40
|
-
scs_int
|
41
|
-
|
42
|
-
b
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
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
|
-
|
61
|
-
|
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 =
|
66
|
-
if (k->
|
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
|
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->
|
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,
|
190
|
-
sprintf(tmp, "
|
191
|
-
if (k->
|
192
|
-
sprintf(tmp + strlen(tmp), "\
|
193
|
-
(long)k->
|
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), "\
|
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), "\
|
206
|
-
(long)soc_vars, (long)
|
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), "\
|
216
|
-
(long)
|
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), "\
|
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), "\
|
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-
|
242
|
-
scs_float f
|
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
|
-
|
287
|
+
t = -z_hat;
|
288
|
+
break;
|
252
289
|
} else if (t <= 0) {
|
253
|
-
|
254
|
-
|
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
|
-
|
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 ((
|
302
|
-
(
|
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;
|
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 <
|
369
|
+
if (ub - lb < CONE_TOL) {
|
325
370
|
break;
|
326
371
|
}
|
327
372
|
}
|
328
|
-
|
329
|
-
|
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
|
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
|
-
|
365
|
-
(
|
366
|
-
|
367
|
-
&
|
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:
|
414
|
+
scs_printf("FATAL: syev failure, info = %li\n", (long)info);
|
371
415
|
return -1;
|
372
416
|
}
|
373
|
-
c->lwork = (blas_int)(wkopt +
|
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
|
420
|
+
if (!c->Xs || !c->Z || !c->e || !c->work) {
|
378
421
|
return -1;
|
379
422
|
}
|
380
423
|
return 0;
|
381
424
|
#else
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
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
|
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
|
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
|
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
|
-
|
493
|
-
X[0] = 0.0;
|
494
|
-
}
|
466
|
+
X[0] = MAX(X[0], 0.);
|
495
467
|
return 0;
|
496
468
|
}
|
497
|
-
|
498
|
-
return project_2x2_sdc(X);
|
499
|
-
}
|
469
|
+
|
500
470
|
#ifdef USE_LAPACK
|
501
471
|
|
502
|
-
|
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(
|
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
|
532
|
-
|
533
|
-
|
534
|
-
|
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
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
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
|
-
|
552
|
-
|
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
|
-
/*
|
639
|
-
|
640
|
-
|
641
|
-
scs_int
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
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
|
-
|
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
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
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
|
753
|
+
/* project onto second-order cones */
|
669
754
|
for (i = 0; i < k->qsize; ++i) {
|
670
|
-
|
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
|
761
|
+
/* project onto PSD cones */
|
700
762
|
for (i = 0; i < k->ssize; ++i) {
|
701
|
-
|
702
|
-
|
703
|
-
|
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
|
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]
|
776
|
-
/*
|
777
|
-
proj_power_cone(&(x[idx]),
|
825
|
+
if (k->p[i] >= 0) {
|
826
|
+
/* primal power cone */
|
827
|
+
proj_power_cone(&(x[idx]), k->p[i]);
|
778
828
|
} else {
|
779
|
-
/*
|
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
|
+
}
|