scs 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +34 -5
  4. data/lib/scs/matrix.rb +72 -0
  5. data/lib/scs/solver.rb +19 -26
  6. data/lib/scs/version.rb +1 -1
  7. data/lib/scs.rb +1 -0
  8. data/vendor/scs/CITATION.cff +1 -1
  9. data/vendor/scs/CMakeLists.txt +2 -2
  10. data/vendor/scs/README.md +3 -1
  11. data/vendor/scs/include/cones.h +5 -3
  12. data/vendor/scs/include/glbopts.h +4 -5
  13. data/vendor/scs/include/normalize.h +1 -0
  14. data/vendor/scs/include/rw.h +3 -3
  15. data/vendor/scs/include/scs.h +45 -22
  16. data/vendor/scs/include/scs_work.h +15 -18
  17. data/vendor/scs/include/util.h +3 -1
  18. data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
  19. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +4 -2
  20. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +0 -5
  21. data/vendor/scs/linsys/scs_matrix.c +38 -67
  22. data/vendor/scs/linsys/scs_matrix.h +4 -3
  23. data/vendor/scs/scs.mk +0 -4
  24. data/vendor/scs/src/aa.c +0 -4
  25. data/vendor/scs/src/cones.c +63 -25
  26. data/vendor/scs/src/normalize.c +49 -0
  27. data/vendor/scs/src/rw.c +48 -40
  28. data/vendor/scs/src/scs.c +212 -170
  29. data/vendor/scs/src/util.c +26 -12
  30. data/vendor/scs/test/problem_utils.h +3 -3
  31. data/vendor/scs/test/problems/degenerate.h +1 -0
  32. data/vendor/scs/test/problems/hs21_tiny_qp.h +1 -0
  33. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +5 -1
  34. data/vendor/scs/test/problems/infeasible_tiny_qp.h +1 -0
  35. data/vendor/scs/test/problems/qafiro_tiny_qp.h +2 -1
  36. data/vendor/scs/test/problems/random_prob.h +5 -1
  37. data/vendor/scs/test/problems/rob_gauss_cov_est.h +8 -1
  38. data/vendor/scs/test/problems/small_lp.h +4 -1
  39. data/vendor/scs/test/problems/small_qp.h +42 -7
  40. data/vendor/scs/test/problems/test_validation.h +4 -1
  41. data/vendor/scs/test/problems/unbounded_tiny_qp.h +3 -3
  42. data/vendor/scs/test/random_socp_prob.c +3 -1
  43. data/vendor/scs/test/run_from_file.c +15 -3
  44. metadata +5 -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
  }
