scs 0.3.2 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +35 -6
- 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 +2 -2
- data/vendor/scs/CMakeLists.txt +285 -169
- data/vendor/scs/Makefile +43 -18
- data/vendor/scs/README.md +3 -1
- data/vendor/scs/include/cones.h +5 -3
- data/vendor/scs/include/glbopts.h +35 -17
- data/vendor/scs/include/linsys.h +8 -8
- data/vendor/scs/include/normalize.h +1 -0
- data/vendor/scs/include/rw.h +3 -3
- data/vendor/scs/include/scs.h +51 -24
- data/vendor/scs/include/scs_types.h +3 -1
- data/vendor/scs/include/scs_work.h +13 -15
- data/vendor/scs/include/util.h +4 -2
- data/vendor/scs/linsys/cpu/direct/private.c +32 -153
- data/vendor/scs/linsys/cpu/direct/private.h +6 -6
- data/vendor/scs/linsys/cpu/indirect/private.c +9 -22
- data/vendor/scs/linsys/cpu/indirect/private.h +4 -2
- data/vendor/scs/linsys/csparse.c +140 -12
- data/vendor/scs/linsys/csparse.h +10 -17
- data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +4 -2
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +0 -5
- data/vendor/scs/linsys/gpu/gpu.c +4 -4
- data/vendor/scs/linsys/gpu/gpu.h +1 -1
- data/vendor/scs/linsys/gpu/indirect/private.c +15 -26
- data/vendor/scs/linsys/mkl/direct/private.c +182 -0
- data/vendor/scs/linsys/mkl/direct/private.h +38 -0
- data/vendor/scs/linsys/scs_matrix.c +49 -72
- data/vendor/scs/linsys/scs_matrix.h +4 -3
- data/vendor/scs/scs.mk +39 -30
- data/vendor/scs/src/aa.c +0 -4
- data/vendor/scs/src/cones.c +78 -184
- data/vendor/scs/src/exp_cone.c +399 -0
- data/vendor/scs/src/normalize.c +51 -0
- data/vendor/scs/src/rw.c +139 -76
- data/vendor/scs/src/scs.c +275 -202
- data/vendor/scs/src/util.c +36 -13
- data/vendor/scs/test/minunit.h +2 -1
- data/vendor/scs/test/problem_utils.h +5 -4
- data/vendor/scs/test/problems/degenerate.h +1 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +13 -4
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +1 -0
- data/vendor/scs/test/problems/max_ent +0 -0
- data/vendor/scs/test/problems/max_ent.h +8 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/random_prob.h +2 -39
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +15 -3
- data/vendor/scs/test/problems/small_lp.h +4 -1
- data/vendor/scs/test/problems/small_qp.h +42 -7
- data/vendor/scs/test/problems/test_exp_cone.h +84 -0
- data/vendor/scs/test/problems/test_prob_from_data_file.h +57 -0
- data/vendor/scs/test/problems/test_validation.h +4 -1
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +3 -3
- data/vendor/scs/test/random_socp_prob.c +3 -1
- data/vendor/scs/test/run_from_file.c +22 -4
- data/vendor/scs/test/run_tests.c +22 -9
- metadata +12 -4
data/vendor/scs/src/scs.c
CHANGED
@@ -40,21 +40,34 @@ static void free_work(ScsWork *w) {
|
|
40
40
|
scs_free(w->rsk);
|
41
41
|
scs_free(w->h);
|
42
42
|
scs_free(w->g);
|
43
|
-
scs_free(w->
|
44
|
-
scs_free(w->
|
43
|
+
scs_free(w->b_orig);
|
44
|
+
scs_free(w->c_orig);
|
45
45
|
scs_free(w->lin_sys_warm_start);
|
46
46
|
scs_free(w->diag_r);
|
47
|
+
SCS(free_sol)(w->xys_orig);
|
47
48
|
if (w->scal) {
|
48
49
|
scs_free(w->scal->D);
|
49
50
|
scs_free(w->scal->E);
|
50
51
|
scs_free(w->scal);
|
51
52
|
}
|
52
|
-
SCS(free_sol)(w->xys_orig);
|
53
53
|
free_residuals(w->r_orig);
|
54
54
|
if (w->stgs && w->stgs->normalize) {
|
55
55
|
SCS(free_sol)(w->xys_normalized);
|
56
56
|
free_residuals(w->r_normalized);
|
57
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
|
+
}
|
58
71
|
scs_free(w);
|
59
72
|
}
|
60
73
|
}
|
@@ -63,7 +76,7 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
|
|
63
76
|
const ScsSettings *stgs) {
|
64
77
|
scs_int i;
|
65
78
|
char *cone_str = SCS(get_cone_header)(k);
|
66
|
-
const char *lin_sys_method =
|
79
|
+
const char *lin_sys_method = scs_get_lin_sys_method();
|
67
80
|
#ifdef USE_LAPACK
|
68
81
|
scs_int acceleration_lookback = stgs->acceleration_lookback;
|
69
82
|
scs_int acceleration_interval = stgs->acceleration_interval;
|
@@ -87,12 +100,11 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
|
|
87
100
|
scs_free(cone_str);
|
88
101
|
scs_printf("settings: eps_abs: %.1e, eps_rel: %.1e, eps_infeas: %.1e\n"
|
89
102
|
"\t alpha: %.2f, scale: %.2e, adaptive_scale: %i\n"
|
90
|
-
"\t max_iters: %i, normalize: %i,
|
91
|
-
/*, rho_x: %.2e\n", */
|
103
|
+
"\t max_iters: %i, normalize: %i, rho_x: %.2e\n",
|
92
104
|
stgs->eps_abs, stgs->eps_rel, stgs->eps_infeas, stgs->alpha,
|
93
105
|
stgs->scale, (int)stgs->adaptive_scale, (int)stgs->max_iters,
|
94
|
-
(int)stgs->normalize,
|
95
|
-
/*
|
106
|
+
(int)stgs->normalize, stgs->rho_x);
|
107
|
+
/* (int)stgs->warm_start); */
|
96
108
|
if (stgs->acceleration_lookback != 0) {
|
97
109
|
scs_printf("\t acceleration_lookback: %i, acceleration_interval: %i\n",
|
98
110
|
(int)acceleration_lookback, (int)acceleration_interval);
|
@@ -154,18 +166,26 @@ static scs_int failure(ScsWork *w, scs_int m, scs_int n, ScsSolution *sol,
|
|
154
166
|
return status;
|
155
167
|
}
|
156
168
|
|
169
|
+
static inline scs_int _is_nan(scs_float x) {
|
170
|
+
return x != x;
|
171
|
+
}
|
172
|
+
|
157
173
|
/* given x,y,s warm start, set v = [x; s / R + y; 1]
|
174
|
+
* check for nans and set to zero if present
|
158
175
|
*/
|
159
176
|
static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
|
160
|
-
scs_int n = w->n, m = w->m, i;
|
177
|
+
scs_int n = w->d->n, m = w->d->m, i;
|
161
178
|
scs_float *v = w->v;
|
162
179
|
/* normalize the warm-start */
|
163
180
|
if (w->stgs->normalize) {
|
164
181
|
SCS(normalize_sol)(w->scal, sol);
|
165
182
|
}
|
166
|
-
|
183
|
+
for (i = 0; i < n; ++i) {
|
184
|
+
v[i] = _is_nan(sol->x[i]) ? 0. : sol->x[i];
|
185
|
+
}
|
167
186
|
for (i = 0; i < m; ++i) {
|
168
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];
|
169
189
|
}
|
170
190
|
v[n + m] = 1.0; /* tau = 1 */
|
171
191
|
/* un-normalize so sol unchanged */
|
@@ -175,17 +195,24 @@ static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
|
|
175
195
|
}
|
176
196
|
|
177
197
|
static void compute_residuals(ScsResiduals *r, scs_int m, scs_int n) {
|
178
|
-
|
179
|
-
|
198
|
+
scs_float nm_ax_s, nm_px, nm_aty;
|
199
|
+
scs_float nm_ax_s_btau = NORM(r->ax_s_btau, m);
|
200
|
+
scs_float nm_px_aty_ctau = NORM(r->px_aty_ctau, n);
|
201
|
+
|
202
|
+
r->res_pri = SAFEDIV_POS(nm_ax_s_btau, r->tau);
|
203
|
+
r->res_dual = SAFEDIV_POS(nm_px_aty_ctau, r->tau);
|
180
204
|
r->res_unbdd_a = NAN;
|
181
205
|
r->res_unbdd_p = NAN;
|
182
206
|
r->res_infeas = NAN;
|
183
207
|
if (r->ctx_tau < 0) {
|
184
|
-
|
185
|
-
|
208
|
+
nm_ax_s = NORM(r->ax_s, m);
|
209
|
+
nm_px = NORM(r->px, n);
|
210
|
+
r->res_unbdd_a = SAFEDIV_POS(nm_ax_s, -r->ctx_tau);
|
211
|
+
r->res_unbdd_p = SAFEDIV_POS(nm_px, -r->ctx_tau);
|
186
212
|
}
|
187
213
|
if (r->bty_tau < 0) {
|
188
|
-
|
214
|
+
nm_aty = NORM(r->aty, n);
|
215
|
+
r->res_infeas = SAFEDIV_POS(nm_aty, -r->bty_tau);
|
189
216
|
}
|
190
217
|
}
|
191
218
|
|
@@ -199,12 +226,12 @@ static void unnormalize_residuals(ScsWork *w) {
|
|
199
226
|
r->tau = r_n->tau;
|
200
227
|
|
201
228
|
/* mem copy arrays */
|
202
|
-
memcpy(r->ax, r_n->ax, w->m * sizeof(scs_float));
|
203
|
-
memcpy(r->ax_s, r_n->ax_s, w->m * sizeof(scs_float));
|
204
|
-
memcpy(r->ax_s_btau, r_n->ax_s_btau, w->m * sizeof(scs_float));
|
205
|
-
memcpy(r->aty, r_n->aty, w->n * sizeof(scs_float));
|
206
|
-
memcpy(r->px, r_n->px, w->n * sizeof(scs_float));
|
207
|
-
memcpy(r->px_aty_ctau, r_n->px_aty_ctau, w->n * sizeof(scs_float));
|
229
|
+
memcpy(r->ax, r_n->ax, w->d->m * sizeof(scs_float));
|
230
|
+
memcpy(r->ax_s, r_n->ax_s, w->d->m * sizeof(scs_float));
|
231
|
+
memcpy(r->ax_s_btau, r_n->ax_s_btau, w->d->m * sizeof(scs_float));
|
232
|
+
memcpy(r->aty, r_n->aty, w->d->n * sizeof(scs_float));
|
233
|
+
memcpy(r->px, r_n->px, w->d->n * sizeof(scs_float));
|
234
|
+
memcpy(r->px_aty_ctau, r_n->px_aty_ctau, w->d->n * sizeof(scs_float));
|
208
235
|
|
209
236
|
/* unnormalize */
|
210
237
|
r->kap = r_n->kap / pd;
|
@@ -225,13 +252,13 @@ static void unnormalize_residuals(ScsWork *w) {
|
|
225
252
|
SCS(un_normalize_dual)(w->scal, r->px);
|
226
253
|
SCS(un_normalize_dual)(w->scal, r->px_aty_ctau);
|
227
254
|
|
228
|
-
compute_residuals(r, w->m, w->n);
|
255
|
+
compute_residuals(r, w->d->m, w->d->n);
|
229
256
|
}
|
230
257
|
|
231
258
|
/* calculates un-normalized residual quantities */
|
232
259
|
/* this is somewhat slow but not a bottleneck */
|
233
260
|
static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
234
|
-
scs_int n = w->n, m = w->m;
|
261
|
+
scs_int n = w->d->n, m = w->d->m;
|
235
262
|
/* normalized x,y,s terms */
|
236
263
|
scs_float *x = w->xys_normalized->x;
|
237
264
|
scs_float *y = w->xys_normalized->y;
|
@@ -254,7 +281,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
254
281
|
/**************** PRIMAL *********************/
|
255
282
|
memset(r->ax, 0, m * sizeof(scs_float));
|
256
283
|
/* ax = Ax */
|
257
|
-
SCS(accum_by_a)(w->A, x, r->ax);
|
284
|
+
SCS(accum_by_a)(w->d->A, x, r->ax);
|
258
285
|
|
259
286
|
memcpy(r->ax_s, r->ax, m * sizeof(scs_float));
|
260
287
|
/* ax_s = Ax + s */
|
@@ -262,13 +289,13 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
262
289
|
|
263
290
|
memcpy(r->ax_s_btau, r->ax_s, m * sizeof(scs_float));
|
264
291
|
/* ax_s_btau = Ax + s - b * tau */
|
265
|
-
SCS(add_scaled_array)(r->ax_s_btau, w->
|
292
|
+
SCS(add_scaled_array)(r->ax_s_btau, w->d->b, m, -r->tau);
|
266
293
|
|
267
294
|
/**************** DUAL *********************/
|
268
295
|
memset(r->px, 0, n * sizeof(scs_float));
|
269
|
-
if (w->P) {
|
296
|
+
if (w->d->P) {
|
270
297
|
/* px = Px */
|
271
|
-
SCS(accum_by_p)(w->P, x, r->px);
|
298
|
+
SCS(accum_by_p)(w->d->P, x, r->px);
|
272
299
|
r->xt_p_x_tau = SCS(dot)(r->px, x, n);
|
273
300
|
} else {
|
274
301
|
r->xt_p_x_tau = 0.;
|
@@ -276,18 +303,18 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
276
303
|
|
277
304
|
memset(r->aty, 0, n * sizeof(scs_float));
|
278
305
|
/* aty = A'y */
|
279
|
-
SCS(accum_by_atrans)(w->A, y, r->aty);
|
306
|
+
SCS(accum_by_atrans)(w->d->A, y, r->aty);
|
280
307
|
|
281
308
|
/* r->px_aty_ctau = Px */
|
282
309
|
memcpy(r->px_aty_ctau, r->px, n * sizeof(scs_float));
|
283
310
|
/* r->px_aty_ctau = Px + A'y */
|
284
311
|
SCS(add_scaled_array)(r->px_aty_ctau, r->aty, n, 1.);
|
285
312
|
/* r->px_aty_ctau = Px + A'y + c * tau */
|
286
|
-
SCS(add_scaled_array)(r->px_aty_ctau, w->
|
313
|
+
SCS(add_scaled_array)(r->px_aty_ctau, w->d->c, n, r->tau);
|
287
314
|
|
288
315
|
/**************** OTHERS *****************/
|
289
|
-
r->bty_tau = SCS(dot)(y, w->
|
290
|
-
r->ctx_tau = SCS(dot)(x, w->
|
316
|
+
r->bty_tau = SCS(dot)(y, w->d->b, m);
|
317
|
+
r->ctx_tau = SCS(dot)(x, w->d->c, n);
|
291
318
|
|
292
319
|
r->bty = SAFEDIV_POS(r->bty_tau, r->tau);
|
293
320
|
r->ctx = SAFEDIV_POS(r->ctx_tau, r->tau);
|
@@ -309,7 +336,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
309
336
|
}
|
310
337
|
|
311
338
|
static void cold_start_vars(ScsWork *w) {
|
312
|
-
scs_int l = w->n + w->m + 1;
|
339
|
+
scs_int l = w->d->n + w->d->m + 1;
|
313
340
|
memset(w->v, 0, l * sizeof(scs_float));
|
314
341
|
w->v[l - 1] = 1.;
|
315
342
|
}
|
@@ -319,7 +346,7 @@ static inline scs_float dot_r(ScsWork *w, const scs_float *x,
|
|
319
346
|
const scs_float *y) {
|
320
347
|
scs_int i;
|
321
348
|
scs_float ip = 0.0;
|
322
|
-
for (i = 0; i < w->n + w->m; ++i) {
|
349
|
+
for (i = 0; i < w->d->n + w->d->m; ++i) {
|
323
350
|
ip += x[i] * y[i] * w->diag_r[i];
|
324
351
|
}
|
325
352
|
return ip;
|
@@ -327,16 +354,17 @@ static inline scs_float dot_r(ScsWork *w, const scs_float *x,
|
|
327
354
|
|
328
355
|
static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
|
329
356
|
scs_float eta) {
|
330
|
-
scs_float a, b, c, tau_scale = w->diag_r[w->n + w->m];
|
357
|
+
scs_float a, b, c, rad, tau_scale = w->diag_r[w->d->n + w->d->m];
|
331
358
|
a = tau_scale + dot_r(w, w->g, w->g);
|
332
359
|
b = dot_r(w, mu, w->g) - 2 * dot_r(w, p, w->g) - eta * tau_scale;
|
333
360
|
c = dot_r(w, p, p) - dot_r(w, p, mu);
|
334
|
-
|
361
|
+
rad = b * b - 4 * a * c;
|
362
|
+
return (-b + SQRTF(MAX(rad, 0.))) / (2 * a);
|
335
363
|
}
|
336
364
|
|
337
|
-
/* status
|
365
|
+
/* status != 0 indicates failure */
|
338
366
|
static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
339
|
-
scs_int n = w->n, m = w->m, l = n + m + 1, status, i;
|
367
|
+
scs_int n = w->d->n, m = w->d->m, l = n + m + 1, status, i;
|
340
368
|
scs_float *warm_start = SCS_NULL;
|
341
369
|
scs_float tol = -1.0; /* only used for indirect methods, overridden later */
|
342
370
|
memcpy(w->u_t, w->v, l * sizeof(scs_float));
|
@@ -344,22 +372,24 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
|
344
372
|
w->u_t[i] *= (i < n ? 1 : -1) * w->diag_r[i];
|
345
373
|
}
|
346
374
|
#if INDIRECT > 0
|
375
|
+
scs_float nm_ax_s_btau, nm_px_aty_ctau, nm_ws;
|
347
376
|
/* compute warm start using the cone projection output */
|
377
|
+
nm_ax_s_btau = CG_NORM(w->r_normalized->ax_s_btau, m);
|
378
|
+
nm_px_aty_ctau = CG_NORM(w->r_normalized->px_aty_ctau, n);
|
348
379
|
warm_start = w->lin_sys_warm_start;
|
349
|
-
memcpy(warm_start, w->u, (l - 1) * sizeof(scs_float));
|
350
380
|
/* warm_start = u[:n] + tau * g[:n] */
|
351
|
-
|
381
|
+
memcpy(warm_start, w->u, n * sizeof(scs_float));
|
382
|
+
SCS(add_scaled_array)(warm_start, w->g, n, w->u[l - 1]);
|
352
383
|
/* use normalized residuals to compute tolerance */
|
353
|
-
tol = MIN(
|
354
|
-
CG_NORM(w->r_normalized->px_aty_ctau, w->n));
|
384
|
+
tol = MIN(nm_ax_s_btau, nm_px_aty_ctau);
|
355
385
|
/* tol ~ O(1/k^(1+eps)) guarantees convergence */
|
356
386
|
/* use warm-start to calculate tolerance rather than w->u_t, since warm_start
|
357
387
|
* should be approximately equal to the true solution */
|
358
|
-
|
359
|
-
|
388
|
+
nm_ws = CG_NORM(warm_start, n) / POWF((scs_float)iter + 1, CG_RATE);
|
389
|
+
tol = CG_TOL_FACTOR * MIN(tol, nm_ws);
|
360
390
|
tol = MAX(CG_BEST_TOL, tol);
|
361
391
|
#endif
|
362
|
-
status =
|
392
|
+
status = scs_solve_lin_sys(w->p, w->u_t, warm_start, tol);
|
363
393
|
if (iter < FEASIBLE_ITERS) {
|
364
394
|
w->u_t[l - 1] = 1.;
|
365
395
|
} else {
|
@@ -378,14 +408,14 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
|
378
408
|
* (no effect of w->stgs->alpha here).
|
379
409
|
*/
|
380
410
|
static void compute_rsk(ScsWork *w) {
|
381
|
-
scs_int i, l = w->m + w->n + 1;
|
411
|
+
scs_int i, l = w->d->m + w->d->n + 1;
|
382
412
|
for (i = 0; i < l; ++i) {
|
383
413
|
w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->diag_r[i];
|
384
414
|
}
|
385
415
|
}
|
386
416
|
|
387
417
|
static void update_dual_vars(ScsWork *w) {
|
388
|
-
scs_int i, l = w->n + w->m + 1;
|
418
|
+
scs_int i, l = w->d->n + w->d->m + 1;
|
389
419
|
for (i = 0; i < l; ++i) {
|
390
420
|
w->v[i] += w->stgs->alpha * (w->u[i] - w->u_t[i]);
|
391
421
|
}
|
@@ -393,7 +423,7 @@ static void update_dual_vars(ScsWork *w) {
|
|
393
423
|
|
394
424
|
/* status < 0 indicates failure */
|
395
425
|
static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
|
396
|
-
scs_int i, n = w->n, l = w->n + w->m + 1, status;
|
426
|
+
scs_int i, n = w->d->n, l = w->d->n + w->d->m + 1, status;
|
397
427
|
for (i = 0; i < l; ++i) {
|
398
428
|
w->u[i] = 2 * w->u_t[i] - w->v[i];
|
399
429
|
}
|
@@ -410,30 +440,30 @@ static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
410
440
|
|
411
441
|
static void sety(const ScsWork *w, ScsSolution *sol) {
|
412
442
|
if (!sol->y) {
|
413
|
-
sol->y = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
|
443
|
+
sol->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
414
444
|
}
|
415
|
-
memcpy(sol->y, &(w->u[w->n]), w->m * sizeof(scs_float));
|
445
|
+
memcpy(sol->y, &(w->u[w->d->n]), w->d->m * sizeof(scs_float));
|
416
446
|
}
|
417
447
|
|
418
448
|
/* s is contained in rsk */
|
419
449
|
static void sets(const ScsWork *w, ScsSolution *sol) {
|
420
450
|
if (!sol->s) {
|
421
|
-
sol->s = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
|
451
|
+
sol->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
422
452
|
}
|
423
|
-
memcpy(sol->s, &(w->rsk[w->n]), w->m * sizeof(scs_float));
|
453
|
+
memcpy(sol->s, &(w->rsk[w->d->n]), w->d->m * sizeof(scs_float));
|
424
454
|
}
|
425
455
|
|
426
456
|
static void setx(const ScsWork *w, ScsSolution *sol) {
|
427
457
|
if (!sol->x) {
|
428
|
-
sol->x = (scs_float *)scs_calloc(w->n, sizeof(scs_float));
|
458
|
+
sol->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
429
459
|
}
|
430
|
-
memcpy(sol->x, w->u, w->n * sizeof(scs_float));
|
460
|
+
memcpy(sol->x, w->u, w->d->n * sizeof(scs_float));
|
431
461
|
}
|
432
462
|
|
433
463
|
static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
434
|
-
SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->n);
|
435
|
-
SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
|
436
|
-
SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
|
464
|
+
SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->n);
|
465
|
+
SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->m);
|
466
|
+
SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->m);
|
437
467
|
info->gap = w->r_orig->gap;
|
438
468
|
info->res_pri = w->r_orig->res_pri;
|
439
469
|
info->res_dual = w->r_orig->res_dual;
|
@@ -444,9 +474,9 @@ static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
444
474
|
}
|
445
475
|
|
446
476
|
static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
447
|
-
SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->m);
|
448
|
-
SCS(scale_array)(sol->x, NAN, w->n);
|
449
|
-
SCS(scale_array)(sol->s, NAN, w->m);
|
477
|
+
SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->d->m);
|
478
|
+
SCS(scale_array)(sol->x, NAN, w->d->n);
|
479
|
+
SCS(scale_array)(sol->s, NAN, w->d->m);
|
450
480
|
info->gap = NAN;
|
451
481
|
info->res_pri = NAN;
|
452
482
|
info->res_dual = NAN;
|
@@ -457,9 +487,9 @@ static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
457
487
|
}
|
458
488
|
|
459
489
|
static void set_unbounded(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
460
|
-
SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->n);
|
461
|
-
SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->m);
|
462
|
-
SCS(scale_array)(sol->y, NAN, w->m);
|
490
|
+
SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->d->n);
|
491
|
+
SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->d->m);
|
492
|
+
SCS(scale_array)(sol->y, NAN, w->d->m);
|
463
493
|
info->gap = NAN;
|
464
494
|
info->res_pri = NAN;
|
465
495
|
info->res_dual = NAN;
|
@@ -494,6 +524,7 @@ static void set_unfinished(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
494
524
|
/* sets solutions, re-scales by inner prods if infeasible or unbounded */
|
495
525
|
static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
496
526
|
scs_int iter) {
|
527
|
+
scs_float nm_s, nm_y, sty;
|
497
528
|
setx(w, sol);
|
498
529
|
sety(w, sol);
|
499
530
|
sets(w, sol);
|
@@ -501,18 +532,22 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
|
501
532
|
SCS(un_normalize_sol)(w->scal, sol);
|
502
533
|
}
|
503
534
|
populate_residual_struct(w, iter);
|
535
|
+
|
536
|
+
nm_s = SCS(norm_inf)(sol->s, w->d->m);
|
537
|
+
nm_y = SCS(norm_inf)(sol->y, w->d->m);
|
538
|
+
sty = SCS(dot)(sol->s, sol->y, w->d->m);
|
539
|
+
|
504
540
|
info->setup_time = w->setup_time;
|
505
541
|
info->iter = iter;
|
506
542
|
info->res_infeas = w->r_orig->res_infeas;
|
507
543
|
info->res_unbdd_a = w->r_orig->res_unbdd_a;
|
508
544
|
info->res_unbdd_p = w->r_orig->res_unbdd_p;
|
509
|
-
info->scale = w->scale;
|
545
|
+
info->scale = w->stgs->scale;
|
510
546
|
info->scale_updates = w->scale_updates;
|
511
547
|
info->rejected_accel_steps = w->rejected_accel_steps;
|
512
548
|
info->accepted_accel_steps = w->accepted_accel_steps;
|
513
|
-
info->comp_slack = ABS(
|
514
|
-
if (info->comp_slack >
|
515
|
-
1e-5 * MAX(SCS(norm_inf)(sol->s, w->m), SCS(norm_inf)(sol->y, w->m))) {
|
549
|
+
info->comp_slack = ABS(sty);
|
550
|
+
if (info->comp_slack > 1e-5 * MAX(nm_s, nm_y)) {
|
516
551
|
scs_printf("WARNING - large complementary slackness residual: %f\n",
|
517
552
|
info->comp_slack);
|
518
553
|
}
|
@@ -542,23 +577,25 @@ static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
|
|
542
577
|
scs_printf("%*.2e ", (int)HSPACE, r->gap);
|
543
578
|
/* report mid point of primal and dual objective values */
|
544
579
|
scs_printf("%*.2e ", (int)HSPACE, 0.5 * (r->pobj + r->dobj));
|
545
|
-
scs_printf("%*.2e ", (int)HSPACE, w->scale);
|
546
|
-
|
580
|
+
scs_printf("%*.2e ", (int)HSPACE, w->stgs->scale);
|
581
|
+
/* Report TOTAL time, including setup */
|
582
|
+
scs_printf("%*.2e ", (int)HSPACE,
|
583
|
+
(SCS(tocq)(solve_timer) + w->setup_time) / 1e3);
|
547
584
|
scs_printf("\n");
|
548
585
|
|
549
586
|
#if VERBOSITY > 0
|
550
|
-
scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->n + w->m + 1));
|
551
|
-
scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->n + w->m + 1));
|
552
|
-
scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->n + w->m + 1));
|
553
|
-
scs_printf("Norm rsk = %4f, ", SCS(norm_2)(w->rsk, w->n + w->m + 1));
|
554
|
-
scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->n));
|
555
|
-
scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->m));
|
556
|
-
scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->m));
|
557
|
-
scs_printf("Norm |Ax + s| = %1.2e, ", SCS(norm_2)(r->ax_s, w->m));
|
558
|
-
scs_printf("tau = %4f, ", w->u[w->n + w->m]);
|
559
|
-
scs_printf("kappa = %4f, ", w->rsk[w->n + w->m]);
|
587
|
+
scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->d->n + w->d->m + 1));
|
588
|
+
scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->d->n + w->d->m + 1));
|
589
|
+
scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->d->n + w->d->m + 1));
|
590
|
+
scs_printf("Norm rsk = %4f, ", SCS(norm_2)(w->rsk, w->d->n + w->d->m + 1));
|
591
|
+
scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->d->n));
|
592
|
+
scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->d->m));
|
593
|
+
scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->d->m));
|
594
|
+
scs_printf("Norm |Ax + s| = %1.2e, ", SCS(norm_2)(r->ax_s, w->d->m));
|
595
|
+
scs_printf("tau = %4f, ", w->u[w->d->n + w->d->m]);
|
596
|
+
scs_printf("kappa = %4f, ", w->rsk[w->d->n + w->d->m]);
|
560
597
|
scs_printf("|u - u_t| = %1.2e, ",
|
561
|
-
SCS(norm_diff)(w->u, w->u_t, w->n + w->m + 1));
|
598
|
+
SCS(norm_diff)(w->u, w->u_t, w->d->n + w->d->m + 1));
|
562
599
|
scs_printf("res_infeas = %1.2e, ", r->res_infeas);
|
563
600
|
scs_printf("res_unbdd_a = %1.2e, ", r->res_unbdd_a);
|
564
601
|
scs_printf("res_unbdd_p = %1.2e, ", r->res_unbdd_p);
|
@@ -629,25 +666,29 @@ static void print_footer(ScsInfo *info) {
|
|
629
666
|
}
|
630
667
|
|
631
668
|
static scs_int has_converged(ScsWork *w, scs_int iter) {
|
669
|
+
scs_float abs_xt_p_x, abs_ctx, abs_bty;
|
670
|
+
scs_float nm_s, nm_px, nm_aty, nm_ax;
|
671
|
+
scs_float grl, prl, drl;
|
632
672
|
scs_float eps_abs = w->stgs->eps_abs;
|
633
673
|
scs_float eps_rel = w->stgs->eps_rel;
|
634
674
|
scs_float eps_infeas = w->stgs->eps_infeas;
|
635
|
-
scs_float grl, prl, drl;
|
636
675
|
|
637
676
|
ScsResiduals *r = w->r_orig;
|
638
|
-
scs_float *b = w->b_orig;
|
639
|
-
scs_float *c = w->c_orig;
|
640
|
-
scs_float *s = w->xys_orig->s;
|
641
677
|
|
642
678
|
if (r->tau > 0.) {
|
679
|
+
abs_xt_p_x = ABS(r->xt_p_x);
|
680
|
+
abs_ctx = ABS(r->ctx);
|
681
|
+
abs_bty = ABS(r->bty);
|
682
|
+
|
683
|
+
nm_s = NORM(w->xys_orig->s, w->d->m);
|
684
|
+
nm_px = NORM(r->px, w->d->n);
|
685
|
+
nm_aty = NORM(r->aty, w->d->n);
|
686
|
+
nm_ax = NORM(r->ax, w->d->m);
|
643
687
|
/* xt_p_x, ctx, bty already have tau divided out */
|
644
|
-
grl = MAX(MAX(
|
688
|
+
grl = MAX(MAX(abs_xt_p_x, abs_ctx), abs_bty);
|
645
689
|
/* s, ax, px, aty do *not* have tau divided out, so need to divide */
|
646
|
-
prl = MAX(MAX(
|
647
|
-
|
648
|
-
drl = MAX(MAX(NORM(c, w->n) * r->tau, NORM(r->px, w->n)),
|
649
|
-
NORM(r->aty, w->n)) /
|
650
|
-
r->tau;
|
690
|
+
prl = MAX(MAX(w->nm_b_orig * r->tau, nm_s), nm_ax) / r->tau;
|
691
|
+
drl = MAX(MAX(w->nm_c_orig * r->tau, nm_px), nm_aty) / r->tau;
|
651
692
|
if (isless(r->res_pri, eps_abs + eps_rel * prl) &&
|
652
693
|
isless(r->res_dual, eps_abs + eps_rel * drl) &&
|
653
694
|
isless(r->gap, eps_abs + eps_rel * grl)) {
|
@@ -664,7 +705,7 @@ static scs_int has_converged(ScsWork *w, scs_int iter) {
|
|
664
705
|
return 0;
|
665
706
|
}
|
666
707
|
|
667
|
-
#if
|
708
|
+
#if NO_VALIDATE == 0
|
668
709
|
static scs_int validate(const ScsData *d, const ScsCone *k,
|
669
710
|
const ScsSettings *stgs) {
|
670
711
|
if (d->m <= 0 || d->n <= 0) {
|
@@ -722,7 +763,6 @@ static scs_int validate(const ScsData *d, const ScsCone *k,
|
|
722
763
|
|
723
764
|
static ScsResiduals *init_residuals(const ScsData *d) {
|
724
765
|
ScsResiduals *r = (ScsResiduals *)scs_calloc(1, sizeof(ScsResiduals));
|
725
|
-
r->last_iter = -1;
|
726
766
|
r->ax = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
727
767
|
r->ax_s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
728
768
|
r->ax_s_btau = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
@@ -732,16 +772,47 @@ static ScsResiduals *init_residuals(const ScsData *d) {
|
|
732
772
|
return r;
|
733
773
|
}
|
734
774
|
|
775
|
+
scs_int scs_update(ScsWork *w, scs_float *b, scs_float *c) {
|
776
|
+
SCS(timer) update_timer;
|
777
|
+
SCS(tic)(&update_timer);
|
778
|
+
|
779
|
+
if (b) {
|
780
|
+
memcpy(w->b_orig, b, w->d->m * sizeof(scs_float));
|
781
|
+
memcpy(w->d->b, b, w->d->m * sizeof(scs_float));
|
782
|
+
} else {
|
783
|
+
memcpy(w->d->b, w->b_orig, w->d->m * sizeof(scs_float));
|
784
|
+
}
|
785
|
+
w->nm_b_orig = NORM(w->b_orig, w->d->m);
|
786
|
+
|
787
|
+
if (c) {
|
788
|
+
memcpy(w->c_orig, c, w->d->n * sizeof(scs_float));
|
789
|
+
memcpy(w->d->c, c, w->d->n * sizeof(scs_float));
|
790
|
+
} else {
|
791
|
+
memcpy(w->d->c, w->c_orig, w->d->n * sizeof(scs_float));
|
792
|
+
}
|
793
|
+
w->nm_c_orig = NORM(w->c_orig, w->d->n);
|
794
|
+
|
795
|
+
/* normalize */
|
796
|
+
if (w->scal) {
|
797
|
+
SCS(normalize_b_c)(w->scal, w->d->b, w->d->c);
|
798
|
+
}
|
799
|
+
|
800
|
+
/* override setup time with update time, since the update is the 'setup' */
|
801
|
+
w->setup_time = SCS(tocq)(&update_timer);
|
802
|
+
return 0;
|
803
|
+
}
|
804
|
+
|
735
805
|
/* Sets the diag_r vector, given the scale parameters in work */
|
736
806
|
static void set_diag_r(ScsWork *w) {
|
737
807
|
scs_int i;
|
738
|
-
for (i = 0; i < w->n; ++i) {
|
808
|
+
for (i = 0; i < w->d->n; ++i) {
|
739
809
|
w->diag_r[i] = w->stgs->rho_x;
|
740
810
|
}
|
741
811
|
/* use cone information to set R_y */
|
742
|
-
SCS(set_r_y)(w->cone_work, w->scale, &(w->diag_r[w->n]));
|
812
|
+
SCS(set_r_y)(w->cone_work, w->stgs->scale, &(w->diag_r[w->d->n]));
|
743
813
|
/* if modified need to SCS(enforce_cone_boundaries)(...) */
|
744
|
-
w->diag_r[w->n + w->m] =
|
814
|
+
w->diag_r[w->d->n + w->d->m] =
|
815
|
+
TAU_FACTOR; /* TODO: is this the best choice? */
|
745
816
|
}
|
746
817
|
|
747
818
|
static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
@@ -755,18 +826,21 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
755
826
|
scs_printf("ERROR: allocating work failure\n");
|
756
827
|
return SCS_NULL;
|
757
828
|
}
|
758
|
-
/*
|
759
|
-
w->d =
|
760
|
-
w->
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
w->
|
765
|
-
w->
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
w->
|
829
|
+
/* deep copy data */
|
830
|
+
w->d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
831
|
+
SCS(deep_copy_data)(w->d, d);
|
832
|
+
d = SCS_NULL; /* for safety */
|
833
|
+
|
834
|
+
/* deep copy cone */
|
835
|
+
w->k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
836
|
+
SCS(deep_copy_cone)(w->k, k);
|
837
|
+
k = SCS_NULL; /* for safety */
|
838
|
+
|
839
|
+
/* deep copy settings */
|
840
|
+
w->stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
841
|
+
SCS(deep_copy_stgs)(w->stgs, stgs);
|
842
|
+
stgs = SCS_NULL; /* for safety */
|
843
|
+
|
770
844
|
/* allocate workspace: */
|
771
845
|
w->u = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
772
846
|
w->u_t = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
@@ -775,68 +849,48 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
775
849
|
w->rsk = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
776
850
|
w->h = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
777
851
|
w->g = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
778
|
-
w->lin_sys_warm_start = (scs_float *)scs_calloc(
|
852
|
+
w->lin_sys_warm_start = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
779
853
|
w->diag_r = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
780
854
|
/* x,y,s struct */
|
781
855
|
w->xys_orig = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
782
|
-
w->xys_orig->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
783
|
-
w->xys_orig->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
784
|
-
w->xys_orig->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
785
|
-
w->r_orig = init_residuals(d);
|
786
|
-
|
787
|
-
w->
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
w->c_orig = d->c;
|
792
|
-
w->b_normalized = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
793
|
-
w->c_normalized = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
794
|
-
memcpy(w->b_normalized, w->b_orig, w->m * sizeof(scs_float));
|
795
|
-
memcpy(w->c_normalized, w->c_orig, w->n * sizeof(scs_float));
|
796
|
-
|
797
|
-
if (!(w->cone_work = SCS(init_cone)(k, w->m))) {
|
798
|
-
scs_printf("ERROR: init_cone failure\n");
|
856
|
+
w->xys_orig->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
857
|
+
w->xys_orig->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
858
|
+
w->xys_orig->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
859
|
+
w->r_orig = init_residuals(w->d);
|
860
|
+
w->b_orig = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
861
|
+
w->c_orig = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
862
|
+
|
863
|
+
if (!w->c_orig) {
|
864
|
+
scs_printf("ERROR: work memory allocation failure\n");
|
799
865
|
return SCS_NULL;
|
800
866
|
}
|
801
|
-
set_diag_r(w);
|
802
867
|
|
803
|
-
if (!w->
|
804
|
-
scs_printf("ERROR:
|
868
|
+
if (!(w->cone_work = SCS(init_cone)(w->k, w->d->m))) {
|
869
|
+
scs_printf("ERROR: init_cone failure\n");
|
805
870
|
return SCS_NULL;
|
806
871
|
}
|
872
|
+
set_diag_r(w);
|
807
873
|
|
808
874
|
if (w->stgs->normalize) {
|
809
875
|
w->xys_normalized = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
810
|
-
w->xys_normalized->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
811
|
-
w->xys_normalized->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
812
|
-
w->xys_normalized->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
813
|
-
w->r_normalized = init_residuals(d);
|
814
|
-
|
815
|
-
#ifdef COPYAMATRIX
|
816
|
-
if (!SCS(copy_matrix)(&(w->A), d->A)) {
|
817
|
-
scs_printf("ERROR: copy A matrix failed\n");
|
818
|
-
return SCS_NULL;
|
819
|
-
}
|
820
|
-
if (w->P && !SCS(copy_matrix)(&(w->P), d->P)) {
|
821
|
-
scs_printf("ERROR: copy P matrix failed\n");
|
822
|
-
return SCS_NULL;
|
823
|
-
}
|
824
|
-
#endif
|
876
|
+
w->xys_normalized->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
|
877
|
+
w->xys_normalized->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
878
|
+
w->xys_normalized->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
|
879
|
+
w->r_normalized = init_residuals(w->d);
|
825
880
|
/* this allocates memory that must be freed */
|
826
|
-
w->scal = SCS(normalize_a_p)(w->P, w->A, w->
|
827
|
-
w->cone_work);
|
881
|
+
w->scal = SCS(normalize_a_p)(w->d->P, w->d->A, w->cone_work);
|
828
882
|
} else {
|
829
883
|
w->xys_normalized = w->xys_orig;
|
830
884
|
w->r_normalized = w->r_orig;
|
831
885
|
w->scal = SCS_NULL;
|
832
886
|
}
|
833
|
-
|
887
|
+
/* set w->*_orig and performs normalization if appropriate */
|
888
|
+
scs_update(w, w->d->b, w->d->c);
|
889
|
+
|
890
|
+
if (!(w->p = scs_init_lin_sys_work(w->d->A, w->d->P, w->diag_r))) {
|
834
891
|
scs_printf("ERROR: init_lin_sys_work failure\n");
|
835
892
|
return SCS_NULL;
|
836
893
|
}
|
837
|
-
/* Acceleration */
|
838
|
-
w->rejected_accel_steps = 0;
|
839
|
-
w->accepted_accel_steps = 0;
|
840
894
|
if (w->stgs->acceleration_lookback) {
|
841
895
|
/* TODO(HACK!) negative acceleration_lookback interpreted as type-II */
|
842
896
|
if (!(w->accel = aa_init(l, ABS(w->stgs->acceleration_lookback),
|
@@ -858,16 +912,31 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
858
912
|
|
859
913
|
static void update_work_cache(ScsWork *w) {
|
860
914
|
/* g = (I + M)^{-1} h */
|
861
|
-
memcpy(w->g, w->h, (w->n + w->m) * sizeof(scs_float));
|
862
|
-
SCS(scale_array)(&(w->g[w->n]), -1., w->m);
|
863
|
-
|
915
|
+
memcpy(w->g, w->h, (w->d->n + w->d->m) * sizeof(scs_float));
|
916
|
+
SCS(scale_array)(&(w->g[w->d->n]), -1., w->d->m);
|
917
|
+
scs_solve_lin_sys(w->p, w->g, SCS_NULL, CG_BEST_TOL);
|
864
918
|
return;
|
865
919
|
}
|
866
920
|
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
921
|
+
/* Reset quantities specific to current solve */
|
922
|
+
static void reset_tracking(ScsWork *w) {
|
923
|
+
w->last_scale_update_iter = 0;
|
924
|
+
w->sum_log_scale_factor = 0.;
|
925
|
+
w->n_log_scale_factor = 0;
|
926
|
+
w->scale_updates = 0;
|
927
|
+
w->time_limit_reached = 0;
|
928
|
+
/* Acceleration */
|
929
|
+
w->rejected_accel_steps = 0;
|
930
|
+
w->accepted_accel_steps = 0;
|
931
|
+
w->aa_norm = 0.;
|
932
|
+
/* Need this to force residual calc if previous solve solved at iter 0 */
|
933
|
+
w->r_normalized->last_iter = -1;
|
934
|
+
w->r_orig->last_iter = -1;
|
935
|
+
}
|
936
|
+
|
937
|
+
static scs_int update_work(ScsWork *w, ScsSolution *sol) {
|
938
|
+
reset_tracking(w);
|
939
|
+
|
871
940
|
if (w->stgs->warm_start) {
|
872
941
|
warm_start_vars(w, sol);
|
873
942
|
} else {
|
@@ -875,8 +944,8 @@ static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
|
|
875
944
|
}
|
876
945
|
|
877
946
|
/* h = [c;b] */
|
878
|
-
memcpy(w->h, w->
|
879
|
-
memcpy(&(w->h[n]), w->
|
947
|
+
memcpy(w->h, w->d->c, w->d->n * sizeof(scs_float));
|
948
|
+
memcpy(&(w->h[w->d->n]), w->d->b, w->d->m * sizeof(scs_float));
|
880
949
|
update_work_cache(w);
|
881
950
|
return 0;
|
882
951
|
}
|
@@ -888,24 +957,27 @@ scs_int should_update_r(scs_float factor, scs_int iter) {
|
|
888
957
|
|
889
958
|
static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
890
959
|
scs_int i;
|
891
|
-
scs_float factor, new_scale;
|
960
|
+
scs_float factor, new_scale, relative_res_pri, relative_res_dual;
|
961
|
+
scs_float denom_pri, denom_dual;
|
892
962
|
|
893
963
|
ScsResiduals *r = w->r_orig;
|
894
|
-
|
895
|
-
scs_float
|
896
|
-
scs_float
|
964
|
+
|
965
|
+
scs_float nm_ax = SCALE_NORM(r->ax, w->d->m);
|
966
|
+
scs_float nm_s = SCALE_NORM(w->xys_orig->s, w->d->m);
|
967
|
+
scs_float nm_px_aty_ctau = SCALE_NORM(r->px_aty_ctau, w->d->n);
|
968
|
+
scs_float nm_px = SCALE_NORM(r->px, w->d->n);
|
969
|
+
scs_float nm_aty = SCALE_NORM(r->aty, w->d->n);
|
970
|
+
scs_float nm_ax_s_btau = SCALE_NORM(r->ax_s_btau, w->d->m);
|
897
971
|
|
898
972
|
scs_int iters_since_last_update = iter - w->last_scale_update_iter;
|
899
973
|
/* ||Ax + s - b * tau|| */
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
SCALE_NORM(b, w->m) * r->tau));
|
974
|
+
denom_pri = MAX(nm_ax, nm_s);
|
975
|
+
denom_pri = MAX(denom_pri, w->nm_b_orig * r->tau);
|
976
|
+
relative_res_pri = SAFEDIV_POS(nm_ax_s_btau, denom_pri);
|
904
977
|
/* ||Px + A'y + c * tau|| */
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
SCALE_NORM(c, w->n) * r->tau));
|
978
|
+
denom_dual = MAX(nm_px, nm_aty);
|
979
|
+
denom_dual = MAX(denom_dual, w->nm_c_orig * r->tau);
|
980
|
+
relative_res_dual = SAFEDIV_POS(nm_px_aty_ctau, denom_dual);
|
909
981
|
|
910
982
|
/* higher scale makes res_pri go down faster, so increase if res_pri larger */
|
911
983
|
w->sum_log_scale_factor += log(relative_res_pri) - log(relative_res_dual);
|
@@ -919,8 +991,9 @@ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
919
991
|
if (iters_since_last_update < RESCALING_MIN_ITERS) {
|
920
992
|
return;
|
921
993
|
}
|
922
|
-
new_scale =
|
923
|
-
|
994
|
+
new_scale =
|
995
|
+
MIN(MAX(w->stgs->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
|
996
|
+
if (new_scale == w->stgs->scale) {
|
924
997
|
return;
|
925
998
|
}
|
926
999
|
if (should_update_r(factor, iters_since_last_update)) {
|
@@ -928,13 +1001,13 @@ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
928
1001
|
w->sum_log_scale_factor = 0;
|
929
1002
|
w->n_log_scale_factor = 0;
|
930
1003
|
w->last_scale_update_iter = iter;
|
931
|
-
w->scale = new_scale;
|
1004
|
+
w->stgs->scale = new_scale;
|
932
1005
|
|
933
1006
|
/* update diag r vector */
|
934
1007
|
set_diag_r(w);
|
935
1008
|
|
936
1009
|
/* update linear systems */
|
937
|
-
|
1010
|
+
scs_update_lin_sys_diag_r(w->p, w->diag_r);
|
938
1011
|
|
939
1012
|
/* update pre-solved quantities */
|
940
1013
|
update_work_cache(w);
|
@@ -947,7 +1020,7 @@ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
947
1020
|
/* solve: R^+ (v^+ + u - 2u_t) = rsk = R(v + u - 2u_t)
|
948
1021
|
* => v^+ = R+^-1 rsk + 2u_t - u
|
949
1022
|
*/
|
950
|
-
for (i = 0; i < w->n + w->m + 1; i++) {
|
1023
|
+
for (i = 0; i < w->d->n + w->d->m + 1; i++) {
|
951
1024
|
w->v[i] = w->rsk[i] / w->diag_r[i] + 2 * w->u_t[i] - w->u[i];
|
952
1025
|
}
|
953
1026
|
}
|
@@ -959,7 +1032,8 @@ static inline void normalize_v(scs_float *v, scs_int len) {
|
|
959
1032
|
SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
|
960
1033
|
}
|
961
1034
|
|
962
|
-
scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info
|
1035
|
+
scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
1036
|
+
scs_int warm_start) {
|
963
1037
|
scs_int i;
|
964
1038
|
SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
|
965
1039
|
scs_float total_accel_time = 0.0, total_cone_time = 0.0,
|
@@ -968,16 +1042,18 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
968
1042
|
scs_printf("ERROR: missing ScsWork, ScsSolution or ScsInfo input\n");
|
969
1043
|
return SCS_FAILED;
|
970
1044
|
}
|
971
|
-
scs_int l = w->m + w->n + 1;
|
972
|
-
const ScsData *d = w->d;
|
1045
|
+
scs_int l = w->d->m + w->d->n + 1;
|
973
1046
|
const ScsCone *k = w->k;
|
974
|
-
|
1047
|
+
ScsSettings *stgs = w->stgs;
|
1048
|
+
/* set warm start */
|
1049
|
+
stgs->warm_start = warm_start;
|
1050
|
+
|
975
1051
|
/* initialize ctrl-c support */
|
976
1052
|
scs_start_interrupt_listener();
|
977
1053
|
SCS(tic)(&solve_timer);
|
978
|
-
strcpy(info->lin_sys_solver,
|
1054
|
+
strcpy(info->lin_sys_solver, scs_get_lin_sys_method());
|
979
1055
|
info->status_val = SCS_UNFINISHED; /* not yet converged */
|
980
|
-
update_work(
|
1056
|
+
update_work(w, sol);
|
981
1057
|
|
982
1058
|
if (w->stgs->verbose) {
|
983
1059
|
print_header(w, k);
|
@@ -1007,8 +1083,8 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1007
1083
|
|
1008
1084
|
/******************* linear system solve ********************/
|
1009
1085
|
SCS(tic)(&lin_sys_timer);
|
1010
|
-
if (project_lin_sys(w, i)
|
1011
|
-
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
1086
|
+
if (project_lin_sys(w, i) != 0) {
|
1087
|
+
return failure(w, w->d->m, w->d->n, sol, info, SCS_FAILED,
|
1012
1088
|
"error in project_lin_sys", "failure");
|
1013
1089
|
}
|
1014
1090
|
total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
|
@@ -1016,7 +1092,7 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1016
1092
|
/****************** project onto the cones ******************/
|
1017
1093
|
SCS(tic)(&cone_timer);
|
1018
1094
|
if (project_cones(w, k, i) < 0) {
|
1019
|
-
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
1095
|
+
return failure(w, w->d->m, w->d->n, sol, info, SCS_FAILED,
|
1020
1096
|
"error in project_cones", "failure");
|
1021
1097
|
}
|
1022
1098
|
total_cone_time += SCS(tocq)(&cone_timer);
|
@@ -1027,8 +1103,8 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1027
1103
|
|
1028
1104
|
if (i % CONVERGED_INTERVAL == 0) {
|
1029
1105
|
if (scs_is_interrupted()) {
|
1030
|
-
return failure(w, w->m, w->n, sol, info, SCS_SIGINT,
|
1031
|
-
"interrupted");
|
1106
|
+
return failure(w, w->d->m, w->d->n, sol, info, SCS_SIGINT,
|
1107
|
+
"interrupted", "interrupted");
|
1032
1108
|
}
|
1033
1109
|
populate_residual_struct(w, i);
|
1034
1110
|
if ((info->status_val = has_converged(w, i)) != 0) {
|
@@ -1076,14 +1152,14 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1076
1152
|
if (w->stgs->log_csv_filename) {
|
1077
1153
|
/* calc residuals every iter if logging to csv */
|
1078
1154
|
populate_residual_struct(w, i);
|
1079
|
-
SCS(log_data_to_csv)(
|
1155
|
+
SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
|
1080
1156
|
}
|
1081
1157
|
}
|
1082
1158
|
|
1083
1159
|
/* Final logging after full run */
|
1084
1160
|
if (w->stgs->log_csv_filename) {
|
1085
1161
|
populate_residual_struct(w, i);
|
1086
|
-
SCS(log_data_to_csv)(
|
1162
|
+
SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
|
1087
1163
|
}
|
1088
1164
|
|
1089
1165
|
if (w->stgs->verbose) {
|
@@ -1111,16 +1187,8 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1111
1187
|
void scs_finish(ScsWork *w) {
|
1112
1188
|
if (w) {
|
1113
1189
|
SCS(finish_cone)(w->cone_work);
|
1114
|
-
if (w->stgs && w->stgs->normalize) {
|
1115
|
-
#ifndef COPYAMATRIX
|
1116
|
-
SCS(un_normalize_a_p)(w->A, w->P, w->scal);
|
1117
|
-
#else
|
1118
|
-
SCS(free_scs_matrix)(w->A);
|
1119
|
-
SCS(free_scs_matrix)(w->P);
|
1120
|
-
#endif
|
1121
|
-
}
|
1122
1190
|
if (w->p) {
|
1123
|
-
|
1191
|
+
scs_free_lin_sys_work(w->p);
|
1124
1192
|
}
|
1125
1193
|
if (w->accel) {
|
1126
1194
|
aa_finish(w->accel);
|
@@ -1137,16 +1205,25 @@ ScsWork *scs_init(const ScsData *d, const ScsCone *k, const ScsSettings *stgs) {
|
|
1137
1205
|
scs_printf("ERROR: Missing ScsData or ScsCone input\n");
|
1138
1206
|
return SCS_NULL;
|
1139
1207
|
}
|
1140
|
-
#if
|
1208
|
+
#if NO_VALIDATE == 0
|
1141
1209
|
if (validate(d, k, stgs) < 0) {
|
1142
1210
|
scs_printf("ERROR: Validation returned failure\n");
|
1143
1211
|
return SCS_NULL;
|
1144
1212
|
}
|
1213
|
+
#endif
|
1214
|
+
#if VERBOSITY > 0
|
1215
|
+
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
|
1216
|
+
sizeof(scs_int), sizeof(scs_float));
|
1145
1217
|
#endif
|
1146
1218
|
SCS(tic)(&init_timer);
|
1147
1219
|
if (stgs->write_data_filename) {
|
1220
|
+
scs_printf("Writing raw problem data to %s\n", stgs->write_data_filename);
|
1148
1221
|
SCS(write_data)(d, k, stgs);
|
1149
1222
|
}
|
1223
|
+
if (stgs->log_csv_filename) {
|
1224
|
+
scs_printf("Logging run data to %s\n", stgs->log_csv_filename);
|
1225
|
+
/* logging done every iteration */
|
1226
|
+
}
|
1150
1227
|
w = init_work(d, k, stgs);
|
1151
1228
|
if (w) {
|
1152
1229
|
w->setup_time = SCS(tocq)(&init_timer);
|
@@ -1160,12 +1237,8 @@ scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
|
|
1160
1237
|
ScsSolution *sol, ScsInfo *info) {
|
1161
1238
|
scs_int status;
|
1162
1239
|
ScsWork *w = scs_init(d, k, stgs);
|
1163
|
-
#if VERBOSITY > 0
|
1164
|
-
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
|
1165
|
-
sizeof(scs_int), sizeof(scs_float));
|
1166
|
-
#endif
|
1167
1240
|
if (w) {
|
1168
|
-
scs_solve(w, sol, info);
|
1241
|
+
scs_solve(w, sol, info, stgs->warm_start);
|
1169
1242
|
status = info->status_val;
|
1170
1243
|
} else {
|
1171
1244
|
status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
|