scs 0.5.1 → 0.5.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/scs/ffi.rb +2 -0
  4. data/lib/scs/version.rb +1 -1
  5. data/vendor/scs/CITATION.cff +2 -2
  6. data/vendor/scs/CMakeLists.txt +136 -6
  7. data/vendor/scs/Makefile +53 -3
  8. data/vendor/scs/README.md +1 -1
  9. data/vendor/scs/include/cones.h +47 -2
  10. data/vendor/scs/include/glbopts.h +1 -1
  11. data/vendor/scs/include/scs.h +29 -0
  12. data/vendor/scs/include/scs_blas.h +4 -0
  13. data/vendor/scs/include/scs_types.h +3 -1
  14. data/vendor/scs/include/util_spectral_cones.h +45 -0
  15. data/vendor/scs/linsys/cpu/direct/private.c +3 -3
  16. data/vendor/scs/linsys/cpu/direct/private.h +2 -1
  17. data/vendor/scs/linsys/csparse.c +1 -1
  18. data/vendor/scs/linsys/cudss/direct/private.c +279 -0
  19. data/vendor/scs/linsys/cudss/direct/private.h +63 -0
  20. data/vendor/scs/linsys/external/qdldl/qdldl_types.h +1 -1
  21. data/vendor/scs/linsys/gpu/indirect/private.c +14 -21
  22. data/vendor/scs/scs.mk +17 -2
  23. data/vendor/scs/src/aa.c +8 -12
  24. data/vendor/scs/src/cones.c +783 -12
  25. data/vendor/scs/src/rw.c +15 -1
  26. data/vendor/scs/src/scs.c +4 -0
  27. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +660 -0
  28. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +279 -0
  29. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +205 -0
  30. data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +143 -0
  31. data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +221 -0
  32. data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +99 -0
  33. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +196 -0
  34. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +140 -0
  35. data/vendor/scs/src/spectral_cones/util_spectral_cones.c +52 -0
  36. data/vendor/scs/test/problems/complex_PSD.h +83 -0
  37. data/vendor/scs/test/rng.h +4 -4
  38. data/vendor/scs/test/run_tests.c +25 -0
  39. data/vendor/scs/test/spectral_cones_problems/exp_design.h +141 -0
  40. data/vendor/scs/test/spectral_cones_problems/graph_partitioning.h +275 -0
  41. data/vendor/scs/test/spectral_cones_problems/robust_pca.h +253 -0
  42. data/vendor/scs/test/spectral_cones_problems/several_logdet_cones.h +222 -0
  43. data/vendor/scs/test/spectral_cones_problems/several_nuc_cone.h +285 -0
  44. data/vendor/scs/test/spectral_cones_problems/several_sum_largest.h +420 -0
  45. metadata +21 -2
