scs 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +42 -13
  4. data/lib/scs/ffi.rb +1 -7
  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 +1 -1
  10. data/vendor/scs/CMakeLists.txt +55 -7
  11. data/vendor/scs/Makefile +9 -9
  12. data/vendor/scs/README.md +4 -1
  13. data/vendor/scs/include/aa.h +1 -1
  14. data/vendor/scs/include/cones.h +17 -12
  15. data/vendor/scs/include/glbopts.h +27 -66
  16. data/vendor/scs/include/linalg.h +2 -1
  17. data/vendor/scs/include/linsys.h +13 -13
  18. data/vendor/scs/include/normalize.h +7 -5
  19. data/vendor/scs/include/rw.h +3 -3
  20. data/vendor/scs/include/scs.h +85 -106
  21. data/vendor/scs/include/scs_types.h +34 -0
  22. data/vendor/scs/include/scs_work.h +80 -0
  23. data/vendor/scs/include/util.h +3 -1
  24. data/vendor/scs/linsys/cpu/direct/private.c +86 -73
  25. data/vendor/scs/linsys/cpu/direct/private.h +2 -2
  26. data/vendor/scs/linsys/cpu/indirect/private.c +42 -33
  27. data/vendor/scs/linsys/cpu/indirect/private.h +1 -2
  28. data/vendor/scs/linsys/csparse.c +3 -3
  29. data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
  30. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +9 -7
  31. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +1 -1
  32. data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
  33. data/vendor/scs/linsys/gpu/gpu.h +8 -11
  34. data/vendor/scs/linsys/gpu/indirect/private.c +72 -49
  35. data/vendor/scs/linsys/gpu/indirect/private.h +14 -13
  36. data/vendor/scs/linsys/scs_matrix.c +55 -104
  37. data/vendor/scs/linsys/scs_matrix.h +5 -4
  38. data/vendor/scs/scs.mk +1 -5
  39. data/vendor/scs/src/aa.c +13 -8
  40. data/vendor/scs/src/cones.c +197 -108
  41. data/vendor/scs/src/linalg.c +25 -0
  42. data/vendor/scs/src/normalize.c +75 -26
  43. data/vendor/scs/src/rw.c +74 -30
  44. data/vendor/scs/src/scs.c +300 -264
  45. data/vendor/scs/src/scs_version.c +8 -6
  46. data/vendor/scs/src/util.c +27 -13
  47. data/vendor/scs/test/minunit.h +6 -1
  48. data/vendor/scs/test/problem_utils.h +28 -35
  49. data/vendor/scs/test/problems/degenerate.h +2 -1
  50. data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
  51. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +6 -2
  52. data/vendor/scs/test/problems/infeasible_tiny_qp.h +2 -1
  53. data/vendor/scs/test/problems/qafiro_tiny_qp.h +5 -4
  54. data/vendor/scs/test/problems/random_prob.h +6 -2
  55. data/vendor/scs/test/problems/rob_gauss_cov_est.h +9 -2
  56. data/vendor/scs/test/problems/small_lp.h +7 -2
  57. data/vendor/scs/test/problems/small_qp.h +387 -0
  58. data/vendor/scs/test/problems/{test_fails.h → test_validation.h} +7 -4
  59. data/vendor/scs/test/problems/unbounded_tiny_qp.h +4 -4
  60. data/vendor/scs/test/random_socp_prob.c +4 -2
  61. data/vendor/scs/test/run_from_file.c +16 -4
  62. data/vendor/scs/test/run_tests.c +23 -14
  63. metadata +10 -35
  64. data/vendor/scs/linsys/cpu/direct/private.o +0 -0
  65. data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
  66. data/vendor/scs/linsys/csparse.o +0 -0
  67. data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
  68. data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
  69. data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
  70. data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
  71. data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
  72. data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
  73. data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
  74. data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
  75. data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
  76. data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
  77. data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
  78. data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
  79. data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
  80. data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
  81. data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
  82. data/vendor/scs/linsys/scs_matrix.o +0 -0
  83. data/vendor/scs/src/aa.o +0 -0
  84. data/vendor/scs/src/cones.o +0 -0
  85. data/vendor/scs/src/ctrlc.o +0 -0
  86. data/vendor/scs/src/linalg.o +0 -0
  87. data/vendor/scs/src/normalize.o +0 -0
  88. data/vendor/scs/src/rw.o +0 -0
  89. data/vendor/scs/src/scs.o +0 -0
  90. data/vendor/scs/src/scs_indir.o +0 -0
  91. data/vendor/scs/src/scs_version.o +0 -0
  92. data/vendor/scs/src/util.o +0 -0
data/vendor/scs/src/scs.c CHANGED
@@ -7,6 +7,7 @@
7
7
  #include "normalize.h"
8
8
  #include "rw.h"
9
9
  #include "scs_matrix.h"
10
+ #include "scs_work.h"
10
11
  #include "util.h"
11
12
 
12
13
  /* printing header */
@@ -39,24 +40,34 @@ static void free_work(ScsWork *w) {
39
40
  scs_free(w->rsk);
40
41
  scs_free(w->h);
41
42
  scs_free(w->g);
42
- scs_free(w->b_normalized);
43
- scs_free(w->c_normalized);
44
- scs_free(w->rho_y_vec);
43
+ scs_free(w->b_orig);
44
+ scs_free(w->c_orig);
45
45
  scs_free(w->lin_sys_warm_start);
46
- if (w->cone_boundaries) {
47
- scs_free(w->cone_boundaries);
48
- }
46
+ scs_free(w->diag_r);
47
+ SCS(free_sol)(w->xys_orig);
49
48
  if (w->scal) {
50
49
  scs_free(w->scal->D);
51
50
  scs_free(w->scal->E);
52
51
  scs_free(w->scal);
53
52
  }
54
- SCS(free_sol)(w->xys_orig);
55
53
  free_residuals(w->r_orig);
56
- if (w->stgs->normalize) {
54
+ if (w->stgs && w->stgs->normalize) {
57
55
  SCS(free_sol)(w->xys_normalized);
58
56
  free_residuals(w->r_normalized);
59
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
+ }
60
71
  scs_free(w);
61
72
  }
62
73
  }
