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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +1 -1
- data/lib/scs/ffi.rb +18 -0
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +2 -3
- data/vendor/scs/CLAUDE.md +115 -0
- data/vendor/scs/CMakeLists.txt +330 -201
- data/vendor/scs/CONTRIBUTING.md +49 -0
- data/vendor/scs/Makefile +90 -43
- data/vendor/scs/README.md +96 -2
- data/vendor/scs/include/aa.h +59 -11
- data/vendor/scs/include/aa_stats.h +47 -0
- data/vendor/scs/include/cones.h +16 -7
- data/vendor/scs/include/glbopts.h +113 -26
- data/vendor/scs/include/linalg.h +5 -1
- data/vendor/scs/include/linsys.h +1 -2
- data/vendor/scs/include/normalize.h +6 -2
- data/vendor/scs/include/rw.h +9 -3
- data/vendor/scs/include/scs.h +17 -1
- data/vendor/scs/include/scs_blas.h +8 -0
- data/vendor/scs/include/scs_types.h +2 -2
- data/vendor/scs/include/scs_work.h +22 -1
- data/vendor/scs/include/util.h +3 -6
- data/vendor/scs/include/util_spectral_cones.h +3 -3
- data/vendor/scs/linsys/accelerate/direct/private.c +126 -0
- data/vendor/scs/linsys/accelerate/direct/private.h +34 -0
- data/vendor/scs/linsys/cpu/dense/private.c +250 -0
- data/vendor/scs/linsys/cpu/dense/private.h +31 -0
- data/vendor/scs/linsys/cpu/direct/private.c +86 -44
- data/vendor/scs/linsys/cpu/indirect/private.c +647 -113
- data/vendor/scs/linsys/cpu/indirect/private.h +28 -0
- data/vendor/scs/linsys/csparse.c +9 -3
- data/vendor/scs/linsys/csparse.h +4 -2
- data/vendor/scs/linsys/cudss/direct/private.c +77 -43
- data/vendor/scs/linsys/cudss/direct/private.h +33 -7
- data/vendor/scs/linsys/gpu/indirect/private.c +6 -2
- data/vendor/scs/linsys/mkl/direct/private.c +63 -31
- data/vendor/scs/linsys/mkl/direct/private.h +0 -1
- data/vendor/scs/linsys/scs_matrix.c +291 -165
- data/vendor/scs/linsys/scs_matrix.h +7 -9
- data/vendor/scs/scs.mk +35 -13
- data/vendor/scs/src/aa.c +673 -166
- data/vendor/scs/src/cones.c +545 -223
- data/vendor/scs/src/ctrlc.c +59 -16
- data/vendor/scs/src/exp_cone.c +70 -50
- data/vendor/scs/src/linalg.c +21 -2
- data/vendor/scs/src/normalize.c +24 -26
- data/vendor/scs/src/rw.c +596 -124
- data/vendor/scs/src/scs.c +990 -513
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +240 -187
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +108 -85
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +62 -63
- data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +85 -78
- data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +92 -97
- data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +39 -28
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +59 -40
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +37 -29
- data/vendor/scs/src/spectral_cones/util_spectral_cones.c +12 -6
- data/vendor/scs/src/util.c +37 -7
- data/vendor/scs/test/mkl_interface_mismatch.c +97 -0
- data/vendor/scs/test/packaging/CMakeLists.txt +21 -0
- data/vendor/scs/test/packaging/consume.c +50 -0
- data/vendor/scs/test/problem_utils.h +9 -2
- data/vendor/scs/test/problems/dense_qp.h +64 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +6 -2
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +10 -2
- data/vendor/scs/test/problems/infeasible_lp.h +66 -0
- data/vendor/scs/test/problems/infeasible_socp.h +75 -0
- data/vendor/scs/test/problems/lp_update.h +110 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -1
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +6 -3
- data/vendor/scs/test/problems/small_qp.h +5 -0
- data/vendor/scs/test/problems/test_box_cone.h +92 -0
- data/vendor/scs/test/problems/test_dual_exp_cone.h +96 -0
- data/vendor/scs/test/problems/test_inaccurate.h +212 -0
- data/vendor/scs/test/problems/test_mixed_cones.h +113 -0
- data/vendor/scs/test/problems/test_normalize_roundtrip.h +279 -0
- data/vendor/scs/test/problems/test_power_cone.h +414 -0
- data/vendor/scs/test/problems/test_psd_metric.h +109 -0
- data/vendor/scs/test/problems/test_psd_n1.h +84 -0
- data/vendor/scs/test/problems/test_root_plus.h +191 -0
- data/vendor/scs/test/problems/test_rw_settings.h +112 -0
- data/vendor/scs/test/problems/test_soc_sizes.h +393 -0
- data/vendor/scs/test/problems/test_solver_options.h +558 -0
- data/vendor/scs/test/problems/test_validation.h +263 -24
- data/vendor/scs/test/problems/test_zero_cone.h +81 -0
- data/vendor/scs/test/problems/unbounded_lp.h +66 -0
- data/vendor/scs/test/problems/unbounded_socp.h +71 -0
- data/vendor/scs/test/run_from_file.c +6 -0
- data/vendor/scs/test/run_tests.c +71 -0
- data/vendor/scs/test/rw_settings.c +7 -0
- data/vendor/scs/test/spectral_cones_problems/test_ell1_and_nuc.h +128 -0
- data/vendor/scs/test/spectral_cones_problems/test_ell1_cone.h +115 -0
- 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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (info
|
|
94
|
-
scs_printf("
|
|
95
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
133
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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"
|
|
5
|
+
#include "util.h"
|
|
7
6
|
#include "util_spectral_cones.h"
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
for (
|
|
128
|
+
xSum = 0;
|
|
129
|
+
theta = 0;
|
|
130
|
+
k = 0;
|
|
131
|
+
for (kk = 1; kk <= n; ++kk) {
|
|
115
132
|
xSum += x0[kk - 1];
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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 ==
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
for (
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
X = tX + 1;
|
|
67
|
+
bm = m;
|
|
68
|
+
bn = n;
|
|
53
69
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
75
|
-
// -------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
/* Project onto spectral *vector* cone */
|
|
76
89
|
SPECTRAL_TIMING(SCS(timer) _timer; SCS(tic)(&_timer);)
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|