@@ -0,0 +1,221 @@
1
+ #include "cones.h"
2
+ // #include "scs.h"
3
+ #include "linalg.h"
4
+ #include "scs_blas.h"
5
+ #include "scs_types.h"
6
+ #include "util.h" // just for timer
7
+ #include "util_spectral_cones.h"
8
+ #include <stdlib.h> // qsort
9
+
10
+ /*
11
+ * Spectral matrix cone projections, from "Projection onto Spectral Matrix
12
+ * Cones" by Daniel Cederberg and Stephen Boyd, 2024.
13
+ *
14
+ * If you have any questions on the code, please reach out to the code author
15
+ * Daniel Cederberg.
16
+ *
17
+ * This file implements code for projecting onto the ell1-norm cone.
18
+ *
19
+ * Last modified: 25 August 2024.
20
+ */
21
+
22
+ #ifdef __cplusplus
23
+ extern "C" {
24
+ #endif
25
+
26
+ void BLAS(axpy)(blas_int *n, const scs_float *a, const scs_float *x,
27
+ blas_int *incx, scs_float *y, blas_int *incy);
28
+
29
+ scs_float BLAS(dot)(const blas_int *n, const scs_float *x, const blas_int *incx,
30
+ const scs_float *y, const blas_int *incy);
31
+
32
+ #ifdef __cplusplus
33
+ }
34
+ #endif
35
+
36
+ #ifdef SPECTRAL_DEBUG
37
+ static void compute_cone_residuals_ell1(const scs_float *tx, scs_float t0,
38
+ const scs_float *x0, scs_int n,
39
+ scs_float residuals[3]) {
40
+ 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
+ scs_float dualt = tx[0] - t0;
48
+ scs_float *dualx = malloc(n * sizeof(scs_float));
49
+ memcpy(dualx, tx + 1, n * sizeof(scs_float));
50
+ blas_int int_n = n;
51
+ scs_float negOne = -1.0;
52
+ blas_int one = 1;
53
+ BLAS(axpy)(&int_n, &negOne, x0, &one, dualx, &one);
54
+
55
+ // ---------------------------------------
56
+ // Compute complementarity measure
57
+ // ---------------------------------------
58
+ complementarity =
59
+ tx[0] * dualt + BLAS(dot)(&int_n, dualx, &one, tx + 1, &one);
60
+
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) {
66
+ ell1_norm += fabs(*xi);
67
+ }
68
+ pri_res = ell1_norm - tx[0];
69
+
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]);
76
+ if (abs_val > inf_norm) {
77
+ inf_norm = abs_val;
78
+ }
79
+ }
80
+ dual_res = inf_norm - dualt;
81
+
82
+ // ------------------------------------------
83
+ // Assign result and free allocated memory
84
+ // ------------------------------------------
85
+ residuals[0] = dual_res;
86
+ residuals[1] = pri_res;
87
+ residuals[2] = complementarity;
88
+ free(dualx);
89
+ }
90
+ #endif
91
+
92
+ // Asssumes that all components of x0 are positive and
93
+ // x0[0] >= x0[1] >= ... x0[n-1].
94
+ scs_int ell1_cone_proj_sorted(scs_float t0, const scs_float *x0,
95
+ scs_float *proj, scs_int n) {
96
+ if (-t0 >= x0[0]) {
97
+ memset(proj, 0, (n + 1) * sizeof(*x0));
98
+ return 0;
99
+ }
100
+
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));
108
+ return 0;
109
+ }
110
+
111
+ scs_float xSum = 0;
112
+ scs_float tempSum = 0;
113
+ int k = -1;
114
+ for (scs_int kk = 1; kk < n; ++kk) {
115
+ xSum += x0[kk - 1];
116
+ tempSum = (-t0 + xSum) / (kk + 1);
117
+
118
+ if (x0[kk - 1] > tempSum && x0[kk] <= tempSum) {
119
+ k = (int)kk;
120
+ break;
121
+ }
122
+ }
123
+
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;
138
+ }
139
+
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;
144
+ }
145
+ 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
+ return 0;
163
+ }
164
+
165
+ static void in_place_shuffle_ell1(scs_float *x, Value_index *work, scs_int n) {
166
+ for (scs_int i = 0; i < n; ++i) {
167
+ 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];
171
+ x[i] = x[target_idx];
172
+ x[target_idx] = temp_x;
173
+
174
+ // Swap indices in `idxs` to reflect the change
175
+ scs_int temp_idx = work[i].index;
176
+ work[i].index = work[target_idx].index;
177
+ work[target_idx].index = temp_idx;
178
+ }
179
+ }
180
+ }
181
+
182
+ int custom_cmp(const void *a, const void *b) {
183
+ Value_index *elemA = (Value_index *)a;
184
+ Value_index *elemB = (Value_index *)b;
185
+ return fabs(elemB->value) - fabs(elemA->value) > 0 ? 1 : -1;
186
+ }
187
+
188
+ void SCS(proj_ell_one)(scs_float *tx, scs_int n, ScsConeWork *c) {
189
+ scs_float t0 = tx[0];
190
+ scs_float *x0 = tx + 1;
191
+ scs_float *proj = c->work_ell1_proj;
192
+ 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) {
197
+ work[i].value = fabs(x0[i]);
198
+ work[i].index = i;
199
+ }
200
+
201
+ qsort(work, n, sizeof(Value_index), custom_cmp);
202
+
203
+ for (scs_int i = 0; i < n; ++i) {
204
+ proj[i + 1] = work[i].value;
205
+ }
206
+
207
+ // ------------------------------------------
208
+ // project preprocessed vector
209
+ // ------------------------------------------
210
+ ell1_cone_proj_sorted(t0, proj + 1, proj, n);
211
+
212
+ // -------------------------------------------
213
+ // recover original vector
214
+ // -------------------------------------------
215
+ in_place_shuffle_ell1(proj + 1, work, n);
216
+ for (scs_int i = 0; i < n; i++) {
217
+ proj[i + 1] = proj[i + 1] * (x0[i] >= 0 ? 1 : -1);
218
+ }
219
+
220
+ memcpy(tx, proj, (n + 1) * sizeof(*proj));
221
+ }
@@ -0,0 +1,99 @@
1
+ #include "cones.h"
2
+ // #include "scs.h"
3
+ #include "linalg.h"
4
+ #include "scs_blas.h"
5
+ #include "scs_types.h"
6
+ #include "util.h" // just for timer
7
+
8
+ /*
9
+ * Spectral matrix cone projections, from "Projection onto Spectral Matrix
10
+ * Cones" by Daniel Cederberg and Stephen Boyd, 2024.
11
+ *
12
+ * If you have any questions on the code, please reach out to the code author
13
+ * Daniel Cederberg.
14
+ *
15
+ * This file implements code for projecting onto the nuclear norm cone.
16
+ *
17
+ * Last modified: 25 August 2024.
18
+ */
19
+
20
+ #ifdef __cplusplus
21
+ extern "C" {
22
+ #endif
23
+
24
+ void BLAS(gemm)(const char *transa, const char *transb, blas_int *m,
25
+ blas_int *n, blas_int *k, scs_float *alpha, scs_float *a,
26
+ blas_int *lda, scs_float *b, blas_int *ldb, scs_float *beta,
27
+ scs_float *c, blas_int *ldc);
28
+
29
+ void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
30
+ const blas_int *incx);
31
+
32
+ void BLAS(gesvd)(const char *jobu, const char *jobvt, const blas_int *m,
33
+ const blas_int *n, scs_float *a, const blas_int *lda,
34
+ scs_float *s, scs_float *u, const blas_int *ldu, scs_float *vt,
35
+ const blas_int *ldvt, scs_float *work, const blas_int *lwork,
36
+ blas_int *info);
37
+
38
+ #ifdef __cplusplus
39
+ }
40
+ #endif
41
+
42
+ // forward declaration from ell1_cone.c
43
+ scs_int ell1_cone_proj_sorted(scs_float t0, const scs_float *x0,
44
+ scs_float *proj, scs_int n);
45
+
46
+ // X is of size m x n, stored column major. It is assumed that m >= n.
47
+ scs_int SCS(proj_nuclear_cone)(scs_float *tX, scs_int m, scs_int n,
48
+ ScsConeWork *c) {
49
+ assert(m >= n);
50
+ scs_float *X = tX + 1;
51
+ blas_int bm = m;
52
+ blas_int bn = n;
53
+
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;
60
+
61
+ scs_float *work = c->work_nuc;
62
+ int lwork = c->lwork_nuc;
63
+ int info = 0;
64
+
65
+ BLAS(gesvd)("S", "A", &bm, &bn, X, &bm, s, u, &bm, vt, &bn, work, &lwork,
66
+ &info);
67
+ if (info != 0) {
68
+ printf("WARN: LAPACK gesvd error, info = %i\n", (int)info);
69
+ if (info < 0) {
70
+ return info;
71
+ }
72
+ }
73
+ // -------------------------------------------------------------------------
74
+ // Project onto spectral *vector* cone
75
+ // -------------------------------------------------------------------------
76
+ SPECTRAL_TIMING(SCS(timer) _timer; SCS(tic)(&_timer);)
77
+ scs_int status = ell1_cone_proj_sorted(tX[0], s, tX, n);
78
+ SPECTRAL_TIMING(c->tot_time_vec_cone_proj += SCS(tocq)(&_timer);)
79
+
80
+ if (status < 0) {
81
+ return status;
82
+ }
83
+
84
+ // -------------------------------------------------------------------------
85
+ // Recover projection onto spectral *matrix* cone
86
+ // -------------------------------------------------------------------------
87
+ int one = 1;
88
+ for (scs_int i = 0; i < n; ++i) {
89
+ BLAS(scal)(&bm, &tX[i + 1], &u[i * m], &one);
90
+ }
91
+
92
+ char trans = 'N';
93
+ scs_float alpha = 1.0;
94
+ scs_float beta = 0.0;
95
+ BLAS(gemm)(&trans, &trans, &bm, &bn, &bn, &alpha, u, &bm, vt, &bn, &beta,
96
+ tX + 1, &bm);
97
+
98
+ return 0;
99
+ }
@@ -0,0 +1,196 @@
1
+ #include "cones.h"
2
+ // #include "scs.h"
3
+ #include "linalg.h"
4
+ #include "scs_blas.h"
5
+ #include "scs_types.h"
6
+ #include "util_spectral_cones.h"
7
+ #include <stdlib.h> // qsort
8
+
9
+ #define TOL_LARGEST_CONE 1e-9
10
+
11
+ /*
12
+ * Spectral matrix cone projections, from "Projection onto Spectral Matrix
13
+ * Cones" by Daniel Cederberg and Stephen Boyd, 2024.
14
+ *
15
+ * If you have any questions on the code, please reach out to the code author
16
+ * Daniel Cederberg.
17
+ *
18
+ * This file implements code for projecting onto the sum-of-largest cone.
19
+ * It assumes that the input is sorted. If you need code that does not make
20
+ * this assumption, please reach out.
21
+ *
22
+ * Last modified: 25 August 2024.
23
+ */
24
+
25
+ #ifdef SPECTRAL_DEBUG
26
+ static void compute_cone_residuals(scs_float t, const scs_float *x,
27
+ scs_float t0, const scs_float *x0,
28
+ scs_float residuals[3], scs_int n,
29
+ scs_int k);
30
+ #endif
31
+
32
+ scs_int assert_sorted(scs_float *x, scs_int n) {
33
+ for (scs_int i = 0; i < n - 1; ++i) {
34
+ if (x[i] < x[i + 1]) {
35
+ return -1;
36
+ }
37
+ }
38
+ return 0;
39
+ }
40
+
41
+ scs_int proj_sum_largest_cone_sorted(scs_float *t, scs_float *x, scs_int n,
42
+ scs_int k) {
43
+ #ifdef SPECTRAL_DEBUG
44
+ scs_float t00 = *t;
45
+ scs_float *x0 = scs_malloc(n * sizeof(*x0));
46
+ memcpy(x0, x, n * sizeof(*x0));
47
+ scs_int status = assert_sorted(x, n);
48
+ if (status < 0) {
49
+ scs_printf("NOT SORTED! \n");
50
+ return status;
51
+ }
52
+ #endif
53
+
54
+ // -------------------------------
55
+ // Initialize state variables
56
+ // -------------------------------
57
+ assert(k < n && k > 0);
58
+ scs_int nu = k, nt = 0;
59
+ scs_float eta = 0.0;
60
+ scs_float t0 = *t;
61
+ scs_float S = x[0];
62
+ for (scs_int i = 1; i < k; ++i) {
63
+ S += x[i];
64
+ }
65
+
66
+ scs_float a_u = x[nu - 1], a_t = x[nu];
67
+
68
+ // ---------------------------------
69
+ // main loop
70
+ // ---------------------------------
71
+ scs_float ratio, s1, s3, s;
72
+ while (S > *t + TOL_LARGEST_CONE) {
73
+ ratio = (nu == k) ? 1.0 : (scs_float)(nt) / (k - nu);
74
+
75
+ // ------------------------------------------------------
76
+ // compute step size
77
+ // ------------------------------------------------------
78
+ s1 = (nu == k) ? a_u - a_t : (a_u - a_t) / (ratio - 1);
79
+ s3 = (S - *t) / (ratio * (nu + 1) + (k - nu));
80
+ s = (nu == 0) ? s3 : MIN(s3, s1);
81
+
82
+ if (!(nu + nt == n || nt == 0)) {
83
+ scs_float val = a_t - x[nu + nt];
84
+ s = MIN(s, val);
85
+ }
86
+
87
+ // --------------------------
88
+ // update state
89
+ // --------------------------
90
+ eta += s * ratio;
91
+ S -= s * (ratio * nu + k - nu);
92
+ *t = t0 + eta;
93
+
94
+ if (nt > 0) {
95
+ a_t -= s;
96
+ }
97
+
98
+ if (nu != 0 && s == s1) {
99
+ nu -= 1;
100
+ } else {
101
+ assert(s != s1);
102
+ }
103
+
104
+ if (nu > 0) {
105
+ a_u = x[nu - 1] - eta;
106
+ }
107
+
108
+ nt = (nt == 0) ? 2 : nt + 1;
109
+ }
110
+
111
+ nt -= 1;
112
+
113
+ // update projection
114
+ scs_int i;
115
+ for (i = 0; i < nu; ++i) {
116
+ x[i] -= eta;
117
+ }
118
+
119
+ for (i = nu; i < nu + nt; ++i) {
120
+ x[i] = a_t;
121
+ }
122
+
123
+ #ifdef SPECTRAL_DEBUG
124
+ scs_float residuals[3];
125
+ compute_cone_residuals(*t, x, t00, x0, residuals, n, k);
126
+ scs_free(x0);
127
+ if (residuals[0] > 1e-10 || residuals[1] > 1e-10 ||
128
+ fabs(residuals[2]) > 1e-10) {
129
+ return -1;
130
+ }
131
+ #endif
132
+
133
+ return 0;
134
+ }
135
+
136
+ scs_int cmp_desc(const void *a, const void *b) {
137
+ scs_float da = *(const scs_float *)a;
138
+ scs_float db = *(const scs_float *)b;
139
+ if (da < db)
140
+ return 1;
141
+ if (da > db)
142
+ return -1;
143
+ return 0;
144
+ }
145
+
146
+ #ifdef SPECTRAL_DEBUG
147
+ // this function is not used in production so fine to allocate memory
148
+ static scs_float sum_largest_val(const scs_float *x, scs_int n, scs_int k) {
149
+ scs_float *x_temp = scs_malloc(n * sizeof(*x));
150
+ memcpy(x_temp, x, n * sizeof(*x));
151
+ qsort(x_temp, n, sizeof(*x_temp), cmp_desc);
152
+
153
+ scs_float val = 0.0;
154
+ for (scs_int i = 0; i < k; ++i) {
155
+ val += x_temp[i];
156
+ }
157
+ scs_free(x_temp);
158
+ return val;
159
+ }
160
+
161
+ static void compute_cone_residuals(scs_float t, const scs_float *x,
162
+ scs_float t0, const scs_float *x0,
163
+ scs_float residuals[3], scs_int n,
164
+ scs_int k) {
165
+ scs_float lmbda_t = t - t0;
166
+ scs_float *lmbda_x = scs_malloc(n * sizeof(*x));
167
+ scs_float sum_lmbda_x = 0.0;
168
+ for (scs_int i = 0; i < n; ++i) {
169
+ lmbda_x[i] = x[i] - x0[i];
170
+ sum_lmbda_x += lmbda_x[i];
171
+ }
172
+
173
+ scs_float comp = lmbda_t * t + SCS(dot)(lmbda_x, x, n);
174
+ scs_float pri_res = sum_largest_val(x, n, k) - t;
175
+
176
+ scs_float dual_res = fabs(sum_lmbda_x + lmbda_t * k);
177
+ dual_res *= dual_res;
178
+
179
+ for (scs_int i = 0; i < n; ++i) {
180
+ if (lmbda_x[i] > 0) {
181
+ dual_res += lmbda_x[i] * lmbda_x[i];
182
+ }
183
+
184
+ if (lmbda_x[i] + lmbda_t < 0) {
185
+ dual_res += (lmbda_x[i] + lmbda_t) * (lmbda_x[i] + lmbda_t);
186
+ }
187
+ }
188
+
189
+ residuals[0] = dual_res;
190
+ residuals[1] = pri_res;
191
+ residuals[2] = comp;
192
+
193
+ scs_free(lmbda_x);
194
+ }
195
+ #endif
196
+
@@ -0,0 +1,140 @@
1
+ #include "cones.h"
2
+ #include "linalg.h"
3
+ #include "scs_blas.h"
4
+ #include "scs_types.h"
5
+ #include "util.h" // just for timer
6
+
7
+ /*
8
+ * Spectral matrix cone projections, from "Projection onto Spectral Matrix
9
+ * Cones" by Daniel Cederberg and Stephen Boyd, 2024.
10
+ *
11
+ * If you have any questions on the code, please reach out to the code author
12
+ * Daniel Cederberg.
13
+ *
14
+ * This file implements code for projecting onto the sum-of-largest eigenvalues
15
+ * cone.
16
+ *
17
+ * Last modified: 25 August 2024.
18
+ */
19
+
20
+ #ifdef __cplusplus
21
+ extern "C" {
22
+ #endif
23
+
24
+ void BLAS(syev)(const char *jobz, const char *uplo, blas_int *n, scs_float *a,
25
+ blas_int *lda, scs_float *w, scs_float *work, blas_int *lwork,
26
+ blas_int *info);
27
+
28
+ void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
29
+ const blas_int *incx);
30
+
31
+ void BLAS(gemm)(const char *transa, const char *transb, blas_int *m,
32
+ blas_int *n, blas_int *k, scs_float *alpha, scs_float *a,
33
+ blas_int *lda, scs_float *b, blas_int *ldb, scs_float *beta,
34
+ scs_float *c, blas_int *ldc);
35
+
36
+ #ifdef __cplusplus
37
+ }
38
+ #endif
39
+
40
+ // forward declaration
41
+ scs_int proj_sum_largest_cone_sorted(scs_float *t, scs_float *x, scs_int n,
42
+ scs_int k);
43
+
44
+ void flip(scs_float *x, int n) {
45
+ scs_float temp;
46
+ for (int i = 0; i < n / 2; i++) {
47
+ temp = x[i];
48
+ x[i] = x[n - i - 1];
49
+ x[n - i - 1] = temp;
50
+ }
51
+ }
52
+
53
+ scs_int SCS(proj_sum_largest_evals)(scs_float *tX, scs_int n, scs_int k,
54
+ ScsConeWork *c) {
55
+ // tvX = [t, X], where X represents the lower triangular part of a matrix
56
+ // stored in a compact form and off-diagonal elements have been scaled by
57
+ // sqrt(2)
58
+ scs_float *X = tX + 1;
59
+
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 sqrt2 = sqrt(2.0);
68
+ scs_float sqrt2_inv = 1.0 / sqrt2;
69
+ scs_float *Xs = c->Xs;
70
+ scs_float *e = c->e;
71
+ scs_float *Z = c->Z;
72
+ scs_float *work = c->work;
73
+ blas_int lwork = c->lwork;
74
+ blas_int info = 0;
75
+
76
+ // copy lower triangular matrix into full matrix
77
+ for (i = 0; i < n; ++i) {
78
+ memcpy(&(Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
79
+ (n - i) * sizeof(scs_float));
80
+ }
81
+
82
+ // rescale diags by sqrt(2)
83
+ BLAS(scal)(&nb, &sqrt2, Xs, &nb_plus_one);
84
+
85
+ // Eigendecomposition. On exit, the lower triangular part of Xs stores
86
+ // the eigenvectors. The vector e stores the eigenvalues in ascending
87
+ // order (smallest eigenvalue first) */
88
+ BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
89
+ if (info != 0) {
90
+ scs_printf("WARN: LAPACK syev error, info = %i\n", (int)info);
91
+ if (info < 0) {
92
+ return info;
93
+ }
94
+ }
95
+
96
+ // ----------------------------------------------------------------------
97
+ // Project onto spectral *vector* cone. Note that e is sqrt(2) times
98
+ // the eigenvalue vector we want to project. We therefore multiply
99
+ // tvX[0] by sqrt(2).
100
+ // ----------------------------------------------------------------------
101
+ tX[0] *= sqrt2;
102
+ SPECTRAL_TIMING(SCS(timer) _timer; SCS(tic)(&_timer);)
103
+ flip(e, n);
104
+ scs_int status = proj_sum_largest_cone_sorted(&tX[0], e, n, k);
105
+ flip(e, n);
106
+ SPECTRAL_TIMING(c->tot_time_vec_cone_proj += SCS(tocq)(&_timer);)
107
+
108
+ if (status < 0) {
109
+ return status;
110
+ }
111
+
112
+ // ----------------------------------------------------------------------
113
+ // recover projection onto spectral *matrix* cone
114
+ // ----------------------------------------------------------------------
115
+ memcpy(c->work_sum_of_largest, Xs, n * n * sizeof(*Xs));
116
+ for (i = 0; i < n; ++i) {
117
+ BLAS(scal)(&nb, &e[i], &Xs[i * n], &one_int);
118
+ }
119
+
120
+ char transN = 'N';
121
+ char transY = 'T';
122
+ scs_float one = 1.0;
123
+ scs_float zero = 0.0;
124
+
125
+ // it is not safe to have overlapping matrices for dgemm_.
126
+ BLAS(gemm)(&transN, &transY, &nb, &nb, &nb, &one, Xs, &nb,
127
+ c->work_sum_of_largest, &nb, &zero, Z, &nb);
128
+
129
+ BLAS(scal)(&nb, &sqrt2_inv, Z, &nb_plus_one);
130
+
131
+ for (i = 0; i < n; ++i) {
132
+ memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(Z[i * (n + 1)]),
133
+ (n - i) * sizeof(scs_float));
134
+ }
135
+
136
+ tX[0] *= sqrt2_inv;
137
+
138
+ return 0;
139
+ }
140
+
@@ -0,0 +1,52 @@
1
+ #include "util_spectral_cones.h"
2
+
3
+ bool is_pos(const scs_float *x, scs_int n) {
4
+ for (scs_int i = 0; i < n; ++i) {
5
+ if (x[i] <= 0.0) {
6
+ return false;
7
+ }
8
+ }
9
+ return true;
10
+ }
11
+
12
+ bool is_negative(const scs_float *x, scs_int n) {
13
+ for (scs_int i = 0; i < n; ++i) {
14
+ if (x[i] >= 0.0) {
15
+ return false;
16
+ }
17
+ }
18
+ return true;
19
+ }
20
+
21
+ void non_neg_proj(const scs_float *src, scs_float *dst, scs_int n) {
22
+ for (scs_int i = 0; i < n; ++i) {
23
+ dst[i] = (src[i] > 0.0) ? src[i] : 0.0;
24
+ }
25
+ }
26
+
27
+ void print_vector(const scs_float *x, scs_int n) {
28
+ for (scs_int i = 0; i < n; ++i) {
29
+ printf("%f ", x[i]);
30
+ }
31
+ printf("\n");
32
+ }
33
+
34
+ scs_float min_vec(const scs_float *vec, scs_int n) {
35
+ scs_float minVal = vec[0];
36
+
37
+ for (scs_int i = 1; i < n; ++i) {
38
+ if (vec[i] < minVal) {
39
+ minVal = vec[i];
40
+ }
41
+ }
42
+
43
+ return minVal;
44
+ }
45
+
46
+ scs_float sum_log(const scs_float *x, scs_int n) {
47
+ scs_float sum = 0.0;
48
+ for (scs_int i = 0; i < n; ++i) {
49
+ sum += log(x[i]);
50
+ }
51
+ return sum;
52
+ }