@@ -78,7 +89,7 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
78
89
  }
79
90
  scs_printf("\n\t SCS v%s - Splitting Conic Solver\n\t(c) Brendan "
80
91
  "O'Donoghue, Stanford University, 2012\n",
81
- SCS(version)());
92
+ scs_version());
82
93
  for (i = 0; i < LINE_LEN; ++i) {
83
94
  scs_printf("-");
84
95
  }
@@ -89,12 +100,11 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
89
100
  scs_free(cone_str);
90
101
  scs_printf("settings: eps_abs: %.1e, eps_rel: %.1e, eps_infeas: %.1e\n"
91
102
  "\t alpha: %.2f, scale: %.2e, adaptive_scale: %i\n"
92
- "\t max_iters: %i, normalize: %i, warm_start: %i\n",
93
- /*, rho_x: %.2e\n", */
103
+ "\t max_iters: %i, normalize: %i, rho_x: %.2e\n",
94
104
  stgs->eps_abs, stgs->eps_rel, stgs->eps_infeas, stgs->alpha,
95
105
  stgs->scale, (int)stgs->adaptive_scale, (int)stgs->max_iters,
96
- (int)stgs->normalize, (int)stgs->warm_start);
97
- /* , stgs->rho_x); */
106
+ (int)stgs->normalize, stgs->rho_x);
107
+ /* (int)stgs->warm_start); */
98
108
  if (stgs->acceleration_lookback != 0) {
99
109
  scs_printf("\t acceleration_lookback: %i, acceleration_interval: %i\n",
100
110
  (int)acceleration_lookback, (int)acceleration_interval);
@@ -156,24 +166,31 @@ static scs_int failure(ScsWork *w, scs_int m, scs_int n, ScsSolution *sol,
156
166
  return status;
157
167
  }
158
168
 
169
+ static inline scs_int _is_nan(scs_float x) {
170
+ return x != x;
171
+ }
172
+
159
173
  /* given x,y,s warm start, set v = [x; s / R + y; 1]
160
- * where R = diag(w->rho_y_vec).
174
+ * check for nans and set to zero if present
161
175
  */
162
176
  static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
163
- scs_int n = w->n, m = w->m, i;
177
+ scs_int n = w->d->n, m = w->d->m, i;
164
178
  scs_float *v = w->v;
165
179
  /* normalize the warm-start */
166
180
  if (w->stgs->normalize) {
167
- SCS(normalize_sol)(w, sol);
181
+ SCS(normalize_sol)(w->scal, sol);
182
+ }
183
+ for (i = 0; i < n; ++i) {
184
+ v[i] = _is_nan(sol->x[i]) ? 0. : sol->x[i];
168
185
  }
169
- memcpy(v, sol->x, n * sizeof(scs_float));
170
186
  for (i = 0; i < m; ++i) {
171
- v[i + n] = sol->y[i] + sol->s[i] / w->rho_y_vec[i];
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];
172
189
  }
173
190
  v[n + m] = 1.0; /* tau = 1 */
174
191
  /* un-normalize so sol unchanged */
175
192
  if (w->stgs->normalize) {
176
- SCS(un_normalize_sol)(w, sol);
193
+ SCS(un_normalize_sol)(w->scal, sol);
177
194
  }
178
195
  }
179
196
 
@@ -202,12 +219,12 @@ static void unnormalize_residuals(ScsWork *w) {
202
219
  r->tau = r_n->tau;
203
220
 
204
221
  /* mem copy arrays */
205
- memcpy(r->ax, r_n->ax, w->m * sizeof(scs_float));
206
- memcpy(r->ax_s, r_n->ax_s, w->m * sizeof(scs_float));
207
- memcpy(r->ax_s_btau, r_n->ax_s_btau, w->m * sizeof(scs_float));
208
- memcpy(r->aty, r_n->aty, w->n * sizeof(scs_float));
209
- memcpy(r->px, r_n->px, w->n * sizeof(scs_float));
210
- 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));
211
228
 
212
229
  /* unnormalize */
213
230
  r->kap = r_n->kap / pd;
@@ -221,20 +238,20 @@ static void unnormalize_residuals(ScsWork *w) {
221
238
  r->dobj = r_n->dobj / pd;
222
239
  r->gap = r_n->gap / pd;
223
240
 
224
- SCS(un_normalize_primal)(w, r->ax);
225
- SCS(un_normalize_primal)(w, r->ax_s);
226
- SCS(un_normalize_primal)(w, r->ax_s_btau);
227
- SCS(un_normalize_dual)(w, r->aty);
228
- SCS(un_normalize_dual)(w, r->px);
229
- SCS(un_normalize_dual)(w, r->px_aty_ctau);
241
+ SCS(un_normalize_primal)(w->scal, r->ax);
242
+ SCS(un_normalize_primal)(w->scal, r->ax_s);
243
+ SCS(un_normalize_primal)(w->scal, r->ax_s_btau);
244
+ SCS(un_normalize_dual)(w->scal, r->aty);
245
+ SCS(un_normalize_dual)(w->scal, r->px);
246
+ SCS(un_normalize_dual)(w->scal, r->px_aty_ctau);
230
247
 
231
- compute_residuals(r, w->m, w->n);
248
+ compute_residuals(r, w->d->m, w->d->n);
232
249
  }
233
250
 
234
251
  /* calculates un-normalized residual quantities */
235
252
  /* this is somewhat slow but not a bottleneck */
