scs 0.3.1 → 0.3.2

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +8 -8
  4. data/lib/scs/ffi.rb +1 -7
  5. data/lib/scs/version.rb +1 -1
  6. data/vendor/scs/CITATION.cff +1 -1
  7. data/vendor/scs/CMakeLists.txt +55 -7
  8. data/vendor/scs/Makefile +9 -9
  9. data/vendor/scs/README.md +2 -1
  10. data/vendor/scs/include/aa.h +1 -1
  11. data/vendor/scs/include/cones.h +14 -11
  12. data/vendor/scs/include/glbopts.h +26 -64
  13. data/vendor/scs/include/linalg.h +2 -1
  14. data/vendor/scs/include/linsys.h +13 -13
  15. data/vendor/scs/include/normalize.h +6 -5
  16. data/vendor/scs/include/scs.h +43 -87
  17. data/vendor/scs/include/scs_types.h +34 -0
  18. data/vendor/scs/include/scs_work.h +83 -0
  19. data/vendor/scs/linsys/cpu/direct/private.c +86 -73
  20. data/vendor/scs/linsys/cpu/direct/private.h +2 -2
  21. data/vendor/scs/linsys/cpu/indirect/private.c +42 -33
  22. data/vendor/scs/linsys/cpu/indirect/private.h +1 -2
  23. data/vendor/scs/linsys/csparse.c +3 -3
  24. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +6 -6
  25. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +6 -1
  26. data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
  27. data/vendor/scs/linsys/gpu/gpu.h +8 -11
  28. data/vendor/scs/linsys/gpu/indirect/private.c +72 -49
  29. data/vendor/scs/linsys/gpu/indirect/private.h +14 -13
  30. data/vendor/scs/linsys/scs_matrix.c +26 -46
  31. data/vendor/scs/linsys/scs_matrix.h +4 -4
  32. data/vendor/scs/scs.mk +1 -1
  33. data/vendor/scs/src/aa.c +13 -4
  34. data/vendor/scs/src/cones.c +143 -92
  35. data/vendor/scs/src/linalg.c +25 -0
  36. data/vendor/scs/src/normalize.c +26 -26
  37. data/vendor/scs/src/rw.c +48 -12
  38. data/vendor/scs/src/scs.c +104 -110
  39. data/vendor/scs/src/scs_version.c +8 -6
  40. data/vendor/scs/src/util.c +1 -1
  41. data/vendor/scs/test/minunit.h +6 -1
  42. data/vendor/scs/test/problem_utils.h +28 -35
  43. data/vendor/scs/test/problems/degenerate.h +1 -1
  44. data/vendor/scs/test/problems/hs21_tiny_qp.h +1 -1
  45. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +1 -1
  46. data/vendor/scs/test/problems/infeasible_tiny_qp.h +1 -1
  47. data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -3
  48. data/vendor/scs/test/problems/random_prob.h +1 -1
  49. data/vendor/scs/test/problems/rob_gauss_cov_est.h +1 -1
  50. data/vendor/scs/test/problems/small_lp.h +3 -1
  51. data/vendor/scs/test/problems/small_qp.h +352 -0
  52. data/vendor/scs/test/problems/{test_fails.h → test_validation.h} +3 -3
  53. data/vendor/scs/test/problems/unbounded_tiny_qp.h +1 -1
  54. data/vendor/scs/test/random_socp_prob.c +1 -1
  55. data/vendor/scs/test/run_from_file.c +1 -1
  56. data/vendor/scs/test/run_tests.c +23 -14
  57. metadata +8 -5
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 */
@@ -41,11 +42,8 @@ static void free_work(ScsWork *w) {
41
42
  scs_free(w->g);
42
43
  scs_free(w->b_normalized);
43
44
  scs_free(w->c_normalized);
44
- scs_free(w->rho_y_vec);
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);
49
47
  if (w->scal) {
50
48
  scs_free(w->scal->D);
51
49
  scs_free(w->scal->E);
@@ -53,7 +51,7 @@ static void free_work(ScsWork *w) {
53
51
  }
54
52
  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
  }
@@ -78,7 +76,7 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
78
76
  }
