scs 0.5.5 → 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 +9 -0
- data/LICENSE.txt +1 -1
- data/lib/scs/ffi.rb +18 -0
- data/lib/scs/solver.rb +11 -7
- 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
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#include "glbopts.h"
|
|
1
|
+
#include "glbopts.h" /* for scs_printf */
|
|
2
2
|
#include "linalg.h"
|
|
3
3
|
#include "scs_blas.h"
|
|
4
|
-
#include "util_spectral_cones.h"
|
|
5
|
-
#include <string.h>
|
|
4
|
+
#include "util_spectral_cones.h" /* for Newton structs */
|
|
5
|
+
#include <string.h> /* for memcpy */
|
|
6
6
|
|
|
7
7
|
/*
|
|
8
8
|
* Spectral matrix cone projections, from "Projection onto Spectral Matrix
|
|
@@ -56,24 +56,29 @@ static void f_oracle(const scs_float *u1, scs_float r, scs_float t0,
|
|
|
56
56
|
scs_float v0, const scs_float *x0, const scs_float *x_inv,
|
|
57
57
|
scs_int n, scs_float *f_u, scs_float *grad_f0,
|
|
58
58
|
scs_float *grad_f1) {
|
|
59
|
-
|
|
59
|
+
scs_float sum_log_xv;
|
|
60
|
+
scs_float norm_2;
|
|
61
|
+
|
|
62
|
+
/* compute grad_f0[0, 1] = t - t0, v - v0, grad_f1[2:-1] = x - x0 */
|
|
60
63
|
grad_f0[0] = u1[0] - t0;
|
|
61
64
|
grad_f0[1] = u1[1] - v0;
|
|
62
65
|
memcpy(grad_f0 + 2, u1 + 2, n * sizeof(*grad_f0));
|
|
63
66
|
SCS(add_scaled_array)(grad_f0 + 2, x0, n, -1.0);
|
|
64
67
|
grad_f0[n + 2] = -1.0;
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
/* compute f_u */
|
|
70
|
+
sum_log_xv = sum_log(u1 + 2, n) - n * log(u1[1]);
|
|
71
|
+
norm_2 = SCS(norm_2)(grad_f0 + 2, n);
|
|
69
72
|
f_u[0] = 0.5 * (grad_f0[0] * grad_f0[0] + grad_f0[1] * grad_f0[1] +
|
|
70
73
|
norm_2 * norm_2) -
|
|
71
74
|
r;
|
|
72
75
|
f_u[1] = -u1[1] * sum_log_xv - u1[0];
|
|
73
76
|
f_u[2] = -u1[1];
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
/*
|
|
79
|
+
* compute grad_f1[0] = -1, grad_f1[1] = n - sum(log(x/v)),
|
|
80
|
+
* grad[2:-1] = - v / x, grad[-1] = 0
|
|
81
|
+
*/
|
|
77
82
|
grad_f1[0] = -1.0;
|
|
78
83
|
grad_f1[1] = n - sum_log_xv;
|
|
79
84
|
memcpy(grad_f1 + 2, x_inv, n * sizeof(*x_inv));
|
|
@@ -81,15 +86,17 @@ static void f_oracle(const scs_float *u1, scs_float r, scs_float t0,
|
|
|
81
86
|
grad_f1[n + 2] = 0.0;
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
|
|
89
|
+
/* u1 = [t, v, x] */
|
|
85
90
|
static scs_float find_max_step_size(const scs_float *u1, const scs_float *z,
|
|
86
91
|
const scs_float *s, const scs_float *du1,
|
|
87
92
|
const scs_float *dz, const scs_float *ds,
|
|
88
93
|
scs_int n) {
|
|
89
94
|
scs_float step_max = 10.0;
|
|
90
95
|
scs_int i;
|
|
96
|
+
scs_float step_max_dom;
|
|
97
|
+
scs_float step_size;
|
|
91
98
|
|
|
92
|
-
|
|
99
|
+
/* find maximum step size with respect to z and s */
|
|
93
100
|
for (i = 0; i < 3; ++i) {
|
|
94
101
|
if (dz[i] < 0) {
|
|
95
102
|
step_max = MIN(step_max, -z[i] / dz[i]);
|
|
@@ -100,16 +107,16 @@ static scs_float find_max_step_size(const scs_float *u1, const scs_float *z,
|
|
|
100
107
|
}
|
|
101
108
|
}
|
|
102
109
|
|
|
103
|
-
|
|
110
|
+
step_max_dom = 10;
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
/* find maximum step size with respect to the domain of f */
|
|
106
113
|
for (i = 1; i < n + 2; i++) {
|
|
107
114
|
if (du1[i] < 0) {
|
|
108
115
|
step_max_dom = MIN(step_max_dom, -u1[i] / du1[i]);
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
|
|
119
|
+
step_size = MIN(1.0, STEP_IPM * step_max);
|
|
113
120
|
|
|
114
121
|
while (step_size > step_max_dom) {
|
|
115
122
|
step_size *= BETA_IPM;
|
|
@@ -135,8 +142,10 @@ typedef struct {
|
|
|
135
142
|
|
|
136
143
|
} KKT_solver_workspace;
|
|
137
144
|
|
|
138
|
-
|
|
139
|
-
|
|
145
|
+
/*
|
|
146
|
+
* Precomputations before solving the KKT system. You can think of this
|
|
147
|
+
* as factoring the KKT matrix.
|
|
148
|
+
*/
|
|
140
149
|
static void KKT_precompute(scs_float v, const scs_float *x_inv,
|
|
141
150
|
const scs_float *z, const scs_float *w, scs_int n,
|
|
142
151
|
KKT_solver_workspace *KKT_work) {
|
|
@@ -146,10 +155,11 @@ static void KKT_precompute(scs_float v, const scs_float *x_inv,
|
|
|
146
155
|
scs_float *GinvC = KKT_work->GinvC;
|
|
147
156
|
scs_float *g0g1 = KKT_work->g0g1;
|
|
148
157
|
scs_float *R = KKT_work->R;
|
|
158
|
+
scs_int i;
|
|
149
159
|
|
|
150
160
|
scs_float a = z[0] + 1 / (w[2] * w[2]) + z[1] * n / v;
|
|
151
161
|
scs_float coeff = 0.0;
|
|
152
|
-
for (
|
|
162
|
+
for (i = 0; i < n; i++) {
|
|
153
163
|
temp1[i] = z[0] + (z[1] * v) * (x_inv[i] * x_inv[i]);
|
|
154
164
|
temp2[i] = x_inv[i] / temp1[i];
|
|
155
165
|
coeff += (x_inv[i] * x_inv[i]) / temp1[i];
|
|
@@ -157,34 +167,30 @@ static void KKT_precompute(scs_float v, const scs_float *x_inv,
|
|
|
157
167
|
coeff = a - z[1] * z[1] * coeff;
|
|
158
168
|
KKT_work->coeff = coeff;
|
|
159
169
|
|
|
160
|
-
|
|
161
|
-
// compute G \ g0
|
|
162
|
-
// --------------------------------------------------------------------
|
|
170
|
+
/* compute G \ g0 */
|
|
163
171
|
GinvC[0] = g0g1[0] / z[0];
|
|
164
172
|
GinvC[1] = (g0g1[1] + z[1] * SCS(dot)(g0g1 + 2, temp2, n)) / coeff;
|
|
165
|
-
for (
|
|
173
|
+
for (i = 2; i < n + 2; i++) {
|
|
166
174
|
GinvC[i] = (g0g1[i] + (z[1] * GinvC[1]) * x_inv[i - 2]) / temp1[i - 2];
|
|
167
175
|
}
|
|
168
176
|
GinvC[n + 2] = -g0g1[n + 2];
|
|
169
177
|
|
|
170
|
-
|
|
171
|
-
// compute G \ g1
|
|
172
|
-
// --------------------------------------------------------------------
|
|
178
|
+
/* compute G \ g1 */
|
|
173
179
|
GinvC[n + 3] = g0g1[n + 3] / z[0];
|
|
174
180
|
GinvC[n + 4] =
|
|
175
181
|
(g0g1[n + 4] + z[1] * SCS(dot)(g0g1 + n + 5, temp2, n)) / coeff;
|
|
176
|
-
for (
|
|
182
|
+
for (i = n + 5; i < 2 * n + 5; i++) {
|
|
177
183
|
GinvC[i] =
|
|
178
184
|
(g0g1[i] + (z[1] * GinvC[n + 4]) * x_inv[i - n - 5]) / temp1[i - n - 5];
|
|
179
185
|
}
|
|
180
186
|
GinvC[2 * n + 5] = -g0g1[2 * n + 5];
|
|
181
187
|
|
|
182
|
-
|
|
188
|
+
/* compute G \ ([0, 0, ..., 0, 1]) */
|
|
183
189
|
GinvC[3 * n + 8] = -1.0;
|
|
184
190
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
/*
|
|
192
|
+
* compute R = I + C.T @ GinvC. This matrix is always reverse triangular.
|
|
193
|
+
*/
|
|
188
194
|
R[0] = 1 + SCS(dot)(g0g1, GinvC, u_dim);
|
|
189
195
|
R[3] = SCS(dot)(g0g1, GinvC + u_dim, u_dim);
|
|
190
196
|
R[6] = SCS(dot)(g0g1, GinvC + 2 * u_dim, u_dim);
|
|
@@ -215,38 +221,39 @@ static void KKT_solve(const scs_float *z, const scs_float *w,
|
|
|
215
221
|
scs_float *bnew = KKT_work->bnew;
|
|
216
222
|
scs_float *g0g1 = KKT_work->g0g1;
|
|
217
223
|
scs_float *CCTdu = KKT_work->CCTdu;
|
|
224
|
+
scs_float scale;
|
|
225
|
+
|
|
226
|
+
const scs_int num_ref = 3;
|
|
227
|
+
scs_int i;
|
|
228
|
+
scs_int ii;
|
|
218
229
|
|
|
219
|
-
|
|
220
|
-
// prepare RHS
|
|
221
|
-
// -------------------------------------------------------------------------
|
|
230
|
+
/* prepare RHS */
|
|
222
231
|
memcpy(rhs_reduced, rhs1, (n + 6) * sizeof(*rhs1));
|
|
223
232
|
rhs_reduced[u_dim] -= w[0] * (rhs2[0] / lmbda[0]);
|
|
224
233
|
rhs_reduced[u_dim + 1] -= w[1] * (rhs2[1] / lmbda[1]);
|
|
225
234
|
rhs_reduced[u_dim + 2] -= w[2] * (rhs2[2] / lmbda[2]);
|
|
226
235
|
memcpy(bnew, rhs_reduced, u_dim * sizeof(*rhs_reduced));
|
|
227
|
-
|
|
236
|
+
scale = rhs_reduced[n + 3] / w[0];
|
|
228
237
|
SCS(add_scaled_array)(bnew, g0g1, u_dim, scale);
|
|
229
238
|
scale = rhs_reduced[n + 4] / w[1];
|
|
230
239
|
SCS(add_scaled_array)(bnew, g0g1 + u_dim, u_dim, scale);
|
|
231
240
|
bnew[1] -= (rhs_reduced[n + 5] / (w[2] * w[2]));
|
|
232
241
|
|
|
233
|
-
|
|
234
|
-
// solve system and apply iterative refinement
|
|
235
|
-
// -------------------------------------------------------------------------
|
|
242
|
+
/* solve system and apply iterative refinement */
|
|
236
243
|
memcpy(residual, bnew, u_dim * sizeof(*bnew));
|
|
237
244
|
memset(du1, 0, u1_dim * sizeof(*du1));
|
|
238
245
|
*dr = 0;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
for (i = 0; i < num_ref; ++i) {
|
|
247
|
+
char trans;
|
|
248
|
+
scs_float *Gdu;
|
|
249
|
+
|
|
250
|
+
/* solve (G + C @ C.T) d = residual */
|
|
244
251
|
GinvRes[0] = residual[0] / z[0];
|
|
245
252
|
GinvRes[1] =
|
|
246
253
|
(residual[1] + z[1] * SCS(dot)(residual + 2, temp2, n)) / coeff;
|
|
247
|
-
for (
|
|
248
|
-
GinvRes[
|
|
249
|
-
(residual[
|
|
254
|
+
for (ii = 2; ii < n + 2; ++ii) {
|
|
255
|
+
GinvRes[ii] =
|
|
256
|
+
(residual[ii] + (z[1] * GinvRes[1]) * x_inv[ii - 2]) / temp1[ii - 2];
|
|
250
257
|
}
|
|
251
258
|
|
|
252
259
|
GinvRes[n + 2] = -residual[n + 2];
|
|
@@ -259,42 +266,42 @@ static void KKT_solve(const scs_float *z, const scs_float *w,
|
|
|
259
266
|
(CTGinvRes[0] - R[0] * RinvCTGinvRes[0] - R[3] * RinvCTGinvRes[1]) /
|
|
260
267
|
R[6];
|
|
261
268
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
269
|
+
/*
|
|
270
|
+
* Here we want to apply the correction d: du = du + d, where
|
|
271
|
+
* d = GinvRes - GinvC @ RinvCTGinvRes. Note that we expect the
|
|
272
|
+
* correction d to be very small, so we *must* compute d first and
|
|
273
|
+
* then add it to du, instead of computing it as
|
|
274
|
+
* du = du + GinvRes, du = du - GinvC @ RinvCTGinvRes.
|
|
275
|
+
* In other words, the following code will result in bugs due to
|
|
276
|
+
* numerics:
|
|
277
|
+
* daxpy_(&u_dim, &d_one, GinvRes, &bi_one, du, &bi_one);
|
|
278
|
+
* char trans = 'N';
|
|
279
|
+
* dgemv_(&trans, &u_dim, &i_three, &d_minus_one, GinvC, &u_dim,
|
|
280
|
+
* RinvCTGinvRes, &bi_one, &d_one, du, &bi_one);
|
|
281
|
+
*/
|
|
282
|
+
|
|
283
|
+
trans = 'N';
|
|
277
284
|
BLAS(gemv)(&trans, &u_dim, &bi_three, &d_minus_one, GinvC, &u_dim,
|
|
278
285
|
RinvCTGinvRes, &bi_one, &d_one, GinvRes, &bi_one);
|
|
279
286
|
SCS(add_scaled_array)(du1, GinvRes, u1_dim, 1.0);
|
|
280
287
|
*dr += GinvRes[n + 2];
|
|
281
288
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
// -----------------------------------
|
|
285
|
-
scs_float *Gdu = GinvRes;
|
|
289
|
+
/* compute new residual */
|
|
290
|
+
Gdu = GinvRes;
|
|
286
291
|
if (i != num_ref - 1) {
|
|
292
|
+
scs_float coeff0;
|
|
293
|
+
scs_float coeff1;
|
|
287
294
|
Gdu[0] = z[0] * du1[0];
|
|
288
295
|
Gdu[1] = ((z[0] + 1 / (w[2] * w[2])) * du1[1] +
|
|
289
296
|
z[1] * (n / v * du1[1] - SCS(dot)(x_inv, du1 + 2, n)));
|
|
290
|
-
for (
|
|
297
|
+
for (ii = 2; ii < n + 2; ++ii) {
|
|
291
298
|
Gdu[ii] = (z[0] * du1[ii] +
|
|
292
299
|
z[1] * (-du1[1] * x_inv[ii - 2] +
|
|
293
300
|
v * du1[ii] * x_inv[ii - 2] * x_inv[ii - 2]));
|
|
294
301
|
}
|
|
295
302
|
Gdu[n + 2] = -(*dr);
|
|
296
|
-
|
|
297
|
-
|
|
303
|
+
coeff0 = SCS(dot)(g0g1, du1, u1_dim) + g0g1[n + 2] * (*dr);
|
|
304
|
+
coeff1 =
|
|
298
305
|
SCS(dot)(g0g1 + u_dim, du1, u1_dim) + g0g1[2 * n + 5] * (*dr);
|
|
299
306
|
memcpy(CCTdu, g0g1, u_dim * sizeof(*g0g1));
|
|
300
307
|
SCS(scale_array)(CCTdu, coeff0, u_dim);
|
|
@@ -302,22 +309,22 @@ static void KKT_solve(const scs_float *z, const scs_float *w,
|
|
|
302
309
|
CCTdu[n + 2] += (*dr);
|
|
303
310
|
memcpy(residual, bnew, u_dim * sizeof(*bnew));
|
|
304
311
|
|
|
305
|
-
|
|
306
|
-
|
|
312
|
+
/*
|
|
313
|
+
* important to compute the residual as residual = bnew - (Gdu +
|
|
314
|
+
* CCTdu) and not as residual = (bnew - Gdu) - CCTdu
|
|
315
|
+
*/
|
|
307
316
|
SCS(add_scaled_array)(Gdu, CCTdu, u_dim, 1.0);
|
|
308
317
|
SCS(add_scaled_array)(residual, Gdu, u_dim, -1.0);
|
|
309
318
|
}
|
|
310
319
|
}
|
|
311
320
|
|
|
312
|
-
|
|
313
|
-
// recover substituted variables
|
|
314
|
-
// -------------------------------------------------------------------------
|
|
321
|
+
/* recover substituted variables */
|
|
315
322
|
memcpy(dz, rhs_reduced + u_dim, 3 * sizeof(*rhs_reduced));
|
|
316
323
|
dz[0] -= w[0] * (SCS(dot)(g0g1, du1, u1_dim) + g0g1[n + 2] * (*dr));
|
|
317
324
|
dz[1] -=
|
|
318
325
|
w[1] * (SCS(dot)(g0g1 + u_dim, du1, u1_dim) + g0g1[2 * n + 5] * (*dr));
|
|
319
326
|
dz[2] += du1[1];
|
|
320
|
-
for (
|
|
327
|
+
for (ii = 0; ii < 3; ++ii) {
|
|
321
328
|
dz[ii] = -dz[ii] / (w[ii] * w[ii]);
|
|
322
329
|
ds[ii] = w[ii] * (rhs2[ii] / lmbda[ii] - w[ii] * dz[ii]);
|
|
323
330
|
}
|
|
@@ -334,11 +341,54 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
334
341
|
scs_int m = 3;
|
|
335
342
|
scs_int u_dim = n + 3;
|
|
336
343
|
scs_int u1_dim = n + 2;
|
|
344
|
+
scs_int i;
|
|
337
345
|
|
|
338
|
-
|
|
339
|
-
// scale (t0, v0, x0)
|
|
340
|
-
// -----------------------------------------------------------------
|
|
346
|
+
/* scale (t0, v0, x0) */
|
|
341
347
|
scs_float scale1 = SCS(norm_inf)(x0, n);
|
|
348
|
+
|
|
349
|
+
scs_float *x_inv;
|
|
350
|
+
scs_float *z;
|
|
351
|
+
scs_float *s;
|
|
352
|
+
scs_float *f_u;
|
|
353
|
+
scs_float *grad_f0;
|
|
354
|
+
scs_float *grad_f1;
|
|
355
|
+
scs_float *rx;
|
|
356
|
+
scs_float *rznl;
|
|
357
|
+
scs_float *w;
|
|
358
|
+
scs_float *lmbda;
|
|
359
|
+
scs_float *du1;
|
|
360
|
+
scs_float *dz;
|
|
361
|
+
scs_float *ds;
|
|
362
|
+
scs_float *u1_new;
|
|
363
|
+
scs_float *z_new;
|
|
364
|
+
scs_float *s_new;
|
|
365
|
+
scs_float *x_inv_new;
|
|
366
|
+
scs_float *f_u_new;
|
|
367
|
+
scs_float *grad_f0_new;
|
|
368
|
+
scs_float *grad_f1_new;
|
|
369
|
+
scs_float *rx_new;
|
|
370
|
+
scs_float *rznl_new;
|
|
371
|
+
scs_float *u1_0;
|
|
372
|
+
scs_float *du1_0;
|
|
373
|
+
scs_float *z0;
|
|
374
|
+
scs_float *dz0;
|
|
375
|
+
scs_float *s0;
|
|
376
|
+
scs_float *ds0;
|
|
377
|
+
|
|
378
|
+
scs_float r;
|
|
379
|
+
scs_float dr;
|
|
380
|
+
scs_float rnew;
|
|
381
|
+
scs_float r0;
|
|
382
|
+
scs_float dr0;
|
|
383
|
+
|
|
384
|
+
KKT_solver_workspace KKT_work;
|
|
385
|
+
|
|
386
|
+
scs_int relaxed_iters;
|
|
387
|
+
size_t iter;
|
|
388
|
+
scs_float theta1, theta2, theta3;
|
|
389
|
+
scs_float pres0, dres0;
|
|
390
|
+
scs_float phi0, dphi0, step_size0;
|
|
391
|
+
|
|
342
392
|
scale1 = MAX(t0, scale1);
|
|
343
393
|
scale1 = MAX(v0, scale1);
|
|
344
394
|
scale1 = 1 / scale1;
|
|
@@ -346,45 +396,42 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
346
396
|
v0 = v0 * scale1;
|
|
347
397
|
SCS(scale_array)(x0, scale1, n);
|
|
348
398
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
scs_float r0 = 0.0;
|
|
385
|
-
scs_float dr0 = 0.0;
|
|
399
|
+
/* Parse workspace */
|
|
400
|
+
x_inv = workspace;
|
|
401
|
+
z = workspace + n;
|
|
402
|
+
s = z + m;
|
|
403
|
+
f_u = s + m;
|
|
404
|
+
grad_f0 = f_u + m;
|
|
405
|
+
grad_f1 = grad_f0 + u_dim;
|
|
406
|
+
rx = grad_f1 + u_dim;
|
|
407
|
+
rznl = rx + u_dim;
|
|
408
|
+
w = rznl + m;
|
|
409
|
+
lmbda = w + m;
|
|
410
|
+
du1 = lmbda + m;
|
|
411
|
+
dz = du1 + u1_dim;
|
|
412
|
+
ds = dz + m;
|
|
413
|
+
|
|
414
|
+
/* for evaluating the new residuals in the line search */
|
|
415
|
+
u1_new = ds + m;
|
|
416
|
+
z_new = u1_new + u1_dim;
|
|
417
|
+
s_new = z_new + m;
|
|
418
|
+
x_inv_new = s_new + m;
|
|
419
|
+
f_u_new = x_inv_new + n;
|
|
420
|
+
grad_f0_new = f_u_new + m;
|
|
421
|
+
grad_f1_new = grad_f0_new + u_dim;
|
|
422
|
+
rx_new = grad_f1_new + u_dim;
|
|
423
|
+
rznl_new = rx_new + u_dim;
|
|
424
|
+
|
|
425
|
+
/* for storing the state for the line search */
|
|
426
|
+
u1_0 = rznl_new + m;
|
|
427
|
+
du1_0 = u1_0 + u1_dim;
|
|
428
|
+
z0 = du1_0 + u1_dim;
|
|
429
|
+
dz0 = z0 + m;
|
|
430
|
+
s0 = dz0 + m;
|
|
431
|
+
ds0 = s0 + m;
|
|
432
|
+
r0 = 0.0;
|
|
433
|
+
dr0 = 0.0;
|
|
386
434
|
|
|
387
|
-
KKT_solver_workspace KKT_work;
|
|
388
435
|
KKT_work.g0g1 = grad_f0;
|
|
389
436
|
KKT_work.temp1 = ds0 + m;
|
|
390
437
|
KKT_work.temp2 = KKT_work.temp1 + u_dim;
|
|
@@ -398,29 +445,28 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
398
445
|
KKT_work.bnew = KKT_work.rhs_reduced + u_dim + 3;
|
|
399
446
|
KKT_work.CCTdu = KKT_work.bnew + u_dim;
|
|
400
447
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
for (
|
|
448
|
+
/*
|
|
449
|
+
* initialize primal variable u1 = [t, v, x], epigraph variable r and
|
|
450
|
+
* primal slack variable s and Lagrange multipliers z
|
|
451
|
+
*/
|
|
452
|
+
for (i = 0; i < n + 2; ++i) {
|
|
406
453
|
u1[i] = 1.0;
|
|
407
454
|
}
|
|
408
455
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
456
|
+
r = 0.0;
|
|
457
|
+
dr = 0.0;
|
|
458
|
+
rnew = 0.0;
|
|
412
459
|
|
|
413
|
-
for (
|
|
460
|
+
for (i = 0; i < m; ++i) {
|
|
414
461
|
z[i] = 1.0;
|
|
415
462
|
s[i] = 1.0;
|
|
416
463
|
}
|
|
417
464
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
// scs_int small_consecutive_steps_counter = 0;
|
|
465
|
+
relaxed_iters = 0;
|
|
466
|
+
iter = 0;
|
|
467
|
+
phi0 = 0.0;
|
|
468
|
+
dphi0 = 0.0;
|
|
469
|
+
step_size0 = 0.0;
|
|
424
470
|
|
|
425
471
|
#ifdef SPECTRAL_DEBUG
|
|
426
472
|
printf("%-3s%-15s%-15s%-15s%-10s%-10s\n", "", "gap", "pres", "dres", "sig",
|
|
@@ -430,18 +476,27 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
430
476
|
for (iter = 0; iter < MAX_ITER_IPM; ++iter) {
|
|
431
477
|
scs_float gap = z[0] * s[0] + z[1] * s[1] + z[2] * s[2];
|
|
432
478
|
scs_float mu = gap / m;
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
479
|
+
scs_float dres;
|
|
480
|
+
scs_float pres;
|
|
481
|
+
scs_float norm_rx;
|
|
482
|
+
scs_float norm_rznl;
|
|
483
|
+
scs_float relgap;
|
|
484
|
+
scs_float scale2;
|
|
485
|
+
scs_float rhs2_aff[3];
|
|
486
|
+
scs_float *rhs1_aff;
|
|
487
|
+
scs_float sigma;
|
|
488
|
+
scs_float phi;
|
|
489
|
+
scs_float dphi;
|
|
490
|
+
scs_float step_size;
|
|
491
|
+
scs_int j;
|
|
492
|
+
|
|
493
|
+
/* evaluate oracle */
|
|
494
|
+
for (i = 0; i < n; i++) {
|
|
438
495
|
x_inv[i] = 1 / u1[i + 2];
|
|
439
496
|
}
|
|
440
497
|
f_oracle(u1, r, t0, v0, x0, x_inv, n, f_u, grad_f0, grad_f1);
|
|
441
498
|
|
|
442
|
-
|
|
443
|
-
// compute residuals and check termination criteria
|
|
444
|
-
// --------------------------------------------------------
|
|
499
|
+
/* compute residuals and check termination criteria */
|
|
445
500
|
memcpy(rx, grad_f0, u_dim * sizeof(*grad_f0));
|
|
446
501
|
SCS(scale_array)(rx, z[0], u_dim);
|
|
447
502
|
SCS(add_scaled_array)(rx, grad_f1, u_dim, z[1]);
|
|
@@ -451,11 +506,11 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
451
506
|
rznl[1] = f_u[1] + s[1];
|
|
452
507
|
rznl[2] = f_u[2] + s[2];
|
|
453
508
|
|
|
454
|
-
|
|
455
|
-
|
|
509
|
+
dres = SCS(norm_2)(rx, u_dim);
|
|
510
|
+
pres =
|
|
456
511
|
sqrt(rznl[0] * rznl[0] + rznl[1] * rznl[1] + rznl[2] * rznl[2]);
|
|
457
|
-
|
|
458
|
-
|
|
512
|
+
norm_rx = dres;
|
|
513
|
+
norm_rznl = pres;
|
|
459
514
|
|
|
460
515
|
if (iter == 0) {
|
|
461
516
|
pres0 = MAX(pres, 1.0);
|
|
@@ -467,7 +522,7 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
467
522
|
|
|
468
523
|
pres = pres / pres0;
|
|
469
524
|
dres = dres / dres0;
|
|
470
|
-
|
|
525
|
+
relgap = gap / MAX(r, 1.0);
|
|
471
526
|
|
|
472
527
|
if (dres < FEASTOL_IPM && pres < FEASTOL_IPM &&
|
|
473
528
|
(gap < ABSTOL_IPM || relgap <= RELTOL_IPM)) {
|
|
@@ -478,45 +533,44 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
478
533
|
break;
|
|
479
534
|
}
|
|
480
535
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
// ----------------------------------------------------
|
|
484
|
-
for (scs_int i = 0; i < m; i++) {
|
|
536
|
+
/* compute scaling matrix and scaling point */
|
|
537
|
+
for (i = 0; i < m; i++) {
|
|
485
538
|
w[i] = sqrt(s[i] / z[i]);
|
|
486
539
|
lmbda[i] = sqrt(s[i] * z[i]);
|
|
487
540
|
}
|
|
488
541
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
// -----------------------------------------------------------------
|
|
492
|
-
scs_float scale2 = 1 / w[0];
|
|
542
|
+
/* precomputations for KKT system */
|
|
543
|
+
scale2 = 1 / w[0];
|
|
493
544
|
SCS(scale_array)(grad_f0, scale2, u_dim);
|
|
494
545
|
scale2 = 1 / w[1];
|
|
495
546
|
SCS(scale_array)(grad_f1, scale2, u_dim);
|
|
496
547
|
KKT_precompute(u1[1], x_inv, z, w, n, &KKT_work);
|
|
497
548
|
|
|
498
|
-
|
|
499
|
-
|
|
549
|
+
rhs2_aff[0] = -lmbda[0] * lmbda[0];
|
|
550
|
+
rhs2_aff[1] = -lmbda[1] * lmbda[1];
|
|
551
|
+
rhs2_aff[2] = -lmbda[2] * lmbda[2];
|
|
500
552
|
|
|
501
|
-
|
|
502
|
-
for (
|
|
553
|
+
/* upper bound on loop is chosen so it also iterates over rznl */
|
|
554
|
+
for (i = 0; i < u_dim + 3; ++i) {
|
|
503
555
|
rx[i] = -rx[i];
|
|
504
556
|
}
|
|
505
|
-
|
|
557
|
+
rhs1_aff = rx;
|
|
506
558
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
559
|
+
sigma = 0.0;
|
|
560
|
+
phi = 0.0;
|
|
561
|
+
dphi = 0.0;
|
|
562
|
+
step_size = 0.0;
|
|
511
563
|
phi = theta1 * gap + theta2 * norm_rx + theta3 * norm_rznl;
|
|
512
564
|
dphi = -theta1 * (1 - sigma) * gap - theta2 * norm_rx - theta3 * norm_rznl;
|
|
513
565
|
|
|
514
|
-
for (
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
566
|
+
for (j = 0; j < 2; ++j) {
|
|
567
|
+
bool backtrack;
|
|
568
|
+
|
|
569
|
+
/*
|
|
570
|
+
* For j = 0 we compute the affine-scaling direction.
|
|
571
|
+
* For j = 1 we compute the actual search direction.
|
|
572
|
+
*/
|
|
573
|
+
if (j == 1 && variant == 0) {
|
|
520
574
|
SCS(scale_array)(rhs1_aff, 1 - sigma, u_dim + 3);
|
|
521
575
|
rhs2_aff[0] += (sigma * mu - ds[0] * dz[0]);
|
|
522
576
|
rhs2_aff[1] += (sigma * mu - ds[1] * dz[1]);
|
|
@@ -526,16 +580,19 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
526
580
|
KKT_solve(z, w, x_inv, u1[1], lmbda, n, rhs1_aff, rhs2_aff, &KKT_work,
|
|
527
581
|
du1, &dr, dz, ds);
|
|
528
582
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
583
|
+
/*
|
|
584
|
+
* For j = 0 we determine the centering parameter.
|
|
585
|
+
* For j = 1 we do a nonmonotone line search.
|
|
586
|
+
*/
|
|
533
587
|
step_size = find_max_step_size(u1, z, s, du1, dz, ds, n);
|
|
534
588
|
|
|
535
|
-
|
|
589
|
+
backtrack = true;
|
|
536
590
|
|
|
537
591
|
while (backtrack) {
|
|
538
|
-
|
|
592
|
+
scs_float gap_new;
|
|
593
|
+
scs_float phi_new;
|
|
594
|
+
|
|
595
|
+
/* u_new = u + step * du, z_new = z + step * dz, s_new = s + step */
|
|
539
596
|
memcpy(u1_new, u1, u1_dim * sizeof(*u1));
|
|
540
597
|
SCS(add_scaled_array)(u1_new, du1, u1_dim, step_size);
|
|
541
598
|
rnew = r + step_size * dr;
|
|
@@ -544,14 +601,14 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
544
601
|
memcpy(s_new, s, 3 * sizeof(*s));
|
|
545
602
|
SCS(add_scaled_array)(s_new, ds, m, step_size);
|
|
546
603
|
|
|
547
|
-
|
|
548
|
-
for (
|
|
604
|
+
/* evaluate oracle in u_new */
|
|
605
|
+
for (i = 0; i < n; i++) {
|
|
549
606
|
x_inv_new[i] = 1 / u1_new[i + 2];
|
|
550
607
|
}
|
|
551
608
|
f_oracle(u1_new, rnew, t0, v0, x0, x_inv_new, n, f_u_new, grad_f0_new,
|
|
552
609
|
grad_f1_new);
|
|
553
610
|
|
|
554
|
-
|
|
611
|
+
/* compute residuals and merit function */
|
|
555
612
|
memcpy(rx_new, grad_f0_new, u_dim * sizeof(*grad_f0_new));
|
|
556
613
|
SCS(scale_array)(rx_new, z_new[0], u_dim);
|
|
557
614
|
SCS(add_scaled_array)(rx_new, grad_f1_new, u_dim, z_new[1]);
|
|
@@ -560,14 +617,12 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
560
617
|
rznl_new[0] = f_u_new[0] + s_new[0];
|
|
561
618
|
rznl_new[1] = f_u_new[1] + s_new[1];
|
|
562
619
|
rznl_new[2] = f_u_new[2] + s_new[2];
|
|
563
|
-
|
|
564
|
-
|
|
620
|
+
gap_new = SCS(dot)(z_new, s_new, m);
|
|
621
|
+
phi_new = theta1 * gap_new +
|
|
565
622
|
theta2 * SCS(norm_2)(rx_new, u_dim) +
|
|
566
623
|
theta3 * SCS(norm_2)(rznl_new, m);
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
// ----------------------------------------------------------
|
|
570
|
-
if (i == 0) {
|
|
624
|
+
/* For j == 0 we determine the centering parameter */
|
|
625
|
+
if (j == 0) {
|
|
571
626
|
if (phi_new <= (1 - ALPHA_IPM * step_size) * phi) {
|
|
572
627
|
backtrack = false;
|
|
573
628
|
sigma = (gap_new / gap);
|
|
@@ -578,14 +633,13 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
578
633
|
step_size *= BETA_IPM;
|
|
579
634
|
}
|
|
580
635
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
636
|
+
/*
|
|
637
|
+
* For j == 1 we do a nonmonotone line search with the actual
|
|
638
|
+
* search direction
|
|
639
|
+
*/
|
|
585
640
|
else {
|
|
586
641
|
if (relaxed_iters == -1 || MAX_RELAXED_ITERS == 0) {
|
|
587
642
|
if (phi_new <= phi + ALPHA_IPM * step_size * dphi) {
|
|
588
|
-
// relaxed_iters = 0;
|
|
589
643
|
backtrack = false;
|
|
590
644
|
} else {
|
|
591
645
|
step_size *= BETA_IPM;
|
|
@@ -611,7 +665,6 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
611
665
|
backtrack = false;
|
|
612
666
|
} else if (relaxed_iters == MAX_RELAXED_ITERS) {
|
|
613
667
|
if (phi_new <= phi0 + ALPHA_IPM * step_size0 * dphi0) {
|
|
614
|
-
// relaxed_iters = 0;
|
|
615
668
|
backtrack = false;
|
|
616
669
|
} else {
|
|
617
670
|
relaxed_iters = -1;
|
|
@@ -640,7 +693,7 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
640
693
|
}
|
|
641
694
|
}
|
|
642
695
|
|
|
643
|
-
|
|
696
|
+
/* update iterates */
|
|
644
697
|
memcpy(u1, u1_new, u1_dim * sizeof(*u1));
|
|
645
698
|
r = rnew;
|
|
646
699
|
memcpy(z, z_new, 3 * sizeof(*z));
|
|
@@ -651,7 +704,7 @@ scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
|
|
|
651
704
|
#endif
|
|
652
705
|
}
|
|
653
706
|
|
|
654
|
-
|
|
707
|
+
/* unscale solution */
|
|
655
708
|
scale1 = 1 / scale1;
|
|
656
709
|
SCS(scale_array)(x0, scale1, n);
|
|
657
710
|
SCS(scale_array)(u1, scale1, u1_dim);
|