236
253
  static void populate_residual_struct(ScsWork *w, scs_int iter) {
237
- scs_int n = w->n, m = w->m;
254
+ scs_int n = w->d->n, m = w->d->m;
238
255
  /* normalized x,y,s terms */
239
256
  scs_float *x = w->xys_normalized->x;
240
257
  scs_float *y = w->xys_normalized->y;
@@ -257,7 +274,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
257
274
  /**************** PRIMAL *********************/
258
275
  memset(r->ax, 0, m * sizeof(scs_float));
259
276
  /* ax = Ax */
260
- SCS(accum_by_a)(w->A, x, r->ax);
277
+ SCS(accum_by_a)(w->d->A, x, r->ax);
261
278
 
262
279
  memcpy(r->ax_s, r->ax, m * sizeof(scs_float));
263
280
  /* ax_s = Ax + s */
@@ -265,13 +282,13 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
265
282
 
266
283
  memcpy(r->ax_s_btau, r->ax_s, m * sizeof(scs_float));
267
284
  /* ax_s_btau = Ax + s - b * tau */
268
- 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);
269
286
 
270
287
  /**************** DUAL *********************/
271
288
  memset(r->px, 0, n * sizeof(scs_float));
272
- if (w->P) {
289
+ if (w->d->P) {
273
290
  /* px = Px */
274
- SCS(accum_by_p)(w->P, x, r->px);
291
+ SCS(accum_by_p)(w->d->P, x, r->px);
275
292
  r->xt_p_x_tau = SCS(dot)(r->px, x, n);
276
293
  } else {
277
294
  r->xt_p_x_tau = 0.;
@@ -279,18 +296,18 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
279
296
 
280
297
  memset(r->aty, 0, n * sizeof(scs_float));
281
298
  /* aty = A'y */
282
- SCS(accum_by_atrans)(w->A, y, r->aty);
299
+ SCS(accum_by_atrans)(w->d->A, y, r->aty);
283
300
 
284
301
  /* r->px_aty_ctau = Px */
285
302
  memcpy(r->px_aty_ctau, r->px, n * sizeof(scs_float));
286
303
  /* r->px_aty_ctau = Px + A'y */
287
304
  SCS(add_scaled_array)(r->px_aty_ctau, r->aty, n, 1.);
288
305
  /* r->px_aty_ctau = Px + A'y + c * tau */
289
- 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);
290
307
 
291
308
  /**************** OTHERS *****************/
292
- r->bty_tau = SCS(dot)(y, w->b_normalized, m);
293
- 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);
294
311
 
295
312
  r->bty = SAFEDIV_POS(r->bty_tau, r->tau);
296
313
  r->ctx = SAFEDIV_POS(r->ctx_tau, r->tau);
@@ -306,58 +323,45 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
306
323
  memcpy(w->xys_orig->x, w->xys_normalized->x, n * sizeof(scs_float));
307
324
  memcpy(w->xys_orig->y, w->xys_normalized->y, m * sizeof(scs_float));
308
325
  memcpy(w->xys_orig->s, w->xys_normalized->s, m * sizeof(scs_float));
309
- SCS(un_normalize_sol)(w, w->xys_orig);
326
+ SCS(un_normalize_sol)(w->scal, w->xys_orig);
310
327
  unnormalize_residuals(w);
311
328
  }
312
329
  }
313
330
 
314
331
  static void cold_start_vars(ScsWork *w) {
315
- scs_int l = w->n + w->m + 1;
332
+ scs_int l = w->d->n + w->d->m + 1;
316
333
  memset(w->v, 0, l * sizeof(scs_float));
317
334
  w->v[l - 1] = 1.;
318
335
  }
319
336
 