79
77
  scs_printf("\n\t SCS v%s - Splitting Conic Solver\n\t(c) Brendan "
80
78
  "O'Donoghue, Stanford University, 2012\n",
81
- SCS(version)());
79
+ scs_version());
82
80
  for (i = 0; i < LINE_LEN; ++i) {
83
81
  scs_printf("-");
84
82
  }
@@ -157,23 +155,22 @@ static scs_int failure(ScsWork *w, scs_int m, scs_int n, ScsSolution *sol,
157
155
  }
158
156
 
159
157
  /* given x,y,s warm start, set v = [x; s / R + y; 1]
160
- * where R = diag(w->rho_y_vec).
161
158
  */
162
159
  static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
163
160
  scs_int n = w->n, m = w->m, i;
164
161
  scs_float *v = w->v;
165
162
  /* normalize the warm-start */
166
163
  if (w->stgs->normalize) {
167
- SCS(normalize_sol)(w, sol);
164
+ SCS(normalize_sol)(w->scal, sol);
168
165
  }
169
166
  memcpy(v, sol->x, n * sizeof(scs_float));
170
167
  for (i = 0; i < m; ++i) {
171
- v[i + n] = sol->y[i] + sol->s[i] / w->rho_y_vec[i];
168
+ v[i + n] = sol->y[i] + sol->s[i] / w->diag_r[i + n];
172
169
  }
173
170
  v[n + m] = 1.0; /* tau = 1 */
174
171
  /* un-normalize so sol unchanged */
175
172
  if (w->stgs->normalize) {
176
- SCS(un_normalize_sol)(w, sol);
173
+ SCS(un_normalize_sol)(w->scal, sol);
177
174
  }
178
175
  }
179
176
 
@@ -221,12 +218,12 @@ static void unnormalize_residuals(ScsWork *w) {
221
218
  r->dobj = r_n->dobj / pd;
222
219
  r->gap = r_n->gap / pd;
223
220
 
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);
221
+ SCS(un_normalize_primal)(w->scal, r->ax);
222
+ SCS(un_normalize_primal)(w->scal, r->ax_s);
223
+ SCS(un_normalize_primal)(w->scal, r->ax_s_btau);
224
+ SCS(un_normalize_dual)(w->scal, r->aty);
225
+ SCS(un_normalize_dual)(w->scal, r->px);
226
+ SCS(un_normalize_dual)(w->scal, r->px_aty_ctau);
230
227
 
231
228
  compute_residuals(r, w->m, w->n);
232
229
  }
@@ -306,7 +303,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
306
303
  memcpy(w->xys_orig->x, w->xys_normalized->x, n * sizeof(scs_float));
307
304
  memcpy(w->xys_orig->y, w->xys_normalized->y, m * sizeof(scs_float));
308
305
  memcpy(w->xys_orig->s, w->xys_normalized->s, m * sizeof(scs_float));
309
- SCS(un_normalize_sol)(w, w->xys_orig);
306
+ SCS(un_normalize_sol)(w->scal, w->xys_orig);
310
307
  unnormalize_residuals(w);
311
308
  }
312
309
  }
@@ -317,47 +314,34 @@ static void cold_start_vars(ScsWork *w) {
317
314
  w->v[l - 1] = 1.;
318
315
  }
319
316
 
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;
317
+ /* utility function that computes x'Ry */
318
+ static inline scs_float dot_r(ScsWork *w, const scs_float *x,
319
+ const scs_float *y) {
320
+ scs_int i;
326
321
  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];
322
+ for (i = 0; i < w->n + w->m; ++i) {
323
+ ip += x[i] * y[i] * w->diag_r[i];
332
324
  }
333
325
  return ip;
334
326
  }
335
327
 
336
- static inline scs_float get_tau_scale(ScsWork *w) {
337
- return TAU_FACTOR; /* TAU_FACTOR * w->scale; */
338
- }
339
-
340
328
  static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
341
329
  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;
330
+ scs_float a, b, c, tau_scale = w->diag_r[w->n + w->m];
331
+ a = tau_scale + dot_r(w, w->g, w->g);
332
+ b = dot_r(w, mu, w->g) - 2 * dot_r(w, p, w->g) - eta * tau_scale;
333
+ c = dot_r(w, p, p) - dot_r(w, p, mu);
334
+ return (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
350
335
  }
