scs 0.3.2 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +35 -6
  5. data/lib/scs/matrix.rb +72 -0
  6. data/lib/scs/solver.rb +19 -26
  7. data/lib/scs/version.rb +1 -1
  8. data/lib/scs.rb +1 -0
  9. data/vendor/scs/CITATION.cff +2 -2
  10. data/vendor/scs/CMakeLists.txt +285 -169
  11. data/vendor/scs/Makefile +43 -18
  12. data/vendor/scs/README.md +3 -1
  13. data/vendor/scs/include/cones.h +5 -3
  14. data/vendor/scs/include/glbopts.h +35 -17
  15. data/vendor/scs/include/linsys.h +8 -8
  16. data/vendor/scs/include/normalize.h +1 -0
  17. data/vendor/scs/include/rw.h +3 -3
  18. data/vendor/scs/include/scs.h +51 -24
  19. data/vendor/scs/include/scs_types.h +3 -1
  20. data/vendor/scs/include/scs_work.h +13 -15
  21. data/vendor/scs/include/util.h +4 -2
  22. data/vendor/scs/linsys/cpu/direct/private.c +32 -153
  23. data/vendor/scs/linsys/cpu/direct/private.h +6 -6
  24. data/vendor/scs/linsys/cpu/indirect/private.c +9 -22
  25. data/vendor/scs/linsys/cpu/indirect/private.h +4 -2
  26. data/vendor/scs/linsys/csparse.c +140 -12
  27. data/vendor/scs/linsys/csparse.h +10 -17
  28. data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
  29. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +4 -2
  30. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +0 -5
  31. data/vendor/scs/linsys/gpu/gpu.c +4 -4
  32. data/vendor/scs/linsys/gpu/gpu.h +1 -1
  33. data/vendor/scs/linsys/gpu/indirect/private.c +15 -26
  34. data/vendor/scs/linsys/mkl/direct/private.c +182 -0
  35. data/vendor/scs/linsys/mkl/direct/private.h +38 -0
  36. data/vendor/scs/linsys/scs_matrix.c +49 -72
  37. data/vendor/scs/linsys/scs_matrix.h +4 -3
  38. data/vendor/scs/scs.mk +39 -30
  39. data/vendor/scs/src/aa.c +0 -4
  40. data/vendor/scs/src/cones.c +78 -184
  41. data/vendor/scs/src/exp_cone.c +399 -0
  42. data/vendor/scs/src/normalize.c +51 -0
  43. data/vendor/scs/src/rw.c +139 -76
  44. data/vendor/scs/src/scs.c +275 -202
  45. data/vendor/scs/src/util.c +36 -13
  46. data/vendor/scs/test/minunit.h +2 -1
  47. data/vendor/scs/test/problem_utils.h +5 -4
  48. data/vendor/scs/test/problems/degenerate.h +1 -0
  49. data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
  50. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +13 -4
  51. data/vendor/scs/test/problems/infeasible_tiny_qp.h +1 -0
  52. data/vendor/scs/test/problems/max_ent +0 -0
  53. data/vendor/scs/test/problems/max_ent.h +8 -0
  54. data/vendor/scs/test/problems/qafiro_tiny_qp.h +2 -1
  55. data/vendor/scs/test/problems/random_prob.h +2 -39
  56. data/vendor/scs/test/problems/rob_gauss_cov_est.h +15 -3
  57. data/vendor/scs/test/problems/small_lp.h +4 -1
  58. data/vendor/scs/test/problems/small_qp.h +42 -7
  59. data/vendor/scs/test/problems/test_exp_cone.h +84 -0
  60. data/vendor/scs/test/problems/test_prob_from_data_file.h +57 -0
  61. data/vendor/scs/test/problems/test_validation.h +4 -1
  62. data/vendor/scs/test/problems/unbounded_tiny_qp.h +3 -3
  63. data/vendor/scs/test/random_socp_prob.c +3 -1
  64. data/vendor/scs/test/run_from_file.c +22 -4
  65. data/vendor/scs/test/run_tests.c +22 -9
  66. 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->b_normalized);
