scs 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +42 -13
- data/lib/scs/ffi.rb +1 -7
- data/lib/scs/matrix.rb +72 -0
- data/lib/scs/solver.rb +19 -26
- data/lib/scs/version.rb +1 -1
- data/lib/scs.rb +1 -0
- data/vendor/scs/CITATION.cff +1 -1
- data/vendor/scs/CMakeLists.txt +55 -7
- data/vendor/scs/Makefile +9 -9
- data/vendor/scs/README.md +4 -1
- data/vendor/scs/include/aa.h +1 -1
- data/vendor/scs/include/cones.h +17 -12
- data/vendor/scs/include/glbopts.h +27 -66
- data/vendor/scs/include/linalg.h +2 -1
- data/vendor/scs/include/linsys.h +13 -13
- data/vendor/scs/include/normalize.h +7 -5
- data/vendor/scs/include/rw.h +3 -3
- data/vendor/scs/include/scs.h +85 -106
- data/vendor/scs/include/scs_types.h +34 -0
- data/vendor/scs/include/scs_work.h +80 -0
- data/vendor/scs/include/util.h +3 -1
- data/vendor/scs/linsys/cpu/direct/private.c +86 -73
- data/vendor/scs/linsys/cpu/direct/private.h +2 -2
- data/vendor/scs/linsys/cpu/indirect/private.c +42 -33
- data/vendor/scs/linsys/cpu/indirect/private.h +1 -2
- data/vendor/scs/linsys/csparse.c +3 -3
- data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +9 -7
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +1 -1
- data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
- data/vendor/scs/linsys/gpu/gpu.h +8 -11
- data/vendor/scs/linsys/gpu/indirect/private.c +72 -49
- data/vendor/scs/linsys/gpu/indirect/private.h +14 -13
- data/vendor/scs/linsys/scs_matrix.c +55 -104
- data/vendor/scs/linsys/scs_matrix.h +5 -4
- data/vendor/scs/scs.mk +1 -5
- data/vendor/scs/src/aa.c +13 -8
- data/vendor/scs/src/cones.c +197 -108
- data/vendor/scs/src/linalg.c +25 -0
- data/vendor/scs/src/normalize.c +75 -26
- data/vendor/scs/src/rw.c +74 -30
- data/vendor/scs/src/scs.c +300 -264
- data/vendor/scs/src/scs_version.c +8 -6
- data/vendor/scs/src/util.c +27 -13
- data/vendor/scs/test/minunit.h +6 -1
- data/vendor/scs/test/problem_utils.h +28 -35
- data/vendor/scs/test/problems/degenerate.h +2 -1
- data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +6 -2
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +5 -4
- data/vendor/scs/test/problems/random_prob.h +6 -2
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +9 -2
- data/vendor/scs/test/problems/small_lp.h +7 -2
- data/vendor/scs/test/problems/small_qp.h +387 -0
- data/vendor/scs/test/problems/{test_fails.h → test_validation.h} +7 -4
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +4 -4
- data/vendor/scs/test/random_socp_prob.c +4 -2
- data/vendor/scs/test/run_from_file.c +16 -4
- data/vendor/scs/test/run_tests.c +23 -14
- metadata +10 -35
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
- data/vendor/scs/linsys/csparse.o +0 -0
- 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_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/qdldl.o +0 -0
- data/vendor/scs/linsys/scs_matrix.o +0 -0
- data/vendor/scs/src/aa.o +0 -0
- data/vendor/scs/src/cones.o +0 -0
- data/vendor/scs/src/ctrlc.o +0 -0
- data/vendor/scs/src/linalg.o +0 -0
- data/vendor/scs/src/normalize.o +0 -0
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.o +0 -0
- data/vendor/scs/src/scs_indir.o +0 -0
- data/vendor/scs/src/scs_version.o +0 -0
- data/vendor/scs/src/util.o +0 -0
data/vendor/scs/src/scs.c
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
#include "normalize.h"
|
8
8
|
#include "rw.h"
|
9
9
|
#include "scs_matrix.h"
|
10
|
+
#include "scs_work.h"
|
10
11
|
#include "util.h"
|
11
12
|
|
12
13
|
/* printing header */
|
@@ -39,24 +40,34 @@ static void free_work(ScsWork *w) {
|
|
39
40
|
scs_free(w->rsk);
|
40
41
|
scs_free(w->h);
|
41
42
|
scs_free(w->g);
|
42
|
-
scs_free(w->
|
43
|
-
scs_free(w->
|
44
|
-
scs_free(w->rho_y_vec);
|
43
|
+
scs_free(w->b_orig);
|
44
|
+
scs_free(w->c_orig);
|
45
45
|
scs_free(w->lin_sys_warm_start);
|
46
|
-
|
47
|
-
|
48
|
-
}
|
46
|
+
scs_free(w->diag_r);
|
47
|
+
SCS(free_sol)(w->xys_orig);
|
49
48
|
if (w->scal) {
|
50
49
|
scs_free(w->scal->D);
|
51
50
|
scs_free(w->scal->E);
|
52
51
|
scs_free(w->scal);
|
53
52
|
}
|
54
|
-
SCS(free_sol)(w->xys_orig);
|
55
53
|
free_residuals(w->r_orig);
|
56
|
-
if (w->stgs->normalize) {
|
54
|
+
if (w->stgs && w->stgs->normalize) {
|
57
55
|
SCS(free_sol)(w->xys_normalized);
|
58
56
|
free_residuals(w->r_normalized);
|
59
57
|
}
|
58
|
+
if (w->stgs) {
|
59
|
+
if (w->stgs->log_csv_filename)
|
60
|
+
scs_free((char *)w->stgs->log_csv_filename);
|
61
|
+
if (w->stgs->write_data_filename)
|
62
|
+
scs_free((char *)w->stgs->write_data_filename);
|
63
|
+
scs_free(w->stgs);
|
64
|
+
}
|
65
|
+
if (w->k) { /* deep copy */
|
66
|
+
SCS(free_cone)(w->k);
|
67
|
+
}
|
68
|
+
if (w->d) { /* deep copy */
|
69
|
+
SCS(free_data)(w->d);
|
70
|
+
}
|
60
71
|
scs_free(w);
|
61
72
|
}
|
62
73
|
}
|
@@ -78,7 +89,7 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
|
|
78
89
|
}
|
79
90
|
scs_printf("\n\t SCS v%s - Splitting Conic Solver\n\t(c) Brendan "
|
80
91
|
"O'Donoghue, Stanford University, 2012\n",
|
81
|
-
|
92
|
+
scs_version());
|
82
93
|
for (i = 0; i < LINE_LEN; ++i) {
|
83
94
|
scs_printf("-");
|
84
95
|
}
|
@@ -89,12 +100,11 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
|
|
89
100
|
scs_free(cone_str);
|
90
101
|
scs_printf("settings: eps_abs: %.1e, eps_rel: %.1e, eps_infeas: %.1e\n"
|
91
102
|
"\t alpha: %.2f, scale: %.2e, adaptive_scale: %i\n"
|
92
|
-
"\t max_iters: %i, normalize: %i,
|
93
|
-
/*, rho_x: %.2e\n", */
|
103
|
+
"\t max_iters: %i, normalize: %i, rho_x: %.2e\n",
|
94
104
|
stgs->eps_abs, stgs->eps_rel, stgs->eps_infeas, stgs->alpha,
|
95
105
|
stgs->scale, (int)stgs->adaptive_scale, (int)stgs->max_iters,
|
96
|
-
(int)stgs->normalize,
|
97
|
-
/*
|
106
|
+
(int)stgs->normalize, stgs->rho_x);
|
107
|
+
/* (int)stgs->warm_start); */
|
98
108
|
if (stgs->acceleration_lookback != 0) {
|
99
109
|
scs_printf("\t acceleration_lookback: %i, acceleration_interval: %i\n",
|
100
110
|
(int)acceleration_lookback, (int)acceleration_interval);
|
@@ -156,24 +166,31 @@ static scs_int failure(ScsWork *w, scs_int m, scs_int n, ScsSolution *sol,
|
|
156
166
|
return status;
|
157
167
|
}
|
158
168
|
|
169
|
+
static inline scs_int _is_nan(scs_float x) {
|
170
|
+
return x != x;
|
171
|
+
}
|
172
|
+
|
159
173
|
/* given x,y,s warm start, set v = [x; s / R + y; 1]
|
160
|
-
*
|
174
|
+
* check for nans and set to zero if present
|
161
175
|
*/
|
162
176
|
static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
|
163
|
-
scs_int n = w->n, m = w->m, i;
|
177
|
+
scs_int n = w->d->n, m = w->d->m, i;
|
164
178
|
scs_float *v = w->v;
|
165
179
|
/* normalize the warm-start */
|
166
180
|
if (w->stgs->normalize) {
|
167
|
-
SCS(normalize_sol)(w, sol);
|
181
|
+
SCS(normalize_sol)(w->scal, sol);
|
182
|
+
}
|
183
|
+
for (i = 0; i < n; ++i) {
|
184
|
+
v[i] = _is_nan(sol->x[i]) ? 0. : sol->x[i];
|
168
185
|
}
|
169
|
-
memcpy(v, sol->x, n * sizeof(scs_float));
|
170
186
|
for (i = 0; i < m; ++i) {
|
171
|
-
v[i + n] = sol->y[i] + sol->s[i] / w->
|
187
|
+
v[i + n] = sol->y[i] + sol->s[i] / w->diag_r[i + n];
|
188
|
+
v[i + n] = _is_nan(v[i + n]) ? 0. : v[i + n];
|
172
189
|
}
|
173
190
|
v[n + m] = 1.0; /* tau = 1 */
|
174
191
|
/* un-normalize so sol unchanged */
|
175
192
|
if (w->stgs->normalize) {
|
176
|
-
SCS(un_normalize_sol)(w, sol);
|
193
|
+
SCS(un_normalize_sol)(w->scal, sol);
|
177
194
|
}
|
178
195
|
}
|
179
196
|
|
@@ -202,12 +219,12 @@ static void unnormalize_residuals(ScsWork *w) {
|
|
202
219
|
r->tau = r_n->tau;
|
203
220
|
|
204
221
|
/* mem copy arrays */
|
205
|
-
memcpy(r->ax, r_n->ax, w->m * sizeof(scs_float));
|
206
|
-
memcpy(r->ax_s, r_n->ax_s, w->m * sizeof(scs_float));
|
207
|
-
memcpy(r->ax_s_btau, r_n->ax_s_btau, w->m * sizeof(scs_float));
|
208
|
-
memcpy(r->aty, r_n->aty, w->n * sizeof(scs_float));
|
209
|
-
memcpy(r->px, r_n->px, w->n * sizeof(scs_float));
|
210
|
-
memcpy(r->px_aty_ctau, r_n->px_aty_ctau, w->n * sizeof(scs_float));
|
222
|
+
memcpy(r->ax, r_n->ax, w->d->m * sizeof(scs_float));
|
223
|
+
memcpy(r->ax_s, r_n->ax_s, w->d->m * sizeof(scs_float));
|
224
|
+
memcpy(r->ax_s_btau, r_n->ax_s_btau, w->d->m * sizeof(scs_float));
|
225
|
+
memcpy(r->aty, r_n->aty, w->d->n * sizeof(scs_float));
|
226
|
+
memcpy(r->px, r_n->px, w->d->n * sizeof(scs_float));
|
227
|
+
memcpy(r->px_aty_ctau, r_n->px_aty_ctau, w->d->n * sizeof(scs_float));
|
211
228
|
|
212
229
|
/* unnormalize */
|
213
230
|
r->kap = r_n->kap / pd;
|
@@ -221,20 +238,20 @@ static void unnormalize_residuals(ScsWork *w) {
|
|
221
238
|
r->dobj = r_n->dobj / pd;
|
222
239
|
r->gap = r_n->gap / pd;
|
223
240
|
|
224
|
-
SCS(un_normalize_primal)(w, r->ax);
|
225
|
-
SCS(un_normalize_primal)(w, r->ax_s);
|
226
|
-
SCS(un_normalize_primal)(w, r->ax_s_btau);
|
227
|
-
SCS(un_normalize_dual)(w, r->aty);
|
228
|
-
SCS(un_normalize_dual)(w, r->px);
|
229
|
-
SCS(un_normalize_dual)(w, r->px_aty_ctau);
|
241
|
+
SCS(un_normalize_primal)(w->scal, r->ax);
|
242
|
+
SCS(un_normalize_primal)(w->scal, r->ax_s);
|
243
|
+
SCS(un_normalize_primal)(w->scal, r->ax_s_btau);
|
244
|
+
SCS(un_normalize_dual)(w->scal, r->aty);
|
245
|
+
SCS(un_normalize_dual)(w->scal, r->px);
|
246
|
+
SCS(un_normalize_dual)(w->scal, r->px_aty_ctau);
|
230
247
|
|
231
|
-
compute_residuals(r, w->m, w->n);
|
248
|
+
compute_residuals(r, w->d->m, w->d->n);
|
232
249
|
}
|
233
250
|
|
234
251
|
/* calculates un-normalized residual quantities */
|
235
252
|
/* this is somewhat slow but not a bottleneck */
|
236
253
|
static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
237
|
-
scs_int n = w->n, m = w->m;
|
254
|
+
scs_int n = w->d->n, m = w->d->m;
|
238
255
|
/* normalized x,y,s terms */
|
239
256
|
scs_float *x = w->xys_normalized->x;
|
240
257
|
scs_float *y = w->xys_normalized->y;
|
@@ -257,7 +274,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
257
274
|
/**************** PRIMAL *********************/
|
258
275
|
memset(r->ax, 0, m * sizeof(scs_float));
|
259
276
|
/* ax = Ax */
|
260
|
-
SCS(accum_by_a)(w->A, x, r->ax);
|
277
|
+
SCS(accum_by_a)(w->d->A, x, r->ax);
|
261
278
|
|
262
279
|
memcpy(r->ax_s, r->ax, m * sizeof(scs_float));
|
263
280
|
/* ax_s = Ax + s */
|
@@ -265,13 +282,13 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
265
282
|
|
266
283
|
memcpy(r->ax_s_btau, r->ax_s, m * sizeof(scs_float));
|
267
284
|
/* ax_s_btau = Ax + s - b * tau */
|
268
|
-
SCS(add_scaled_array)(r->ax_s_btau, w->
|
285
|
+
SCS(add_scaled_array)(r->ax_s_btau, w->d->b, m, -r->tau);
|
269
286
|
|
270
287
|
/**************** DUAL *********************/
|
271
288
|
memset(r->px, 0, n * sizeof(scs_float));
|
272
|
-
if (w->P) {
|
289
|
+
if (w->d->P) {
|
273
290
|
/* px = Px */
|
274
|
-
SCS(accum_by_p)(w->P, x, r->px);
|
291
|
+
SCS(accum_by_p)(w->d->P, x, r->px);
|
275
292
|
r->xt_p_x_tau = SCS(dot)(r->px, x, n);
|
276
293
|
} else {
|
277
294
|
r->xt_p_x_tau = 0.;
|
@@ -279,18 +296,18 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
279
296
|
|
280
297
|
memset(r->aty, 0, n * sizeof(scs_float));
|
281
298
|
/* aty = A'y */
|
282
|
-
SCS(accum_by_atrans)(w->A, y, r->aty);
|
299
|
+
SCS(accum_by_atrans)(w->d->A, y, r->aty);
|
283
300
|
|
284
301
|
/* r->px_aty_ctau = Px */
|
285
302
|
memcpy(r->px_aty_ctau, r->px, n * sizeof(scs_float));
|
286
303
|
/* r->px_aty_ctau = Px + A'y */
|
287
304
|
SCS(add_scaled_array)(r->px_aty_ctau, r->aty, n, 1.);
|
288
305
|
/* r->px_aty_ctau = Px + A'y + c * tau */
|
289
|
-
SCS(add_scaled_array)(r->px_aty_ctau, w->
|
306
|
+
SCS(add_scaled_array)(r->px_aty_ctau, w->d->c, n, r->tau);
|
290
307
|
|
291
308
|
/**************** OTHERS *****************/
|
292
|
-
r->bty_tau = SCS(dot)(y, w->
|
293
|
-
r->ctx_tau = SCS(dot)(x, w->
|
309
|
+
r->bty_tau = SCS(dot)(y, w->d->b, m);
|
310
|
+
r->ctx_tau = SCS(dot)(x, w->d->c, n);
|
294
311
|
|
295
312
|
r->bty = SAFEDIV_POS(r->bty_tau, r->tau);
|
296
313
|
r->ctx = SAFEDIV_POS(r->ctx_tau, r->tau);
|
@@ -306,58 +323,45 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
306
323
|
memcpy(w->xys_orig->x, w->xys_normalized->x, n * sizeof(scs_float));
|
307
324
|
memcpy(w->xys_orig->y, w->xys_normalized->y, m * sizeof(scs_float));
|
308
325
|
memcpy(w->xys_orig->s, w->xys_normalized->s, m * sizeof(scs_float));
|
309
|
-
SCS(un_normalize_sol)(w, w->xys_orig);
|
326
|
+
SCS(un_normalize_sol)(w->scal, w->xys_orig);
|
310
327
|
unnormalize_residuals(w);
|
311
328
|
}
|
312
329
|
}
|
313
330
|
|
314
331
|
static void cold_start_vars(ScsWork *w) {
|
315
|
-
scs_int l = w->n + w->m + 1;
|
332
|
+
scs_int l = w->d->n + w->d->m + 1;
|
316
333
|
memset(w->v, 0, l * sizeof(scs_float));
|
317
334
|
w->v[l - 1] = 1.;
|
318
335
|
}
|
319
336
|
|
320
|
-
/* utility function that
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
const scs_float *y) {
|
325
|
-
scs_int i, n = w->n, len = w->n + w->m;
|
337
|
+
/* utility function that computes x'Ry */
|
338
|
+
static inline scs_float dot_r(ScsWork *w, const scs_float *x,
|
339
|
+
const scs_float *y) {
|
340
|
+
scs_int i;
|
326
341
|
scs_float ip = 0.0;
|
327
|
-
for (i = 0; i < n; ++i) {
|
328
|
-
ip +=
|
329
|
-
}
|
330
|
-
for (i = n; i < len; ++i) {
|
331
|
-
ip += x[i] * y[i] * w->rho_y_vec[i - n];
|
342
|
+
for (i = 0; i < w->d->n + w->d->m; ++i) {
|
343
|
+
ip += x[i] * y[i] * w->diag_r[i];
|
332
344
|
}
|
333
345
|
return ip;
|
334
346
|
}
|
335
347
|
|
336
|
-
static inline scs_float get_tau_scale(ScsWork *w) {
|
337
|
-
return TAU_FACTOR; /* TAU_FACTOR * w->scale; */
|
338
|
-
}
|
339
|
-
|
340
348
|
static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
|
341
349
|
scs_float eta) {
|
342
|
-
scs_float b, c,
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
c = dot_with_diag_scaling(w, p, p) - dot_with_diag_scaling(w, p, mu);
|
348
|
-
tau = (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
|
349
|
-
return tau;
|
350
|
+
scs_float a, b, c, tau_scale = w->diag_r[w->d->n + w->d->m];
|
351
|
+
a = tau_scale + dot_r(w, w->g, w->g);
|
352
|
+
b = dot_r(w, mu, w->g) - 2 * dot_r(w, p, w->g) - eta * tau_scale;
|
353
|
+
c = dot_r(w, p, p) - dot_r(w, p, mu);
|
354
|
+
return (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
|
350
355
|
}
|
351
356
|
|
352
357
|
/* status < 0 indicates failure */
|
353
358
|
static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
354
|
-
scs_int n = w->n, m = w->m, l = n + m + 1, status, i;
|
359
|
+
scs_int n = w->d->n, m = w->d->m, l = n + m + 1, status, i;
|
355
360
|
scs_float *warm_start = SCS_NULL;
|
356
|
-
scs_float tol = -1.0; /* only used for indirect methods,
|
361
|
+
scs_float tol = -1.0; /* only used for indirect methods, overridden later */
|
357
362
|
memcpy(w->u_t, w->v, l * sizeof(scs_float));
|
358
|
-
|
359
|
-
|
360
|
-
w->u_t[i] *= -w->rho_y_vec[i - n];
|
363
|
+
for (i = 0; i < l - 1; ++i) {
|
364
|
+
w->u_t[i] *= (i < n ? 1 : -1) * w->diag_r[i];
|
361
365
|
}
|
362
366
|
#if INDIRECT > 0
|
363
367
|
/* compute warm start using the cone projection output */
|
@@ -366,12 +370,12 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
|
366
370
|
/* warm_start = u[:n] + tau * g[:n] */
|
367
371
|
SCS(add_scaled_array)(warm_start, w->g, l - 1, w->u[l - 1]);
|
368
372
|
/* use normalized residuals to compute tolerance */
|
369
|
-
tol = MIN(CG_NORM(w->r_normalized->ax_s_btau, w->m),
|
370
|
-
CG_NORM(w->r_normalized->px_aty_ctau, w->n));
|
373
|
+
tol = MIN(CG_NORM(w->r_normalized->ax_s_btau, w->d->m),
|
374
|
+
CG_NORM(w->r_normalized->px_aty_ctau, w->d->n));
|
371
375
|
/* tol ~ O(1/k^(1+eps)) guarantees convergence */
|
372
376
|
/* use warm-start to calculate tolerance rather than w->u_t, since warm_start
|
373
377
|
* should be approximately equal to the true solution */
|
374
|
-
tol = CG_TOL_FACTOR * MIN(tol, CG_NORM(warm_start, w->n) /
|
378
|
+
tol = CG_TOL_FACTOR * MIN(tol, CG_NORM(warm_start, w->d->n) /
|
375
379
|
POWF((scs_float)iter + 1, CG_RATE));
|
376
380
|
tol = MAX(CG_BEST_TOL, tol);
|
377
381
|
#endif
|
@@ -394,40 +398,28 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
|
394
398
|
* (no effect of w->stgs->alpha here).
|
395
399
|
*/
|
396
400
|
static void compute_rsk(ScsWork *w) {
|
397
|
-
scs_int i, l = w->m + w->n + 1;
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
w->rsk[i] = w->stgs->rho_x * (w->v[i] + w->u[i] - 2 * w->u_t[i]);
|
402
|
-
}
|
403
|
-
*/
|
404
|
-
/* s */
|
405
|
-
for (i = w->n; i < l - 1; ++i) {
|
406
|
-
w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->rho_y_vec[i - w->n];
|
407
|
-
}
|
408
|
-
/* kappa, incorporates tau scaling parameter */
|
409
|
-
w->rsk[l - 1] =
|
410
|
-
get_tau_scale(w) * (w->v[l - 1] + w->u[l - 1] - 2 * w->u_t[l - 1]);
|
401
|
+
scs_int i, l = w->d->m + w->d->n + 1;
|
402
|
+
for (i = 0; i < l; ++i) {
|
403
|
+
w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->diag_r[i];
|
404
|
+
}
|
411
405
|
}
|
412
406
|
|
413
407
|
static void update_dual_vars(ScsWork *w) {
|
414
|
-
scs_int i, l = w->n + w->m + 1;
|
415
|
-
scs_float a = w->stgs->alpha;
|
416
|
-
/* compute and store [r;s;kappa] */
|
417
|
-
compute_rsk(w);
|
408
|
+
scs_int i, l = w->d->n + w->d->m + 1;
|
418
409
|
for (i = 0; i < l; ++i) {
|
419
|
-
w->v[i] +=
|
410
|
+
w->v[i] += w->stgs->alpha * (w->u[i] - w->u_t[i]);
|
420
411
|
}
|
421
412
|
}
|
422
413
|
|
423
414
|
/* status < 0 indicates failure */
|
424
415
|
static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
|
425
|
-
scs_int i, n = w->n, l = w->n + w->m + 1, status;
|
416
|
+
scs_int i, n = w->d->n, l = w->d->n + w->d->m + 1, status;
|
426
417
|
for (i = 0; i < l; ++i) {
|
427
418
|
w->u[i] = 2 * w->u_t[i] - w->v[i];
|
428
419
|
}
|
429
420
|
/* u = [x;y;tau] */
|
430
|
-
status =
|
421
|
+
status =
|
422
|
+
SCS(proj_dual_cone)(&(w->u[n]), w->cone_work, w->scal, &(w->diag_r[n]));
|
431
423
|
if (iter < FEASIBLE_ITERS) {
|
432
424
|
w->u[l - 1] = 1.0;
|
433
425
|
} else {
|
@@ -438,30 +430,30 @@ static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
438
430
|
|
439
431
|
static void sety(const ScsWork *w, ScsSolution *sol) {
|
440
432
|
if (!sol->y) {
|
441
|
-
sol->y = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
|
433
|
+
sol->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
442
434
|
}
|
443
|
-
memcpy(sol->y, &(w->u[w->n]), w->m * sizeof(scs_float));
|
435
|
+
memcpy(sol->y, &(w->u[w->d->n]), w->d->m * sizeof(scs_float));
|
444
436
|
}
|
445
437
|
|
446
438
|
/* s is contained in rsk */
|
447
439
|
static void sets(const ScsWork *w, ScsSolution *sol) {
|
448
440
|
if (!sol->s) {
|
449
|
-
sol->s = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
|
441
|
+
sol->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
450
442
|
}
|
451
|
-
memcpy(sol->s, &(w->rsk[w->n]), w->m * sizeof(scs_float));
|
443
|
+
memcpy(sol->s, &(w->rsk[w->d->n]), w->d->m * sizeof(scs_float));
|
452
444
|
}
|
453
445
|
|
454
446
|
static void setx(const ScsWork *w, ScsSolution *sol) {
|
455
447
|
if (!sol->x) {
|
456
|
-
sol->x = (scs_float *)scs_calloc(w->n, sizeof(scs_float));
|
448
|
+
sol->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
457
449
|
}
|
458
|
-
memcpy(sol->x, w->u, w->n * sizeof(scs_float));
|
450
|
+
memcpy(sol->x, w->u, w->d->n * sizeof(scs_float));
|
459
451
|
}
|
460
452
|
|
461
453
|
static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
462
|
-
SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->n);
|
463
|
-
SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
|
464
|
-
SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
|
454
|
+
SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->n);
|
455
|
+
SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->m);
|
456
|
+
SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->m);
|
465
457
|
info->gap = w->r_orig->gap;
|
466
458
|
info->res_pri = w->r_orig->res_pri;
|
467
459
|
info->res_dual = w->r_orig->res_dual;
|
@@ -472,9 +464,9 @@ static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
472
464
|
}
|
473
465
|
|
474
466
|
static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
475
|
-
SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->m);
|
476
|
-
SCS(scale_array)(sol->x, NAN, w->n);
|
477
|
-
SCS(scale_array)(sol->s, NAN, w->m);
|
467
|
+
SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->d->m);
|
468
|
+
SCS(scale_array)(sol->x, NAN, w->d->n);
|
469
|
+
SCS(scale_array)(sol->s, NAN, w->d->m);
|
478
470
|
info->gap = NAN;
|
479
471
|
info->res_pri = NAN;
|
480
472
|
info->res_dual = NAN;
|
@@ -485,9 +477,9 @@ static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
485
477
|
}
|
486
478
|
|
487
479
|
static void set_unbounded(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
488
|
-
SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->n);
|
489
|
-
SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->m);
|
490
|
-
SCS(scale_array)(sol->y, NAN, w->m);
|
480
|
+
SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->d->n);
|
481
|
+
SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->d->m);
|
482
|
+
SCS(scale_array)(sol->y, NAN, w->d->m);
|
491
483
|
info->gap = NAN;
|
492
484
|
info->res_pri = NAN;
|
493
485
|
info->res_dual = NAN;
|
@@ -526,7 +518,7 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
|
526
518
|
sety(w, sol);
|
527
519
|
sets(w, sol);
|
528
520
|
if (w->stgs->normalize) {
|
529
|
-
SCS(un_normalize_sol)(w, sol);
|
521
|
+
SCS(un_normalize_sol)(w->scal, sol);
|
530
522
|
}
|
531
523
|
populate_residual_struct(w, iter);
|
532
524
|
info->setup_time = w->setup_time;
|
@@ -534,13 +526,13 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
|
534
526
|
info->res_infeas = w->r_orig->res_infeas;
|
535
527
|
info->res_unbdd_a = w->r_orig->res_unbdd_a;
|
536
528
|
info->res_unbdd_p = w->r_orig->res_unbdd_p;
|
537
|
-
info->scale = w->scale;
|
529
|
+
info->scale = w->stgs->scale;
|
538
530
|
info->scale_updates = w->scale_updates;
|
539
531
|
info->rejected_accel_steps = w->rejected_accel_steps;
|
540
532
|
info->accepted_accel_steps = w->accepted_accel_steps;
|
541
|
-
info->comp_slack = ABS(SCS(dot)(sol->s, sol->y, w->m));
|
542
|
-
if (info->comp_slack >
|
543
|
-
|
533
|
+
info->comp_slack = ABS(SCS(dot)(sol->s, sol->y, w->d->m));
|
534
|
+
if (info->comp_slack > 1e-5 * MAX(SCS(norm_inf)(sol->s, w->d->m),
|
535
|
+
SCS(norm_inf)(sol->y, w->d->m))) {
|
544
536
|
scs_printf("WARNING - large complementary slackness residual: %f\n",
|
545
537
|
info->comp_slack);
|
546
538
|
}
|
@@ -570,22 +562,23 @@ static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
|
|
570
562
|
scs_printf("%*.2e ", (int)HSPACE, r->gap);
|
571
563
|
/* report mid point of primal and dual objective values */
|
572
564
|
scs_printf("%*.2e ", (int)HSPACE, 0.5 * (r->pobj + r->dobj));
|
573
|
-
scs_printf("%*.2e ", (int)HSPACE, w->scale);
|
565
|
+
scs_printf("%*.2e ", (int)HSPACE, w->stgs->scale);
|
574
566
|
scs_printf("%*.2e ", (int)HSPACE, SCS(tocq)(solve_timer) / 1e3);
|
575
567
|
scs_printf("\n");
|
576
568
|
|
577
569
|
#if VERBOSITY > 0
|
578
|
-
scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->n + w->m + 1));
|
579
|
-
scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->n + w->m + 1));
|
580
|
-
scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->n + w->m + 1));
|
581
|
-
scs_printf("Norm
|
582
|
-
scs_printf("Norm
|
583
|
-
scs_printf("Norm
|
584
|
-
scs_printf("Norm
|
585
|
-
scs_printf("
|
586
|
-
scs_printf("
|
570
|
+
scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->d->n + w->d->m + 1));
|
571
|
+
scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->d->n + w->d->m + 1));
|
572
|
+
scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->d->n + w->d->m + 1));
|
573
|
+
scs_printf("Norm rsk = %4f, ", SCS(norm_2)(w->rsk, w->d->n + w->d->m + 1));
|
574
|
+
scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->d->n));
|
575
|
+
scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->d->m));
|
576
|
+
scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->d->m));
|
577
|
+
scs_printf("Norm |Ax + s| = %1.2e, ", SCS(norm_2)(r->ax_s, w->d->m));
|
578
|
+
scs_printf("tau = %4f, ", w->u[w->d->n + w->d->m]);
|
579
|
+
scs_printf("kappa = %4f, ", w->rsk[w->d->n + w->d->m]);
|
587
580
|
scs_printf("|u - u_t| = %1.2e, ",
|
588
|
-
SCS(norm_diff)(w->u, w->u_t, w->n + w->m + 1));
|
581
|
+
SCS(norm_diff)(w->u, w->u_t, w->d->n + w->d->m + 1));
|
589
582
|
scs_printf("res_infeas = %1.2e, ", r->res_infeas);
|
590
583
|
scs_printf("res_unbdd_a = %1.2e, ", r->res_unbdd_a);
|
591
584
|
scs_printf("res_unbdd_p = %1.2e, ", r->res_unbdd_p);
|
@@ -670,10 +663,11 @@ static scs_int has_converged(ScsWork *w, scs_int iter) {
|
|
670
663
|
/* xt_p_x, ctx, bty already have tau divided out */
|
671
664
|
grl = MAX(MAX(ABS(r->xt_p_x), ABS(r->ctx)), ABS(r->bty));
|
672
665
|
/* s, ax, px, aty do *not* have tau divided out, so need to divide */
|
673
|
-
prl = MAX(MAX(NORM(b, w->m) * r->tau, NORM(s, w->m)),
|
666
|
+
prl = MAX(MAX(NORM(b, w->d->m) * r->tau, NORM(s, w->d->m)),
|
667
|
+
NORM(r->ax, w->d->m)) /
|
674
668
|
r->tau;
|
675
|
-
drl = MAX(MAX(NORM(c, w->n) * r->tau, NORM(r->px, w->n)),
|
676
|
-
NORM(r->aty, w->n)) /
|
669
|
+
drl = MAX(MAX(NORM(c, w->d->n) * r->tau, NORM(r->px, w->d->n)),
|
670
|
+
NORM(r->aty, w->d->n)) /
|
677
671
|
r->tau;
|
678
672
|
if (isless(r->res_pri, eps_abs + eps_rel * prl) &&
|
679
673
|
isless(r->res_dual, eps_abs + eps_rel * drl) &&
|
@@ -739,13 +733,16 @@ static scs_int validate(const ScsData *d, const ScsCone *k,
|
|
739
733
|
scs_printf("scale must be positive (1 works well).\n");
|
740
734
|
return -1;
|
741
735
|
}
|
736
|
+
if (stgs->acceleration_interval <= 0) {
|
737
|
+
scs_printf("acceleration_interval must be positive (10 works well).\n");
|
738
|
+
return -1;
|
739
|
+
}
|
742
740
|
return 0;
|
743
741
|
}
|
744
742
|
#endif
|
745
743
|
|
746
744
|
static ScsResiduals *init_residuals(const ScsData *d) {
|
747
745
|
ScsResiduals *r = (ScsResiduals *)scs_calloc(1, sizeof(ScsResiduals));
|
748
|
-
r->last_iter = -1;
|
749
746
|
r->ax = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
750
747
|
r->ax_s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
751
748
|
r->ax_s_btau = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
@@ -755,6 +752,46 @@ static ScsResiduals *init_residuals(const ScsData *d) {
|
|
755
752
|
return r;
|
756
753
|
}
|
757
754
|
|
755
|
+
scs_int scs_update(ScsWork *w, scs_float *b, scs_float *c) {
|
756
|
+
SCS(timer) update_timer;
|
757
|
+
SCS(tic)(&update_timer);
|
758
|
+
|
759
|
+
if (b) {
|
760
|
+
memcpy(w->b_orig, b, w->d->m * sizeof(scs_float));
|
761
|
+
memcpy(w->d->b, b, w->d->m * sizeof(scs_float));
|
762
|
+
} else {
|
763
|
+
memcpy(w->d->b, w->b_orig, w->d->m * sizeof(scs_float));
|
764
|
+
}
|
765
|
+
if (c) {
|
766
|
+
memcpy(w->c_orig, c, w->d->n * sizeof(scs_float));
|
767
|
+
memcpy(w->d->c, c, w->d->n * sizeof(scs_float));
|
768
|
+
} else {
|
769
|
+
memcpy(w->d->c, w->c_orig, w->d->n * sizeof(scs_float));
|
770
|
+
}
|
771
|
+
|
772
|
+
/* normalize */
|
773
|
+
if (w->scal) {
|
774
|
+
SCS(normalize_b_c)(w->scal, w->d->b, w->d->c);
|
775
|
+
}
|
776
|
+
|
777
|
+
/* override setup time with update time, since the update is the 'setup' */
|
778
|
+
w->setup_time = SCS(tocq)(&update_timer);
|
779
|
+
return 0;
|
780
|
+
}
|
781
|
+
|
782
|
+
/* Sets the diag_r vector, given the scale parameters in work */
|
783
|
+
static void set_diag_r(ScsWork *w) {
|
784
|
+
scs_int i;
|
785
|
+
for (i = 0; i < w->d->n; ++i) {
|
786
|
+
w->diag_r[i] = w->stgs->rho_x;
|
787
|
+
}
|
788
|
+
/* use cone information to set R_y */
|
789
|
+
SCS(set_r_y)(w->cone_work, w->stgs->scale, &(w->diag_r[w->d->n]));
|
790
|
+
/* if modified need to SCS(enforce_cone_boundaries)(...) */
|
791
|
+
w->diag_r[w->d->n + w->d->m] =
|
792
|
+
TAU_FACTOR; /* TODO: is this the best choice? */
|
793
|
+
}
|
794
|
+
|
758
795
|
static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
759
796
|
const ScsSettings *stgs) {
|
760
797
|
ScsWork *w = (ScsWork *)scs_calloc(1, sizeof(ScsWork));
|
@@ -766,18 +803,21 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
766
803
|
scs_printf("ERROR: allocating work failure\n");
|
767
804
|
return SCS_NULL;
|
768
805
|
}
|
769
|
-
/*
|
770
|
-
w->d =
|
771
|
-
w->
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
w->
|
776
|
-
w->
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
w->
|
806
|
+
/* deep copy data */
|
807
|
+
w->d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
808
|
+
SCS(deep_copy_data)(w->d, d);
|
809
|
+
d = SCS_NULL; /* for safety */
|
810
|
+
|
811
|
+
/* deep copy cone */
|
812
|
+
w->k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
813
|
+
SCS(deep_copy_cone)(w->k, k);
|
814
|
+
k = SCS_NULL; /* for safety */
|
815
|
+
|
816
|
+
/* deep copy settings */
|
817
|
+
w->stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
818
|
+
SCS(deep_copy_stgs)(w->stgs, stgs);
|
819
|
+
stgs = SCS_NULL; /* for safety */
|
820
|
+
|
781
821
|
/* allocate workspace: */
|
782
822
|
w->u = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
783
823
|
w->u_t = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
@@ -787,72 +827,47 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
787
827
|
w->h = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
788
828
|
w->g = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
789
829
|
w->lin_sys_warm_start = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
790
|
-
w->
|
830
|
+
w->diag_r = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
791
831
|
/* x,y,s struct */
|
792
832
|
w->xys_orig = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
793
|
-
w->xys_orig->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
794
|
-
w->xys_orig->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
795
|
-
w->xys_orig->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
796
|
-
w->r_orig = init_residuals(d);
|
797
|
-
|
798
|
-
w->
|
799
|
-
|
800
|
-
|
801
|
-
w->b_orig = d->b;
|
802
|
-
w->c_orig = d->c;
|
803
|
-
w->b_normalized = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
804
|
-
w->c_normalized = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
805
|
-
memcpy(w->b_normalized, w->b_orig, w->m * sizeof(scs_float));
|
806
|
-
memcpy(w->c_normalized, w->c_orig, w->n * sizeof(scs_float));
|
807
|
-
SCS(set_rho_y_vec)(k, w->scale, w->rho_y_vec, w->m);
|
808
|
-
|
809
|
-
if (!w->c_normalized) {
|
833
|
+
w->xys_orig->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
834
|
+
w->xys_orig->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
835
|
+
w->xys_orig->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
836
|
+
w->r_orig = init_residuals(w->d);
|
837
|
+
w->b_orig = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
838
|
+
w->c_orig = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
839
|
+
|
840
|
+
if (!w->c_orig) {
|
810
841
|
scs_printf("ERROR: work memory allocation failure\n");
|
811
842
|
return SCS_NULL;
|
812
843
|
}
|
813
844
|
|
845
|
+
if (!(w->cone_work = SCS(init_cone)(w->k, w->d->m))) {
|
846
|
+
scs_printf("ERROR: init_cone failure\n");
|
847
|
+
return SCS_NULL;
|
848
|
+
}
|
849
|
+
set_diag_r(w);
|
850
|
+
|
814
851
|
if (w->stgs->normalize) {
|
815
852
|
w->xys_normalized = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
816
|
-
w->xys_normalized->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
817
|
-
w->xys_normalized->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
818
|
-
w->xys_normalized->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
819
|
-
w->r_normalized = init_residuals(d);
|
820
|
-
|
821
|
-
#ifdef COPYAMATRIX
|
822
|
-
if (!SCS(copy_matrix)(&(w->A), d->A)) {
|
823
|
-
scs_printf("ERROR: copy A matrix failed\n");
|
824
|
-
return SCS_NULL;
|
825
|
-
}
|
826
|
-
if (w->P && !SCS(copy_matrix)(&(w->P), d->P)) {
|
827
|
-
scs_printf("ERROR: copy P matrix failed\n");
|
828
|
-
return SCS_NULL;
|
829
|
-
}
|
830
|
-
#endif
|
853
|
+
w->xys_normalized->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
854
|
+
w->xys_normalized->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
855
|
+
w->xys_normalized->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
856
|
+
w->r_normalized = init_residuals(w->d);
|
831
857
|
/* this allocates memory that must be freed */
|
832
|
-
w->
|
833
|
-
w->scal = (ScsScaling *)scs_calloc(1, sizeof(ScsScaling));
|
834
|
-
SCS(normalize)
|
835
|
-
(w->P, w->A, w->b_normalized, w->c_normalized, w->scal, w->cone_boundaries,
|
836
|
-
w->cone_boundaries_len);
|
858
|
+
w->scal = SCS(normalize_a_p)(w->d->P, w->d->A, w->cone_work);
|
837
859
|
} else {
|
838
860
|
w->xys_normalized = w->xys_orig;
|
839
861
|
w->r_normalized = w->r_orig;
|
840
|
-
w->cone_boundaries_len = 0;
|
841
|
-
w->cone_boundaries = SCS_NULL;
|
842
862
|
w->scal = SCS_NULL;
|
843
863
|
}
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
if (!(w->p =
|
849
|
-
SCS(init_lin_sys_work)(w->A, w->P, w->rho_y_vec, w->stgs->rho_x))) {
|
864
|
+
/* set w->*_orig and performs normalization if appropriate */
|
865
|
+
scs_update(w, w->d->b, w->d->c);
|
866
|
+
|
867
|
+
if (!(w->p = SCS(init_lin_sys_work)(w->d->A, w->d->P, w->diag_r))) {
|
850
868
|
scs_printf("ERROR: init_lin_sys_work failure\n");
|
851
869
|
return SCS_NULL;
|
852
870
|
}
|
853
|
-
/* Acceleration */
|
854
|
-
w->rejected_accel_steps = 0;
|
855
|
-
w->accepted_accel_steps = 0;
|
856
871
|
if (w->stgs->acceleration_lookback) {
|
857
872
|
/* TODO(HACK!) negative acceleration_lookback interpreted as type-II */
|
858
873
|
if (!(w->accel = aa_init(l, ABS(w->stgs->acceleration_lookback),
|
@@ -874,16 +889,31 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
874
889
|
|
875
890
|
static void update_work_cache(ScsWork *w) {
|
876
891
|
/* g = (I + M)^{-1} h */
|
877
|
-
memcpy(w->g, w->h, (w->n + w->m) * sizeof(scs_float));
|
878
|
-
SCS(scale_array)(&(w->g[w->n]), -1., w->m);
|
892
|
+
memcpy(w->g, w->h, (w->d->n + w->d->m) * sizeof(scs_float));
|
893
|
+
SCS(scale_array)(&(w->g[w->d->n]), -1., w->d->m);
|
879
894
|
SCS(solve_lin_sys)(w->p, w->g, SCS_NULL, CG_BEST_TOL);
|
880
895
|
return;
|
881
896
|
}
|
882
897
|
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
898
|
+
/* Reset quantities specific to current solve */
|
899
|
+
static void reset_tracking(ScsWork *w) {
|
900
|
+
w->last_scale_update_iter = 0;
|
901
|
+
w->sum_log_scale_factor = 0.;
|
902
|
+
w->n_log_scale_factor = 0;
|
903
|
+
w->scale_updates = 0;
|
904
|
+
w->time_limit_reached = 0;
|
905
|
+
/* Acceleration */
|
906
|
+
w->rejected_accel_steps = 0;
|
907
|
+
w->accepted_accel_steps = 0;
|
908
|
+
w->aa_norm = 0.;
|
909
|
+
/* Need this to force residual calc if previous solve solved at iter 0 */
|
910
|
+
w->r_normalized->last_iter = -1;
|
911
|
+
w->r_orig->last_iter = -1;
|
912
|
+
}
|
913
|
+
|
914
|
+
static scs_int update_work(ScsWork *w, ScsSolution *sol) {
|
915
|
+
reset_tracking(w);
|
916
|
+
|
887
917
|
if (w->stgs->warm_start) {
|
888
918
|
warm_start_vars(w, sol);
|
889
919
|
} else {
|
@@ -891,18 +921,18 @@ static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
|
|
891
921
|
}
|
892
922
|
|
893
923
|
/* h = [c;b] */
|
894
|
-
memcpy(w->h, w->
|
895
|
-
memcpy(&(w->h[n]), w->
|
924
|
+
memcpy(w->h, w->d->c, w->d->n * sizeof(scs_float));
|
925
|
+
memcpy(&(w->h[w->d->n]), w->d->b, w->d->m * sizeof(scs_float));
|
896
926
|
update_work_cache(w);
|
897
927
|
return 0;
|
898
928
|
}
|
899
929
|
|
900
930
|
/* will update if the factor is outside of range */
|
901
|
-
scs_int
|
931
|
+
scs_int should_update_r(scs_float factor, scs_int iter) {
|
902
932
|
return (factor > SQRTF(10.) || factor < 1. / SQRTF(10.));
|
903
933
|
}
|
904
934
|
|
905
|
-
static void
|
935
|
+
static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
906
936
|
scs_int i;
|
907
937
|
scs_float factor, new_scale;
|
908
938
|
|
@@ -913,15 +943,15 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
913
943
|
|
914
944
|
scs_int iters_since_last_update = iter - w->last_scale_update_iter;
|
915
945
|
/* ||Ax + s - b * tau|| */
|
916
|
-
scs_float relative_res_pri =
|
917
|
-
|
918
|
-
|
919
|
-
|
946
|
+
scs_float relative_res_pri = SAFEDIV_POS(
|
947
|
+
SCALE_NORM(r->ax_s_btau, w->d->m),
|
948
|
+
MAX(MAX(SCALE_NORM(r->ax, w->d->m), SCALE_NORM(xys->s, w->d->m)),
|
949
|
+
SCALE_NORM(b, w->d->m) * r->tau));
|
920
950
|
/* ||Px + A'y + c * tau|| */
|
921
|
-
scs_float relative_res_dual =
|
922
|
-
|
923
|
-
|
924
|
-
|
951
|
+
scs_float relative_res_dual = SAFEDIV_POS(
|
952
|
+
SCALE_NORM(r->px_aty_ctau, w->d->n),
|
953
|
+
MAX(MAX(SCALE_NORM(r->px, w->d->n), SCALE_NORM(r->aty, w->d->n)),
|
954
|
+
SCALE_NORM(c, w->d->n) * r->tau));
|
925
955
|
|
926
956
|
/* higher scale makes res_pri go down faster, so increase if res_pri larger */
|
927
957
|
w->sum_log_scale_factor += log(relative_res_pri) - log(relative_res_dual);
|
@@ -935,18 +965,23 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
935
965
|
if (iters_since_last_update < RESCALING_MIN_ITERS) {
|
936
966
|
return;
|
937
967
|
}
|
938
|
-
new_scale =
|
939
|
-
|
968
|
+
new_scale =
|
969
|
+
MIN(MAX(w->stgs->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
|
970
|
+
if (new_scale == w->stgs->scale) {
|
940
971
|
return;
|
941
972
|
}
|
942
|
-
if (
|
973
|
+
if (should_update_r(factor, iters_since_last_update)) {
|
943
974
|
w->scale_updates++;
|
944
975
|
w->sum_log_scale_factor = 0;
|
945
976
|
w->n_log_scale_factor = 0;
|
946
977
|
w->last_scale_update_iter = iter;
|
947
|
-
w->scale = new_scale;
|
948
|
-
|
949
|
-
|
978
|
+
w->stgs->scale = new_scale;
|
979
|
+
|
980
|
+
/* update diag r vector */
|
981
|
+
set_diag_r(w);
|
982
|
+
|
983
|
+
/* update linear systems */
|
984
|
+
SCS(update_lin_sys_diag_r)(w->p, w->diag_r);
|
950
985
|
|
951
986
|
/* update pre-solved quantities */
|
952
987
|
update_work_cache(w);
|
@@ -956,10 +991,11 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
956
991
|
aa_reset(w->accel);
|
957
992
|
}
|
958
993
|
/* update v, using fact that rsk, u, u_t vectors should be the same */
|
959
|
-
/* solve: R (v^+ + u - 2u_t) = rsk
|
960
|
-
|
961
|
-
|
962
|
-
|
994
|
+
/* solve: R^+ (v^+ + u - 2u_t) = rsk = R(v + u - 2u_t)
|
995
|
+
* => v^+ = R+^-1 rsk + 2u_t - u
|
996
|
+
*/
|
997
|
+
for (i = 0; i < w->d->n + w->d->m + 1; i++) {
|
998
|
+
w->v[i] = w->rsk[i] / w->diag_r[i] + 2 * w->u_t[i] - w->u[i];
|
963
999
|
}
|
964
1000
|
}
|
965
1001
|
}
|
@@ -970,7 +1006,8 @@ static inline void normalize_v(scs_float *v, scs_int len) {
|
|
970
1006
|
SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
|
971
1007
|
}
|
972
1008
|
|
973
|
-
scs_int
|
1009
|
+
scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
1010
|
+
scs_int warm_start) {
|
974
1011
|
scs_int i;
|
975
1012
|
SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
|
976
1013
|
scs_float total_accel_time = 0.0, total_cone_time = 0.0,
|
@@ -979,15 +1016,18 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
979
1016
|
scs_printf("ERROR: missing ScsWork, ScsSolution or ScsInfo input\n");
|
980
1017
|
return SCS_FAILED;
|
981
1018
|
}
|
982
|
-
scs_int l = w->m + w->n + 1;
|
983
|
-
const ScsData *d = w->d;
|
1019
|
+
scs_int l = w->d->m + w->d->n + 1;
|
984
1020
|
const ScsCone *k = w->k;
|
985
|
-
|
1021
|
+
ScsSettings *stgs = w->stgs;
|
1022
|
+
/* set warm start */
|
1023
|
+
stgs->warm_start = warm_start;
|
1024
|
+
|
986
1025
|
/* initialize ctrl-c support */
|
987
1026
|
scs_start_interrupt_listener();
|
988
1027
|
SCS(tic)(&solve_timer);
|
1028
|
+
strcpy(info->lin_sys_solver, SCS(get_lin_sys_method)());
|
989
1029
|
info->status_val = SCS_UNFINISHED; /* not yet converged */
|
990
|
-
update_work(
|
1030
|
+
update_work(w, sol);
|
991
1031
|
|
992
1032
|
if (w->stgs->verbose) {
|
993
1033
|
print_header(w, k);
|
@@ -1015,29 +1055,30 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1015
1055
|
/* store v_prev = v, *after* normalizing */
|
1016
1056
|
memcpy(w->v_prev, w->v, l * sizeof(scs_float));
|
1017
1057
|
|
1018
|
-
|
1058
|
+
/******************* linear system solve ********************/
|
1019
1059
|
SCS(tic)(&lin_sys_timer);
|
1020
1060
|
if (project_lin_sys(w, i) < 0) {
|
1021
|
-
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
1061
|
+
return failure(w, w->d->m, w->d->n, sol, info, SCS_FAILED,
|
1022
1062
|
"error in project_lin_sys", "failure");
|
1023
1063
|
}
|
1024
1064
|
total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
|
1025
1065
|
|
1026
|
-
|
1066
|
+
/****************** project onto the cones ******************/
|
1027
1067
|
SCS(tic)(&cone_timer);
|
1028
1068
|
if (project_cones(w, k, i) < 0) {
|
1029
|
-
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
1069
|
+
return failure(w, w->d->m, w->d->n, sol, info, SCS_FAILED,
|
1030
1070
|
"error in project_cones", "failure");
|
1031
1071
|
}
|
1032
1072
|
total_cone_time += SCS(tocq)(&cone_timer);
|
1033
1073
|
|
1034
|
-
/* dual
|
1035
|
-
|
1074
|
+
/* compute [r;s;kappa], must be before dual var update */
|
1075
|
+
/* since Moreau decomp logic relies on v at start */
|
1076
|
+
compute_rsk(w);
|
1036
1077
|
|
1037
1078
|
if (i % CONVERGED_INTERVAL == 0) {
|
1038
1079
|
if (scs_is_interrupted()) {
|
1039
|
-
return failure(w, w->m, w->n, sol, info, SCS_SIGINT,
|
1040
|
-
"interrupted");
|
1080
|
+
return failure(w, w->d->m, w->d->n, sol, info, SCS_SIGINT,
|
1081
|
+
"interrupted", "interrupted");
|
1041
1082
|
}
|
1042
1083
|
populate_residual_struct(w, i);
|
1043
1084
|
if ((info->status_val = has_converged(w, i)) != 0) {
|
@@ -1051,6 +1092,21 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1051
1092
|
}
|
1052
1093
|
}
|
1053
1094
|
|
1095
|
+
/* Compute residuals. */
|
1096
|
+
if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
|
1097
|
+
populate_residual_struct(w, i);
|
1098
|
+
print_summary(w, i, &solve_timer);
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
/* If residuals are fresh then maybe compute new scale. */
|
1102
|
+
if (w->stgs->adaptive_scale && i == w->r_orig->last_iter) {
|
1103
|
+
update_scale(w, k, i);
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
/****************** dual variable step **********************/
|
1107
|
+
/* do this after update_scale due to remapping that happens there */
|
1108
|
+
update_dual_vars(w);
|
1109
|
+
|
1054
1110
|
/* AA safeguard check.
|
1055
1111
|
* Perform safeguarding *after* convergence check to prevent safeguard
|
1056
1112
|
* overwriting converged iterate, since safeguard is on `v` and convergence
|
@@ -1066,29 +1122,18 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1066
1122
|
}
|
1067
1123
|
}
|
1068
1124
|
|
1069
|
-
/* Compute residuals. */
|
1070
|
-
if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
|
1071
|
-
populate_residual_struct(w, i);
|
1072
|
-
print_summary(w, i, &solve_timer);
|
1073
|
-
}
|
1074
|
-
|
1075
|
-
/* If residuals are fresh then maybe compute new scale. */
|
1076
|
-
if (w->stgs->adaptive_scale && i == w->r_orig->last_iter) {
|
1077
|
-
maybe_update_scale(w, k, i);
|
1078
|
-
}
|
1079
|
-
|
1080
1125
|
/* Log *after* updating scale so residual recalc does not affect alg */
|
1081
1126
|
if (w->stgs->log_csv_filename) {
|
1082
1127
|
/* calc residuals every iter if logging to csv */
|
1083
1128
|
populate_residual_struct(w, i);
|
1084
|
-
SCS(log_data_to_csv)(
|
1129
|
+
SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
|
1085
1130
|
}
|
1086
1131
|
}
|
1087
1132
|
|
1088
1133
|
/* Final logging after full run */
|
1089
1134
|
if (w->stgs->log_csv_filename) {
|
1090
1135
|
populate_residual_struct(w, i);
|
1091
|
-
SCS(log_data_to_csv)(
|
1136
|
+
SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
|
1092
1137
|
}
|
1093
1138
|
|
1094
1139
|
if (w->stgs->verbose) {
|
@@ -1113,17 +1158,9 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1113
1158
|
return info->status_val;
|
1114
1159
|
}
|
1115
1160
|
|
1116
|
-
void
|
1161
|
+
void scs_finish(ScsWork *w) {
|
1117
1162
|
if (w) {
|
1118
1163
|
SCS(finish_cone)(w->cone_work);
|
1119
|
-
if (w->stgs && w->stgs->normalize) {
|
1120
|
-
#ifndef COPYAMATRIX
|
1121
|
-
SCS(un_normalize)(w->A, w->P, w->scal);
|
1122
|
-
#else
|
1123
|
-
SCS(free_scs_matrix)(w->A);
|
1124
|
-
SCS(free_scs_matrix)(w->P);
|
1125
|
-
#endif
|
1126
|
-
}
|
1127
1164
|
if (w->p) {
|
1128
1165
|
SCS(free_lin_sys_work)(w->p);
|
1129
1166
|
}
|
@@ -1134,8 +1171,7 @@ void SCS(finish)(ScsWork *w) {
|
|
1134
1171
|
}
|
1135
1172
|
}
|
1136
1173
|
|
1137
|
-
ScsWork *
|
1138
|
-
const ScsSettings *stgs) {
|
1174
|
+
ScsWork *scs_init(const ScsData *d, const ScsCone *k, const ScsSettings *stgs) {
|
1139
1175
|
ScsWork *w;
|
1140
1176
|
SCS(timer) init_timer;
|
1141
1177
|
scs_start_interrupt_listener();
|
@@ -1148,6 +1184,10 @@ ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
|
|
1148
1184
|
scs_printf("ERROR: Validation returned failure\n");
|
1149
1185
|
return SCS_NULL;
|
1150
1186
|
}
|
1187
|
+
#endif
|
1188
|
+
#if VERBOSITY > 0
|
1189
|
+
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
|
1190
|
+
sizeof(scs_int), sizeof(scs_float));
|
1151
1191
|
#endif
|
1152
1192
|
SCS(tic)(&init_timer);
|
1153
1193
|
if (stgs->write_data_filename) {
|
@@ -1161,22 +1201,18 @@ ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
|
|
1161
1201
|
return w;
|
1162
1202
|
}
|
1163
1203
|
|
1164
|
-
/* this just calls
|
1204
|
+
/* this just calls scs_init, scs_solve, and scs_finish */
|
1165
1205
|
scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
|
1166
1206
|
ScsSolution *sol, ScsInfo *info) {
|
1167
1207
|
scs_int status;
|
1168
|
-
ScsWork *w =
|
1169
|
-
#if VERBOSITY > 0
|
1170
|
-
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
|
1171
|
-
sizeof(scs_int), sizeof(scs_float));
|
1172
|
-
#endif
|
1208
|
+
ScsWork *w = scs_init(d, k, stgs);
|
1173
1209
|
if (w) {
|
1174
|
-
|
1210
|
+
scs_solve(w, sol, info, stgs->warm_start);
|
1175
1211
|
status = info->status_val;
|
1176
1212
|
} else {
|
1177
1213
|
status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
|
1178
1214
|
SCS_FAILED, "could not initialize work", "failure");
|
1179
1215
|
}
|
1180
|
-
|
1216
|
+
scs_finish(w);
|
1181
1217
|
return status;
|
1182
1218
|
}
|