351
336
 
352
337
  /* status < 0 indicates failure */
353
338
  static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
354
339
  scs_int n = w->n, m = w->m, l = n + m + 1, status, i;
355
340
  scs_float *warm_start = SCS_NULL;
356
- scs_float tol = -1.0; /* only used for indirect methods, overriden later */
341
+ scs_float tol = -1.0; /* only used for indirect methods, overridden later */
357
342
  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];
343
+ for (i = 0; i < l - 1; ++i) {
344
+ w->u_t[i] *= (i < n ? 1 : -1) * w->diag_r[i];
361
345
  }
362
346
  #if INDIRECT > 0
363
347
  /* compute warm start using the cone projection output */
@@ -395,28 +379,15 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
395
379
  */
396
380
  static void compute_rsk(ScsWork *w) {
397
381
  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];
382
+ for (i = 0; i < l; ++i) {
383
+ w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->diag_r[i];
407
384
  }
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]);
411
385
  }
412
386
 
413
387
  static void update_dual_vars(ScsWork *w) {
414
388
  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);
418
389
  for (i = 0; i < l; ++i) {
419
- w->v[i] += a * (w->u[i] - w->u_t[i]);
390
+ w->v[i] += w->stgs->alpha * (w->u[i] - w->u_t[i]);
420
391
  }
421
392
  }
422
393
 
@@ -427,7 +398,8 @@ static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
427
398
  w->u[i] = 2 * w->u_t[i] - w->v[i];
428
399
  }
429
400
  /* u = [x;y;tau] */
430
- status = SCS(proj_dual_cone)(&(w->u[n]), k, w->cone_work, w->stgs->normalize);
401
+ status =
402
+ SCS(proj_dual_cone)(&(w->u[n]), w->cone_work, w->scal, &(w->diag_r[n]));
431
403
  if (iter < FEASIBLE_ITERS) {
432
404
  w->u[l - 1] = 1.0;
433
405
  } else {
@@ -526,7 +498,7 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
526
498
  sety(w, sol);
527
499
  sets(w, sol);
528
500
  if (w->stgs->normalize) {
529
- SCS(un_normalize_sol)(w, sol);
501
+ SCS(un_normalize_sol)(w->scal, sol);
530
502
  }
531
503
  populate_residual_struct(w, iter);
532
504
  info->setup_time = w->setup_time;
@@ -578,6 +550,7 @@ static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
578
550
  scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->n + w->m + 1));
579
551
  scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->n + w->m + 1));
580
552
  scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->n + w->m + 1));
553
+ scs_printf("Norm rsk = %4f, ", SCS(norm_2)(w->rsk, w->n + w->m + 1));
581
554
  scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->n));
582
555
  scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->m));
583
556
  scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->m));
@@ -739,6 +712,10 @@ static scs_int validate(const ScsData *d, const ScsCone *k,
739
712
  scs_printf("scale must be positive (1 works well).\n");
740
713
  return -1;
741
714
  }
715
+ if (stgs->acceleration_interval <= 0) {
716
+ scs_printf("acceleration_interval must be positive (10 works well).\n");
717
+ return -1;
718
+ }
742
719
  return 0;
743
720
  }
744
721
  #endif
@@ -755,6 +732,18 @@ static ScsResiduals *init_residuals(const ScsData *d) {
755
732
  return r;
756
733
  }
757
734
 
735
+ /* Sets the diag_r vector, given the scale parameters in work */
736
+ static void set_diag_r(ScsWork *w) {
737
+ scs_int i;
738
+ for (i = 0; i < w->n; ++i) {
739
+ w->diag_r[i] = w->stgs->rho_x;
740
+ }
741
+ /* use cone information to set R_y */
742
+ SCS(set_r_y)(w->cone_work, w->scale, &(w->diag_r[w->n]));
743
+ /* if modified need to SCS(enforce_cone_boundaries)(...) */
744
+ w->diag_r[w->n + w->m] = TAU_FACTOR; /* TODO: is this the best choice? */
745
+ }
746
+
758
747
  static ScsWork *init_work(const ScsData *d, const ScsCone *k,
759
748
  const ScsSettings *stgs) {
760
749
  ScsWork *w = (ScsWork *)scs_calloc(1, sizeof(ScsWork));
@@ -787,7 +776,7 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
787
776
  w->h = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
788
777
  w->g = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
789
778
  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));