@@ -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 */
@@ -199,12 +219,12 @@ static void unnormalize_residuals(ScsWork *w) {
199
219
  r->tau = r_n->tau;
200
220
 
201
221
  /* 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));
222
+ memcpy(r->ax, r_n->ax, w->d->m * sizeof(scs_float));
223
+ memcpy(r->ax_s, r_n->ax_s, w->d->m * sizeof(scs_float));
224
+ memcpy(r->ax_s_btau, r_n->ax_s_btau, w->d->m * sizeof(scs_float));
225
+ memcpy(r->aty, r_n->aty, w->d->n * sizeof(scs_float));
226
+ memcpy(r->px, r_n->px, w->d->n * sizeof(scs_float));
227
+ memcpy(r->px_aty_ctau, r_n->px_aty_ctau, w->d->n * sizeof(scs_float));
208
228
 
209
229
  /* unnormalize */
210
230
  r->kap = r_n->kap / pd;
@@ -225,13 +245,13 @@ static void unnormalize_residuals(ScsWork *w) {
225
245
  SCS(un_normalize_dual)(w->scal, r->px);
226
246
  SCS(un_normalize_dual)(w->scal, r->px_aty_ctau);
227
247
 
228
- compute_residuals(r, w->m, w->n);
248
+ compute_residuals(r, w->d->m, w->d->n);
229
249
  }
230
250
 
231
251
  /* calculates un-normalized residual quantities */
232
252
  /* this is somewhat slow but not a bottleneck */
233
253
  static void populate_residual_struct(ScsWork *w, scs_int iter) {
234
- scs_int n = w->n, m = w->m;
254
+ scs_int n = w->d->n, m = w->d->m;
235
255
  /* normalized x,y,s terms */
236
256
  scs_float *x = w->xys_normalized->x;
237
257
  scs_float *y = w->xys_normalized->y;
@@ -254,7 +274,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
254
274
  /**************** PRIMAL *********************/
255
275
  memset(r->ax, 0, m * sizeof(scs_float));
256
276
  /* ax = Ax */
257
- SCS(accum_by_a)(w->A, x, r->ax);
277
+ SCS(accum_by_a)(w->d->A, x, r->ax);
258
278
 
259
279
  memcpy(r->ax_s, r->ax, m * sizeof(scs_float));
260
280
  /* ax_s = Ax + s */
@@ -262,13 +282,13 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
262
282
 
263
283
  memcpy(r->ax_s_btau, r->ax_s, m * sizeof(scs_float));
264
284
  /* ax_s_btau = Ax + s - b * tau */
265
- SCS(add_scaled_array)(r->ax_s_btau, w->b_normalized, m, -r->tau);
285
+ SCS(add_scaled_array)(r->ax_s_btau, w->d->b, m, -r->tau);
266
286
 
267
287
  /**************** DUAL *********************/
268
288
  memset(r->px, 0, n * sizeof(scs_float));
269
- if (w->P) {
289
+ if (w->d->P) {
270
290
  /* px = Px */
271
- SCS(accum_by_p)(w->P, x, r->px);
291
+ SCS(accum_by_p)(w->d->P, x, r->px);
272
292
  r->xt_p_x_tau = SCS(dot)(r->px, x, n);
273
293
  } else {
274
294
  r->xt_p_x_tau = 0.;
@@ -276,18 +296,18 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
276
296
 
277
297
  memset(r->aty, 0, n * sizeof(scs_float));
278
298
  /* aty = A'y */
279
- SCS(accum_by_atrans)(w->A, y, r->aty);
299
+ SCS(accum_by_atrans)(w->d->A, y, r->aty);
280
300
 
281
301
  /* r->px_aty_ctau = Px */
282
302
  memcpy(r->px_aty_ctau, r->px, n * sizeof(scs_float));
283
303
  /* r->px_aty_ctau = Px + A'y */
284
304
  SCS(add_scaled_array)(r->px_aty_ctau, r->aty, n, 1.);
285
305
  /* r->px_aty_ctau = Px + A'y + c * tau */
286
- SCS(add_scaled_array)(r->px_aty_ctau, w->c_normalized, n, r->tau);
306
+ SCS(add_scaled_array)(r->px_aty_ctau, w->d->c, n, r->tau);
287
307
 
288
308
  /**************** OTHERS *****************/
289
- r->bty_tau = SCS(dot)(y, w->b_normalized, m);
290
- r->ctx_tau = SCS(dot)(x, w->c_normalized, n);
309
+ r->bty_tau = SCS(dot)(y, w->d->b, m);
310
+ r->ctx_tau = SCS(dot)(x, w->d->c, n);
291
311
 
292
312
  r->bty = SAFEDIV_POS(r->bty_tau, r->tau);
293
313
  r->ctx = SAFEDIV_POS(r->ctx_tau, r->tau);
@@ -309,7 +329,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
309
329
  }
310
330
 
311
331
  static void cold_start_vars(ScsWork *w) {
312
- scs_int l = w->n + w->m + 1;
332
+ scs_int l = w->d->n + w->d->m + 1;
313
333
  memset(w->v, 0, l * sizeof(scs_float));
314
334
  w->v[l - 1] = 1.;
315
335
  }
@@ -319,7 +339,7 @@ static inline scs_float dot_r(ScsWork *w, const scs_float *x,
319
339
  const scs_float *y) {
320
340
  scs_int i;
321
341
  scs_float ip = 0.0;
322
- for (i = 0; i < w->n + w->m; ++i) {
342
+ for (i = 0; i < w->d->n + w->d->m; ++i) {
323
343
  ip += x[i] * y[i] * w->diag_r[i];
324
344
  }
325
345
  return ip;
@@ -327,7 +347,7 @@ static inline scs_float dot_r(ScsWork *w, const scs_float *x,
327
347
 
328
348
  static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
329
349
  scs_float eta) {
330
- scs_float a, b, c, tau_scale = w->diag_r[w->n + w->m];
350
+ scs_float a, b, c, tau_scale = w->diag_r[w->d->n + w->d->m];
331
351
  a = tau_scale + dot_r(w, w->g, w->g);
332
352
  b = dot_r(w, mu, w->g) - 2 * dot_r(w, p, w->g) - eta * tau_scale;
333
353
  c = dot_r(w, p, p) - dot_r(w, p, mu);
@@ -336,7 +356,7 @@ static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
336
356
 
337
357
  /* status < 0 indicates failure */
338
358
  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;
359
+ scs_int n = w->d->n, m = w->d->m, l = n + m + 1, status, i;
340
360
  scs_float *warm_start = SCS_NULL;
341
361
  scs_float tol = -1.0; /* only used for indirect methods, overridden later */
342
362
  memcpy(w->u_t, w->v, l * sizeof(scs_float));
@@ -350,12 +370,12 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
350
370
  /* warm_start = u[:n] + tau * g[:n] */
351
371
  SCS(add_scaled_array)(warm_start, w->g, l - 1, w->u[l - 1]);
352
372
  /* 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));
373
+ tol = MIN(CG_NORM(w->r_normalized->ax_s_btau, w->d->m),
374
+ CG_NORM(w->r_normalized->px_aty_ctau, w->d->n));
355
375
  /* tol ~ O(1/k^(1+eps)) guarantees convergence */
356
376
  /* use warm-start to calculate tolerance rather than w->u_t, since warm_start
357
377
  * should be approximately equal to the true solution */
358
- tol = CG_TOL_FACTOR * MIN(tol, CG_NORM(warm_start, w->n) /
378
+ tol = CG_TOL_FACTOR * MIN(tol, CG_NORM(warm_start, w->d->n) /
359
379
  POWF((scs_float)iter + 1, CG_RATE));
360
380
  tol = MAX(CG_BEST_TOL, tol);
361
381
  #endif
@@ -378,14 +398,14 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
378
398
  * (no effect of w->stgs->alpha here).
379
399
  */
380
400
  static void compute_rsk(ScsWork *w) {
381
- scs_int i, l = w->m + w->n + 1;
401
+ scs_int i, l = w->d->m + w->d->n + 1;
382
402
  for (i = 0; i < l; ++i) {
383
403
  w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->diag_r[i];
384
404
  }
385
405
  }
386
406
 
387
407
  static void update_dual_vars(ScsWork *w) {
388
- scs_int i, l = w->n + w->m + 1;
408
+ scs_int i, l = w->d->n + w->d->m + 1;
389
409
  for (i = 0; i < l; ++i) {
390
410
  w->v[i] += w->stgs->alpha * (w->u[i] - w->u_t[i]);
391
411
  }
@@ -393,7 +413,7 @@ static void update_dual_vars(ScsWork *w) {
393
413
 
394
414
  /* status < 0 indicates failure */
395
415
  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;
416
+ scs_int i, n = w->d->n, l = w->d->n + w->d->m + 1, status;
397
417
  for (i = 0; i < l; ++i) {
398
418
  w->u[i] = 2 * w->u_t[i] - w->v[i];
399
419
  }
@@ -410,30 +430,30 @@ static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
410
430
 
411
431
  static void sety(const ScsWork *w, ScsSolution *sol) {
412
432
  if (!sol->y) {
413
- sol->y = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
433
+ sol->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
414
434
  }
415
- memcpy(sol->y, &(w->u[w->n]), w->m * sizeof(scs_float));
435
+ memcpy(sol->y, &(w->u[w->d->n]), w->d->m * sizeof(scs_float));
416
436
  }
417
437
 
418
438
  /* s is contained in rsk */
419
439
  static void sets(const ScsWork *w, ScsSolution *sol) {
420
440
  if (!sol->s) {
421
- sol->s = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
441
+ sol->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
422
442
  }
423
- memcpy(sol->s, &(w->rsk[w->n]), w->m * sizeof(scs_float));
443
+ memcpy(sol->s, &(w->rsk[w->d->n]), w->d->m * sizeof(scs_float));
424
444
  }
425
445
 
426
446
  static void setx(const ScsWork *w, ScsSolution *sol) {
427
447
  if (!sol->x) {
428
- sol->x = (scs_float *)scs_calloc(w->n, sizeof(scs_float));
448
+ sol->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
429
449
  }
430
- memcpy(sol->x, w->u, w->n * sizeof(scs_float));
450
+ memcpy(sol->x, w->u, w->d->n * sizeof(scs_float));
431
451
  }
432
452
 
433
453
  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);
454
+ SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->n);
455
+ SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->m);
456
+ SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, w->r_orig->tau), w->d->m);
437
457
  info->gap = w->r_orig->gap;
438
458
  info->res_pri = w->r_orig->res_pri;
439
459
  info->res_dual = w->r_orig->res_dual;
@@ -444,9 +464,9 @@ static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
444
464
  }
445
465
 
446
466
  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);
467
+ SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->d->m);
468
+ SCS(scale_array)(sol->x, NAN, w->d->n);
469
+ SCS(scale_array)(sol->s, NAN, w->d->m);
450
470
  info->gap = NAN;
451
471
  info->res_pri = NAN;
452
472
  info->res_dual = NAN;
@@ -457,9 +477,9 @@ static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
457
477
  }
