scs 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +42 -13
  4. data/lib/scs/ffi.rb +1 -7
  5. data/lib/scs/matrix.rb +72 -0
  6. data/lib/scs/solver.rb +19 -26
  7. data/lib/scs/version.rb +1 -1
  8. data/lib/scs.rb +1 -0
  9. data/vendor/scs/CITATION.cff +1 -1
  10. data/vendor/scs/CMakeLists.txt +55 -7
  11. data/vendor/scs/Makefile +9 -9
  12. data/vendor/scs/README.md +4 -1
  13. data/vendor/scs/include/aa.h +1 -1
  14. data/vendor/scs/include/cones.h +17 -12
  15. data/vendor/scs/include/glbopts.h +27 -66
  16. data/vendor/scs/include/linalg.h +2 -1
  17. data/vendor/scs/include/linsys.h +13 -13
  18. data/vendor/scs/include/normalize.h +7 -5
  19. data/vendor/scs/include/rw.h +3 -3
  20. data/vendor/scs/include/scs.h +85 -106
  21. data/vendor/scs/include/scs_types.h +34 -0
  22. data/vendor/scs/include/scs_work.h +80 -0
  23. data/vendor/scs/include/util.h +3 -1
  24. data/vendor/scs/linsys/cpu/direct/private.c +86 -73
  25. data/vendor/scs/linsys/cpu/direct/private.h +2 -2
  26. data/vendor/scs/linsys/cpu/indirect/private.c +42 -33
  27. data/vendor/scs/linsys/cpu/indirect/private.h +1 -2
  28. data/vendor/scs/linsys/csparse.c +3 -3
  29. data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
  30. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +9 -7
  31. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +1 -1
  32. data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
  33. data/vendor/scs/linsys/gpu/gpu.h +8 -11
  34. data/vendor/scs/linsys/gpu/indirect/private.c +72 -49
  35. data/vendor/scs/linsys/gpu/indirect/private.h +14 -13
  36. data/vendor/scs/linsys/scs_matrix.c +55 -104
  37. data/vendor/scs/linsys/scs_matrix.h +5 -4
  38. data/vendor/scs/scs.mk +1 -5
  39. data/vendor/scs/src/aa.c +13 -8
  40. data/vendor/scs/src/cones.c +197 -108
  41. data/vendor/scs/src/linalg.c +25 -0
  42. data/vendor/scs/src/normalize.c +75 -26
  43. data/vendor/scs/src/rw.c +74 -30
  44. data/vendor/scs/src/scs.c +300 -264
  45. data/vendor/scs/src/scs_version.c +8 -6
  46. data/vendor/scs/src/util.c +27 -13
  47. data/vendor/scs/test/minunit.h +6 -1
  48. data/vendor/scs/test/problem_utils.h +28 -35
  49. data/vendor/scs/test/problems/degenerate.h +2 -1
  50. data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
  51. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +6 -2
  52. data/vendor/scs/test/problems/infeasible_tiny_qp.h +2 -1
  53. data/vendor/scs/test/problems/qafiro_tiny_qp.h +5 -4
  54. data/vendor/scs/test/problems/random_prob.h +6 -2
  55. data/vendor/scs/test/problems/rob_gauss_cov_est.h +9 -2
  56. data/vendor/scs/test/problems/small_lp.h +7 -2
  57. data/vendor/scs/test/problems/small_qp.h +387 -0
  58. data/vendor/scs/test/problems/{test_fails.h → test_validation.h} +7 -4
  59. data/vendor/scs/test/problems/unbounded_tiny_qp.h +4 -4
  60. data/vendor/scs/test/random_socp_prob.c +4 -2
  61. data/vendor/scs/test/run_from_file.c +16 -4
  62. data/vendor/scs/test/run_tests.c +23 -14
  63. metadata +10 -35
  64. data/vendor/scs/linsys/cpu/direct/private.o +0 -0
  65. data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
  66. data/vendor/scs/linsys/csparse.o +0 -0
  67. data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
  68. data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
  69. data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
  70. data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
  71. data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
  72. data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
  73. data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
  74. data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
  75. data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
  76. data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
  77. data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
  78. data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
  79. data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
  80. data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
  81. data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
  82. data/vendor/scs/linsys/scs_matrix.o +0 -0
  83. data/vendor/scs/src/aa.o +0 -0
  84. data/vendor/scs/src/cones.o +0 -0
  85. data/vendor/scs/src/ctrlc.o +0 -0
  86. data/vendor/scs/src/linalg.o +0 -0
  87. data/vendor/scs/src/normalize.o +0 -0
  88. data/vendor/scs/src/rw.o +0 -0
  89. data/vendor/scs/src/scs.o +0 -0
  90. data/vendor/scs/src/scs_indir.o +0 -0
  91. data/vendor/scs/src/scs_version.o +0 -0
  92. data/vendor/scs/src/util.o +0 -0