779
+ w->diag_r = (scs_float *)scs_calloc(l, sizeof(scs_float));
791
780
  /* x,y,s struct */
792
781
  w->xys_orig = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
793
782
  w->xys_orig->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
@@ -804,7 +793,12 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
804
793
  w->c_normalized = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
805
794
  memcpy(w->b_normalized, w->b_orig, w->m * sizeof(scs_float));
806
795
  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);
796
+
797
+ if (!(w->cone_work = SCS(init_cone)(k, w->m))) {
798
+ scs_printf("ERROR: init_cone failure\n");
799
+ return SCS_NULL;
800
+ }
801
+ set_diag_r(w);
808
802
 
809
803
  if (!w->c_normalized) {
810
804
  scs_printf("ERROR: work memory allocation failure\n");
@@ -829,24 +823,14 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
829
823
  }
830
824
  #endif
831
825
  /* 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);
826
+ w->scal = SCS(normalize_a_p)(w->P, w->A, w->b_normalized, w->c_normalized,
827
+ w->cone_work);
837
828
  } else {
838
829
  w->xys_normalized = w->xys_orig;
839
830
  w->r_normalized = w->r_orig;
840
- w->cone_boundaries_len = 0;
841
- w->cone_boundaries = SCS_NULL;
842
831
  w->scal = SCS_NULL;
843
832
  }
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))) {
833
+ if (!(w->p = SCS(init_lin_sys_work)(w->A, w->P, w->diag_r))) {
850
834
  scs_printf("ERROR: init_lin_sys_work failure\n");
851
835
  return SCS_NULL;
852
836
  }
@@ -898,11 +882,11 @@ static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
898
882
  }
899
883
 
900
884
  /* will update if the factor is outside of range */
901
- scs_int should_update_rho_y_vec(scs_float factor, scs_int iter) {
885
+ scs_int should_update_r(scs_float factor, scs_int iter) {
902
886
  return (factor > SQRTF(10.) || factor < 1. / SQRTF(10.));
903
887
  }
904
888
 
905
- static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
889
+ static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
906
890
  scs_int i;
907
891
  scs_float factor, new_scale;
908
892
 
@@ -939,14 +923,18 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
939
923
  if (new_scale == w->scale) {
940
924
  return;
941
925
  }
942
- if (should_update_rho_y_vec(factor, iters_since_last_update)) {
926
+ if (should_update_r(factor, iters_since_last_update)) {
943
927
  w->scale_updates++;
944
928
  w->sum_log_scale_factor = 0;
945
929
  w->n_log_scale_factor = 0;
946
930
  w->last_scale_update_iter = iter;
947
931
  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);
932
+
933
+ /* update diag r vector */
934
+ set_diag_r(w);
935
+
936
+ /* update linear systems */
937
+ SCS(update_lin_sys_diag_r)(w->p, w->diag_r);
950
938
 
951
939
  /* update pre-solved quantities */
952
940
  update_work_cache(w);
@@ -956,10 +944,11 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
956
944
  aa_reset(w->accel);
957
945
  }
958
946
  /* 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];
947
+ /* solve: R^+ (v^+ + u - 2u_t) = rsk = R(v + u - 2u_t)
948
+ * => v^+ = R+^-1 rsk + 2u_t - u
949
+ */
950
+ for (i = 0; i < w->n + w->m + 1; i++) {
951
+ w->v[i] = w->rsk[i] / w->diag_r[i] + 2 * w->u_t[i] - w->u[i];
963
952
  }
964
953
  }
965
954
  }
@@ -970,7 +959,7 @@ static inline void normalize_v(scs_float *v, scs_int len) {
970
959
  SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
971
960
  }
972
961
 