44
- scs_free(w->c_normalized);
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 = SCS(get_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, warm_start: %i\n",
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, (int)stgs->warm_start);
95
- /* , stgs->rho_x); */
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
- memcpy(v, sol->x, n * sizeof(scs_float));
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
- r->res_pri = SAFEDIV_POS(NORM(r->ax_s_btau, m), r->tau);
179
- r->res_dual = SAFEDIV_POS(NORM(r->px_aty_ctau, n), r->tau);
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
- r->res_unbdd_a = SAFEDIV_POS(NORM(r->ax_s, m), -r->ctx_tau);
185
- r->res_unbdd_p = SAFEDIV_POS(NORM(r->px, n), -r->ctx_tau);
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
- r->res_infeas = SAFEDIV_POS(NORM(r->aty, n), -r->bty_tau);
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->b_normalized, m, -r->tau);
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->c_normalized, n, r->tau);
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->b_normalized, m);
290
- r->ctx_tau = SCS(dot)(x, w->c_normalized, n);
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
- return (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
361
+ rad = b * b - 4 * a * c;
362
+ return (-b + SQRTF(MAX(rad, 0.))) / (2 * a);
335
363
  }
336
364
 
337
- /* status < 0 indicates failure */
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
- SCS(add_scaled_array)(warm_start, w->g, l - 1, w->u[l - 1]);
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(CG_NORM(w->r_normalized->ax_s_btau, w->m),
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
- tol = CG_TOL_FACTOR * MIN(tol, CG_NORM(warm_start, w->n) /
359
- POWF((scs_float)iter + 1, CG_RATE));
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 = SCS(solve_lin_sys)(w->p, w->u_t, warm_start, tol);
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(SCS(dot)(sol->s, sol->y, w->m));
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
- scs_printf("%*.2e ", (int)HSPACE, SCS(tocq)(solve_timer) / 1e3);
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(ABS(r->xt_p_x), ABS(r->ctx)), ABS(r->bty));
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(NORM(b, w->m) * r->tau, NORM(s, w->m)), NORM(r->ax, w->m)) /
647
- r->tau;
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 NOVALIDATE == 0
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] = TAU_FACTOR; /* TODO: is this the best choice? */
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
- /* get settings and dims from data struct */
759
- w->d = d;
760
- w->k = k;
761
- w->stgs = stgs;
762
- w->scale = stgs->scale; /* initial scale, may be updated */
763
- w->m = d->m;
764
- w->n = d->n;
765
- w->last_scale_update_iter = 0;
766
- w->sum_log_scale_factor = 0.;
767
- w->n_log_scale_factor = 0;
768
- w->scale_updates = 0;
769
- w->time_limit_reached = 0;
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((l - 1), sizeof(scs_float));
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->A = d->A;
788
- w->P = d->P;
789
-
790
- w->b_orig = d->b;
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->c_normalized) {
804
- scs_printf("ERROR: work memory allocation failure\n");
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->b_normalized, w->c_normalized,
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
- if (!(w->p = SCS(init_lin_sys_work)(w->A, w->P, w->diag_r))) {
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
- SCS(solve_lin_sys)(w->p, w->g, SCS_NULL, CG_BEST_TOL);
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
- static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
868
- /* before normalization */
869
- scs_int n = d->n;
870
- scs_int m = d->m;
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->c_normalized, n * sizeof(scs_float));
879
- memcpy(&(w->h[n]), w->b_normalized, m * sizeof(scs_float));
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
- ScsSolution *xys = w->xys_orig;
895
- scs_float *b = w->b_orig;
896
- scs_float *c = w->c_orig;
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
- scs_float relative_res_pri =
901
- SAFEDIV_POS(SCALE_NORM(r->ax_s_btau, w->m),
902
- MAX(MAX(SCALE_NORM(r->ax, w->m), SCALE_NORM(xys->s, w->m)),
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
- scs_float relative_res_dual =
906
- SAFEDIV_POS(SCALE_NORM(r->px_aty_ctau, w->n),
907
- MAX(MAX(SCALE_NORM(r->px, w->n), SCALE_NORM(r->aty, w->n)),
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 = MIN(MAX(w->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
923
- if (new_scale == w->scale) {
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
- SCS(update_lin_sys_diag_r)(w->p, w->diag_r);
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
- const ScsSettings *stgs = w->stgs;
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, SCS(get_lin_sys_method)());
1054
+ strcpy(info->lin_sys_solver, scs_get_lin_sys_method());
979
1055
  info->status_val = SCS_UNFINISHED; /* not yet converged */
980
- update_work(d, w, sol);
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) < 0) {
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, "interrupted",
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)(d, k, stgs, w, i, &solve_timer);
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)(d, k, stgs, w, i, &solve_timer);
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
- SCS(free_lin_sys_work)(w->p);
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 NOVALIDATE == 0
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,