458
478
 
459
479
  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);
480
+ SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->d->n);
481
+ SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->d->m);
482
+ SCS(scale_array)(sol->y, NAN, w->d->m);
463
483
  info->gap = NAN;
464
484
  info->res_pri = NAN;
465
485
  info->res_dual = NAN;
@@ -506,13 +526,13 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
506
526
  info->res_infeas = w->r_orig->res_infeas;
507
527
  info->res_unbdd_a = w->r_orig->res_unbdd_a;
508
528
  info->res_unbdd_p = w->r_orig->res_unbdd_p;
509
- info->scale = w->scale;
529
+ info->scale = w->stgs->scale;
510
530
  info->scale_updates = w->scale_updates;
511
531
  info->rejected_accel_steps = w->rejected_accel_steps;
512
532
  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))) {
533
+ info->comp_slack = ABS(SCS(dot)(sol->s, sol->y, w->d->m));
534
+ if (info->comp_slack > 1e-5 * MAX(SCS(norm_inf)(sol->s, w->d->m),
535
+ SCS(norm_inf)(sol->y, w->d->m))) {
516
536
  scs_printf("WARNING - large complementary slackness residual: %f\n",
517
537
  info->comp_slack);
518
538
  }
@@ -542,23 +562,23 @@ static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
542
562
  scs_printf("%*.2e ", (int)HSPACE, r->gap);
543
563
  /* report mid point of primal and dual objective values */
544
564
  scs_printf("%*.2e ", (int)HSPACE, 0.5 * (r->pobj + r->dobj));
545
- scs_printf("%*.2e ", (int)HSPACE, w->scale);
565
+ scs_printf("%*.2e ", (int)HSPACE, w->stgs->scale);
546
566
  scs_printf("%*.2e ", (int)HSPACE, SCS(tocq)(solve_timer) / 1e3);
547
567
  scs_printf("\n");
548
568
 
549
569
  #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]);
570
+ scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->d->n + w->d->m + 1));
571
+ scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->d->n + w->d->m + 1));
572
+ scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->d->n + w->d->m + 1));
573
+ scs_printf("Norm rsk = %4f, ", SCS(norm_2)(w->rsk, w->d->n + w->d->m + 1));
574
+ scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->d->n));
575
+ scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->d->m));
576
+ scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->d->m));
577
+ scs_printf("Norm |Ax + s| = %1.2e, ", SCS(norm_2)(r->ax_s, w->d->m));
578
+ scs_printf("tau = %4f, ", w->u[w->d->n + w->d->m]);
579
+ scs_printf("kappa = %4f, ", w->rsk[w->d->n + w->d->m]);
560
580
  scs_printf("|u - u_t| = %1.2e, ",
561
- SCS(norm_diff)(w->u, w->u_t, w->n + w->m + 1));
581
+ SCS(norm_diff)(w->u, w->u_t, w->d->n + w->d->m + 1));
562
582
  scs_printf("res_infeas = %1.2e, ", r->res_infeas);