320
- /* utility function that scales first n entries in inner prod by rho_x */
321
- /* and last m entries by 1 / rho_y_vec, assumes length of array is n + m */
322
- /* See .note_on_scale in repo for explanation */
323
- static scs_float dot_with_diag_scaling(ScsWork *w, const scs_float *x,
324
- const scs_float *y) {
325
- scs_int i, n = w->n, len = w->n + w->m;
337
+ /* utility function that computes x'Ry */
338
+ static inline scs_float dot_r(ScsWork *w, const scs_float *x,
339
+ const scs_float *y) {
340
+ scs_int i;
326
341
  scs_float ip = 0.0;
327
- for (i = 0; i < n; ++i) {
328
- ip += w->stgs->rho_x * x[i] * y[i];
329
- }
330
- for (i = n; i < len; ++i) {
331
- ip += x[i] * y[i] * w->rho_y_vec[i - n];
342
+ for (i = 0; i < w->d->n + w->d->m; ++i) {
343
+ ip += x[i] * y[i] * w->diag_r[i];
332
344
  }
333
345
  return ip;
334
346
  }
335
347
 
336
- static inline scs_float get_tau_scale(ScsWork *w) {
337
- return TAU_FACTOR; /* TAU_FACTOR * w->scale; */
338
- }
339
-
340
348
  static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
341
349
  scs_float eta) {
342
- scs_float b, c, tau, a, tau_scale;
343
- tau_scale = get_tau_scale(w);
344
- a = tau_scale + dot_with_diag_scaling(w, w->g, w->g);
345
- b = (dot_with_diag_scaling(w, mu, w->g) -
346
- 2 * dot_with_diag_scaling(w, p, w->g) - eta * tau_scale);
347
- c = dot_with_diag_scaling(w, p, p) - dot_with_diag_scaling(w, p, mu);
348
- tau = (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
349
- return tau;
350
+ scs_float a, b, c, tau_scale = w->diag_r[w->d->n + w->d->m];
351
+ a = tau_scale + dot_r(w, w->g, w->g);
352
+ b = dot_r(w, mu, w->g) - 2 * dot_r(w, p, w->g) - eta * tau_scale;
353
+ c = dot_r(w, p, p) - dot_r(w, p, mu);
354
+ return (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
350
355
  }
351
356
 
352
357
  /* status < 0 indicates failure */
353
358
  static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
354
- 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;
355
360
  scs_float *warm_start = SCS_NULL;
356
- scs_float tol = -1.0; /* only used for indirect methods, overriden later */
361
+ scs_float tol = -1.0; /* only used for indirect methods, overridden later */
357
362
  memcpy(w->u_t, w->v, l * sizeof(scs_float));
358
- SCS(scale_array)(w->u_t, w->stgs->rho_x, n);
359
- for (i = n; i < l - 1; ++i) {
360
- w->u_t[i] *= -w->rho_y_vec[i - n];
363
+ for (i = 0; i < l - 1; ++i) {
364
+ w->u_t[i] *= (i < n ? 1 : -1) * w->diag_r[i];
361
365
  }
362
366
  #if INDIRECT > 0
363
367
  /* compute warm start using the cone projection output */
@@ -366,12 +370,12 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
366
370
  /* warm_start = u[:n] + tau * g[:n] */
367
371
  SCS(add_scaled_array)(warm_start, w->g, l - 1, w->u[l - 1]);
368
372
  /* use normalized residuals to compute tolerance */
369
- tol = MIN(CG_NORM(w->r_normalized->ax_s_btau, w->m),
370
- 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));
371
375
  /* tol ~ O(1/k^(1+eps)) guarantees convergence */
372
376
  /* use warm-start to calculate tolerance rather than w->u_t, since warm_start
373
377
  * should be approximately equal to the true solution */
374
- 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) /
375
379
  POWF((scs_float)iter + 1, CG_RATE));
376
380
  tol = MAX(CG_BEST_TOL, tol);
377
381
  #endif
@@ -394,40 +398,28 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
394
398
  * (no effect of w->stgs->alpha here).
395
399
  */
396
400
  static void compute_rsk(ScsWork *w) {
397
- scs_int i, l = w->m + w->n + 1;
398
- /* r, should = 0 so skip */
399
- /*
400
- for (i = 0; i < w->n; ++i) {
401
- w->rsk[i] = w->stgs->rho_x * (w->v[i] + w->u[i] - 2 * w->u_t[i]);
402
- }
403
- */
404
- /* s */
405
- for (i = w->n; i < l - 1; ++i) {
406
- w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->rho_y_vec[i - w->n];
407
- }
408
- /* kappa, incorporates tau scaling parameter */
409
- w->rsk[l - 1] =
410
- get_tau_scale(w) * (w->v[l - 1] + w->u[l - 1] - 2 * w->u_t[l - 1]);
401
+ scs_int i, l = w->d->m + w->d->n + 1;
402
+ for (i = 0; i < l; ++i) {
403
+ w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->diag_r[i];
404
+ }
411
405
  }
412
406
 
413
407
  static void update_dual_vars(ScsWork *w) {
414
- scs_int i, l = w->n + w->m + 1;
415
- scs_float a = w->stgs->alpha;
416
- /* compute and store [r;s;kappa] */
417
- compute_rsk(w);
408
+ scs_int i, l = w->d->n + w->d->m + 1;
418
409
  for (i = 0; i < l; ++i) {
419
- w->v[i] += a * (w->u[i] - w->u_t[i]);
410
+ w->v[i] += w->stgs->alpha * (w->u[i] - w->u_t[i]);
420
411
  }
421
412
  }
422
413
 
423
414
  /* status < 0 indicates failure */
424
415
  static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
425
- 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;
426
417
  for (i = 0; i < l; ++i) {
427
418
  w->u[i] = 2 * w->u_t[i] - w->v[i];
428
419
  }
429
420
  /* u = [x;y;tau] */
430
- status = SCS(proj_dual_cone)(&(w->u[n]), k, w->cone_work, w->stgs->normalize);
421
+ status =
422
+ SCS(proj_dual_cone)(&(w->u[n]), w->cone_work, w->scal, &(w->diag_r[n]));
431
423
  if (iter < FEASIBLE_ITERS) {
432
424
  w->u[l - 1] = 1.0;
433
425
  } else {
@@ -438,30 +430,30 @@ static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
438
430
 
439
431
  static void sety(const ScsWork *w, ScsSolution *sol) {
440
432
  if (!sol->y) {
441
- sol->y = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
433
+ sol->y = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
442
434
  }
443
- 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));
444
436
  }
445
437
 
446
438
  /* s is contained in rsk */
447
439
  static void sets(const ScsWork *w, ScsSolution *sol) {
448
440
  if (!sol->s) {
449
- sol->s = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
441
+ sol->s = (scs_float *)scs_calloc(w->d->m, sizeof(scs_float));
450
442
  }
451
- 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));
452
444
  }
453
445
 
454
446
  static void setx(const ScsWork *w, ScsSolution *sol) {
455
447
  if (!sol->x) {
456
- sol->x = (scs_float *)scs_calloc(w->n, sizeof(scs_float));
448
+ sol->x = (scs_float *)scs_calloc(w->d->n, sizeof(scs_float));
457
449
  }
458
- memcpy(sol->x, w->u, w->n * sizeof(scs_float));
450
+ memcpy(sol->x, w->u, w->d->n * sizeof(scs_float));
459
451
  }
460
452
 
461
453
  static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
462
- SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->n);
463
- SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
464
- 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);
465
457
  info->gap = w->r_orig->gap;
466
458
  info->res_pri = w->r_orig->res_pri;
467
459
  info->res_dual = w->r_orig->res_dual;
@@ -472,9 +464,9 @@ static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
472
464
  }
473
465
 
474
466
  static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
475
- SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->m);
476
- SCS(scale_array)(sol->x, NAN, w->n);
477
- 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);
478
470
  info->gap = NAN;
479
471
  info->res_pri = NAN;
