scs 0.2.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 +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/ext/scs/Rakefile +11 -0
- data/lib/scs/ffi.rb +117 -0
- data/lib/scs/solver.rb +178 -0
- data/lib/scs/version.rb +3 -0
- data/lib/scs.rb +17 -0
- data/vendor/scs/LICENSE.txt +21 -0
- data/vendor/scs/Makefile +164 -0
- data/vendor/scs/README.md +220 -0
- data/vendor/scs/include/aa.h +56 -0
- data/vendor/scs/include/cones.h +46 -0
- data/vendor/scs/include/ctrlc.h +33 -0
- data/vendor/scs/include/glbopts.h +177 -0
- data/vendor/scs/include/linalg.h +26 -0
- data/vendor/scs/include/linsys.h +64 -0
- data/vendor/scs/include/normalize.h +18 -0
- data/vendor/scs/include/rw.h +17 -0
- data/vendor/scs/include/scs.h +161 -0
- data/vendor/scs/include/scs_blas.h +51 -0
- data/vendor/scs/include/util.h +65 -0
- data/vendor/scs/linsys/amatrix.c +305 -0
- data/vendor/scs/linsys/amatrix.h +36 -0
- data/vendor/scs/linsys/amatrix.o +0 -0
- data/vendor/scs/linsys/cpu/direct/private.c +366 -0
- data/vendor/scs/linsys/cpu/direct/private.h +26 -0
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.c +256 -0
- data/vendor/scs/linsys/cpu/indirect/private.h +31 -0
- data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
- data/vendor/scs/linsys/external/amd/LICENSE.txt +934 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +469 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +254 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
- data/vendor/scs/linsys/external/amd/amd.h +400 -0
- data/vendor/scs/linsys/external/amd/amd_1.c +180 -0
- data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_2.c +1842 -0
- data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_aat.c +184 -0
- data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_control.c +64 -0
- data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.c +37 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_dump.c +179 -0
- data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_global.c +16 -0
- data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_info.c +119 -0
- data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_internal.h +304 -0
- data/vendor/scs/linsys/external/amd/amd_order.c +199 -0
- data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.c +120 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.c +206 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.c +118 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_valid.c +92 -0
- data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
- data/vendor/scs/linsys/external/amd/changes +11 -0
- data/vendor/scs/linsys/external/qdldl/LICENSE +201 -0
- data/vendor/scs/linsys/external/qdldl/README.md +120 -0
- data/vendor/scs/linsys/external/qdldl/changes +4 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.c +298 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.h +177 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
- data/vendor/scs/linsys/external/qdldl/qdldl_types.h +21 -0
- data/vendor/scs/linsys/gpu/gpu.c +41 -0
- data/vendor/scs/linsys/gpu/gpu.h +85 -0
- data/vendor/scs/linsys/gpu/indirect/private.c +304 -0
- data/vendor/scs/linsys/gpu/indirect/private.h +36 -0
- data/vendor/scs/scs.mk +181 -0
- data/vendor/scs/src/aa.c +224 -0
- data/vendor/scs/src/aa.o +0 -0
- data/vendor/scs/src/cones.c +802 -0
- data/vendor/scs/src/cones.o +0 -0
- data/vendor/scs/src/ctrlc.c +77 -0
- data/vendor/scs/src/ctrlc.o +0 -0
- data/vendor/scs/src/linalg.c +84 -0
- data/vendor/scs/src/linalg.o +0 -0
- data/vendor/scs/src/normalize.c +93 -0
- data/vendor/scs/src/normalize.o +0 -0
- data/vendor/scs/src/rw.c +167 -0
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.c +975 -0
- data/vendor/scs/src/scs.o +0 -0
- data/vendor/scs/src/scs_version.c +5 -0
- data/vendor/scs/src/scs_version.o +0 -0
- data/vendor/scs/src/util.c +196 -0
- data/vendor/scs/src/util.o +0 -0
- data/vendor/scs/test/data/small_random_socp +0 -0
- data/vendor/scs/test/minunit.h +13 -0
- data/vendor/scs/test/problem_utils.h +93 -0
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +85 -0
- data/vendor/scs/test/problems/small_lp.h +50 -0
- data/vendor/scs/test/problems/small_random_socp.h +33 -0
- data/vendor/scs/test/random_socp_prob.c +171 -0
- data/vendor/scs/test/run_from_file.c +69 -0
- data/vendor/scs/test/run_tests +2 -0
- data/vendor/scs/test/run_tests.c +32 -0
- metadata +203 -0
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
#include "cones.h"
|
|
2
|
+
|
|
3
|
+
#include "linalg.h"
|
|
4
|
+
#include "scs.h"
|
|
5
|
+
#include "scs_blas.h" /* contains BLAS(X) macros and type info */
|
|
6
|
+
#include "util.h"
|
|
7
|
+
|
|
8
|
+
#define CONE_RATE (2)
|
|
9
|
+
#define CONE_TOL (1e-8)
|
|
10
|
+
#define CONE_THRESH (1e-6)
|
|
11
|
+
#define EXP_CONE_MAX_ITERS (100)
|
|
12
|
+
#define POW_CONE_MAX_ITERS (20)
|
|
13
|
+
|
|
14
|
+
#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);
|
|
24
|
+
void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
|
|
25
|
+
const blas_int *incx);
|
|
26
|
+
scs_float BLAS(nrm2)(const blas_int *n, scs_float *x, const blas_int *incx);
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
static scs_int get_sd_cone_size(scs_int s) { return (s * (s + 1)) / 2; }
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* boundaries will contain array of indices of rows of A corresponding to
|
|
33
|
+
* 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
|
|
37
|
+
*/
|
|
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));
|
|
46
|
+
}
|
|
47
|
+
count += k->qsize;
|
|
48
|
+
for (i = 0; i < k->ssize; ++i) {
|
|
49
|
+
b[count + i] = get_sd_cone_size(k->s[i]);
|
|
50
|
+
}
|
|
51
|
+
count += k->ssize;
|
|
52
|
+
for (i = 0; i < k->ep + k->ed; ++i) {
|
|
53
|
+
b[count + i] = 3;
|
|
54
|
+
}
|
|
55
|
+
count += k->ep + k->ed;
|
|
56
|
+
for (i = 0; i < k->psize; ++i) {
|
|
57
|
+
b[count + i] = 3;
|
|
58
|
+
}
|
|
59
|
+
count += k->psize;
|
|
60
|
+
*boundaries = b;
|
|
61
|
+
return len;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
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) {
|
|
73
|
+
for (i = 0; i < k->qsize; ++i) {
|
|
74
|
+
c += k->q[i];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (k->ssize && k->s) {
|
|
78
|
+
for (i = 0; i < k->ssize; ++i) {
|
|
79
|
+
c += get_sd_cone_size(k->s[i]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (k->ed) {
|
|
83
|
+
c += 3 * k->ed;
|
|
84
|
+
}
|
|
85
|
+
if (k->ep) {
|
|
86
|
+
c += 3 * k->ep;
|
|
87
|
+
}
|
|
88
|
+
if (k->p) {
|
|
89
|
+
c += 3 * k->psize;
|
|
90
|
+
}
|
|
91
|
+
return c;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
|
|
95
|
+
scs_int i;
|
|
96
|
+
if (get_full_cone_dims(k) != d->m) {
|
|
97
|
+
scs_printf("cone dimensions %li not equal to num rows in A = m = %li\n",
|
|
98
|
+
(long)get_full_cone_dims(k), (long)d->m);
|
|
99
|
+
return -1;
|
|
100
|
+
}
|
|
101
|
+
if (k->f && k->f < 0) {
|
|
102
|
+
scs_printf("free cone error\n");
|
|
103
|
+
return -1;
|
|
104
|
+
}
|
|
105
|
+
if (k->l && k->l < 0) {
|
|
106
|
+
scs_printf("lp cone error\n");
|
|
107
|
+
return -1;
|
|
108
|
+
}
|
|
109
|
+
if (k->qsize && k->q) {
|
|
110
|
+
if (k->qsize < 0) {
|
|
111
|
+
scs_printf("soc cone error\n");
|
|
112
|
+
return -1;
|
|
113
|
+
}
|
|
114
|
+
for (i = 0; i < k->qsize; ++i) {
|
|
115
|
+
if (k->q[i] < 0) {
|
|
116
|
+
scs_printf("soc cone error\n");
|
|
117
|
+
return -1;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (k->ssize && k->s) {
|
|
122
|
+
if (k->ssize < 0) {
|
|
123
|
+
scs_printf("sd cone error\n");
|
|
124
|
+
return -1;
|
|
125
|
+
}
|
|
126
|
+
for (i = 0; i < k->ssize; ++i) {
|
|
127
|
+
if (k->s[i] < 0) {
|
|
128
|
+
scs_printf("sd cone error\n");
|
|
129
|
+
return -1;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (k->ed && k->ed < 0) {
|
|
134
|
+
scs_printf("ep cone error\n");
|
|
135
|
+
return -1;
|
|
136
|
+
}
|
|
137
|
+
if (k->ep && k->ep < 0) {
|
|
138
|
+
scs_printf("ed cone error\n");
|
|
139
|
+
return -1;
|
|
140
|
+
}
|
|
141
|
+
if (k->psize && k->p) {
|
|
142
|
+
if (k->psize < 0) {
|
|
143
|
+
scs_printf("power cone error\n");
|
|
144
|
+
return -1;
|
|
145
|
+
}
|
|
146
|
+
for (i = 0; i < k->psize; ++i) {
|
|
147
|
+
if (k->p[i] < -1 || k->p[i] > 1) {
|
|
148
|
+
scs_printf("power cone error, values must be in [-1,1]\n");
|
|
149
|
+
return -1;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
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
|
+
void SCS(finish_cone)(ScsConeWork *c) {
|
|
165
|
+
#ifdef USE_LAPACK
|
|
166
|
+
if (c->Xs) {
|
|
167
|
+
scs_free(c->Xs);
|
|
168
|
+
}
|
|
169
|
+
if (c->Z) {
|
|
170
|
+
scs_free(c->Z);
|
|
171
|
+
}
|
|
172
|
+
if (c->e) {
|
|
173
|
+
scs_free(c->e);
|
|
174
|
+
}
|
|
175
|
+
if (c->work) {
|
|
176
|
+
scs_free(c->work);
|
|
177
|
+
}
|
|
178
|
+
if (c->iwork) {
|
|
179
|
+
scs_free(c->iwork);
|
|
180
|
+
}
|
|
181
|
+
#endif
|
|
182
|
+
if (c) {
|
|
183
|
+
scs_free(c);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
char *SCS(get_cone_header)(const ScsCone *k) {
|
|
188
|
+
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);
|
|
194
|
+
}
|
|
195
|
+
if (k->l) {
|
|
196
|
+
sprintf(tmp + strlen(tmp), "\tlinear vars: %li\n", (long)k->l);
|
|
197
|
+
}
|
|
198
|
+
soc_vars = 0;
|
|
199
|
+
soc_blks = 0;
|
|
200
|
+
if (k->qsize && k->q) {
|
|
201
|
+
soc_blks = k->qsize;
|
|
202
|
+
for (i = 0; i < k->qsize; i++) {
|
|
203
|
+
soc_vars += k->q[i];
|
|
204
|
+
}
|
|
205
|
+
sprintf(tmp + strlen(tmp), "\tsoc vars: %li, soc blks: %li\n",
|
|
206
|
+
(long)soc_vars, (long)soc_blks);
|
|
207
|
+
}
|
|
208
|
+
sd_vars = 0;
|
|
209
|
+
sd_blks = 0;
|
|
210
|
+
if (k->ssize && k->s) {
|
|
211
|
+
sd_blks = k->ssize;
|
|
212
|
+
for (i = 0; i < k->ssize; i++) {
|
|
213
|
+
sd_vars += get_sd_cone_size(k->s[i]);
|
|
214
|
+
}
|
|
215
|
+
sprintf(tmp + strlen(tmp), "\tsd vars: %li, sd blks: %li\n", (long)sd_vars,
|
|
216
|
+
(long)sd_blks);
|
|
217
|
+
}
|
|
218
|
+
if (k->ep || k->ed) {
|
|
219
|
+
sprintf(tmp + strlen(tmp), "\texp vars: %li, dual exp vars: %li\n",
|
|
220
|
+
(long)(3 * k->ep), (long)(3 * k->ed));
|
|
221
|
+
}
|
|
222
|
+
if (k->psize && k->p) {
|
|
223
|
+
sprintf(tmp + strlen(tmp), "\tprimal + dual power vars: %li\n",
|
|
224
|
+
(long)(3 * k->psize));
|
|
225
|
+
}
|
|
226
|
+
return tmp;
|
|
227
|
+
}
|
|
228
|
+
|
|
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
|
+
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;
|
|
243
|
+
scs_int i;
|
|
244
|
+
for (i = 0; i < EXP_CONE_MAX_ITERS; ++i) {
|
|
245
|
+
f = t * (t + z_hat) / rho / rho - y_hat / rho + log(t / rho) + 1;
|
|
246
|
+
fp = (2 * t + z_hat) / rho / rho + 1 / t;
|
|
247
|
+
|
|
248
|
+
t = t - f / fp;
|
|
249
|
+
|
|
250
|
+
if (t <= -z_hat) {
|
|
251
|
+
return 0;
|
|
252
|
+
} else if (t <= 0) {
|
|
253
|
+
return z_hat;
|
|
254
|
+
} else if (ABS(f) < CONE_TOL) {
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return t + z_hat;
|
|
259
|
+
}
|
|
260
|
+
|
|
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]);
|
|
264
|
+
x[1] = (x[2] - v[2]) * x[2] / rho;
|
|
265
|
+
x[0] = v[0] - rho;
|
|
266
|
+
}
|
|
267
|
+
|
|
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);
|
|
270
|
+
if (x[1] <= 1e-12) {
|
|
271
|
+
return x[0];
|
|
272
|
+
}
|
|
273
|
+
return x[0] + x[1] * log(x[1] / x[2]);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
static void exp_get_rho_ub(scs_float *v, scs_float *x, scs_float *ub,
|
|
277
|
+
scs_float *lb) {
|
|
278
|
+
*lb = 0;
|
|
279
|
+
*ub = 0.125;
|
|
280
|
+
while (exp_calc_grad(v, x, *ub) > 0) {
|
|
281
|
+
*lb = *ub;
|
|
282
|
+
(*ub) *= 2;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* project onto the exponential cone, v has dimension *exactly* 3 */
|
|
287
|
+
static scs_int proj_exp_cone(scs_float *v) {
|
|
288
|
+
scs_int i;
|
|
289
|
+
scs_float ub, lb, rho, g, x[3];
|
|
290
|
+
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
|
+
|
|
294
|
+
/* v in cl(Kexp) */
|
|
295
|
+
if ((s * exp(r / s) - t <= CONE_THRESH && s > 0) ||
|
|
296
|
+
(r <= 0 && s == 0 && t >= 0)) {
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* -v in Kexp^* */
|
|
301
|
+
if ((-r < 0 && r * exp(s / r) + exp(1) * t <= CONE_THRESH) ||
|
|
302
|
+
(-r == 0 && -s >= 0 && -t >= 0)) {
|
|
303
|
+
memset(v, 0, 3 * sizeof(scs_float));
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* special case with analytical solution */
|
|
308
|
+
if (r < 0 && s < 0) {
|
|
309
|
+
v[1] = 0.0;
|
|
310
|
+
v[2] = MAX(v[2], 0);
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* iterative procedure to find projection, bisects on dual variable: */
|
|
315
|
+
exp_get_rho_ub(v, x, &ub, &lb); /* get starting upper and lower bounds */
|
|
316
|
+
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 */
|
|
319
|
+
if (g > 0) {
|
|
320
|
+
lb = rho;
|
|
321
|
+
} else {
|
|
322
|
+
ub = rho;
|
|
323
|
+
}
|
|
324
|
+
if (ub - lb < tol) {
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/*
|
|
329
|
+
#if EXTRA_VERBOSE > 0
|
|
330
|
+
scs_printf("exponential cone proj iters %i\n", i);
|
|
331
|
+
#endif
|
|
332
|
+
*/
|
|
333
|
+
v[0] = x[0];
|
|
334
|
+
v[1] = x[1];
|
|
335
|
+
v[2] = x[2];
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
340
|
+
#ifdef USE_LAPACK
|
|
341
|
+
scs_int i;
|
|
342
|
+
blas_int n_max = 0;
|
|
343
|
+
scs_float eig_tol = 1e-8;
|
|
344
|
+
blas_int neg_one = -1;
|
|
345
|
+
blas_int m = 0;
|
|
346
|
+
blas_int info = 0;
|
|
347
|
+
scs_float wkopt = 0.0;
|
|
348
|
+
#if EXTRA_VERBOSE > 0
|
|
349
|
+
#define _STR_EXPAND(tok) #tok
|
|
350
|
+
#define _STR(tok) _STR_EXPAND(tok)
|
|
351
|
+
scs_printf("BLAS(func) = '%s'\n", _STR(BLAS(func)));
|
|
352
|
+
#endif
|
|
353
|
+
/* eigenvector decomp workspace */
|
|
354
|
+
for (i = 0; i < k->ssize; ++i) {
|
|
355
|
+
if (k->s[i] > n_max) {
|
|
356
|
+
n_max = (blas_int)k->s[i];
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
c->Xs = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
|
|
360
|
+
c->Z = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
|
|
361
|
+
c->e = (scs_float *)scs_calloc(n_max, sizeof(scs_float));
|
|
362
|
+
c->liwork = 0;
|
|
363
|
+
|
|
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);
|
|
368
|
+
|
|
369
|
+
if (info != 0) {
|
|
370
|
+
scs_printf("FATAL: syevr failure, info = %li\n", (long)info);
|
|
371
|
+
return -1;
|
|
372
|
+
}
|
|
373
|
+
c->lwork = (blas_int)(wkopt + 0.01); /* 0.01 for int casting safety */
|
|
374
|
+
c->work = (scs_float *)scs_calloc(c->lwork, sizeof(scs_float));
|
|
375
|
+
c->iwork = (blas_int *)scs_calloc(c->liwork, sizeof(blas_int));
|
|
376
|
+
|
|
377
|
+
if (!c->Xs || !c->Z || !c->e || !c->work || !c->iwork) {
|
|
378
|
+
return -1;
|
|
379
|
+
}
|
|
380
|
+
return 0;
|
|
381
|
+
#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;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
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
|
+
return 0;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/* size of X is get_sd_cone_size(n) */
|
|
461
|
+
static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
462
|
+
ScsConeWork *c) {
|
|
463
|
+
/* project onto the positive semi-definite cone */
|
|
464
|
+
#ifdef USE_LAPACK
|
|
465
|
+
scs_int i;
|
|
466
|
+
blas_int one = 1;
|
|
467
|
+
blas_int m = 0;
|
|
468
|
+
blas_int nb = (blas_int)n;
|
|
469
|
+
blas_int nb_plus_one = (blas_int)(n + 1);
|
|
470
|
+
blas_int cone_sz = (blas_int)(get_sd_cone_size(n));
|
|
471
|
+
|
|
472
|
+
scs_float sqrt2 = SQRTF(2.0);
|
|
473
|
+
scs_float sqrt2Inv = 1.0 / sqrt2;
|
|
474
|
+
scs_float *Xs = c->Xs;
|
|
475
|
+
scs_float *Z = c->Z;
|
|
476
|
+
scs_float *e = c->e;
|
|
477
|
+
scs_float *work = c->work;
|
|
478
|
+
blas_int *iwork = c->iwork;
|
|
479
|
+
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
|
+
blas_int info = 0;
|
|
486
|
+
scs_float vupper = 0.0;
|
|
487
|
+
#endif
|
|
488
|
+
if (n == 0) {
|
|
489
|
+
return 0;
|
|
490
|
+
}
|
|
491
|
+
if (n == 1) {
|
|
492
|
+
if (X[0] < 0.0) {
|
|
493
|
+
X[0] = 0.0;
|
|
494
|
+
}
|
|
495
|
+
return 0;
|
|
496
|
+
}
|
|
497
|
+
if (n == 2) {
|
|
498
|
+
return project_2x2_sdc(X);
|
|
499
|
+
}
|
|
500
|
+
#ifdef USE_LAPACK
|
|
501
|
+
|
|
502
|
+
memset(Xs, 0, n * n * sizeof(scs_float));
|
|
503
|
+
/* expand lower triangular matrix to full matrix */
|
|
504
|
+
for (i = 0; i < n; ++i) {
|
|
505
|
+
memcpy(&(Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
|
|
506
|
+
(n - i) * sizeof(scs_float));
|
|
507
|
+
}
|
|
508
|
+
/*
|
|
509
|
+
rescale so projection works, and matrix norm preserved
|
|
510
|
+
see http://www.seas.ucla.edu/~vandenbe/publications/mlbook.pdf pg 3
|
|
511
|
+
*/
|
|
512
|
+
/* scale diags by sqrt(2) */
|
|
513
|
+
BLAS(scal)(&nb, &sqrt2, Xs, &nb_plus_one); /* not n_squared */
|
|
514
|
+
|
|
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
|
+
/* 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
|
|
530
|
+
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;
|
|
544
|
+
}
|
|
545
|
+
|
|
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);
|
|
550
|
+
}
|
|
551
|
+
/* scale diags by 1/sqrt(2) */
|
|
552
|
+
BLAS(scal)(&nb, &sqrt2Inv, Xs, &nb_plus_one); /* not n_squared */
|
|
553
|
+
/* extract just lower triangular matrix */
|
|
554
|
+
for (i = 0; i < n; ++i) {
|
|
555
|
+
memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(Xs[i * (n + 1)]),
|
|
556
|
+
(n - i) * sizeof(scs_float));
|
|
557
|
+
}
|
|
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
|
|
563
|
+
|
|
564
|
+
#else
|
|
565
|
+
scs_printf(
|
|
566
|
+
"FAILURE: solving SDP with > 2x2 matrices, but no blas/lapack "
|
|
567
|
+
"libraries were linked!\n");
|
|
568
|
+
scs_printf("SCS will return nonsense!\n");
|
|
569
|
+
SCS(scale_array)(X, NAN, n);
|
|
570
|
+
return -1;
|
|
571
|
+
#endif
|
|
572
|
+
return 0;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
static scs_float pow_calc_x(scs_float r, scs_float xh, scs_float rh,
|
|
576
|
+
scs_float a) {
|
|
577
|
+
scs_float x = 0.5 * (xh + SQRTF(xh * xh + 4 * a * (rh - r) * r));
|
|
578
|
+
return MAX(x, 1e-12);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
static scs_float pow_calcdxdr(scs_float x, scs_float xh, scs_float rh,
|
|
582
|
+
scs_float r, scs_float a) {
|
|
583
|
+
return a * (rh - 2 * r) / (2 * x - xh);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
static scs_float pow_calc_f(scs_float x, scs_float y, scs_float r,
|
|
587
|
+
scs_float a) {
|
|
588
|
+
return POWF(x, a) * POWF(y, (1 - a)) - r;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
|
|
592
|
+
scs_float dydr, scs_float a) {
|
|
593
|
+
return POWF(x, a) * POWF(y, (1 - a)) * (a * dxdr / x + (1 - a) * dydr / y) -
|
|
594
|
+
1;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
static void proj_power_cone(scs_float *v, scs_float a) {
|
|
598
|
+
scs_float xh = v[0], yh = v[1], rh = ABS(v[2]);
|
|
599
|
+
scs_float x = 0.0, y = 0.0, r;
|
|
600
|
+
scs_int i;
|
|
601
|
+
/* v in K_a */
|
|
602
|
+
if (xh >= 0 && yh >= 0 &&
|
|
603
|
+
CONE_THRESH + POWF(xh, a) * POWF(yh, (1 - a)) >= rh) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/* -v in K_a^* */
|
|
608
|
+
if (xh <= 0 && yh <= 0 &&
|
|
609
|
+
CONE_THRESH + POWF(-xh, a) * POWF(-yh, 1 - a) >=
|
|
610
|
+
rh * POWF(a, a) * POWF(1 - a, 1 - a)) {
|
|
611
|
+
v[0] = v[1] = v[2] = 0;
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
r = rh / 2;
|
|
616
|
+
for (i = 0; i < POW_CONE_MAX_ITERS; ++i) {
|
|
617
|
+
scs_float f, fp, dxdr, dydr;
|
|
618
|
+
x = pow_calc_x(r, xh, rh, a);
|
|
619
|
+
y = pow_calc_x(r, yh, rh, 1 - a);
|
|
620
|
+
|
|
621
|
+
f = pow_calc_f(x, y, r, a);
|
|
622
|
+
if (ABS(f) < CONE_TOL) {
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
dxdr = pow_calcdxdr(x, xh, rh, r, a);
|
|
627
|
+
dydr = pow_calcdxdr(y, yh, rh, r, (1 - a));
|
|
628
|
+
fp = pow_calc_fp(x, y, dxdr, dydr, a);
|
|
629
|
+
|
|
630
|
+
r = MAX(r - f / fp, 0);
|
|
631
|
+
r = MIN(r, rh);
|
|
632
|
+
}
|
|
633
|
+
v[0] = x;
|
|
634
|
+
v[1] = y;
|
|
635
|
+
v[2] = (v[2] < 0) ? -(r) : (r);
|
|
636
|
+
}
|
|
637
|
+
|
|
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);
|
|
651
|
+
|
|
652
|
+
if (k->l) {
|
|
653
|
+
/* project onto positive orthant */
|
|
654
|
+
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]; */
|
|
659
|
+
}
|
|
660
|
+
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
|
+
}
|
|
666
|
+
|
|
667
|
+
if (k->qsize && k->q) {
|
|
668
|
+
/* project onto SOC */
|
|
669
|
+
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
|
+
}
|
|
690
|
+
count += k->q[i];
|
|
691
|
+
}
|
|
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
|
+
}
|
|
697
|
+
|
|
698
|
+
if (k->ssize && k->s) {
|
|
699
|
+
/* project onto PSD cone */
|
|
700
|
+
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;
|
|
709
|
+
}
|
|
710
|
+
count += get_sd_cone_size(k->s[i]);
|
|
711
|
+
}
|
|
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
|
+
}
|
|
717
|
+
|
|
718
|
+
if (k->ep) {
|
|
719
|
+
scs_float r, s, t;
|
|
720
|
+
scs_int idx;
|
|
721
|
+
/*
|
|
722
|
+
* exponential cone is not self dual, if s \in K
|
|
723
|
+
* then y \in K^* and so if K is the primal cone
|
|
724
|
+
* here we project onto K^*, via Moreau
|
|
725
|
+
* \Pi_C^*(y) = y + \Pi_C(-y)
|
|
726
|
+
*/
|
|
727
|
+
SCS(scale_array)(&(x[count]), -1, 3 * k->ep); /* x = -x; */
|
|
728
|
+
#ifdef _OPENMP
|
|
729
|
+
#pragma omp parallel for private(r, s, t, idx)
|
|
730
|
+
#endif
|
|
731
|
+
for (i = 0; i < k->ep; ++i) {
|
|
732
|
+
idx = count + 3 * i;
|
|
733
|
+
r = x[idx];
|
|
734
|
+
s = x[idx + 1];
|
|
735
|
+
t = x[idx + 2];
|
|
736
|
+
|
|
737
|
+
proj_exp_cone(&(x[idx]));
|
|
738
|
+
|
|
739
|
+
x[idx] -= r;
|
|
740
|
+
x[idx + 1] -= s;
|
|
741
|
+
x[idx + 2] -= t;
|
|
742
|
+
}
|
|
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
|
+
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
|
+
}
|
|
764
|
+
|
|
765
|
+
if (k->psize && k->p) {
|
|
766
|
+
scs_float v[3];
|
|
767
|
+
scs_int idx;
|
|
768
|
+
/* don't use openmp for power cone
|
|
769
|
+
ifdef _OPENMP
|
|
770
|
+
pragma omp parallel for private(v, idx)
|
|
771
|
+
endif
|
|
772
|
+
*/
|
|
773
|
+
for (i = 0; i < k->psize; ++i) {
|
|
774
|
+
idx = count + 3 * i;
|
|
775
|
+
if (k->p[i] <= 0) {
|
|
776
|
+
/* dual power cone */
|
|
777
|
+
proj_power_cone(&(x[idx]), -k->p[i]);
|
|
778
|
+
} else {
|
|
779
|
+
/* primal power cone, using Moreau */
|
|
780
|
+
v[0] = -x[idx];
|
|
781
|
+
v[1] = -x[idx + 1];
|
|
782
|
+
v[2] = -x[idx + 2];
|
|
783
|
+
|
|
784
|
+
proj_power_cone(v, k->p[i]);
|
|
785
|
+
|
|
786
|
+
x[idx] += v[0];
|
|
787
|
+
x[idx + 1] += v[1];
|
|
788
|
+
x[idx + 2] += v[2];
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
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
|
+
}
|
|
797
|
+
/* project onto OTHER cones */
|
|
798
|
+
if (c) {
|
|
799
|
+
c->total_cone_time += SCS(tocq)(&cone_timer);
|
|
800
|
+
}
|
|
801
|
+
return 0;
|
|
802
|
+
}
|