scs 0.5.6 → 0.6.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +1 -1
  4. data/lib/scs/ffi.rb +18 -0
  5. data/lib/scs/version.rb +1 -1
  6. data/vendor/scs/CITATION.cff +2 -3
  7. data/vendor/scs/CLAUDE.md +115 -0
  8. data/vendor/scs/CMakeLists.txt +330 -201
  9. data/vendor/scs/CONTRIBUTING.md +49 -0
  10. data/vendor/scs/Makefile +90 -43
  11. data/vendor/scs/README.md +96 -2
  12. data/vendor/scs/include/aa.h +59 -11
  13. data/vendor/scs/include/aa_stats.h +47 -0
  14. data/vendor/scs/include/cones.h +16 -7
  15. data/vendor/scs/include/glbopts.h +113 -26
  16. data/vendor/scs/include/linalg.h +5 -1
  17. data/vendor/scs/include/linsys.h +1 -2
  18. data/vendor/scs/include/normalize.h +6 -2
  19. data/vendor/scs/include/rw.h +9 -3
  20. data/vendor/scs/include/scs.h +17 -1
  21. data/vendor/scs/include/scs_blas.h +8 -0
  22. data/vendor/scs/include/scs_types.h +2 -2
  23. data/vendor/scs/include/scs_work.h +22 -1
  24. data/vendor/scs/include/util.h +3 -6
  25. data/vendor/scs/include/util_spectral_cones.h +3 -3
  26. data/vendor/scs/linsys/accelerate/direct/private.c +126 -0
  27. data/vendor/scs/linsys/accelerate/direct/private.h +34 -0
  28. data/vendor/scs/linsys/cpu/dense/private.c +250 -0
  29. data/vendor/scs/linsys/cpu/dense/private.h +31 -0
  30. data/vendor/scs/linsys/cpu/direct/private.c +86 -44
  31. data/vendor/scs/linsys/cpu/indirect/private.c +647 -113
  32. data/vendor/scs/linsys/cpu/indirect/private.h +28 -0
  33. data/vendor/scs/linsys/csparse.c +9 -3
  34. data/vendor/scs/linsys/csparse.h +4 -2
  35. data/vendor/scs/linsys/cudss/direct/private.c +77 -43
  36. data/vendor/scs/linsys/cudss/direct/private.h +33 -7
  37. data/vendor/scs/linsys/gpu/indirect/private.c +6 -2
  38. data/vendor/scs/linsys/mkl/direct/private.c +63 -31
  39. data/vendor/scs/linsys/mkl/direct/private.h +0 -1
  40. data/vendor/scs/linsys/scs_matrix.c +291 -165
  41. data/vendor/scs/linsys/scs_matrix.h +7 -9
  42. data/vendor/scs/scs.mk +35 -13
  43. data/vendor/scs/src/aa.c +673 -166
  44. data/vendor/scs/src/cones.c +545 -223
  45. data/vendor/scs/src/ctrlc.c +59 -16
  46. data/vendor/scs/src/exp_cone.c +70 -50
  47. data/vendor/scs/src/linalg.c +21 -2
  48. data/vendor/scs/src/normalize.c +24 -26
  49. data/vendor/scs/src/rw.c +596 -124
  50. data/vendor/scs/src/scs.c +990 -513
  51. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +240 -187
  52. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +108 -85
  53. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +62 -63
  54. data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +85 -78
  55. data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +92 -97
  56. data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +39 -28
  57. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +59 -40
  58. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +37 -29
  59. data/vendor/scs/src/spectral_cones/util_spectral_cones.c +12 -6
  60. data/vendor/scs/src/util.c +37 -7
  61. data/vendor/scs/test/mkl_interface_mismatch.c +97 -0
  62. data/vendor/scs/test/packaging/CMakeLists.txt +21 -0
  63. data/vendor/scs/test/packaging/consume.c +50 -0
  64. data/vendor/scs/test/problem_utils.h +9 -2
  65. data/vendor/scs/test/problems/dense_qp.h +64 -0
  66. data/vendor/scs/test/problems/hs21_tiny_qp.h +6 -2
  67. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +10 -2
  68. data/vendor/scs/test/problems/infeasible_lp.h +66 -0
  69. data/vendor/scs/test/problems/infeasible_socp.h +75 -0
  70. data/vendor/scs/test/problems/lp_update.h +110 -0
  71. data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -1
  72. data/vendor/scs/test/problems/rob_gauss_cov_est.h +6 -3
  73. data/vendor/scs/test/problems/small_qp.h +5 -0
  74. data/vendor/scs/test/problems/test_box_cone.h +92 -0
  75. data/vendor/scs/test/problems/test_dual_exp_cone.h +96 -0
  76. data/vendor/scs/test/problems/test_inaccurate.h +212 -0
  77. data/vendor/scs/test/problems/test_mixed_cones.h +113 -0
  78. data/vendor/scs/test/problems/test_normalize_roundtrip.h +279 -0
  79. data/vendor/scs/test/problems/test_power_cone.h +414 -0
  80. data/vendor/scs/test/problems/test_psd_metric.h +109 -0
  81. data/vendor/scs/test/problems/test_psd_n1.h +84 -0
  82. data/vendor/scs/test/problems/test_root_plus.h +191 -0
  83. data/vendor/scs/test/problems/test_rw_settings.h +112 -0
  84. data/vendor/scs/test/problems/test_soc_sizes.h +393 -0
  85. data/vendor/scs/test/problems/test_solver_options.h +558 -0
  86. data/vendor/scs/test/problems/test_validation.h +263 -24
  87. data/vendor/scs/test/problems/test_zero_cone.h +81 -0
  88. data/vendor/scs/test/problems/unbounded_lp.h +66 -0
  89. data/vendor/scs/test/problems/unbounded_socp.h +71 -0
  90. data/vendor/scs/test/run_from_file.c +6 -0
  91. data/vendor/scs/test/run_tests.c +71 -0
  92. data/vendor/scs/test/rw_settings.c +7 -0
  93. data/vendor/scs/test/spectral_cones_problems/test_ell1_and_nuc.h +128 -0
  94. data/vendor/scs/test/spectral_cones_problems/test_ell1_cone.h +115 -0
  95. metadata +35 -3