480
472
  info->res_dual = NAN;
@@ -485,9 +477,9 @@ static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
485
477
  }
486
478
 
487
479
  static void set_unbounded(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
488
- SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->n);
489
- SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->m);
490
- 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);
491
483
  info->gap = NAN;
492
484
  info->res_pri = NAN;
493
485
  info->res_dual = NAN;
@@ -526,7 +518,7 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
526
518
  sety(w, sol);
527
519
  sets(w, sol);
528
520
  if (w->stgs->normalize) {
529
- SCS(un_normalize_sol)(w, sol);
521
+ SCS(un_normalize_sol)(w->scal, sol);
530
522
  }
531
523
  populate_residual_struct(w, iter);
532
524
  info->setup_time = w->setup_time;
@@ -534,13 +526,13 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
534
526
  info->res_infeas = w->r_orig->res_infeas;
535
527
  info->res_unbdd_a = w->r_orig->res_unbdd_a;
536
528
  info->res_unbdd_p = w->r_orig->res_unbdd_p;
537
- info->scale = w->scale;
529
+ info->scale = w->stgs->scale;
538
530
  info->scale_updates = w->scale_updates;
539
531
  info->rejected_accel_steps = w->rejected_accel_steps;
540
532
  info->accepted_accel_steps = w->accepted_accel_steps;
541
- info->comp_slack = ABS(SCS(dot)(sol->s, sol->y, w->m));
542
- if (info->comp_slack >
543
- 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))) {
544
536
  scs_printf("WARNING - large complementary slackness residual: %f\n",
545
537
  info->comp_slack);
546
538
  }
@@ -570,22 +562,23 @@ static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
570
562
  scs_printf("%*.2e ", (int)HSPACE, r->gap);
571
563
  /* report mid point of primal and dual objective values */
572
564
  scs_printf("%*.2e ", (int)HSPACE, 0.5 * (r->pobj + r->dobj));
573
- scs_printf("%*.2e ", (int)HSPACE, w->scale);
565
+ scs_printf("%*.2e ", (int)HSPACE, w->stgs->scale);
574
566
  scs_printf("%*.2e ", (int)HSPACE, SCS(tocq)(solve_timer) / 1e3);
575
567
  scs_printf("\n");
576
568
 
577
569
  #if VERBOSITY > 0
578
- scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->n + w->m + 1));
579
- scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->n + w->m + 1));
580
- scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->n + w->m + 1));
581
- scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->n));
582
- scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->m));
583
- scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->m));
584
- scs_printf("Norm |Ax + s| = %1.2e, ", SCS(norm_2)(r->ax_s, w->m));
585
- scs_printf("tau = %4f, ", w->u[w->n + w->m]);
586
- 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]);
587
580
  scs_printf("|u - u_t| = %1.2e, ",
588
- 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));
589
582
  scs_printf("res_infeas = %1.2e, ", r->res_infeas);
590
583
  scs_printf("res_unbdd_a = %1.2e, ", r->res_unbdd_a);
591
584
  scs_printf("res_unbdd_p = %1.2e, ", r->res_unbdd_p);
@@ -670,10 +663,11 @@ static scs_int has_converged(ScsWork *w, scs_int iter) {
670
663
  /* xt_p_x, ctx, bty already have tau divided out */
671
664
  grl = MAX(MAX(ABS(r->xt_p_x), ABS(r->ctx)), ABS(r->bty));
672
665
  /* s, ax, px, aty do *not* have tau divided out, so need to divide */
673
- 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)) /
674
668
  r->tau;
675
- drl = MAX(MAX(NORM(c, w->n) * r->tau, NORM(r->px, w->n)),
676
- 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)) /
677
671
  r->tau;
678
672
  if (isless(r->res_pri, eps_abs + eps_rel * prl) &&
679
673
  isless(r->res_dual, eps_abs + eps_rel * drl) &&
@@ -739,13 +733,16 @@ static scs_int validate(const ScsData *d, const ScsCone *k,
739
733
  scs_printf("scale must be positive (1 works well).\n");
740
734
  return -1;
741
735
  }
736
+ if (stgs->acceleration_interval <= 0) {
737
+ scs_printf("acceleration_interval must be positive (10 works well).\n");
738
+ return -1;
739
+ }
742
740
  return 0;
743
741
  }
744
742
  #endif
745
743
 