563
583
  scs_printf("res_unbdd_a = %1.2e, ", r->res_unbdd_a);
564
584
  scs_printf("res_unbdd_p = %1.2e, ", r->res_unbdd_p);
@@ -643,10 +663,11 @@ static scs_int has_converged(ScsWork *w, scs_int iter) {
643
663
  /* xt_p_x, ctx, bty already have tau divided out */
644
664
  grl = MAX(MAX(ABS(r->xt_p_x), ABS(r->ctx)), ABS(r->bty));
645
665
  /* 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)) /
666
+ prl = MAX(MAX(NORM(b, w->d->m) * r->tau, NORM(s, w->d->m)),
667
+ NORM(r->ax, w->d->m)) /
647
668
  r->tau;
648
- drl = MAX(MAX(NORM(c, w->n) * r->tau, NORM(r->px, w->n)),
649
- NORM(r->aty, w->n)) /
669
+ drl = MAX(MAX(NORM(c, w->d->n) * r->tau, NORM(r->px, w->d->n)),
670
+ NORM(r->aty, w->d->n)) /
650
671
  r->tau;
651
672
  if (isless(r->res_pri, eps_abs + eps_rel * prl) &&
652
673
  isless(r->res_dual, eps_abs + eps_rel * drl) &&
@@ -722,7 +743,6 @@ static scs_int validate(const ScsData *d, const ScsCone *k,
722
743
 
723
744
  static ScsResiduals *init_residuals(const ScsData *d) {
724
745
  ScsResiduals *r = (ScsResiduals *)scs_calloc(1, sizeof(ScsResiduals));
725
- r->last_iter = -1;
726
746
  r->ax = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
727
747
  r->ax_s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
728
748
  r->ax_s_btau = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
@@ -732,16 +752,44 @@ static ScsResiduals *init_residuals(const ScsData *d) {
732
752
  return r;
733
753
  }
734
754
 
755
+ scs_int scs_update(ScsWork *w, scs_float *b, scs_float *c) {
756
+ SCS(timer) update_timer;
757
+ SCS(tic)(&update_timer);
758
+
759
+ if (b) {
760
+ memcpy(w->b_orig, b, w->d->m * sizeof(scs_float));
761
+ memcpy(w->d->b, b, w->d->m * sizeof(scs_float));
762
+ } else {
763
+ memcpy(w->d->b, w->b_orig, w->d->m * sizeof(scs_float));
764
+ }
765
+ if (c) {
766
+ memcpy(w->c_orig, c, w->d->n * sizeof(scs_float));
767
+ memcpy(w->d->c, c, w->d->n * sizeof(scs_float));
768
+ } else {
769
+ memcpy(w->d->c, w->c_orig, w->d->n * sizeof(scs_float));
770
+ }
771
+
772
+ /* normalize */
773
+ if (w->scal) {
774
+ SCS(normalize_b_c)(w->scal, w->d->b, w->d->c);
775
+ }
776
+
777
+ /* override setup time with update time, since the update is the 'setup' */
778
+ w->setup_time = SCS(tocq)(&update_timer);
779
+ return 0;
780
+ }
781
+
735
782
  /* Sets the diag_r vector, given the scale parameters in work */