@@ -6,6 +6,8 @@
6
6
  #include "util.h"
7
7
  #include "util_spectral_cones.h"
8
8
 
9
+ #include <string.h>
10
+
9
11
  /*
10
12
  * Spectral matrix cone projections, from "Projection onto Spectral Matrix
11
13
  * Cones" by Daniel Cederberg and Stephen Boyd, 2024.
@@ -36,7 +38,7 @@ void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
36
38
  }
37
39
  #endif
38
40
 
39
- // forward declare from log_cone_wrapper.c
41
+ /* forward declare from log_cone_wrapper.c */
40
42
  scs_int log_cone_proj_wrapper(scs_float t0, scs_float v0, scs_float *x0,
41
43
  scs_float *proj, scs_int n, scs_float *workspace,
42
44
  Newton_stats *stats, bool *warm_start);
@@ -45,9 +47,11 @@ scs_int SCS(proj_logdet_cone)(scs_float *tvX, scs_int n, ScsConeWork *c,
45
47
  scs_int offset, bool *warmstart) {
46
48
  Newton_stats *stats = &(c->newton_stats);
47
49
 
48
- // tvX = [t, v, X], where X represents the lower triangular part of a matrix
49
- // stored in a compact form and off-diagonal elements have been scaled by
50
- // sqrt(2)
50
+ /*
51
+ * tvX = [t, v, X], where X represents the lower triangular part of a matrix
52
+ * stored in a compact form and off-diagonal elements have been scaled by
53
+ * sqrt(2)
54
+ */
51
55
  scs_float *X = tvX + 2;
52
56
 
53
57
  #ifndef USE_LAPACK
@@ -57,87 +61,90 @@ scs_int SCS(proj_logdet_cone)(scs_float *tvX, scs_int n, ScsConeWork *c,
57
61
  return -1;
58
62
  #endif
59
63
 
60
- // ----------------------------------------------------------------------
61
- // compute eigendecomposition
62
- // ----------------------------------------------------------------------
63
- scs_int i;
64
- blas_int nb = (blas_int)n;
65
- blas_int nb_plus_one = (blas_int)(n + 1);
66
- blas_int one_int = 1;
67
- scs_float zero = 0., one = 1.;
68
- scs_float sqrt2 = SQRTF(2.0);
69
- scs_float sqrt2_inv = 1.0 / sqrt2;
70
- scs_float *Xs = c->Xs;
71
- scs_float *Z = c->Z;
72
- scs_float *e = c->e;
73
- scs_float *work = c->work;
74
- blas_int lwork = c->lwork;
75
- blas_int info = 0;
76
- scs_float sq_eig_pos;
77
-
78
- // copy lower triangular matrix into full matrix
79
- for (i = 0; i < n; ++i) {
80
- memcpy(&(Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
81
- (n - i) * sizeof(scs_float));
82
- }
64
+ /* compute eigendecomposition */
65
+ {
66
+ scs_int i;
67
+ blas_int nb = (blas_int)n;
68
+ blas_int nb_plus_one = (blas_int)(n + 1);
69
+ blas_int one_int = 1;
70
+ scs_float zero = 0., one = 1.;
71
+ scs_float sqrt2 = SQRTF(2.0);
72
+ scs_float sqrt2_inv = 1.0 / sqrt2;
73
+ scs_float *Xs = c->Xs;
74
+ scs_float *Z = c->Z;
75
+ scs_float *e = c->e;
76
+ scs_float *work = c->work;
77
+ blas_int lwork = c->lwork;
78
+ blas_int info = 0;
79
+ scs_float sq_eig_pos;
80
+ scs_float *current_log_proj;
81
+ scs_int status;
82
+ scs_float *evals_proj;
83
+
84
+ /* copy lower triangular matrix into full matrix */
85
+ for (i = 0; i < n; ++i) {
86
+ memcpy(&(Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
87
+ (n - i) * sizeof(scs_float));
88
+ }
83
89
 
84
- // rescale diags by sqrt(2)
85
- BLAS(scal)(&nb, &sqrt2, Xs, &nb_plus_one);
86
-
87
- // Eigendecomposition. On exit, the lower triangular part of Xs stores
88
- // the eigenvectors. The vector e stores the eigenvalues in ascending
89
- // order (smallest eigenvalue first) */
90
- BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
91
- if (info != 0) {
92
- scs_printf("WARN: LAPACK syev error, info = %i\n", (int)info);
93
- if (info < 0) {
94
- scs_printf("entering LAPACK stuff!\n");
95
- return info;
90
+ /* rescale diags by sqrt(2) */
91
+ BLAS(scal)(&nb, &sqrt2, Xs, &nb_plus_one);
92
+
93
+ /*
94
+ * Eigendecomposition. On exit, the lower triangular part of Xs stores
95
+ * the eigenvectors. The vector e stores the eigenvalues in ascending
96
+ * order (smallest eigenvalue first)
97
+ */
98
+ BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
99
+ if (info != 0) {
100
+ scs_printf("WARN: LAPACK syev error, info = %i\n", (int)info);
101
+ if (info < 0) {
102
+ scs_printf("entering LAPACK stuff!\n");
103
+ return info;
104
+ }
96
105
  }
97
- }
98
106
 
99
- // ----------------------------------------------------------------------
100
- // Project onto spectral *vector* cone. Note that e is sqrt(2) times
101
- // the eigenvalue vector we want to project. We therefore multiply
102
- // tvX[0] and tvX[1] by sqrt(2). The projection of sqrt(2) * (t0, v0,
103
- // evals) is stored in current_log_proj
104
- // (or equivalently, in c->saved_log_projs + offset)
105
- // ----------------------------------------------------------------------
106
- scs_float *current_log_proj = c->saved_log_projs + offset;
107
- SPECTRAL_TIMING(SCS(timer) _timer; SCS(tic)(&_timer);)
108
- scs_int status =
109
- log_cone_proj_wrapper(sqrt2 * tvX[0], sqrt2 * tvX[1], e, current_log_proj,
110
- n, c->work_logdet, stats, warmstart);
111
- SPECTRAL_TIMING(c->tot_time_vec_cone_proj += SCS(tocq)(&_timer);)
112
-
113
- if (status < 0) {
114
- return status;
115
- }
116
- // return immediately if the origin is the solution
117
- else if (status == IN_NEGATIVE_DUAL_CONE) {
118
- memset(tvX, 0, sizeof(scs_float) * ((n * (n + 1)) / 2 + 2));
119
- return 0;
120
- }
107
+ /*
108
+ * Project onto spectral *vector* cone. Note that e is sqrt(2) times
109
+ * the eigenvalue vector we want to project. We therefore multiply
110
+ * tvX[0] and tvX[1] by sqrt(2). The projection of sqrt(2) * (t0, v0,
111
+ * evals) is stored in current_log_proj
112
+ * (or equivalently, in c->saved_log_projs + offset)
113
+ */
114
+ current_log_proj = c->saved_log_projs + offset;
115
+ SPECTRAL_TIMING(SCS(timer) _timer; SCS(tic)(&_timer);)
116
+ status =
117
+ log_cone_proj_wrapper(sqrt2 * tvX[0], sqrt2 * tvX[1], e, current_log_proj,
118
+ n, c->work_logdet, stats, warmstart);
119
+ SPECTRAL_TIMING(c->tot_time_vec_cone_proj += SCS(tocq)(&_timer);)
120
+
121
+ if (status < 0) {
122
+ return status;
123
+ }
124
+ /* return immediately if the origin is the solution */
125
+ else if (status == IN_NEGATIVE_DUAL_CONE) {
126
+ memset(tvX, 0, sizeof(scs_float) * ((n * (n + 1)) / 2 + 2));
127
+ return 0;
128
+ }
121
129
 
122
- // ----------------------------------------------------------------------
123
- // recover projection onto spectral *matrix* cone
124
- // ----------------------------------------------------------------------
125
- scs_float *evals_proj = current_log_proj + 2;
126
- for (i = 0; i < n; ++i) {
127
- assert(evals_proj[i] >= 0);
128
- sq_eig_pos = SQRTF(evals_proj[i]);
129
- BLAS(scal)(&nb, &sq_eig_pos, &Xs[i * n], &one_int);
130
- }
130
+ /* recover projection onto spectral *matrix* cone */
131
+ evals_proj = current_log_proj + 2;
132
+ for (i = 0; i < n; ++i) {
133
+ assert(evals_proj[i] >= 0);
134
+ sq_eig_pos = SQRTF(evals_proj[i]);
135
+ BLAS(scal)(&nb, &sq_eig_pos, &Xs[i * n], &one_int);
136
+ }
131
137
 
132
- BLAS(syrk)("Lower", "NoTrans", &nb, &nb, &one, Xs, &nb, &zero, Z, &nb);
133
- BLAS(scal)(&nb, &sqrt2_inv, Z, &nb_plus_one);
138
+ BLAS(syrk)("Lower", "NoTrans", &nb, &nb, &one, Xs, &nb, &zero, Z, &nb);
139
+ BLAS(scal)(&nb, &sqrt2_inv, Z, &nb_plus_one);
134
140
 
135
- for (i = 0; i < n; ++i) {
136
- memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(Z[i * (n + 1)]),
137
- (n - i) * sizeof(scs_float));
141
+ for (i = 0; i < n; ++i) {
142
+ memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(Z[i * (n + 1)]),
143
+ (n - i) * sizeof(scs_float));
144
+ }
145
+ tvX[0] = sqrt2_inv * current_log_proj[0];
146
+ tvX[1] = sqrt2_inv * current_log_proj[1];
138
147
  }
139
- tvX[0] = sqrt2_inv * current_log_proj[0];
140
- tvX[1] = sqrt2_inv * current_log_proj[1];
141
148
 
142
149
  return 0;
143
150
  }
@@ -1,11 +1,12 @@
1
1
  #include "cones.h"
2
- // #include "scs.h"
3
2
  #include "linalg.h"
4
3
  #include "scs_blas.h"
5
4
  #include "scs_types.h"
6
- #include "util.h" // just for timer
5
+ #include "util.h"
7
6
  #include "util_spectral_cones.h"
8
- #include <stdlib.h> // qsort
7
+
8
+ #include <stdlib.h>
9
+ #include <string.h>
9
10
 
10
11
  /*
11
12
  * Spectral matrix cone projections, from "Projection onto Spectral Matrix
@@ -38,50 +39,53 @@ static void compute_cone_residuals_ell1(const scs_float *tx, scs_float t0,
38
39
  const scs_float *x0, scs_int n,
39
40
  scs_float residuals[3]) {
40
41
  scs_float dual_res, pri_res, complementarity;
41
-
42
- // -------------------------------------
43
- // Compute Lagrange multiplier.
44
- // (This function is not used in production so it is fine to allocate
45
- // memory here)
46
- // -------------------------------------
47
42
  scs_float dualt = tx[0] - t0;
48
43
  scs_float *dualx = malloc(n * sizeof(scs_float));
49
- memcpy(dualx, tx + 1, n * sizeof(scs_float));
50
44
  blas_int int_n = n;
51
45
  scs_float negOne = -1.0;
52
46
  blas_int one = 1;
47
+ scs_float ell1_norm = 0;
48
+ scs_float inf_norm = 0;
49
+ scs_float abs_val;
50
+ const scs_float *xi;
51
+ scs_int i;
52
+
53
+ /* -------------------------------------
54
+ * Compute Lagrange multiplier.
55
+ * (This function is not used in production so it is fine to allocate
56
+ * memory here)
57
+ * ------------------------------------- */
58
+ memcpy(dualx, tx + 1, n * sizeof(scs_float));
53
59
  BLAS(axpy)(&int_n, &negOne, x0, &one, dualx, &one);
54
60
 
55
- // ---------------------------------------
56
- // Compute complementarity measure
57
- // ---------------------------------------
61
+ /* ---------------------------------------
62
+ * Compute complementarity measure
63
+ * --------------------------------------- */
58
64
  complementarity =
59
65
  tx[0] * dualt + BLAS(dot)(&int_n, dualx, &one, tx + 1, &one);
60
66
 
61
- // -----------------------------------------------
62
- // Compute primal feasibility measure
63
- // -----------------------------------------------
64
- scs_float ell1_norm = 0;
65
- for (const scs_float *xi = tx + 1; xi < tx + 1 + n; ++xi) {
67
+ /* -----------------------------------------------
68
+ * Compute primal feasibility measure
69
+ * ----------------------------------------------- */
70
+ for (xi = tx + 1; xi < tx + 1 + n; ++xi) {
66
71
  ell1_norm += fabs(*xi);
67
72
  }
68
73
  pri_res = ell1_norm - tx[0];
69
74
 
70
- // ---------------------------------------
71
- // Compute dual feasibility measure
72
- // ---------------------------------------
73
- scs_float inf_norm = 0;
74
- for (scs_int i = 0; i < n; ++i) {
75
- scs_float abs_val = fabs(dualx[i]);
75
+ /* ---------------------------------------
76
+ * Compute dual feasibility measure
77
+ * --------------------------------------- */
78
+ for (i = 0; i < n; ++i) {
79
+ abs_val = fabs(dualx[i]);
76
80
  if (abs_val > inf_norm) {
77
81
  inf_norm = abs_val;
78
82
  }
79
83
  }
80
84
  dual_res = inf_norm - dualt;
81
85
 
82
- // ------------------------------------------
83
- // Assign result and free allocated memory
84
- // ------------------------------------------
86
+ /* ------------------------------------------
87
+ * Assign result and free allocated memory
88
+ * ------------------------------------------ */
85
89
  residuals[0] = dual_res;
86
90
  residuals[1] = pri_res;
87
91
  residuals[2] = complementarity;
@@ -89,90 +93,82 @@ static void compute_cone_residuals_ell1(const scs_float *tx, scs_float t0,
89
93
  }
90
94
  #endif
91
95
 
92
- // Asssumes that all components of x0 are positive and
93
- // x0[0] >= x0[1] >= ... x0[n-1].
96
+ /* Assumes that all components of x0 are nonnegative and
97
+ * x0[0] >= x0[1] >= ... x0[n-1].
98
+ *
99
+ * Projects (t0, x0) onto {(t, x) : ||x||_1 <= t}. For sorted nonnegative
100
+ * input the projection is proj_x[i] = max(x0[i] - theta, 0) and
101
+ * proj_t = t0 + theta, where theta = (sum_{i<k} x0[i] - t0) / (k + 1) and
102
+ * k is the largest index with x0[k-1] - theta(k) > 0 (Duchi et al. 2008,
103
+ * "Efficient projections onto the l1-ball"). Scanning for the largest such
104
+ * k is robust to repeated entries, where two-sided bracket searches can
105
+ * fail to fire and produce points far outside the cone. */
94
106
  scs_int ell1_cone_proj_sorted(scs_float t0, const scs_float *x0,
95
107
  scs_float *proj, scs_int n) {
108
+ scs_float xSum, theta, th;
109
+ scs_int k, kk, i;
110
+
96
111
  if (-t0 >= x0[0]) {
112
+ /* (t0, x0) lies in the polar cone: projection is the origin */
97
113
  memset(proj, 0, (n + 1) * sizeof(*x0));
98
114
  return 0;
99
115
  }
100
116
 
101
- // -------------------------------------------
102
- // Find the value on k
103
- // -------------------------------------------
104
-
105
- // check if k = 0 suffices
106
- if (-t0 >= x0[0]) {
107
- memset(proj, 0, (n + 1) * sizeof(*x0));
117
+ xSum = 0;
118
+ for (i = 0; i < n; ++i) {
119
+ xSum += x0[i];
120
+ }
121
+ if (xSum <= t0) {
122
+ /* (t0, x0) already lies in the cone: projection is the identity */
123
+ proj[0] = t0;
124
+ memcpy(proj + 1, x0, n * sizeof(*x0));
108
125
  return 0;
109
126
  }
110
127
 
111
- scs_float xSum = 0;
112
- scs_float tempSum = 0;
113
- int k = -1;
114
- for (scs_int kk = 1; kk < n; ++kk) {
128
+ xSum = 0;
129
+ theta = 0;
130
+ k = 0;
131
+ for (kk = 1; kk <= n; ++kk) {
115
132
  xSum += x0[kk - 1];
116
- tempSum = (-t0 + xSum) / (kk + 1);
117
-
118
- if (x0[kk - 1] > tempSum && x0[kk] <= tempSum) {
119
- k = (int)kk;
133
+ th = (xSum - t0) / (kk + 1);
134
+ if (x0[kk - 1] - th > 0) {
135
+ k = kk;
136
+ theta = th;
137
+ } else {
138
+ /* x0 is nonincreasing and theta(kk) nondecreasing: no later kk works */
120
139
  break;
121
140
  }
122
141
  }
123
142
 
124
- if (k == -1) {
125
- k = n;
126
- xSum += x0[n - 1];
127
- }
128
-
129
- // ---------------------------------------------
130
- // Execute projection
131
- // ---------------------------------------------
132
- proj[0] = -t0 + xSum;
133
-
134
- if (proj[0] > 0) {
135
- proj[0] = t0 + proj[0] / (k + 1);
136
- } else {
137
- proj[0] = t0;
143
+ if (k == 0) {
144
+ /* only reachable through rounding on polar-boundary inputs */
145
+ memset(proj, 0, (n + 1) * sizeof(*x0));
146
+ return 0;
138
147
  }
139
148
 
140
- memcpy(proj + 1, x0, k * sizeof(*x0));
141
- scs_float diff = proj[0] - t0;
142
- for (int i = 1; i < k + 1; i++) {
143
- proj[i] -= diff;
149
+ proj[0] = MAX(t0 + theta, 0.);
150
+ for (i = 0; i < k; ++i) {
151
+ proj[i + 1] = x0[i] - theta;
144
152
  }
145
153
  memset(proj + 1 + k, 0, (n - k) * sizeof(*x0));
146
-
147
- #ifdef SPECTRAL_DEBUG
148
- //-------------------------------------------------------------------------
149
- // Check residuals - not needed in production
150
- //-------------------------------------------------------------------------
151
- scs_float residuals[3];
152
- compute_cone_residuals_ell1(proj, t0, x0, n, residuals);
153
-
154
- if (residuals[0] > 1e-8 || residuals[1] > 1e-8 || residuals[2] > 1e-8) {
155
- scs_printf("WARN: something is wrong in nuclear norm cone projection.\n");
156
- scs_printf("dual_res / primal_res / comp : %.3e, %.3e, %.3e\n",
157
- residuals[0], residuals[1], residuals[2]);
158
- return -1;
159
- }
160
- #endif
161
-
162
154
  return 0;
163
155
  }
164
156
 
165
157
  static void in_place_shuffle_ell1(scs_float *x, Value_index *work, scs_int n) {
166
- for (scs_int i = 0; i < n; ++i) {
158
+ scs_int i;
159
+ scs_int target_idx;
160
+ scs_int temp_idx;
161
+ scs_float temp_x;
162
+ for (i = 0; i < n; ++i) {
167
163
  while (work[i].index != i) {
168
- // Swap elements in `x`
169
- scs_int target_idx = work[i].index;
170
- scs_float temp_x = x[i];
164
+ /* Swap elements in `x` */
165
+ target_idx = work[i].index;
166
+ temp_x = x[i];
171
167
  x[i] = x[target_idx];
172
168
  x[target_idx] = temp_x;
173
169
 
174
- // Swap indices in `idxs` to reflect the change
175
- scs_int temp_idx = work[i].index;
170
+ /* Swap indices in `idxs` to reflect the change */
171
+ temp_idx = work[i].index;
176
172
  work[i].index = work[target_idx].index;
177
173
  work[target_idx].index = temp_idx;
178
174
  }
@@ -182,7 +178,10 @@ static void in_place_shuffle_ell1(scs_float *x, Value_index *work, scs_int n) {
182
178
  int custom_cmp(const void *a, const void *b) {
183
179
  Value_index *elemA = (Value_index *)a;
184
180
  Value_index *elemB = (Value_index *)b;
185
- return fabs(elemB->value) - fabs(elemA->value) > 0 ? 1 : -1;
181
+ scs_float diff = fabs(elemB->value) - fabs(elemA->value);
182
+ if (diff > 0) return 1;
183
+ if (diff < 0) return -1;
184
+ return 0;
186
185
  }
187
186
 
188
187
  void SCS(proj_ell_one)(scs_float *tx, scs_int n, ScsConeWork *c) {
@@ -190,30 +189,26 @@ void SCS(proj_ell_one)(scs_float *tx, scs_int n, ScsConeWork *c) {
190
189
  scs_float *x0 = tx + 1;
191
190
  scs_float *proj = c->work_ell1_proj;
192
191
  Value_index *work = c->work_ell1;
193
- // ------------------------------------------------------
194
- // Preprocess vector so it is nonnegative and sorted
195
- // ------------------------------------------------------
196
- for (scs_int i = 0; i < n; ++i) {
192
+ scs_int i;
193
+
194
+ /* Preprocess vector so it is nonnegative and sorted */
195
+ for (i = 0; i < n; ++i) {
197
196
  work[i].value = fabs(x0[i]);
198
197
  work[i].index = i;
199
198
  }
200
199
 
201
200
  qsort(work, n, sizeof(Value_index), custom_cmp);
202
201
 
203
- for (scs_int i = 0; i < n; ++i) {
202
+ for (i = 0; i < n; ++i) {
204
203
  proj[i + 1] = work[i].value;
205
204
  }
206
205
 
207
- // ------------------------------------------
208
- // project preprocessed vector
209
- // ------------------------------------------
206
+ /* project preprocessed vector */
210
207
  ell1_cone_proj_sorted(t0, proj + 1, proj, n);
211
208
 
212
- // -------------------------------------------
213
- // recover original vector
214
- // -------------------------------------------
209
+ /* recover original vector */
215
210
  in_place_shuffle_ell1(proj + 1, work, n);
216
- for (scs_int i = 0; i < n; i++) {
211
+ for (i = 0; i < n; i++) {
217
212
  proj[i + 1] = proj[i + 1] * (x0[i] >= 0 ? 1 : -1);
218
213
  }
219
214
 
@@ -1,9 +1,9 @@
1
1
  #include "cones.h"
2
- // #include "scs.h"
2
+ /* #include "scs.h" */
3
3
  #include "linalg.h"
4
4
  #include "scs_blas.h"
5
5
  #include "scs_types.h"
6
- #include "util.h" // just for timer
6
+ #include "util.h" /* just for timer */
7
7
 
8
8
  /*
9
9
  * Spectral matrix cone projections, from "Projection onto Spectral Matrix
@@ -39,28 +39,42 @@ void BLAS(gesvd)(const char *jobu, const char *jobvt, const blas_int *m,
39
39
  }
40
40
  #endif
41
41
 
42
- // forward declaration from ell1_cone.c
42
+ /* forward declaration from ell1_cone.c */
43
43
  scs_int ell1_cone_proj_sorted(scs_float t0, const scs_float *x0,
44
44
  scs_float *proj, scs_int n);
45
45
 
46
- // X is of size m x n, stored column major. It is assumed that m >= n.
46
+ /* X is of size m x n, stored column major. It is assumed that m >= n. */
47
47
  scs_int SCS(proj_nuclear_cone)(scs_float *tX, scs_int m, scs_int n,
48
48
  ScsConeWork *c) {
49
+ scs_float *X;
50
+ blas_int bm;
51
+ blas_int bn;
52
+ scs_float *s;
53
+ scs_float *u;
54
+ scs_float *vt;
55
+ scs_float *work;
56
+ blas_int lwork;
57
+ blas_int info;
58
+ scs_int status;
59
+ blas_int one;
60
+ scs_int i;
61
+ char trans;
62
+ scs_float alpha;
63
+ scs_float beta;
64
+
49
65
  assert(m >= n);
50
- scs_float *X = tX + 1;
51
- blas_int bm = m;
52
- blas_int bn = n;
66
+ X = tX + 1;
67
+ bm = m;
68
+ bn = n;
53
69
 
54
- // -------------------------------------------------------------------------
55
- // Compute SVD
56
- // -------------------------------------------------------------------------
57
- scs_float *s = c->s_nuc;
58
- scs_float *u = c->u_nuc;
59
- scs_float *vt = c->vt_nuc;
70
+ /* Compute SVD */
71
+ s = c->s_nuc;
72
+ u = c->u_nuc;
73
+ vt = c->vt_nuc;
60
74
 
61
- scs_float *work = c->work_nuc;
62
- int lwork = c->lwork_nuc;
63
- int info = 0;
75
+ work = c->work_nuc;
76
+ lwork = c->lwork_nuc;
77
+ info = 0;
64
78
 
65
79
  BLAS(gesvd)("S", "A", &bm, &bn, X, &bm, s, u, &bm, vt, &bn, work, &lwork,
66
80
  &info);
@@ -70,28 +84,25 @@ scs_int SCS(proj_nuclear_cone)(scs_float *tX, scs_int m, scs_int n,
70
84
  return info;
71
85
  }
72
86
  }
73
- // -------------------------------------------------------------------------
74
- // Project onto spectral *vector* cone
75
- // -------------------------------------------------------------------------
87
+
88
+ /* Project onto spectral *vector* cone */
76
89
  SPECTRAL_TIMING(SCS(timer) _timer; SCS(tic)(&_timer);)
77
- scs_int status = ell1_cone_proj_sorted(tX[0], s, tX, n);
90
+ status = ell1_cone_proj_sorted(tX[0], s, tX, n);
78
91
  SPECTRAL_TIMING(c->tot_time_vec_cone_proj += SCS(tocq)(&_timer);)
79
92
 
80
93
  if (status < 0) {
81
94
  return status;
82
95
  }
83
96
 
84
- // -------------------------------------------------------------------------
85
- // Recover projection onto spectral *matrix* cone
86
- // -------------------------------------------------------------------------
87
- int one = 1;
88
- for (scs_int i = 0; i < n; ++i) {
97
+ /* Recover projection onto spectral *matrix* cone */
98
+ one = 1;
99
+ for (i = 0; i < n; ++i) {
89
100
  BLAS(scal)(&bm, &tX[i + 1], &u[i * m], &one);
90
101
  }
91
102
 
92
- char trans = 'N';
93
- scs_float alpha = 1.0;
94
- scs_float beta = 0.0;
103
+ trans = 'N';
104
+ alpha = 1.0;
105
+ beta = 0.0;
95
106
  BLAS(gemm)(&trans, &trans, &bm, &bn, &bn, &alpha, u, &bm, vt, &bn, &beta,
96
107
  tX + 1, &bm);
97
108