746
744
  static ScsResiduals *init_residuals(const ScsData *d) {
747
745
  ScsResiduals *r = (ScsResiduals *)scs_calloc(1, sizeof(ScsResiduals));
748
- r->last_iter = -1;
749
746
  r->ax = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
750
747
  r->ax_s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
751
748
  r->ax_s_btau = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
@@ -755,6 +752,46 @@ static ScsResiduals *init_residuals(const ScsData *d) {
755
752
  return r;
756
753
  }
757
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
+
782
+ /* Sets the diag_r vector, given the scale parameters in work */
783
+ static void set_diag_r(ScsWork *w) {
784
+ scs_int i;
785
+ for (i = 0; i < w->d->n; ++i) {
786
+ w->diag_r[i] = w->stgs->rho_x;
787
+ }
788
+ /* use cone information to set R_y */
789
+ SCS(set_r_y)(w->cone_work, w->stgs->scale, &(w->diag_r[w->d->n]));
790
+ /* if modified need to SCS(enforce_cone_boundaries)(...) */
791
+ w->diag_r[w->d->n + w->d->m] =
792
+ TAU_FACTOR; /* TODO: is this the best choice? */
793
+ }
794
+
758
795
  static ScsWork *init_work(const ScsData *d, const ScsCone *k,
759
796
  const ScsSettings *stgs) {
760
797
  ScsWork *w = (ScsWork *)scs_calloc(1, sizeof(ScsWork));
@@ -766,18 +803,21 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
766
803
  scs_printf("ERROR: allocating work failure\n");
767
804
  return SCS_NULL;
768
805
  }
769
- /* get settings and dims from data struct */
770
- w->d = d;
771
- w->k = k;
772
- w->stgs = stgs;
773
- w->scale = stgs->scale; /* initial scale, may be updated */
774
- w->m = d->m;
775
- w->n = d->n;
776
- w->last_scale_update_iter = 0;
777
- w->sum_log_scale_factor = 0.;
778
- w->n_log_scale_factor = 0;
779
- w->scale_updates = 0;
780
- 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
+
781
821
  /* allocate workspace: */
782
822
  w->u = (scs_float *)scs_calloc(l, sizeof(scs_float));
783
823
  w->u_t = (scs_float *)scs_calloc(l, sizeof(scs_float));
@@ -787,72 +827,47 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
787
827
  w->h = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
788
828
  w->g = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
789
829
  w->lin_sys_warm_start = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
790
- w->rho_y_vec = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
830
+ w->diag_r = (scs_float *)scs_calloc(l, sizeof(scs_float));
791
831
  /* x,y,s struct */
792
832
  w->xys_orig = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
793
- w->xys_orig->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
794
- w->xys_orig->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
795
- w->xys_orig->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
796
- w->r_orig = init_residuals(d);
797
-
798
- w->A = d->A;
799
- w->P = d->P;
800
-
801
- w->b_orig = d->b;
802
- w->c_orig = d->c;
803
- w->b_normalized = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
804
- w->c_normalized = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
805
- memcpy(w->b_normalized, w->b_orig, w->m * sizeof(scs_float));
806
- memcpy(w->c_normalized, w->c_orig, w->n * sizeof(scs_float));
807
- SCS(set_rho_y_vec)(k, w->scale, w->rho_y_vec, w->m);
808
-
809
- if (!w->c_normalized) {
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) {
810
841
  scs_printf("ERROR: work memory allocation failure\n");
811
842
  return SCS_NULL;
812
843
  }
813
844
 
845
+ if (!(w->cone_work = SCS(init_cone)(w->k, w->d->m))) {
846
+ scs_printf("ERROR: init_cone failure\n");
847
+ return SCS_NULL;
848
+ }
849
+ set_diag_r(w);
850
+
814
851
  if (w->stgs->normalize) {
815
852
  w->xys_normalized = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
816
- w->xys_normalized->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
817
- w->xys_normalized->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
818
- w->xys_normalized->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
819
- w->r_normalized = init_residuals(d);
820
-
821
- #ifdef COPYAMATRIX
822
- if (!SCS(copy_matrix)(&(w->A), d->A)) {
823
- scs_printf("ERROR: copy A matrix failed\n");
824
- return SCS_NULL;
825
- }
826
- if (w->P && !SCS(copy_matrix)(&(w->P), d->P)) {
827
- scs_printf("ERROR: copy P matrix failed\n");
828
- return SCS_NULL;
829
- }
830
- #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);
831
857
  /* this allocates memory that must be freed */
832
- w->cone_boundaries_len = SCS(set_cone_boundaries)(k, &w->cone_boundaries);
833
- w->scal = (ScsScaling *)scs_calloc(1, sizeof(ScsScaling));
834
- SCS(normalize)
835
- (w->P, w->A, w->b_normalized, w->c_normalized, w->scal, w->cone_boundaries,
836
- w->cone_boundaries_len);
858
+ w->scal = SCS(normalize_a_p)(w->d->P, w->d->A, w->cone_work);
837
859
  } else {
838
860
  w->xys_normalized = w->xys_orig;
839
861
  w->r_normalized = w->r_orig;
840
- w->cone_boundaries_len = 0;
841
- w->cone_boundaries = SCS_NULL;
842
862
  w->scal = SCS_NULL;
843
863
  }
844
- if (!(w->cone_work = SCS(init_cone)(k, w->scal, w->m))) {
845
- scs_printf("ERROR: init_cone failure\n");
846
- return SCS_NULL;
847
- }
848
- if (!(w->p =
849
- SCS(init_lin_sys_work)(w->A, w->P, w->rho_y_vec, w->stgs->rho_x))) {
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))) {
850
868
  scs_printf("ERROR: init_lin_sys_work failure\n");
851
869
  return SCS_NULL;
852
870
  }
853
- /* Acceleration */
854
- w->rejected_accel_steps = 0;
855
- w->accepted_accel_steps = 0;
856
871
  if (w->stgs->acceleration_lookback) {
857
872
  /* TODO(HACK!) negative acceleration_lookback interpreted as type-II */
858
873
  if (!(w->accel = aa_init(l, ABS(w->stgs->acceleration_lookback),
@@ -874,16 +889,31 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
874
889
 
875
890
  static void update_work_cache(ScsWork *w) {
876
891
  /* g = (I + M)^{-1} h */
877
- memcpy(w->g, w->h, (w->n + w->m) * sizeof(scs_float));
878
- 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);
879
894
  SCS(solve_lin_sys)(w->p, w->g, SCS_NULL, CG_BEST_TOL);
880
895
  return;
881
896
  }
882
897
 
883
- static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
884
- /* before normalization */
885
- scs_int n = d->n;
886
- 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
+
887
917
  if (w->stgs->warm_start) {
888
918
  warm_start_vars(w, sol);
889
919
  } else {
@@ -891,18 +921,18 @@ static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
891
921
  }
892
922
 
893
923
  /* h = [c;b] */
894
- memcpy(w->h, w->c_normalized, n * sizeof(scs_float));
895
- 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));
896
926
  update_work_cache(w);
897
927
  return 0;
898
928
  }
899
929
 
900
930
  /* will update if the factor is outside of range */
