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.
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,