scs 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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,
|