901
- scs_int should_update_rho_y_vec(scs_float factor, scs_int iter) {
931
+ scs_int should_update_r(scs_float factor, scs_int iter) {
902
932
  return (factor > SQRTF(10.) || factor < 1. / SQRTF(10.));
903
933
  }
904
934
 
905
- static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
935
+ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
906
936
  scs_int i;
907
937
  scs_float factor, new_scale;
908
938
 
@@ -913,15 +943,15 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
913
943
 
914
944
  scs_int iters_since_last_update = iter - w->last_scale_update_iter;
915
945
  /* ||Ax + s - b * tau|| */
916
- scs_float relative_res_pri =
917
- SAFEDIV_POS(SCALE_NORM(r->ax_s_btau, w->m),
918
- MAX(MAX(SCALE_NORM(r->ax, w->m), SCALE_NORM(xys->s, w->m)),
919
- 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));
920
950
  /* ||Px + A'y + c * tau|| */
921
- scs_float relative_res_dual =
922
- SAFEDIV_POS(SCALE_NORM(r->px_aty_ctau, w->n),
923
- MAX(MAX(SCALE_NORM(r->px, w->n), SCALE_NORM(r->aty, w->n)),
924
- 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));
925
955
 
926
956
  /* higher scale makes res_pri go down faster, so increase if res_pri larger */
927
957
  w->sum_log_scale_factor += log(relative_res_pri) - log(relative_res_dual);
@@ -935,18 +965,23 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
935
965
  if (iters_since_last_update < RESCALING_MIN_ITERS) {
936
966
  return;
937
967
  }
938
- new_scale = MIN(MAX(w->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
939
- 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) {
940
971
  return;
941
972
  }
942
- if (should_update_rho_y_vec(factor, iters_since_last_update)) {
973
+ if (should_update_r(factor, iters_since_last_update)) {
943
974
  w->scale_updates++;
944
975
  w->sum_log_scale_factor = 0;
945
976
  w->n_log_scale_factor = 0;
946
977
  w->last_scale_update_iter = iter;
947
- w->scale = new_scale;
948
- SCS(set_rho_y_vec)(k, w->scale, w->rho_y_vec, w->m);
949
- SCS(update_lin_sys_rho_y_vec)(w->p, w->rho_y_vec);
978
+ w->stgs->scale = new_scale;
979
+
980
+ /* update diag r vector */
981
+ set_diag_r(w);
982
+
983
+ /* update linear systems */
984
+ SCS(update_lin_sys_diag_r)(w->p, w->diag_r);
950
985
 
951
986
  /* update pre-solved quantities */
952
987
  update_work_cache(w);
@@ -956,10 +991,11 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
956
991
  aa_reset(w->accel);
957
992
  }
958
993
  /* update v, using fact that rsk, u, u_t vectors should be the same */
959
- /* solve: R (v^+ + u - 2u_t) = rsk => v^+ = R^-1 rsk + 2u_t - u */
960
- /* only elements with scale on diag */
961
- for (i = w->n; i < w->n + w->m; i++) {
962
- w->v[i] = w->rsk[i] / w->rho_y_vec[i - w->n] + 2 * w->u_t[i] - w->u[i];
994
+ /* solve: R^+ (v^+ + u - 2u_t) = rsk = R(v + u - 2u_t)
995
+ * => v^+ = R+^-1 rsk + 2u_t - u
996
+ */
997
+ for (i = 0; i < w->d->n + w->d->m + 1; i++) {
998
+ w->v[i] = w->rsk[i] / w->diag_r[i] + 2 * w->u_t[i] - w->u[i];
963
999
  }
964
1000
  }
965
1001
  }
@@ -970,7 +1006,8 @@ static inline void normalize_v(scs_float *v, scs_int len) {
970
1006
  SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
971
1007
  }
972
1008
 
973
- 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) {
974
1011
  scs_int i;
975
1012
  SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
976
1013
  scs_float total_accel_time = 0.0, total_cone_time = 0.0,
@@ -979,15 +1016,18 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
979
1016
  scs_printf("ERROR: missing ScsWork, ScsSolution or ScsInfo input\n");
980
1017
  return SCS_FAILED;
981
1018
  }
982
- scs_int l = w->m + w->n + 1;
983
- const ScsData *d = w->d;
1019
+ scs_int l = w->d->m + w->d->n + 1;
984
1020
  const ScsCone *k = w->k;
985
- const ScsSettings *stgs = w->stgs;
1021
+ ScsSettings *stgs = w->stgs;
1022
+ /* set warm start */
1023
+ stgs->warm_start = warm_start;
1024
+
986
1025
  /* initialize ctrl-c support */
987
1026
  scs_start_interrupt_listener();
988
1027
  SCS(tic)(&solve_timer);
1028
+ strcpy(info->lin_sys_solver, SCS(get_lin_sys_method)());
989
1029
  info->status_val = SCS_UNFINISHED; /* not yet converged */
990
- update_work(d, w, sol);
1030
+ update_work(w, sol);
991
1031
 
992
1032
  if (w->stgs->verbose) {
993
1033
  print_header(w, k);
@@ -1015,29 +1055,30 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1015
1055
  /* store v_prev = v, *after* normalizing */
1016
1056
  memcpy(w->v_prev, w->v, l * sizeof(scs_float));
1017
1057
 
1018
- /* linear system solve */
1058
+ /******************* linear system solve ********************/
1019
1059
  SCS(tic)(&lin_sys_timer);
1020
1060
  if (project_lin_sys(w, i) < 0) {
1021
- 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,
1022
1062
  "error in project_lin_sys", "failure");
1023
1063
  }
1024
1064
  total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
1025
1065
 
1026
- /* project onto the cones */
1066
+ /****************** project onto the cones ******************/
1027
1067
  SCS(tic)(&cone_timer);
1028
1068
  if (project_cones(w, k, i) < 0) {
1029
- 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,
1030
1070
  "error in project_cones", "failure");
1031
1071
  }