@@ -10,18 +10,15 @@
10
10
  #define BOX_CONE_MAX_ITERS (25)
11
11
  #define POW_CONE_MAX_ITERS (20)
12
12
 
13
- /* In the box cone projection we penalize the `t` term additionally by this
14
- * factor. This encourages the `t` term to stay close to the incoming `t` term,
15
- * which should provide better convergence since typically the `t` term does
16
- * not appear in the linear system other than `t = 1`. Setting to 1 is
17
- * the vanilla projection.
18
- */
19
- #define BOX_T_SCALE (1.)
20
-
21
13
  /* Box cone limits (+ or -) taken to be INF */
22
14
  #define MAX_BOX_VAL (1e15)
23
15
 
24
16
  #ifdef USE_LAPACK
17
+
18
+ #ifdef __cplusplus
19
+ extern "C" {
20
+ #endif
21
+
25
22
  void BLAS(syev)(const char *jobz, const char *uplo, blas_int *n, scs_float *a,
26
23
  blas_int *lda, scs_float *w, scs_float *work, blas_int *lwork,
27
24
  blas_int *info);
@@ -31,34 +28,94 @@ blas_int BLAS(syrk)(const char *uplo, const char *trans, const blas_int *n,
31
28
  const scs_float *beta, scs_float *c, const blas_int *ldc);
32
29
  void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
33
30
  const blas_int *incx);
31
+
32
+ #ifdef __cplusplus
33
+ }
34
+ #endif
35
+
34
36
  #endif
35
37
 
38
+ void SCS(free_cone)(ScsCone *k) {
39
+ if (k) {
40
+ if (k->bu)
41
+ scs_free(k->bu);
42
+ if (k->bl)
43
+ scs_free(k->bl);
44
+ if (k->q)
45
+ scs_free(k->q);
46
+ if (k->s)
47
+ scs_free(k->s);
48
+ if (k->p)
49
+ scs_free(k->p);
50
+ scs_free(k);
51
+ }
52
+ }
53
+
54
+ void SCS(deep_copy_cone)(ScsCone *dest, const ScsCone *src) {
55
+ memcpy(dest, src, sizeof(ScsCone));
56
+ /* copy bu, bl */
57
+ if (src->bsize > 1) {
58
+ dest->bu = (scs_float *)scs_calloc(src->bsize - 1, sizeof(scs_float));
59
+ memcpy(dest->bu, src->bu, (src->bsize - 1) * sizeof(scs_float));
60
+ dest->bl = (scs_float *)scs_calloc(src->bsize - 1, sizeof(scs_float));
61
+ memcpy(dest->bl, src->bl, (src->bsize - 1) * sizeof(scs_float));
62
+ } else {
63
+ dest->bu = SCS_NULL;
64
+ dest->bl = SCS_NULL;
65
+ }
66
+ /* copy SOC */
67
+ if (src->qsize > 0) {
68
+ dest->q = (scs_int *)scs_calloc(src->qsize, sizeof(scs_int));
69
+ memcpy(dest->q, src->q, src->qsize * sizeof(scs_int));
70
+ } else {
71
+ dest->q = SCS_NULL;
72
+ }
73
+ /* copy PSD cone */
74
+ if (src->ssize > 0) {
75
+ dest->s = (scs_int *)scs_calloc(src->ssize, sizeof(scs_int));
76
+ memcpy(dest->s, src->s, src->ssize * sizeof(scs_int));
77
+ } else {
78
+ dest->s = SCS_NULL;
79
+ }
80
+ /* copy power cone */
81
+ if (src->psize > 0) {
82
+ dest->p = (scs_float *)scs_calloc(src->psize, sizeof(scs_float));
83
+ memcpy(dest->p, src->p, src->psize * sizeof(scs_float));
84
+ } else {
85
+ dest->p = SCS_NULL;
86
+ }
87
+ }
88
+
36
89
  /* set the vector of rho y terms, based on scale and cones */