973
- scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
962
+ scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
974
963
  scs_int i;
975
964
  SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
976
965
  scs_float total_accel_time = 0.0, total_cone_time = 0.0,
@@ -986,6 +975,7 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
986
975
  /* initialize ctrl-c support */
987
976
  scs_start_interrupt_listener();
988
977
  SCS(tic)(&solve_timer);
978
+ strcpy(info->lin_sys_solver, SCS(get_lin_sys_method)());
989
979
  info->status_val = SCS_UNFINISHED; /* not yet converged */
990
980
  update_work(d, w, sol);
991
981
 
@@ -1015,7 +1005,7 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1015
1005
  /* store v_prev = v, *after* normalizing */
1016
1006
  memcpy(w->v_prev, w->v, l * sizeof(scs_float));
1017
1007
 
1018
- /* linear system solve */
1008
+ /******************* linear system solve ********************/
1019
1009
  SCS(tic)(&lin_sys_timer);
1020
1010
  if (project_lin_sys(w, i) < 0) {
1021
1011
  return failure(w, w->m, w->n, sol, info, SCS_FAILED,
@@ -1023,7 +1013,7 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1023
1013
  }
1024
1014
  total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
1025
1015
 
1026
- /* project onto the cones */
1016
+ /****************** project onto the cones ******************/
1027
1017
  SCS(tic)(&cone_timer);
1028
1018
  if (project_cones(w, k, i) < 0) {
1029
1019
  return failure(w, w->m, w->n, sol, info, SCS_FAILED,
@@ -1031,8 +1021,9 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1031
1021
  }
1032
1022
  total_cone_time += SCS(tocq)(&cone_timer);
1033
1023
 
1034
- /* dual variable step */
1035
- update_dual_vars(w);
1024
+ /* compute [r;s;kappa], must be before dual var update */
1025
+ /* since Moreau decomp logic relies on v at start */
1026
+ compute_rsk(w);
1036
1027
 
1037
1028
  if (i % CONVERGED_INTERVAL == 0) {
1038
1029
  if (scs_is_interrupted()) {
@@ -1051,6 +1042,21 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1051
1042
  }
1052
1043
  }
1053
1044
 
1045
+ /* Compute residuals. */
1046
+ if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
1047
+ populate_residual_struct(w, i);
1048
+ print_summary(w, i, &solve_timer);
1049
+ }
1050
+
1051
+ /* If residuals are fresh then maybe compute new scale. */
1052
+ if (w->stgs->adaptive_scale && i == w->r_orig->last_iter) {
1053
+ update_scale(w, k, i);
1054
+ }
1055
+
1056
+ /****************** dual variable step **********************/
1057
+ /* do this after update_scale due to remapping that happens there */
1058
+ update_dual_vars(w);
1059
+
1054
1060
  /* AA safeguard check.
1055
1061
  * Perform safeguarding *after* convergence check to prevent safeguard
1056
1062
  * overwriting converged iterate, since safeguard is on `v` and convergence
@@ -1066,17 +1072,6 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1066
1072
  }
1067
1073
  }
1068
1074
 
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
1075
  /* Log *after* updating scale so residual recalc does not affect alg */
1081
1076
  if (w->stgs->log_csv_filename) {
1082
1077
  /* calc residuals every iter if logging to csv */
@@ -1113,12 +1108,12 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
1113
1108
  return info->status_val;
1114
1109
  }
1115
1110
 
1116
- void SCS(finish)(ScsWork *w) {
1111
+ void scs_finish(ScsWork *w) {
1117
1112
  if (w) {
1118
1113
  SCS(finish_cone)(w->cone_work);
1119
1114
  if (w->stgs && w->stgs->normalize) {
1120
1115
  #ifndef COPYAMATRIX
1121
- SCS(un_normalize)(w->A, w->P, w->scal);
1116
+ SCS(un_normalize_a_p)(w->A, w->P, w->scal);
1122
1117
  #else
1123
1118
  SCS(free_scs_matrix)(w->A);
1124
1119
  SCS(free_scs_matrix)(w->P);
@@ -1134,8 +1129,7 @@ void SCS(finish)(ScsWork *w) {
1134
1129
  }
1135
1130
  }
1136
1131
 
1137
- ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
1138
- const ScsSettings *stgs) {
1132
+ ScsWork *scs_init(const ScsData *d, const ScsCone *k, const ScsSettings *stgs) {
1139
1133
  ScsWork *w;
1140
1134
  SCS(timer) init_timer;
1141
1135
  scs_start_interrupt_listener();
@@ -1161,22 +1155,22 @@ ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
1161
1155
  return w;
1162
1156
  }
1163
1157
 
1164
- /* this just calls SCS(init), SCS(solve), and SCS(finish) */
1158
+ /* this just calls scs_init, scs_solve, and scs_finish */
1165
1159
  scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
1166
1160
  ScsSolution *sol, ScsInfo *info) {
1167
1161
  scs_int status;
1168
- ScsWork *w = SCS(init)(d, k, stgs);
1162
+ ScsWork *w = scs_init(d, k, stgs);
1169
1163
  #if VERBOSITY > 0
1170
1164
  scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
1171
1165
  sizeof(scs_int), sizeof(scs_float));
1172
1166
  #endif
1173
1167
  if (w) {
1174
- SCS(solve)(w, sol, info);
1168
+ scs_solve(w, sol, info);
1175
1169
  status = info->status_val;
1176
1170
  } else {
1177
1171
  status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
1178
1172
  SCS_FAILED, "could not initialize work", "failure");
1179
1173
  }
1180
- SCS(finish)(w);
1174
+ scs_finish(w);
1181
1175
  return status;
1182
1176
  }
@@ -1,11 +1,13 @@
1
+ #ifdef __cplusplus
2
+ extern "C" {
3
+ #endif
4
+
1
5
  #include "glbopts.h"
2
6
 
3
- const char *SCS(version)(void) {
7
+ const char *scs_version(void) {
4
8
  return SCS_VERSION;
5
9
  }
6
- size_t SCS(sizeof_int)(void) {
7
- return sizeof(scs_int);
8
- }
9
- size_t SCS(sizeof_float)(void) {
10
- return sizeof(scs_float);
10
+
11
+ #ifdef __cplusplus
11
12
  }
13
+ #endif
@@ -106,7 +106,7 @@ void SCS(free_sol)(ScsSolution *sol) {
106
106
  }
107
107
 
108
108
  /* assumes stgs already allocated memory */
109
- void SCS(set_default_settings)(ScsSettings *stgs) {
109
+ void scs_set_default_settings(ScsSettings *stgs) {
110
110
  /* These constants are defined in include/glbopts.h */
111
111
  stgs->max_iters = MAX_ITERS;
112
112
  stgs->eps_abs = EPS_ABS;
@@ -13,10 +13,15 @@
13
13
  if (!(test)) \
14
14
  return message; \
15
15
  } while (0)
16
- #define mu_run_test(test) \
16
+ #define mu_run_test(test) _mu_run_test(#test, test)
17
+
18
+ #define _mu_run_test(name, test) \
17
19
  do { \
20
+ scs_printf("*********************************************************\n"); \
21
+ scs_printf("Running test: %s\n", name); \
18
22
  const char *message = test(); \
19
23
  tests_run++; \
24
+ scs_printf("*********************************************************\n"); \
20
25
  if (message) \
21
26
  return message; \
22
27
  } while (0)
@@ -10,21 +10,11 @@
10
10
  #include "scs_matrix.h"
11
11
  #include "util.h"
12
12
 
13
- #define PI (3.141592654)
14
- #ifdef DLONG
15
- #ifdef _WIN64
16
- /* this is a Microsoft extension, but also works with min_g_w-w64 */
17
- #define INTRW "%I64d"
18
- #else
19
- #define INTRW "%ld"
20
- #endif
21
- #else
22
- #define INTRW "%i"
23
- #endif
13
+ #define _MAX_RAND_VAL (1073741823) /* 2^30 - 1 */
24
14
 
25
15
  /* uniform random number in [-1,1] */
26
16
  static scs_float rand_scs_float(void) {
27
- return 2 * (((scs_float)ran_arr_next()) / RAND_MAX) - 1;
17
+ return 2 * (((scs_float)ran_arr_next()) / _MAX_RAND_VAL) - 1; /* in [-1, 1] */
28
18
  }
29
19
 
30
20
  void gen_random_prob_data(scs_int nnz, scs_int col_nnz, ScsData *d, ScsCone *k,
@@ -51,8 +41,8 @@ void gen_random_prob_data(scs_int nnz, scs_int col_nnz, ScsData *d, ScsCone *k,
51
41
  for (i = 0; i < m; i++) {
52
42
  y[i] = z[i] = rand_scs_float();
53
43
  }
54
- tmp_cone_work = SCS(init_cone)(k, SCS_NULL, m);
55
- SCS(proj_dual_cone)(y, k, tmp_cone_work, 0);
44
+ tmp_cone_work = SCS(init_cone)(k, m);
45
+ SCS(proj_dual_cone)(y, tmp_cone_work, SCS_NULL, SCS_NULL);
56
46
  SCS(finish_cone(tmp_cone_work));
57
47
 
58
48
  for (i = 0; i < m; i++) {
@@ -88,25 +78,25 @@ void gen_random_prob_data(scs_int nnz, scs_int col_nnz, ScsData *d, ScsCone *k,
88
78
  scs_free(z);
89
79
  }
90
80
 
91
- static scs_float get_dual_cone_dist(const scs_float *y, const ScsCone *k,
92
- ScsConeWork *c, scs_int m) {
81
+ static scs_float get_dual_cone_dist(const scs_float *y, ScsConeWork *c,
82
+ scs_int m) {
93
83
  scs_float dist;
94
84
  scs_float *t = (scs_float *)scs_calloc(m, sizeof(scs_float));
95
85
  memcpy(t, y, m * sizeof(scs_float));
96
- SCS(proj_dual_cone)(t, k, c, 0);
86
+ SCS(proj_dual_cone)(t, c, SCS_NULL, SCS_NULL);
97
87
  dist = SCS(norm_inf_diff)(t, y, m);
98
88
  scs_free(t);
99
89
  return dist;
100
90
  }
101
91
 
102
92
  /* via moreau */
103
- static scs_float get_pri_cone_dist(const scs_float *s, const ScsCone *k,
104
- ScsConeWork *c, scs_int m) {
93
+ static scs_float get_pri_cone_dist(const scs_float *s, ScsConeWork *c,
94
+ scs_int m) {
105
95
  scs_float dist;
106
96
  scs_float *t = (scs_float *)scs_calloc(m, sizeof(scs_float));
107
97
  memcpy(t, s, m * sizeof(scs_float));
108
98
  SCS(scale_array)(t, -1.0, m);
109
- SCS(proj_dual_cone)(t, k, c, 0);
99
+ SCS(proj_dual_cone)(t, c, SCS_NULL, SCS_NULL);
110
100
  dist = SCS(norm_inf)(t, m); /* ||s - Pi_c(s)|| = ||Pi_c*(-s)|| */
111
101
  scs_free(t);
112
102
  return dist;
@@ -123,11 +113,11 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
123
113
  scs_float *c = d->c;
124
114
  scs_float *b = d->b;
125
115
 
126
- scs_float *primal = scs_calloc(m, sizeof(scs_float));
127
- scs_float *ax = scs_calloc(m, sizeof(scs_float));
128
- scs_float *dual = scs_calloc(n, sizeof(scs_float));
129
- scs_float *px = scs_calloc(n, sizeof(scs_float));
130
- scs_float *aty = scs_calloc(n, sizeof(scs_float));
116
+ scs_float *primal = (scs_float *)scs_calloc(m, sizeof(scs_float));
117
+ scs_float *ax = (scs_float *)scs_calloc(m, sizeof(scs_float));
118
+ scs_float *dual = (scs_float *)scs_calloc(n, sizeof(scs_float));
119
+ scs_float *px = (scs_float *)scs_calloc(n, sizeof(scs_float));
120
+ scs_float *aty = (scs_float *)scs_calloc(n, sizeof(scs_float));
131
121
 
132
122
  scs_float res_pri, res_dual, res_infeas, res_unbdd_a, res_unbdd_p;
133
123
  scs_float ctx, bty, xt_p_x, gap, pobj, dobj, sty;
@@ -135,7 +125,7 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
135
125
 
136
126
  scs_float sdist = NAN, ydist = NAN;
137
127
 
138
- ScsConeWork *cone_work = SCS(init_cone)(k, SCS_NULL, m);
128
+ ScsConeWork *cone_work = SCS(init_cone)(k, m);
139
129
 
140
130
  /**************** PRIMAL *********************/
141
131
  memset(ax, 0, m * sizeof(scs_float));
@@ -182,10 +172,10 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
182
172
  /**************** CONES *****************/
183
173
 
184
174
  if (status == SCS_SOLVED || status == SCS_UNBOUNDED) {
185
- sdist = get_pri_cone_dist(sol->s, k, cone_work, m);
175
+ sdist = get_pri_cone_dist(sol->s, cone_work, m);
186
176
  }
187
177
  if (status == SCS_SOLVED || status == SCS_INFEASIBLE) {
188
- ydist = get_dual_cone_dist(sol->y, k, cone_work, m);
178
+ ydist = get_dual_cone_dist(sol->y, cone_work, m);
189
179
  }
190
180
 
191
181
  /**************** OTHERS *****************/
@@ -215,14 +205,17 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
215
205
  /**************** ASSERTS *****************/
216
206
  if (status == SCS_SOLVED) {
217
207
  mu_assert_less("Primal residual ERROR", ABS(res_pri - info->res_pri),
218
- 1e-12);
208
+ 1e-11);
219
209
  mu_assert_less("Dual residual ERROR", ABS(res_dual - info->res_dual),
220
- 1e-12);
221
- mu_assert_less("Gap ERROR", ABS(gap - info->gap), 1e-12);
222
- mu_assert_less("Primal obj ERROR", ABS(pobj - info->pobj), 1e-12);
223
- mu_assert_less("Dual obj ERROR", ABS(dobj - info->dobj), 1e-12);
210
+ 1e-11);
211
+ mu_assert_less("Gap ERROR", ABS(gap - info->gap), 1e-8 * (1 + ABS(gap)));
212
+ mu_assert_less("Primal obj ERROR", ABS(pobj - info->pobj),
213
+ 1e-9 * (1 + ABS(pobj)));
214
+ mu_assert_less("Dual obj ERROR", ABS(dobj - info->dobj),
215
+ 1e-9 * (1 + ABS(dobj)));
224
216
  /* slightly looser tol */
225
- mu_assert_less("Complementary slackness ERROR", ABS(sty), 1e-6);
217
+ mu_assert_less("Complementary slackness ERROR", ABS(sty),
218
+ 1e-8 * MAX(NORM(s, m), NORM(y, m)));
226
219
  mu_assert_less("s cone dist ERROR", ABS(sdist), 1e-5);
227
220
  mu_assert_less("y cone dist ERROR", ABS(ydist), 1e-5);
228
221
 
@@ -230,7 +223,7 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
230
223
  stgs->eps_abs + stgs->eps_rel * prl);
231
224
  mu_assert_less("Dual feas ERROR", res_dual,
232
225
  stgs->eps_abs + stgs->eps_rel * drl);
233
- mu_assert_less("Gap ERROR", gap, stgs->eps_abs + stgs->eps_rel * grl);
226
+ mu_assert_less("Gap feas ERROR", gap, stgs->eps_abs + stgs->eps_rel * grl);
234
227
 
235
228
  } else if (status == SCS_INFEASIBLE) {
236
229
  mu_assert_less("Infeas ERROR", ABS(res_infeas - info->res_infeas), 1e-8);
@@ -58,7 +58,7 @@ static const char *degenerate(void) {
58
58
  d->P->i = Pi;
59
59
  d->P->p = Pp;
60
60
 
61
- SCS(set_default_settings)(stgs);
61
+ scs_set_default_settings(stgs);
62
62
  stgs->eps_abs = 1e-6;
63
63
  stgs->eps_rel = 1e-6;
64
64
  stgs->eps_infeas = 1e-9;