1032
1072
  total_cone_time += SCS(tocq)(&cone_timer);
1033
1073
 
1034
- /* dual variable step */
1035
- update_dual_vars(w);
1074
+ /* compute [r;s;kappa], must be before dual var update */
1075
+ /* since Moreau decomp logic relies on v at start */
1076
+ compute_rsk(w);
1036
1077
 
1037
1078
  if (i % CONVERGED_INTERVAL == 0) {
1038
1079
  if (scs_is_interrupted()) {
1039
- return failure(w, w->m, w->n, sol, info, SCS_SIGINT, "interrupted",
1040
- "interrupted");
1080
+ return failure(w, w->d->m, w->d->n, sol, info, SCS_SIGINT,
1081
+ "interrupted", "interrupted");
1041
1082
  }
1042
1083
  populate_residual_struct(w, i);
1043
1084
  if ((info->status_val = has_converged(w, i)) != 0) {
@@ -1051,6 +1092,21 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1051
1092
  }
1052
1093
  }
1053
1094
 
1095
+ /* Compute residuals. */
1096
+ if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
1097
+ populate_residual_struct(w, i);
1098
+ print_summary(w, i, &solve_timer);
1099
+ }
1100
+
1101
+ /* If residuals are fresh then maybe compute new scale. */
1102
+ if (w->stgs->adaptive_scale && i == w->r_orig->last_iter) {
1103
+ update_scale(w, k, i);
1104
+ }
1105
+
1106
+ /****************** dual variable step **********************/
1107
+ /* do this after update_scale due to remapping that happens there */
1108
+ update_dual_vars(w);
1109
+
1054
1110
  /* AA safeguard check.
1055
1111
  * Perform safeguarding *after* convergence check to prevent safeguard
1056
1112
  * overwriting converged iterate, since safeguard is on `v` and convergence
@@ -1066,29 +1122,18 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1066
1122
  }
1067
1123
  }
1068
1124
 
1069
- /* Compute residuals. */
1070
- if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
1071
- populate_residual_struct(w, i);
1072
- print_summary(w, i, &solve_timer);
1073
- }
1074
-
1075
- /* If residuals are fresh then maybe compute new scale. */
1076
- if (w->stgs->adaptive_scale && i == w->r_orig->last_iter) {
1077
- maybe_update_scale(w, k, i);
1078
- }
1079
-
1080
1125
  /* Log *after* updating scale so residual recalc does not affect alg */
1081
1126
  if (w->stgs->log_csv_filename) {
1082
1127
  /* calc residuals every iter if logging to csv */
1083
1128
  populate_residual_struct(w, i);
1084
- SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
1129
+ SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
1085
1130
  }
1086
1131
  }
1087
1132
 
1088
1133
  /* Final logging after full run */
1089
1134
  if (w->stgs->log_csv_filename) {
1090
1135
  populate_residual_struct(w, i);
1091
- SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
1136
+ SCS(log_data_to_csv)(k, stgs, w, i, &solve_timer);
1092
1137
  }
1093
1138
 
1094
1139
  if (w->stgs->verbose) {
@@ -1113,17 +1158,9 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1113
1158
  return info->status_val;
1114
1159
  }
1115
1160
 
1116
- void SCS(finish)(ScsWork *w) {
1161
+ void scs_finish(ScsWork *w) {
1117
1162
  if (w) {
1118
1163
  SCS(finish_cone)(w->cone_work);
1119
- if (w->stgs && w->stgs->normalize) {
1120
- #ifndef COPYAMATRIX
1121
- SCS(un_normalize)(w->A, w->P, w->scal);
1122
- #else
1123
- SCS(free_scs_matrix)(w->A);
1124
- SCS(free_scs_matrix)(w->P);
1125
- #endif
1126
- }
1127
1164
  if (w->p) {
1128
1165
  SCS(free_lin_sys_work)(w->p);
1129
1166
  }
@@ -1134,8 +1171,7 @@ void SCS(finish)(ScsWork *w) {
1134
1171
  }
1135
1172
  }
1136
1173
 
1137
- ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
1138
- const ScsSettings *stgs) {
1174
+ ScsWork *scs_init(const ScsData *d, const ScsCone *k, const ScsSettings *stgs) {
1139
1175
  ScsWork *w;
1140
1176
  SCS(timer) init_timer;
1141
1177
  scs_start_interrupt_listener();
@@ -1148,6 +1184,10 @@ ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
1148
1184
  scs_printf("ERROR: Validation returned failure\n");
1149
1185
  return SCS_NULL;
1150
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));
1151
1191
  #endif
1152
1192
  SCS(tic)(&init_timer);
1153
1193
  if (stgs->write_data_filename) {
@@ -1161,22 +1201,18 @@ ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
1161
1201
  return w;
1162
1202
  }
1163
1203
 
1164
- /* this just calls SCS(init), SCS(solve), and SCS(finish) */
1204
+ /* this just calls scs_init, scs_solve, and scs_finish */
1165
1205
  scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
1166
1206
  ScsSolution *sol, ScsInfo *info) {
1167
1207
  scs_int status;
1168
- ScsWork *w = SCS(init)(d, k, stgs);
1169
- #if VERBOSITY > 0
1170
- scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
1171
- sizeof(scs_int), sizeof(scs_float));
1172
- #endif
1208
+ ScsWork *w = scs_init(d, k, stgs);
1173
1209
  if (w) {
1174
- SCS(solve)(w, sol, info);
1210
+ scs_solve(w, sol, info, stgs->warm_start);
1175
1211
  status = info->status_val;
1176
1212
  } else {
1177
1213
  status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
1178
1214
  SCS_FAILED, "could not initialize work", "failure");
1179
1215
  }
1180
- SCS(finish)(w);
1216
+ scs_finish(w);
1181
1217
  return status;
1182
1218
  }