37
- void SCS(set_rho_y_vec)(const ScsCone *k, scs_float scale, scs_float *rho_y_vec,
38
- scs_int m) {
39
- scs_int i, count = 0;
40
- /* f cone */
41
- for (i = 0; i < k->z; ++i) {
90
+ void SCS(set_r_y)(const ScsConeWork *c, scs_float scale, scs_float *r_y) {
91
+ scs_int i;
92
+ /* z cone */
93
+ for (i = 0; i < c->k->z; ++i) {
42
94
  /* set rho_y small for z, similar to rho_x term, since z corresponds to
43
95
  * dual free cone, this effectively decreases penalty on those entries
44
96
  * and lets them be determined almost entirely by the linear system solve
45
97
  */
46
- rho_y_vec[i] = 1.0 / (1000. * scale);
98
+ r_y[i] = 1.0 / (1000. * scale);
47
99
  }
48
- count += k->z;
49
100
  /* others */
50
- for (i = count; i < m; ++i) {
51
- rho_y_vec[i] = 1.0 / scale;
101
+ for (i = c->k->z; i < c->m; ++i) {
102
+ r_y[i] = 1.0 / scale;
52
103
  }
104
+ }
53
105
 
54
- /* Note, if updating this to use different scales for other cones (e.g. box)
55
- * then you must be careful to also include the effect of the rho_y_vec
56
- * in the cone projection operator.
57
- */
58
-
59
- /* Increase rho_y_vec for the t term in the box cone */
60
- if (k->bsize) {
61
- rho_y_vec[k->z + k->l] *= BOX_T_SCALE;
106
+ /* the function f aggregates the entries within each cone */
107
+ void SCS(enforce_cone_boundaries)(const ScsConeWork *c, scs_float *vec,
108
+ scs_float (*f)(const scs_float *, scs_int)) {
109
+ scs_int i, j, delta;
110
+ scs_int count = c->cone_boundaries[0];
111
+ scs_float wrk;
112
+ for (i = 1; i < c->cone_boundaries_len; ++i) {
113
+ delta = c->cone_boundaries[i];
114
+ wrk = f(&(vec[count]), delta);
115
+ for (j = count; j < count + delta; ++j) {
116
+ vec[j] = wrk;
117
+ }
118
+ count += delta;
62
119
  }
63
120
  }
64
121
 
@@ -71,7 +128,7 @@ static inline scs_int get_sd_cone_size(scs_int s) {
71
128
  * cone boundaries, boundaries[0] is starting index for cones of size strictly
72
129
  * larger than 1, boundaries malloc-ed here so should be freed.
73
130
  */
74
- scs_int SCS(set_cone_boundaries)(const ScsCone *k, scs_int **cone_boundaries) {
131
+ void set_cone_boundaries(const ScsCone *k, ScsConeWork *c) {
75
132
  scs_int i, s_cone_sz, count = 0;
76
133
  scs_int cone_boundaries_len =
77
134
  1 + k->qsize + k->ssize + k->ed + k->ep + k->psize;
@@ -99,8 +156,8 @@ scs_int SCS(set_cone_boundaries)(const ScsCone *k, scs_int **cone_boundaries) {
99
156
  }
100
157
  count += k->psize;
101
158
  /* other cones */
102
- *cone_boundaries = b;
103
- return cone_boundaries_len;
159
+ c->cone_boundaries = b;
160
+ c->cone_boundaries_len = cone_boundaries_len;
104
161
  }
105
162
 
106
163
  static scs_int get_full_cone_dims(const ScsCone *k) {
@@ -121,7 +178,7 @@ static scs_int get_full_cone_dims(const ScsCone *k) {
121
178
  if (k->ep) {
122
179
  c += 3 * k->ep;
123
180
  }
124
- if (k->p) {
181
+ if (k->psize) {
125
182
  c += 3 * k->psize;
126
183
  }
127
184
  return c;
@@ -216,15 +273,12 @@ void SCS(finish_cone)(ScsConeWork *c) {
216
273
  scs_free(c->work);
217
274
  }
218
275
  #endif
276
+ if (c->cone_boundaries) {
277
+ scs_free(c->cone_boundaries);
278
+ }
219
279
  if (c->s) {
220
280
  scs_free(c->s);
221
281
  }
222
- if (c->bu) {
223
- scs_free(c->bu);
224
- }
225
- if (c->bl) {
226
- scs_free(c->bl);
227
- }
228
282
  if (c) {
229
283
  scs_free(c);
230
284
  }
@@ -484,7 +538,7 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
484
538
  /* Solve eigenproblem, reuse workspaces */
485
539
  BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
486
540
  if (info != 0) {
487
- scs_printf("WARN: LAPACK syev error, info = %i\n", info);
541
+ scs_printf("WARN: LAPACK syev error, info = %i\n", (int)info);
488
542
  if (info < 0) {
489
543
  return info;
490
544
  }
@@ -571,52 +625,56 @@ static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
571
625
  * { (t', s') | t' * l' <= s' <= t' u', t >= 0 } = K'
572
626
  * where l' = D l / d0, u' = D u / d0.
573
627
  */
574
- static void normalize_box_cone(ScsConeWork *c, scs_float *D, scs_int bsize) {
628
+ static void normalize_box_cone(ScsCone *k, scs_float *D, scs_int bsize) {
575
629
  scs_int j;
576
630
  for (j = 0; j < bsize - 1; j++) {
577
- if (c->bu[j] >= MAX_BOX_VAL) {
578
- c->bu[j] = INFINITY;
631
+ if (k->bu[j] >= MAX_BOX_VAL) {
632
+ k->bu[j] = INFINITY;
579
633
  } else {
580
- c->bu[j] = D ? D[j + 1] * c->bu[j] / D[0] : c->bu[j];
634
+ k->bu[j] = D ? D[j + 1] * k->bu[j] / D[0] : k->bu[j];
581
635
  }
582
- if (c->bl[j] <= -MAX_BOX_VAL) {
583
- c->bl[j] = -INFINITY;
636
+ if (k->bl[j] <= -MAX_BOX_VAL) {
637
+ k->bl[j] = -INFINITY;
584
638
  } else {
585
- c->bl[j] = D ? D[j + 1] * c->bl[j] / D[0] : c->bl[j];
639
+ k->bl[j] = D ? D[j + 1] * k->bl[j] / D[0] : k->bl[j];
586
640
  }
587
641
  }
588
642
  }
589
643
 
590
- /* project onto { (t, s) | t * l <= s <= t * u, t >= 0 }, Newton's method on t
591
- tx = [t; s], total length = bsize
592
- uses Moreau since \Pi_K*(tx) = \Pi_K(-tx) + tx
644
+ /* Project onto { (t, s) | t * l <= s <= t * u, t >= 0 }, Newton's method on t
645
+ tx = [t; s], total length = bsize, under Euclidean metric 1/r_box.
593
646
  */
594
647
  static scs_float proj_box_cone(scs_float *tx, const scs_float *bl,
595
648
  const scs_float *bu, scs_int bsize,
596
- scs_float t_warm_start) {
649
+ scs_float t_warm_start, scs_float *r_box) {
597
650
  scs_float *x, gt, ht, t_prev, t = t_warm_start;
651
+ scs_float rho_t = 1, *rho = SCS_NULL, r;
598
652
  scs_int iter, j;
599
653
 
600
654
  if (bsize == 1) { /* special case */
601
655
  tx[0] = MAX(tx[0], 0.0);
602
656
  return tx[0];
603
657
  }
604
-
605
658
  x = &(tx[1]);
606
659
 
660
+ if (r_box) {
661
+ rho_t = 1.0 / r_box[0];
662
+ rho = &(r_box[1]);
663
+ }
664
+
607
665
  /* should only require about 5 or so iterations, 1 or 2 if warm-started */
608
666
  for (iter = 0; iter < BOX_CONE_MAX_ITERS; iter++) {
609
667
  t_prev = t;
610
- /* incorporate the additional BOX_T_SCALE factor into the projection */
611
- gt = BOX_T_SCALE * (t - tx[0]); /* gradient */
612
- ht = BOX_T_SCALE; /* hessian */
668
+ gt = rho_t * (t - tx[0]); /* gradient */
669
+ ht = rho_t; /* hessian */
613
670
  for (j = 0; j < bsize - 1; j++) {
671
+ r = rho ? 1.0 / rho[j] : 1.;
614
672
  if (x[j] > t * bu[j]) {
615
- gt += (t * bu[j] - x[j]) * bu[j]; /* gradient */
616
- ht += bu[j] * bu[j]; /* hessian */
673
+ gt += r * (t * bu[j] - x[j]) * bu[j]; /* gradient */
674
+ ht += r * bu[j] * bu[j]; /* hessian */
617
675
  } else if (x[j] < t * bl[j]) {
618
- gt += (t * bl[j] - x[j]) * bl[j]; /* gradient */
619
- ht += bl[j] * bl[j]; /* hessian */
676
+ gt += r * (t * bl[j] - x[j]) * bl[j]; /* gradient */
677
+ ht += r * bl[j] * bl[j]; /* hessian */
620
678
  }
621
679
  }
622
680
  t = MAX(t - gt / MAX(ht, 1e-8), 0.); /* newton step */
@@ -647,6 +705,7 @@ static scs_float proj_box_cone(scs_float *tx, const scs_float *bl,
647
705
  /* x[j] unchanged otherwise */
648
706
  }
649
707
  tx[0] = t;
708
+
650
709
  #if VERBOSITY > 3
651
710
  scs_printf("box cone iters %i\n", (int)iter + 1);
652
711
  #endif
@@ -718,18 +777,22 @@ static void proj_power_cone(scs_float *v, scs_float a) {
718
777
  }
719
778
 
720
779
  /* project onto the primal K cone in the paper */
780
+ /* the r_y vector determines the INVERSE metric, ie, project under the
781
+ * diag(r_y)^-1 norm.
782
+ */
721
783
  static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
722
- scs_int normalize) {
784
+ scs_int normalize, scs_float *r_y) {
723
785
  scs_int i, status;
724
786
  scs_int count = 0;
787
+ scs_float *r_box = SCS_NULL;
725
788
 
726
- if (k->z) {
789
+ if (k->z) { /* doesn't use r_y */
727
790
  /* project onto primal zero / dual free cone */
728
791
  memset(x, 0, k->z * sizeof(scs_float));
729
792
  count += k->z;
730
793
  }
731
794
 
732
- if (k->l) {
795
+ if (k->l) { /* doesn't use r_y */
733
796
  /* project onto positive orthant */
734
797
  for (i = count; i < count + k->l; ++i) {
735
798
  x[i] = MAX(x[i], 0.0);
@@ -737,19 +800,17 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
737
800
  count += k->l;
738
801
  }
739
802
 
740
- if (k->bsize) {
741
- /* project onto box cone */
742
- if (normalize) {
743
- c->box_t_warm_start = proj_box_cone(&(x[count]), c->bl, c->bu, k->bsize,
744
- c->box_t_warm_start);
745
- } else {
746
- c->box_t_warm_start = proj_box_cone(&(x[count]), k->bl, k->bu, k->bsize,
747
- c->box_t_warm_start);
803
+ if (k->bsize) { /* DOES use r_y */
804
+ if (r_y) {
805
+ r_box = &(r_y[count]);
748
806
  }
807
+ /* project onto box cone */
808
+ c->box_t_warm_start = proj_box_cone(&(x[count]), k->bl, k->bu, k->bsize,
809
+ c->box_t_warm_start, r_box);
749
810
  count += k->bsize; /* since b = (t,s), len(s) = bsize - 1 */
750
811
  }
751
812
 
752
- if (k->qsize && k->q) {
813
+ if (k->qsize && k->q) { /* doesn't use r_y */
753
814
  /* project onto second-order cones */
754
815
  for (i = 0; i < k->qsize; ++i) {
755
816
  proj_soc(&(x[count]), k->q[i]);
@@ -757,7 +818,7 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
757
818
  }
758
819
  }
759
820
 
760
- if (k->ssize && k->s) {
821
+ if (k->ssize && k->s) { /* doesn't use r_y */
761
822
  /* project onto PSD cones */
762
823
  for (i = 0; i < k->ssize; ++i) {
763
824
  status = proj_semi_definite_cone(&(x[count]), k->s[i], c);
@@ -768,13 +829,13 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
768
829
  }
769
830
  }
770
831
 
771
- if (k->ep) {
772
- /*
773
- * exponential cone is not self dual, if s \in K
774
- * then y \in K^* and so if K is the primal cone
775
- * here we project onto K^*, via Moreau
776
- * \Pi_C^*(y) = y + \Pi_C(-y)
777
- */
832
+ if (k->ep) { /* doesn't use r_y */
833
+ /*
834
+ * exponential cone is not self dual, if s \in K
835
+ * then y \in K^* and so if K is the primal cone
836
+ * here we project onto K^*, via Moreau
837
+ * \Pi_C^*(y) = y + \Pi_C(-y)
838
+ */
778
839
  #ifdef _OPENMP
779
840
  #pragma omp parallel for
780
841
  #endif
@@ -784,7 +845,8 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
784
845
  count += 3 * k->ep;
785
846
  }
786
847
 
787
- if (k->ed) { /* dual exponential cone */
848
+ /* dual exponential cone */
849
+ if (k->ed) { /* doesn't use r_y */
788
850
  /*
789
851
  * exponential cone is not self dual, if s \in K
790
852
  * then y \in K^* and so if K is the primal cone
@@ -812,7 +874,7 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
812
874
  count += 3 * k->ed;
813
875
  }
814
876
 
815
- if (k->psize && k->p) {
877
+ if (k->psize && k->p) { /* doesn't use r_y */
816
878
  scs_float v[3];
817
879
  scs_int idx;
818
880
  /* don't use openmp for power cone
@@ -820,7 +882,7 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
820
882
  pragma omp parallel for private(v, idx)
821
883
  endif
822
884
  */
823
- for (i = 0; i < k->psize; ++i) {
885
+ for (i = 0; i < k->psize; ++i) { /* doesn't use r_y */
824
886
  idx = count + 3 * i;
825
887
  if (k->p[i] >= 0) {
826
888
  /* primal power cone */
@@ -844,23 +906,13 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
844
906
  return 0;
845
907
  }
846
908
 
847
- ScsConeWork *SCS(init_cone)(const ScsCone *k, const ScsScaling *scal,
848
- scs_int cone_len) {
909
+ ScsConeWork *SCS(init_cone)(ScsCone *k, scs_int m) {
849
910
  ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
850
- c->cone_len = cone_len;
851
- c->s = (scs_float *)scs_calloc(cone_len, sizeof(scs_float));
852
- if (k->bsize && k->bu && k->bl) {
853
- c->box_t_warm_start = 1.;
854
- if (scal) {
855
- c->bu = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
856
- c->bl = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
857
- memcpy(c->bu, k->bu, (k->bsize - 1) * sizeof(scs_float));
858
- memcpy(c->bl, k->bl, (k->bsize - 1) * sizeof(scs_float));
859
- /* also does some sanitizing */
860
- normalize_box_cone(c, scal ? &(scal->D[k->z + k->l]) : SCS_NULL,
861
- k->bsize);
862
- }
863
- }
911
+ c->k = k;
912
+ c->m = m;
913
+ c->scaled_cones = 0;
914
+ set_cone_boundaries(k, c);
915
+ c->s = (scs_float *)scs_calloc(m, sizeof(scs_float));
864
916
  if (k->ssize && k->s) {
865
917
  if (set_up_sd_cone_work_space(c, k) < 0) {
866
918
  SCS(finish_cone)(c);
@@ -870,20 +922,57 @@ ScsConeWork *SCS(init_cone)(const ScsCone *k, const ScsScaling *scal,
870
922
  return c;
871
923
  }
872
924
 
873
- /* outward facing cone projection routine
874
- performs projection in-place
875
- if normalize > 0 then will use normalized (equilibrated) cones if applicable.
925
+ void scale_box_cone(ScsCone *k, ScsConeWork *c, ScsScaling *scal) {
926
+ if (k->bsize && k->bu && k->bl) {
927
+ c->box_t_warm_start = 1.;
928
+ if (scal) {
929
+ /* also does some sanitizing */
930
+ normalize_box_cone(k, &(scal->D[k->z + k->l]), k->bsize);
931
+ }
932
+ }
933
+ }
934
+
935
+ /* Outward facing cone projection routine, performs projection in-place.
936
+ If normalize > 0 then will use normalized (equilibrated) cones if applicable.
937
+
938
+ Moreau decomposition for R-norm projections:
939
+
940
+ `x + R^{-1} \Pi_{C^*}^{R^{-1}} ( - R x ) = \Pi_C^R ( x )`
941
+
942
+ where \Pi^R_C is the projection onto C under the R-norm:
943
+
944
+ `||x||_R = \sqrt{x ' R x}`.
945
+
876
946
  */
877
- scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
878
- scs_int normalize) {
879
- scs_int status;
880
- /* copy x, s = x */
881
- memcpy(c->s, x, c->cone_len * sizeof(scs_float));
882
- /* negate x -> -x */
883
- SCS(scale_array)(x, -1., c->cone_len);
884
- /* project -x onto cone, x -> Pi_K(-x) */
885
- status = proj_cone(x, k, c, normalize);
886
- /* return Pi_K*(x) = s + Pi_K(-x) */
887
- SCS(add_scaled_array)(x, c->s, c->cone_len, 1.);
947
+ scs_int SCS(proj_dual_cone)(scs_float *x, ScsConeWork *c, ScsScaling *scal,
948
+ scs_float *r_y) {
949
+ scs_int status, i;
950
+ ScsCone *k = c->k;
951
+
952
+ if (!c->scaled_cones) {
953
+ scale_box_cone(k, c, scal);
954
+ c->scaled_cones = 1;
955
+ }
956
+
957
+ /* copy s = x */
958
+ memcpy(c->s, x, c->m * sizeof(scs_float));
959
+
960
+ /* x -> - Rx */
961
+ for (i = 0; i < c->m; ++i) {
962
+ x[i] *= r_y ? -r_y[i] : -1;
963
+ }
964
+
965
+ /* project -x onto cone, x -> \Pi_{C^*}^{R^{-1}}(-x) under r_y metric */
966
+ status = proj_cone(x, k, c, scal ? 1 : 0, r_y);
967
+
968
+ /* return x + R^{-1} \Pi_{C^*}^{R^{-1}} ( -x ) */
969
+ for (i = 0; i < c->m; ++i) {
970
+ if (r_y) {
971
+ x[i] = x[i] / r_y[i] + c->s[i];
972
+ } else {
973
+ x[i] += c->s[i];
974
+ }
975
+ }
976
+
888
977
  return status;
889
978
  }
@@ -83,9 +83,22 @@ void SCS(add_scaled_array)(scs_float *a, const scs_float *b, scs_int n,
83
83
  }
84
84
  }
85
85
 
86
+ scs_float SCS(mean)(const scs_float *x, scs_int n) {
87
+ scs_int i;
88
+ scs_float mean = 0.;
89
+ for (i = 0; i < n; ++i) {
90
+ mean += x[i];
91
+ }
92
+ return mean / n;
93
+ }
94
+
86
95
  #else
87
96
  /* If we have BLAS / LAPACK we may as well use them */
88
97
 
98
+ #ifdef __cplusplus
99
+ extern "C" {
100
+ #endif
101
+
89
102
  scs_float BLAS(nrm2)(blas_int *n, const scs_float *x, blas_int *incx);
90
103
  scs_float BLAS(dot)(const blas_int *n, const scs_float *x, const blas_int *incx,
91
104
  const scs_float *y, const blas_int *incy);
@@ -96,6 +109,10 @@ void BLAS(axpy)(blas_int *n, const scs_float *a, const scs_float *x,
96
109
  void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
97
110
  const blas_int *incx);
98
111
 
112
+ #ifdef __cplusplus
113
+ }
114
+ #endif
115
+
99
116
  /* a *= b */
100
117
  void SCS(scale_array)(scs_float *a, const scs_float b, scs_int len) {
101
118
  blas_int bone = 1;
@@ -137,4 +154,12 @@ void SCS(add_scaled_array)(scs_float *a, const scs_float *b, scs_int len,
137
154
  BLAS(axpy)(&blen, &sc, b, &bone, a, &bone);
138
155
  }
139
156
 
157
+ scs_float SCS(mean)(const scs_float *x, scs_int n) {
158
+ blas_int bone = 1;
159
+ blas_int bzero = 0;
160
+ blas_int blen = (blas_int)n;
161
+ scs_float y = 1.0;
162
+ return BLAS(dot)(&blen, x, &bone, &y, &bzero) / n;
163
+ }
164
+
140
165
  #endif
@@ -3,49 +3,98 @@
3
3
  #include "linalg.h"
4
4
  #include "scs.h"
5
5
 
6
+ /* copied from linsys/scs_matrix.c */
7
+ #define MIN_NORMALIZATION_FACTOR (1e-4)
8
+ #define MAX_NORMALIZATION_FACTOR (1e4)
9
+
10
+ /* Given D, E in scaling normalize b, c and compute primal / dual scales.
11
+ *
12
+ * Recall that the normalization routine is performing:
13
+ *
14
+ * [P A' c] with [E 0 0] on both sides (D, E diagonal)
15
+ * [A 0 b] [0 D 0]
16
+ * [c' b' 0] [0 0 s]
17
+ *
18
+ * which results in:
19
+ *
20
+ * [ EPE EA'D sEc ]
21
+ * [ DAE 0 sDb ]
22
+ * [ sc'E sb'D 0 ]
23
+ *
24
+ * `s` is incorporated into dual_scale and primal_scale
25
+ *
26
+ */
27
+ void SCS(normalize_b_c)(ScsScaling *scal, scs_float *b, scs_float *c) {
28
+ scs_int i;
29
+ scs_float sigma;
30
+
31
+ /* scale c */
32
+ for (i = 0; i < scal->n; ++i) {
33
+ c[i] *= scal->E[i];
34
+ }
35
+ /* scale b */
36
+ for (i = 0; i < scal->m; ++i) {
37
+ b[i] *= scal->D[i];
38
+ }
39
+
40
+ /* calculate primal and dual scales */
41
+ sigma = MAX(SCS(norm_inf)(c, scal->n), SCS(norm_inf)(b, scal->m));
42
+ sigma = sigma < MIN_NORMALIZATION_FACTOR ? 1.0 : sigma;
43
+ sigma = sigma > MAX_NORMALIZATION_FACTOR ? MAX_NORMALIZATION_FACTOR : sigma;
44
+ sigma = SAFEDIV_POS(1.0, sigma);
45
+
46
+ /* Scale b, c */
47
+ SCS(scale_array)(c, sigma, scal->n);
48
+ SCS(scale_array)(b, sigma, scal->m);
49
+
50
+ /* We assume that primal_scale = dual_scale, otherwise need to refactorize */
51
+ scal->primal_scale = sigma;
52
+ scal->dual_scale = sigma;
53
+ }
54
+
6
55
  /* needed for normalizing the warm-start */
7
- void SCS(normalize_sol)(ScsWork *w, ScsSolution *sol) {
56
+ void SCS(normalize_sol)(ScsScaling *scal, ScsSolution *sol) {
8
57
  scs_int i;
9
- scs_float *D = w->scal->D;
10
- scs_float *E = w->scal->E;
11
- for (i = 0; i < w->n; ++i) {
12
- sol->x[i] /= (E[i] / w->scal->dual_scale);
58
+ scs_float *D = scal->D;
59
+ scs_float *E = scal->E;
60
+ for (i = 0; i < scal->n; ++i) {
61
+ sol->x[i] /= (E[i] / scal->dual_scale);
13
62
  }
14
- for (i = 0; i < w->m; ++i) {
15
- sol->y[i] /= (D[i] / w->scal->primal_scale);
63
+ for (i = 0; i < scal->m; ++i) {
64
+ sol->y[i] /= (D[i] / scal->primal_scale);
16
65
  }
17
- for (i = 0; i < w->m; ++i) {
18
- sol->s[i] *= (D[i] * w->scal->dual_scale);
66
+ for (i = 0; i < scal->m; ++i) {
67
+ sol->s[i] *= (D[i] * scal->dual_scale);
19
68
  }
20
69
  }
21
70
 
22
- void SCS(un_normalize_sol)(ScsWork *w, ScsSolution *sol) {
71
+ void SCS(un_normalize_sol)(ScsScaling *scal, ScsSolution *sol) {
23
72
  scs_int i;
24
- scs_float *D = w->scal->D;
25
- scs_float *E = w->scal->E;
26
- for (i = 0; i < w->n; ++i) {
27
- sol->x[i] *= (E[i] / w->scal->dual_scale);
73
+ scs_float *D = scal->D;
74
+ scs_float *E = scal->E;
75
+ for (i = 0; i < scal->n; ++i) {
76
+ sol->x[i] *= (E[i] / scal->dual_scale);
28
77
  }
29
- for (i = 0; i < w->m; ++i) {
30
- sol->y[i] *= (D[i] / w->scal->primal_scale);
78
+ for (i = 0; i < scal->m; ++i) {
79
+ sol->y[i] *= (D[i] / scal->primal_scale);
31
80
  }
32
- for (i = 0; i < w->m; ++i) {
33
- sol->s[i] /= (D[i] * w->scal->dual_scale);
81
+ for (i = 0; i < scal->m; ++i) {
82
+ sol->s[i] /= (D[i] * scal->dual_scale);
34
83
  }
35
84
  }
36
85
 
37
- void SCS(un_normalize_primal)(ScsWork *w, scs_float *r) {
86
+ void SCS(un_normalize_primal)(ScsScaling *scal, scs_float *r) {
38
87
  scs_int i;
39
- scs_float *D = w->scal->D;
40
- for (i = 0; i < w->m; ++i) {
41
- r[i] /= (D[i] * w->scal->dual_scale);
88
+ scs_float *D = scal->D;
89
+ for (i = 0; i < scal->m; ++i) {
90
+ r[i] /= (D[i] * scal->dual_scale);
42
91
  }
43
92
  }
44
93
 
45
- void SCS(un_normalize_dual)(ScsWork *w, scs_float *r) {
94
+ void SCS(un_normalize_dual)(ScsScaling *scal, scs_float *r) {
46
95
  scs_int i;
47
- scs_float *E = w->scal->E;
48
- for (i = 0; i < w->n; ++i) {
49
- r[i] /= (E[i] * w->scal->primal_scale);
96
+ scs_float *E = scal->E;
97
+ for (i = 0; i < scal->n; ++i) {
98
+ r[i] /= (E[i] * scal->primal_scale);
50
99
  }
51
100
  }