scs 0.3.0 → 0.4.0

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 (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
  }