scs 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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;