736
783
  static void set_diag_r(ScsWork *w) {
737
784
  scs_int i;
738
- for (i = 0; i < w->n; ++i) {
785
+ for (i = 0; i < w->d->n; ++i) {
739
786
  w->diag_r[i] = w->stgs->rho_x;
740
787
  }
741
788
  /* use cone information to set R_y */
742
- SCS(set_r_y)(w->cone_work, w->scale, &(w->diag_r[w->n]));
789
+ SCS(set_r_y)(w->cone_work, w->stgs->scale, &(w->diag_r[w->d->n]));
743
790
  /* if modified need to SCS(enforce_cone_boundaries)(...) */
744
- w->diag_r[w->n + w->m] = TAU_FACTOR; /* TODO: is this the best choice? */
791
+ w->diag_r[w->d->n + w->d->m] =
792
+ TAU_FACTOR; /* TODO: is this the best choice? */
745
793
  }
746
794
 
747
795
  static ScsWork *init_work(const ScsData *d, const ScsCone *k,
@@ -755,18 +803,21 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
755
803
  scs_printf("ERROR: allocating work failure\n");
756
804
  return SCS_NULL;
757
805
  }
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;
806
+ /* deep copy data */
807
+ w->d = (ScsData *)scs_calloc(1, sizeof(ScsData));
808
+ SCS(deep_copy_data)(w->d, d);
809
+ d = SCS_NULL; /* for safety */
810
+
811
+ /* deep copy cone */
812
+ w->k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
813
+ SCS(deep_copy_cone)(w->k, k);
814
+ k = SCS_NULL; /* for safety */
815
+
816
+ /* deep copy settings */
817
+ w->stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
818
+ SCS(deep_copy_stgs)(w->stgs, stgs);
819
+ stgs = SCS_NULL; /* for safety */
820
+
770
821
  /* allocate workspace: */
771
822
  w->u = (scs_float *)scs_calloc(l, sizeof(scs_float));
772
823
  w->u_t = (scs_float *)scs_calloc(l, sizeof(scs_float));
@@ -779,64 +830,44 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
779
830
  w->diag_r = (scs_float *)scs_calloc(l, sizeof(scs_float));
780
831
  /* x,y,s struct */
781
832
  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");
833
+ w->xys_orig->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
834
+ w->xys_orig->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
835
+ w->xys_orig->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
836
+ w->r_orig = init_residuals(w->d);
837
+ w->b_orig = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
838
+ w->c_orig = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
839
+
840
+ if (!w->c_orig) {
841
+ scs_printf("ERROR: work memory allocation failure\n");
799
842
  return SCS_NULL;
800
843
  }
801
- set_diag_r(w);
802
844
 
803
- if (!w->c_normalized) {
804
- scs_printf("ERROR: work memory allocation failure\n");
845
+ if (!(w->cone_work = SCS(init_cone)(w->k, w->d->m))) {
846
+ scs_printf("ERROR: init_cone failure\n");
805
847
  return SCS_NULL;
806
848
  }
849
+ set_diag_r(w);
807
850
 
808
851
  if (w->stgs->normalize) {
809
852
  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
853
+ w->xys_normalized->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
854
+ w->xys_normalized->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
855
+ w->xys_normalized->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
856
+ w->r_normalized = init_residuals(w->d);
825
857
  /* 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);
858
+ w->scal = SCS(normalize_a_p)(w->d->P, w->d->A, w->cone_work);
828
859
  } else {
829
860
  w->xys_normalized = w->xys_orig;
830
861
  w->r_normalized = w->r_orig;
831
862
  w->scal = SCS_NULL;
832
863
  }
833
- if (!(w->p = SCS(init_lin_sys_work)(w->A, w->P, w->diag_r))) {
864
+ /* set w->*_orig and performs normalization if appropriate */
865
+ scs_update(w, w->d->b, w->d->c);
866
+
867
+ if (!(w->p = SCS(init_lin_sys_work)(w->d->A, w->d->P, w->diag_r))) {
834
868
  scs_printf("ERROR: init_lin_sys_work failure\n");
835
869
  return SCS_NULL;
836
870
  }
837
- /* Acceleration */
838
- w->rejected_accel_steps = 0;
839
- w->accepted_accel_steps = 0;
840
871
  if (w->stgs->acceleration_lookback) {
841
872
  /* TODO(HACK!) negative acceleration_lookback interpreted as type-II */
842
873
  if (!(w->accel = aa_init(l, ABS(w->stgs->acceleration_lookback),
@@ -858,16 +889,31 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
858
889
 
859
890
  static void update_work_cache(ScsWork *w) {
860
891
  /* 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);
892
+ memcpy(w->g, w->h, (w->d->n + w->d->m) * sizeof(scs_float));
893
+ SCS(scale_array)(&(w->g[w->d->n]), -1., w->d->m);
863
894
  SCS(solve_lin_sys)(w->p, w->g, SCS_NULL, CG_BEST_TOL);
864
895
  return;
865
896
  }
866
897
 
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;
898
+ /* Reset quantities specific to current solve */
899
+ static void reset_tracking(ScsWork *w) {
900
+ w->last_scale_update_iter = 0;
901
+ w->sum_log_scale_factor = 0.;
902
+ w->n_log_scale_factor = 0;
903
+ w->scale_updates = 0;
904
+ w->time_limit_reached = 0;
905
+ /* Acceleration */
906
+ w->rejected_accel_steps = 0;
907
+ w->accepted_accel_steps = 0;
908
+ w->aa_norm = 0.;
909
+ /* Need this to force residual calc if previous solve solved at iter 0 */
910
+ w->r_normalized->last_iter = -1;
911
+ w->r_orig->last_iter = -1;
912
+ }
913
+
914
+ static scs_int update_work(ScsWork *w, ScsSolution *sol) {
915
+ reset_tracking(w);
916
+
871
917
  if (w->stgs->warm_start) {
872
918
  warm_start_vars(w, sol);
873
919
  } else {
@@ -875,8 +921,8 @@ static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
875
921
  }
876
922
 
877
923
  /* 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));
924
+ memcpy(w->h, w->d->c, w->d->n * sizeof(scs_float));
925
+ memcpy(&(w->h[w->d->n]), w->d->b, w->d->m * sizeof(scs_float));
880
926
  update_work_cache(w);
881
927
  return 0;
882
928
  }
@@ -897,15 +943,15 @@ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
897
943
 
898
944
  scs_int iters_since_last_update = iter - w->last_scale_update_iter;
899
945
  /* ||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));
946
+ scs_float relative_res_pri = SAFEDIV_POS(
947
+ SCALE_NORM(r->ax_s_btau, w->d->m),
948
+ MAX(MAX(SCALE_NORM(r->ax, w->d->m), SCALE_NORM(xys->s, w->d->m)),
949
+ SCALE_NORM(b, w->d->m) * r->tau));
904
950
  /* ||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));
951
+ scs_float relative_res_dual = SAFEDIV_POS(
952
+ SCALE_NORM(r->px_aty_ctau, w->d->n),
953
+ MAX(MAX(SCALE_NORM(r->px, w->d->n), SCALE_NORM(r->aty, w->d->n)),
954
+ SCALE_NORM(c, w->d->n) * r->tau));
909
955
 
910
956
  /* higher scale makes res_pri go down faster, so increase if res_pri larger */
911
957
  w->sum_log_scale_factor += log(relative_res_pri) - log(relative_res_dual);
@@ -919,8 +965,9 @@ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
919
965
  if (iters_since_last_update < RESCALING_MIN_ITERS) {
920
966
  return;
921
967
  }
922
- new_scale = MIN(MAX(w->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
923
- if (new_scale == w->scale) {
968
+ new_scale =
969
+ MIN(MAX(w->stgs->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
970
+ if (new_scale == w->stgs->scale) {
924
971
  return;
925
972
  }
926
973
  if (should_update_r(factor, iters_since_last_update)) {
@@ -928,7 +975,7 @@ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
928
975
  w->sum_log_scale_factor = 0;
929
976
  w->n_log_scale_factor = 0;
930
977
  w->last_scale_update_iter = iter;
931
- w->scale = new_scale;
978
+ w->stgs->scale = new_scale;
932
979
 
933
980
  /* update diag r vector */
934
981
  set_diag_r(w);
@@ -947,7 +994,7 @@ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
947
994
  /* solve: R^+ (v^+ + u - 2u_t) = rsk = R(v + u - 2u_t)
948
995
  * => v^+ = R+^-1 rsk + 2u_t - u
949
996
  */
950
- for (i = 0; i < w->n + w->m + 1; i++) {
997
+ for (i = 0; i < w->d->n + w->d->m + 1; i++) {
951
998
  w->v[i] = w->rsk[i] / w->diag_r[i] + 2 * w->u_t[i] - w->u[i];
952
999
  }
953
1000
  }
@@ -959,7 +1006,8 @@ static inline void normalize_v(scs_float *v, scs_int len) {
959
1006
  SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
960
1007
  }
961
1008
 
962
- scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1009
+ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info,
1010
+ scs_int warm_start) {
963
1011
  scs_int i;
964
1012
  SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
965
1013
  scs_float total_accel_time = 0.0, total_cone_time = 0.0,
@@ -968,16 +1016,18 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
968
1016
  scs_printf("ERROR: missing ScsWork, ScsSolution or ScsInfo input\n");
969
1017
  return SCS_FAILED;
970
1018
  }
971
- scs_int l = w->m + w->n + 1;
972
- const ScsData *d = w->d;
1019
+ scs_int l = w->d->m + w->d->n + 1;
973
1020
  const ScsCone *k = w->k;
974
- const ScsSettings *stgs = w->stgs;
1021
+ ScsSettings *stgs = w->stgs;
1022
+ /* set warm start */
1023
+ stgs->warm_start = warm_start;
1024
+
975
1025
  /* initialize ctrl-c support */
976
1026
  scs_start_interrupt_listener();
977
1027
  SCS(tic)(&solve_timer);
978
1028
  strcpy(info->lin_sys_solver, SCS(get_lin_sys_method)());
979
1029
  info->status_val = SCS_UNFINISHED; /* not yet converged */
980
- update_work(d, w, sol);
1030
+ update_work(w, sol);
981
1031
 
982
1032
  if (w->stgs->verbose) {
983
1033
  print_header(w, k);
@@ -1008,7 +1058,7 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1008
1058
  /******************* linear system solve ********************/
1009
1059
  SCS(tic)(&lin_sys_timer);
1010
1060
  if (project_lin_sys(w, i) < 0) {
1011
- return failure(w, w->m, w->n, sol, info, SCS_FAILED,
1061
+ return failure(w, w->d->m, w->d->n, sol, info, SCS_FAILED,
1012
1062
  "error in project_lin_sys", "failure");
1013
1063
  }
1014
1064
  total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
@@ -1016,7 +1066,7 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1016
1066
  /****************** project onto the cones ******************/
1017
1067
  SCS(tic)(&cone_timer);
1018
1068
  if (project_cones(w, k, i) < 0) {
1019
- return failure(w, w->m, w->n, sol, info, SCS_FAILED,
1069
+ return failure(w, w->d->m, w->d->n, sol, info, SCS_FAILED,
1020
1070
  "error in project_cones", "failure");
1021
1071
  }
1022
1072
  total_cone_time += SCS(tocq)(&cone_timer);
@@ -1027,8 +1077,8 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1027
1077
 
1028
1078
  if (i % CONVERGED_INTERVAL == 0) {
1029
1079
  if (scs_is_interrupted()) {
1030
- return failure(w, w->m, w->n, sol, info, SCS_SIGINT, "interrupted",
1031
- "interrupted");
1080
+ return failure(w, w->d->m, w->d->n, sol, info, SCS_SIGINT,
1081
+ "interrupted", "interrupted");
1032
1082
  }
1033
1083
  populate_residual_struct(w, i);
1034
1084
  if ((info->status_val = has_converged(w, i)) != 0) {
@@ -1076,14 +1126,14 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1076
1126
  if (w->stgs->log_csv_filename) {
1077
1127
  /* calc residuals every iter if logging to csv */
1078
1128
  populate_residual_struct(w, i);
1079
- SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
1129
+ SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
1080
1130
  }
1081
1131
  }
1082
1132
 
1083
1133
  /* Final logging after full run */
1084
1134
  if (w->stgs->log_csv_filename) {
1085
1135
  populate_residual_struct(w, i);
1086
- SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
1136
+ SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
1087
1137
  }
1088
1138
 
1089
1139
  if (w->stgs->verbose) {
@@ -1111,14 +1161,6 @@ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1111
1161
  void scs_finish(ScsWork *w) {
1112
1162
  if (w) {
1113
1163
  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
1164
  if (w->p) {
1123
1165
  SCS(free_lin_sys_work)(w->p);
1124
1166
  }
@@ -1142,6 +1184,10 @@ ScsWork *scs_init(const ScsData *d, const ScsCone *k, const ScsSettings *stgs) {
1142
1184
  scs_printf("ERROR: Validation returned failure\n");
1143
1185
  return SCS_NULL;
1144
1186
  }
1187
+ #endif
1188
+ #if VERBOSITY > 0
1189
+ scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
1190
+ sizeof(scs_int), sizeof(scs_float));
1145
1191
  #endif
1146
1192
  SCS(tic)(&init_timer);
1147
1193
  if (stgs->write_data_filename) {
@@ -1160,12 +1206,8 @@ scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
1160
1206
  ScsSolution *sol, ScsInfo *info) {
1161
1207
  scs_int status;
1162
1208
  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
1209
  if (w) {
1168
- scs_solve(w, sol, info);
1210
+ scs_solve(w, sol, info, stgs->warm_start);
1169
1211
  status = info->status_val;
1170
1212
  } else {
1171
1213
  status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,