scs 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +2 -2
- data/vendor/scs/CMakeLists.txt +284 -168
- data/vendor/scs/Makefile +43 -18
- data/vendor/scs/README.md +1 -1
- data/vendor/scs/include/glbopts.h +32 -13
- data/vendor/scs/include/linsys.h +8 -8
- data/vendor/scs/include/scs.h +6 -2
- data/vendor/scs/include/scs_types.h +3 -1
- data/vendor/scs/include/scs_work.h +9 -8
- data/vendor/scs/include/util.h +1 -1
- data/vendor/scs/linsys/cpu/direct/private.c +32 -153
- data/vendor/scs/linsys/cpu/direct/private.h +6 -6
- data/vendor/scs/linsys/cpu/indirect/private.c +9 -22
- data/vendor/scs/linsys/cpu/indirect/private.h +4 -2
- data/vendor/scs/linsys/csparse.c +140 -12
- data/vendor/scs/linsys/csparse.h +10 -17
- data/vendor/scs/linsys/gpu/gpu.c +4 -4
- data/vendor/scs/linsys/gpu/gpu.h +1 -1
- data/vendor/scs/linsys/gpu/indirect/private.c +15 -26
- data/vendor/scs/linsys/mkl/direct/private.c +182 -0
- data/vendor/scs/linsys/mkl/direct/private.h +38 -0
- data/vendor/scs/linsys/scs_matrix.c +11 -5
- data/vendor/scs/scs.mk +39 -26
- data/vendor/scs/src/cones.c +15 -159
- data/vendor/scs/src/exp_cone.c +399 -0
- data/vendor/scs/src/normalize.c +4 -2
- data/vendor/scs/src/rw.c +93 -38
- data/vendor/scs/src/scs.c +83 -52
- data/vendor/scs/src/util.c +12 -3
- data/vendor/scs/test/minunit.h +2 -1
- data/vendor/scs/test/problem_utils.h +2 -1
- data/vendor/scs/test/problems/hs21_tiny_qp.h +1 -1
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +8 -3
- data/vendor/scs/test/problems/max_ent +0 -0
- data/vendor/scs/test/problems/max_ent.h +8 -0
- data/vendor/scs/test/problems/random_prob.h +2 -43
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +7 -2
- data/vendor/scs/test/problems/test_exp_cone.h +84 -0
- data/vendor/scs/test/problems/test_prob_from_data_file.h +57 -0
- data/vendor/scs/test/run_from_file.c +7 -1
- data/vendor/scs/test/run_tests.c +22 -9
- metadata +10 -3
@@ -0,0 +1,399 @@
|
|
1
|
+
#include "cones.h"
|
2
|
+
#include "glbopts.h"
|
3
|
+
#include "linalg.h"
|
4
|
+
#include "scs.h"
|
5
|
+
|
6
|
+
#define EXP_CONE_INFINITY_VALUE (1E15)
|
7
|
+
|
8
|
+
/*
|
9
|
+
* Exponential cone projection routines, from:
|
10
|
+
*
|
11
|
+
* Projection onto the exponential cone: a univariate root-finding problem,
|
12
|
+
* by Henrik A. Friberg, 2021.
|
13
|
+
*
|
14
|
+
*/
|
15
|
+
|
16
|
+
static inline scs_int _isfinite(scs_float x) {
|
17
|
+
return ABS(x) < EXP_CONE_INFINITY_VALUE;
|
18
|
+
}
|
19
|
+
|
20
|
+
static inline scs_float _clip(scs_float x, scs_float l, scs_float u) {
|
21
|
+
return MAX(l, MIN(u, x));
|
22
|
+
}
|
23
|
+
|
24
|
+
/* As defined in Friberg, 2021 (multiplied by positive polynomial) */
|
25
|
+
static void hfun(const scs_float *v0, scs_float rho, scs_float *f,
|
26
|
+
scs_float *df) {
|
27
|
+
scs_float t0 = v0[2], s0 = v0[1], r0 = v0[0];
|
28
|
+
scs_float exprho = exp(rho);
|
29
|
+
scs_float expnegrho = exp(-rho);
|
30
|
+
/* function value at v0 */
|
31
|
+
*f = ((rho - 1) * r0 + s0) * exprho - (r0 - rho * s0) * expnegrho -
|
32
|
+
(rho * (rho - 1) + 1) * t0;
|
33
|
+
/* gradient of function at v0 */
|
34
|
+
*df = (rho * r0 + s0) * exprho + (r0 - (rho - 1) * s0) * expnegrho -
|
35
|
+
(2 * rho - 1) * t0;
|
36
|
+
}
|
37
|
+
|
38
|
+
/* Binary search for the root of the hfun function */
|
39
|
+
static scs_float root_search_binary(const scs_float *v0, scs_float xl,
|
40
|
+
scs_float xu, scs_float x) {
|
41
|
+
#if VERBOSITY > 0
|
42
|
+
scs_printf("Exp cone: Newton method failed, resorting to binary search.\n");
|
43
|
+
#endif
|
44
|
+
const scs_float EPS = 1e-12; /* expensive so loosen tol */
|
45
|
+
const scs_int MAXITER = 40;
|
46
|
+
scs_int i;
|
47
|
+
scs_float x_plus = x, f, df;
|
48
|
+
for (i = 0; i < MAXITER; i++) {
|
49
|
+
hfun(v0, x, &f, &df);
|
50
|
+
if (f < 0.0) {
|
51
|
+
xl = x;
|
52
|
+
} else {
|
53
|
+
xu = x;
|
54
|
+
}
|
55
|
+
/* binary search step */
|
56
|
+
x_plus = 0.5 * (xl + xu);
|
57
|
+
if (ABS(x_plus - x) <= EPS * MAX(1., ABS(x_plus)) || (x_plus == xl) ||
|
58
|
+
(x_plus == xu)) {
|
59
|
+
break;
|
60
|
+
}
|
61
|
+
x = x_plus;
|
62
|
+
}
|
63
|
+
return x_plus;
|
64
|
+
}
|
65
|
+
|
66
|
+
/* Use damped Newton's to find the root of the hfun function */
|
67
|
+
static scs_float root_search_newton(const scs_float *v0, scs_float xl,
|
68
|
+
scs_float xu, scs_float x) {
|
69
|
+
/* params taken from Friberg code */
|
70
|
+
const scs_float EPS = 1e-15;
|
71
|
+
const scs_float DFTOL = 1e-13; /* pow(EPS, 6.0 / 7.0) */
|
72
|
+
const scs_int MAXITER = 20;
|
73
|
+
const scs_float LODAMP = 0.05;
|
74
|
+
const scs_float HIDAMP = 0.95;
|
75
|
+
|
76
|
+
scs_float x_plus, f, df;
|
77
|
+
scs_int i;
|
78
|
+
|
79
|
+
for (i = 0; i < MAXITER; i++) {
|
80
|
+
hfun(v0, x, &f, &df);
|
81
|
+
|
82
|
+
if (ABS(f) <= EPS) { /* root found */
|
83
|
+
break;
|
84
|
+
}
|
85
|
+
|
86
|
+
if (f < 0.0) {
|
87
|
+
xl = x;
|
88
|
+
} else {
|
89
|
+
xu = x;
|
90
|
+
}
|
91
|
+
|
92
|
+
if (xu <= xl) {
|
93
|
+
xu = 0.5 * (xu + xl);
|
94
|
+
xl = xu;
|
95
|
+
break;
|
96
|
+
}
|
97
|
+
|
98
|
+
if (!_isfinite(f) || df < DFTOL) {
|
99
|
+
break;
|
100
|
+
}
|
101
|
+
|
102
|
+
/* Newton step */
|
103
|
+
x_plus = x - f / df;
|
104
|
+
|
105
|
+
if (ABS(x_plus - x) <= EPS * MAX(1., ABS(x_plus))) {
|
106
|
+
break;
|
107
|
+
}
|
108
|
+
|
109
|
+
if (x_plus >= xu) {
|
110
|
+
x = MIN(LODAMP * x + HIDAMP * xu, xu);
|
111
|
+
} else if (x_plus <= xl) {
|
112
|
+
x = MAX(LODAMP * x + HIDAMP * xl, xl);
|
113
|
+
} else {
|
114
|
+
x = x_plus;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
if (i < MAXITER) { /* Newton's method converged */
|
118
|
+
#if VERBOSITY > 0
|
119
|
+
scs_printf("Exp cone: Newton iters:%i, f:%.4e, df:%.4e\n", (int)i, f, df);
|
120
|
+
#endif
|
121
|
+
return _clip(x, xl, xu);
|
122
|
+
}
|
123
|
+
/* Fall back to binary search if Newton failed */
|
124
|
+
return root_search_binary(v0, xl, xu, x);
|
125
|
+
}
|
126
|
+
|
127
|
+
/* try heuristic (cheap) projection */
|
128
|
+
static scs_float proj_primal_exp_cone_heuristic(const scs_float *v0,
|
129
|
+
scs_float *vp) {
|
130
|
+
scs_float t0 = v0[2], s0 = v0[1], r0 = v0[0];
|
131
|
+
scs_float dist, tp, newdist;
|
132
|
+
/* perspective boundary */
|
133
|
+
vp[2] = MAX(t0, 0);
|
134
|
+
vp[1] = 0.0;
|
135
|
+
vp[0] = MIN(r0, 0);
|
136
|
+
dist = SCS(norm_diff)(v0, vp, 3);
|
137
|
+
|
138
|
+
/* perspective interior */
|
139
|
+
if (s0 > 0.0) {
|
140
|
+
tp = MAX(t0, s0 * exp(r0 / s0));
|
141
|
+
newdist = tp - t0;
|
142
|
+
if (newdist < dist) {
|
143
|
+
vp[2] = tp;
|
144
|
+
vp[1] = s0;
|
145
|
+
vp[0] = r0;
|
146
|
+
dist = newdist;
|
147
|
+
}
|
148
|
+
}
|
149
|
+
return dist;
|
150
|
+
}
|
151
|
+
|
152
|
+
/* try heuristic (cheap) projection */
|
153
|
+
static scs_float proj_polar_exp_cone_heuristic(const scs_float *v0,
|
154
|
+
scs_float *vd) {
|
155
|
+
scs_float t0 = v0[2], s0 = v0[1], r0 = v0[0];
|
156
|
+
scs_float dist, td, newdist;
|
157
|
+
/* perspective boundary */
|
158
|
+
vd[2] = MIN(t0, 0);
|
159
|
+
vd[1] = MIN(s0, 0);
|
160
|
+
vd[0] = 0.0;
|
161
|
+
dist = SCS(norm_diff)(v0, vd, 3);
|
162
|
+
|
163
|
+
/* perspective interior */
|
164
|
+
if (r0 > 0.0) {
|
165
|
+
td = MIN(t0, -r0 * exp(s0 / r0 - 1));
|
166
|
+
newdist = t0 - td;
|
167
|
+
if (newdist < dist) {
|
168
|
+
vd[2] = td;
|
169
|
+
vd[1] = s0;
|
170
|
+
vd[0] = r0;
|
171
|
+
dist = newdist;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
return dist;
|
175
|
+
}
|
176
|
+
|
177
|
+
static scs_float ppsi(const scs_float *v0) {
|
178
|
+
scs_float s0 = v0[1], r0 = v0[0];
|
179
|
+
scs_float psi;
|
180
|
+
|
181
|
+
if (r0 > s0) {
|
182
|
+
psi = (r0 - s0 + sqrt(r0 * r0 + s0 * s0 - r0 * s0)) / r0;
|
183
|
+
} else {
|
184
|
+
psi = -s0 / (r0 - s0 - sqrt(r0 * r0 + s0 * s0 - r0 * s0));
|
185
|
+
}
|
186
|
+
|
187
|
+
return ((psi - 1) * r0 + s0) / (psi * (psi - 1) + 1);
|
188
|
+
}
|
189
|
+
|
190
|
+
static scs_float pomega(scs_float rho) {
|
191
|
+
scs_float val = exp(rho) / (rho * (rho - 1) + 1);
|
192
|
+
|
193
|
+
if (rho < 2.0) {
|
194
|
+
val = MIN(val, exp(2.0) / 3);
|
195
|
+
}
|
196
|
+
|
197
|
+
return val;
|
198
|
+
}
|
199
|
+
|
200
|
+
static scs_float dpsi(const scs_float *v0) {
|
201
|
+
scs_float s0 = v0[1], r0 = v0[0];
|
202
|
+
scs_float psi;
|
203
|
+
|
204
|
+
if (s0 > r0) {
|
205
|
+
psi = (r0 - sqrt(r0 * r0 + s0 * s0 - r0 * s0)) / s0;
|
206
|
+
} else {
|
207
|
+
psi = (r0 - s0) / (r0 + sqrt(r0 * r0 + s0 * s0 - r0 * s0));
|
208
|
+
}
|
209
|
+
|
210
|
+
return (r0 - psi * s0) / (psi * (psi - 1) + 1);
|
211
|
+
}
|
212
|
+
|
213
|
+
static scs_float domega(scs_float rho) {
|
214
|
+
scs_float val = -exp(-rho) / (rho * (rho - 1) + 1);
|
215
|
+
|
216
|
+
if (rho > -1.0) {
|
217
|
+
val = MAX(val, -exp(1.0) / 3);
|
218
|
+
}
|
219
|
+
|
220
|
+
return val;
|
221
|
+
}
|
222
|
+
|
223
|
+
/* Generate upper and lower search bounds for root of hfun */
|
224
|
+
static void exp_search_bracket(const scs_float *v0, scs_float pdist,
|
225
|
+
scs_float ddist, scs_float *low_out,
|
226
|
+
scs_float *upr_out) {
|
227
|
+
scs_float t0 = v0[2], s0 = v0[1], r0 = v0[0];
|
228
|
+
scs_float baselow = -EXP_CONE_INFINITY_VALUE,
|
229
|
+
baseupr = EXP_CONE_INFINITY_VALUE;
|
230
|
+
scs_float low = -EXP_CONE_INFINITY_VALUE, upr = EXP_CONE_INFINITY_VALUE;
|
231
|
+
|
232
|
+
scs_float Dp = SQRTF(pdist * pdist - MIN(s0, 0) * MIN(s0, 0));
|
233
|
+
scs_float Dd = SQRTF(ddist * ddist - MIN(r0, 0) * MIN(r0, 0));
|
234
|
+
|
235
|
+
scs_float curbnd, fl, fu, df, tpu, tdl;
|
236
|
+
|
237
|
+
if (t0 > 0) {
|
238
|
+
curbnd = log(t0 / ppsi(v0));
|
239
|
+
low = MAX(low, curbnd);
|
240
|
+
} else if (t0 < 0) {
|
241
|
+
curbnd = -log(-t0 / dpsi(v0));
|
242
|
+
upr = MIN(upr, curbnd);
|
243
|
+
}
|
244
|
+
|
245
|
+
if (r0 > 0) {
|
246
|
+
baselow = 1 - s0 / r0;
|
247
|
+
low = MAX(low, baselow);
|
248
|
+
tpu = MAX(1e-12, MIN(Dd, Dp + t0));
|
249
|
+
curbnd = MAX(low, baselow + tpu / r0 / pomega(low));
|
250
|
+
upr = MIN(upr, curbnd);
|
251
|
+
}
|
252
|
+
|
253
|
+
if (s0 > 0) {
|
254
|
+
baseupr = r0 / s0;
|
255
|
+
upr = MIN(upr, baseupr);
|
256
|
+
tdl = -MAX(1e-12, MIN(Dp, Dd - t0));
|
257
|
+
curbnd = MIN(upr, baseupr - tdl / s0 / domega(upr));
|
258
|
+
low = MAX(low, curbnd);
|
259
|
+
}
|
260
|
+
|
261
|
+
/* Guarantee valid bracket */
|
262
|
+
/* TODO do we need these 2 lines? */
|
263
|
+
low = _clip(MIN(low, upr), baselow, baseupr);
|
264
|
+
upr = _clip(MAX(low, upr), baselow, baseupr);
|
265
|
+
|
266
|
+
if (low != upr) {
|
267
|
+
hfun(v0, low, &fl, &df);
|
268
|
+
hfun(v0, upr, &fu, &df);
|
269
|
+
|
270
|
+
if (fl * fu > 0) {
|
271
|
+
if (ABS(fl) < ABS(fu)) {
|
272
|
+
upr = low;
|
273
|
+
} else {
|
274
|
+
low = upr;
|
275
|
+
}
|
276
|
+
}
|
277
|
+
}
|
278
|
+
|
279
|
+
*low_out = low;
|
280
|
+
*upr_out = upr;
|
281
|
+
}
|
282
|
+
|
283
|
+
/* convert from rho to primal projection */
|
284
|
+
static scs_float proj_sol_primal_exp_cone(const scs_float *v0, scs_float rho,
|
285
|
+
scs_float *vp) {
|
286
|
+
scs_float linrho = (rho - 1) * v0[0] + v0[1];
|
287
|
+
scs_float exprho = exp(rho);
|
288
|
+
scs_float quadrho, dist;
|
289
|
+
if (linrho > 0 && _isfinite(exprho)) {
|
290
|
+
quadrho = rho * (rho - 1) + 1;
|
291
|
+
vp[2] = exprho * linrho / quadrho;
|
292
|
+
vp[1] = linrho / quadrho;
|
293
|
+
vp[0] = rho * linrho / quadrho;
|
294
|
+
dist = SCS(norm_diff)(vp, v0, 3);
|
295
|
+
} else {
|
296
|
+
vp[2] = EXP_CONE_INFINITY_VALUE;
|
297
|
+
vp[1] = 0.0;
|
298
|
+
vp[0] = 0.0;
|
299
|
+
dist = EXP_CONE_INFINITY_VALUE;
|
300
|
+
}
|
301
|
+
return dist;
|
302
|
+
}
|
303
|
+
|
304
|
+
/* convert from rho to polar projection */
|
305
|
+
static scs_float proj_sol_polar_exp_cone(const scs_float *v0, scs_float rho,
|
306
|
+
scs_float *vd) {
|
307
|
+
scs_float linrho = v0[0] - rho * v0[1];
|
308
|
+
scs_float exprho = exp(-rho);
|
309
|
+
scs_float quadrho, dist;
|
310
|
+
if (linrho > 0 && _isfinite(exprho)) {
|
311
|
+
quadrho = rho * (rho - 1) + 1;
|
312
|
+
vd[2] = -exprho * linrho / quadrho;
|
313
|
+
vd[1] = (1 - rho) * linrho / quadrho;
|
314
|
+
vd[0] = linrho / quadrho;
|
315
|
+
dist = SCS(norm_diff)(v0, vd, 3);
|
316
|
+
} else {
|
317
|
+
vd[2] = -EXP_CONE_INFINITY_VALUE;
|
318
|
+
vd[1] = 0.0;
|
319
|
+
vd[0] = 0.0;
|
320
|
+
dist = EXP_CONE_INFINITY_VALUE;
|
321
|
+
}
|
322
|
+
return dist;
|
323
|
+
}
|
324
|
+
|
325
|
+
static inline void _copy(scs_float *dest, scs_float *src) {
|
326
|
+
dest[0] = src[0];
|
327
|
+
dest[1] = src[1];
|
328
|
+
dest[2] = src[2];
|
329
|
+
}
|
330
|
+
|
331
|
+
/* Project onto primal or dual exponential cone, performed in-place.
|
332
|
+
* If `primal=0` then project on the dual cone, otherwise project
|
333
|
+
* onto primal. Taken from algorithm in Friberg, 2021.
|
334
|
+
*/
|
335
|
+
scs_float SCS(proj_pd_exp_cone)(scs_float *v0, scs_int primal) {
|
336
|
+
scs_float TOL = 1e-8; /* pow(1e-10, 2.0 / 3.0); */
|
337
|
+
scs_float xl, xh, pdist, ddist, err, rho, dist_hat;
|
338
|
+
scs_float vp[3], vd[3], v_hat[3];
|
339
|
+
scs_int opt;
|
340
|
+
if (!primal) {
|
341
|
+
/* This routine actually projects onto primal and polar cones
|
342
|
+
* simultaneously. So to make it project onto dual, use this:
|
343
|
+
* Pi_{C^*}(v0) = -Pi_{C^polar}(-v0)
|
344
|
+
*/
|
345
|
+
v0[0] *= -1.;
|
346
|
+
v0[1] *= -1.;
|
347
|
+
v0[2] *= -1.;
|
348
|
+
}
|
349
|
+
|
350
|
+
pdist = proj_primal_exp_cone_heuristic(v0, vp);
|
351
|
+
ddist = proj_polar_exp_cone_heuristic(v0, vd);
|
352
|
+
|
353
|
+
err = ABS(vp[0] + vd[0] - v0[0]);
|
354
|
+
err = MAX(err, ABS(vp[1] + vd[1] - v0[1]));
|
355
|
+
err = MAX(err, ABS(vp[2] + vd[2] - v0[2]));
|
356
|
+
|
357
|
+
/* Skip root search if presolve rules apply
|
358
|
+
* or optimality conditions are satisfied
|
359
|
+
*/
|
360
|
+
opt = (v0[1] <= 0 && v0[0] <= 0);
|
361
|
+
opt |= (MIN(pdist, ddist) <= TOL);
|
362
|
+
opt |= (err <= TOL && SCS(dot)(vp, vd, 3) <= TOL);
|
363
|
+
if (opt) {
|
364
|
+
if (primal) {
|
365
|
+
_copy(v0, vp);
|
366
|
+
return pdist;
|
367
|
+
}
|
368
|
+
/* polar cone -> dual cone */
|
369
|
+
v0[0] = -vd[0];
|
370
|
+
v0[1] = -vd[1];
|
371
|
+
v0[2] = -vd[2];
|
372
|
+
return ddist;
|
373
|
+
}
|
374
|
+
|
375
|
+
exp_search_bracket(v0, pdist, ddist, &xl, &xh);
|
376
|
+
rho = root_search_newton(v0, xl, xh, 0.5 * (xl + xh));
|
377
|
+
|
378
|
+
if (primal) {
|
379
|
+
/* primal cone projection */
|
380
|
+
dist_hat = proj_sol_primal_exp_cone(v0, rho, v_hat);
|
381
|
+
if (dist_hat <= pdist) {
|
382
|
+
_copy(vp, v_hat);
|
383
|
+
pdist = dist_hat;
|
384
|
+
}
|
385
|
+
_copy(v0, vp);
|
386
|
+
return pdist;
|
387
|
+
}
|
388
|
+
/* polar cone projection */
|
389
|
+
dist_hat = proj_sol_polar_exp_cone(v0, rho, v_hat);
|
390
|
+
if (dist_hat <= ddist) {
|
391
|
+
_copy(vd, v_hat);
|
392
|
+
ddist = dist_hat;
|
393
|
+
}
|
394
|
+
/* polar cone -> dual cone */
|
395
|
+
v0[0] = -vd[0];
|
396
|
+
v0[1] = -vd[1];
|
397
|
+
v0[2] = -vd[2];
|
398
|
+
return ddist;
|
399
|
+
}
|
data/vendor/scs/src/normalize.c
CHANGED
@@ -26,7 +26,7 @@
|
|
26
26
|
*/
|
27
27
|
void SCS(normalize_b_c)(ScsScaling *scal, scs_float *b, scs_float *c) {
|
28
28
|
scs_int i;
|
29
|
-
scs_float sigma;
|
29
|
+
scs_float sigma, nm_c, nm_b;
|
30
30
|
|
31
31
|
/* scale c */
|
32
32
|
for (i = 0; i < scal->n; ++i) {
|
@@ -38,7 +38,9 @@ void SCS(normalize_b_c)(ScsScaling *scal, scs_float *b, scs_float *c) {
|
|
38
38
|
}
|
39
39
|
|
40
40
|
/* calculate primal and dual scales */
|
41
|
-
|
41
|
+
nm_c = SCS(norm_inf)(c, scal->n);
|
42
|
+
nm_b = SCS(norm_inf)(b, scal->m);
|
43
|
+
sigma = MAX(nm_c, nm_b);
|
42
44
|
sigma = sigma < MIN_NORMALIZATION_FACTOR ? 1.0 : sigma;
|
43
45
|
sigma = sigma > MAX_NORMALIZATION_FACTOR ? MAX_NORMALIZATION_FACTOR : sigma;
|
44
46
|
sigma = SAFEDIV_POS(1.0, sigma);
|
data/vendor/scs/src/rw.c
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "rw.h"
|
2
2
|
|
3
|
+
#include <errno.h>
|
3
4
|
#include <stdint.h>
|
4
5
|
#include <stdio.h>
|
5
6
|
#include <stdlib.h>
|
@@ -9,6 +10,25 @@
|
|
9
10
|
#include "scs_matrix.h"
|
10
11
|
#include "util.h"
|
11
12
|
|
13
|
+
#if NO_READ_WRITE > 0 /* Disables all read / write functionality */
|
14
|
+
|
15
|
+
void SCS(write_data)(const ScsData *d, const ScsCone *k,
|
16
|
+
const ScsSettings *stgs) {
|
17
|
+
/* Do nothing */
|
18
|
+
}
|
19
|
+
scs_int SCS(read_data)(const char *filename, ScsData **d, ScsCone **k,
|
20
|
+
ScsSettings **stgs) {
|
21
|
+
/* Failure */
|
22
|
+
return -1;
|
23
|
+
}
|
24
|
+
void SCS(log_data_to_csv)(const ScsCone *k, const ScsSettings *stgs,
|
25
|
+
const ScsWork *w, scs_int iter,
|
26
|
+
SCS(timer) * solve_timer) {
|
27
|
+
/* Do nothing */
|
28
|
+
}
|
29
|
+
|
30
|
+
#else
|
31
|
+
|
12
32
|
/* writes/reads problem data to/from filename */
|
13
33
|
/* This is a VERY naive implementation, doesn't care about portability etc */
|
14
34
|
|
@@ -28,30 +48,61 @@ static void write_scs_cone(const ScsCone *k, FILE *fout) {
|
|
28
48
|
fwrite(k->p, sizeof(scs_float), k->psize, fout);
|
29
49
|
}
|
30
50
|
|
31
|
-
|
51
|
+
/*
|
52
|
+
* Read integer data from file. If the integer width on file is
|
53
|
+
* different to scs_int then it will cast the ints after reading
|
54
|
+
* to be compatible with the SCS data types.
|
55
|
+
*/
|
56
|
+
static size_t read_int(scs_int *dest, size_t file_int_sz, size_t nitems,
|
57
|
+
FILE *fin) {
|
58
|
+
if (file_int_sz == sizeof(scs_int)) {
|
59
|
+
return fread(dest, sizeof(scs_int), nitems, fin);
|
60
|
+
}
|
61
|
+
void *ptr = scs_calloc(nitems, file_int_sz);
|
62
|
+
size_t val = fread(ptr, file_int_sz, nitems, fin);
|
63
|
+
scs_int i;
|
64
|
+
switch (file_int_sz) {
|
65
|
+
case 4:
|
66
|
+
for (i = 0; i < nitems; ++i) {
|
67
|
+
dest[i] = (scs_int)(((int *)ptr)[i]);
|
68
|
+
}
|
69
|
+
break;
|
70
|
+
case 8:
|
71
|
+
for (i = 0; i < nitems; ++i) {
|
72
|
+
dest[i] = (scs_int)(((long long *)ptr)[i]);
|
73
|
+
}
|
74
|
+
break;
|
75
|
+
}
|
76
|
+
if (ptr) {
|
77
|
+
scs_free(ptr);
|
78
|
+
}
|
79
|
+
return val;
|
80
|
+
}
|
81
|
+
|
82
|
+
static ScsCone *read_scs_cone(FILE *fin, size_t file_int_sz) {
|
32
83
|
ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
33
|
-
|
34
|
-
|
35
|
-
|
84
|
+
read_int(&(k->z), file_int_sz, 1, fin);
|
85
|
+
read_int(&(k->l), file_int_sz, 1, fin);
|
86
|
+
read_int(&(k->bsize), file_int_sz, 1, fin);
|
36
87
|
if (k->bsize > 1) {
|
37
88
|
k->bl = (scs_float *)scs_calloc(MAX(k->bsize - 1, 0), sizeof(scs_float));
|
38
89
|
k->bu = (scs_float *)scs_calloc(MAX(k->bsize - 1, 0), sizeof(scs_float));
|
39
90
|
fread(k->bl, sizeof(scs_float), MAX(k->bsize - 1, 0), fin);
|
40
91
|
fread(k->bu, sizeof(scs_float), MAX(k->bsize - 1, 0), fin);
|
41
92
|
}
|
42
|
-
|
93
|
+
read_int(&(k->qsize), file_int_sz, 1, fin);
|
43
94
|
if (k->qsize) {
|
44
95
|
k->q = (scs_int *)scs_calloc(k->qsize, sizeof(scs_int));
|
45
|
-
|
96
|
+
read_int(k->q, file_int_sz, k->qsize, fin);
|
46
97
|
}
|
47
|
-
|
98
|
+
read_int(&(k->ssize), file_int_sz, 1, fin);
|
48
99
|
if (k->ssize) {
|
49
100
|
k->s = (scs_int *)scs_calloc(k->ssize, sizeof(scs_int));
|
50
|
-
|
101
|
+
read_int(k->s, file_int_sz, k->ssize, fin);
|
51
102
|
}
|
52
|
-
|
53
|
-
|
54
|
-
|
103
|
+
read_int(&(k->ep), file_int_sz, 1, fin);
|
104
|
+
read_int(&(k->ed), file_int_sz, 1, fin);
|
105
|
+
read_int(&(k->psize), file_int_sz, 1, fin);
|
55
106
|
if (k->psize) {
|
56
107
|
k->p = (scs_float *)scs_calloc(k->psize, sizeof(scs_float));
|
57
108
|
fread(k->p, sizeof(scs_float), k->psize, fin);
|
@@ -79,21 +130,21 @@ static void write_scs_stgs(const ScsSettings *s, FILE *fout) {
|
|
79
130
|
/* Do not write the log_csv_filename */
|
80
131
|
}
|
81
132
|
|
82
|
-
static ScsSettings *read_scs_stgs(FILE *fin) {
|
133
|
+
static ScsSettings *read_scs_stgs(FILE *fin, size_t file_int_sz) {
|
83
134
|
ScsSettings *s = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
84
|
-
|
135
|
+
read_int(&(s->normalize), file_int_sz, 1, fin);
|
85
136
|
fread(&(s->scale), sizeof(scs_float), 1, fin);
|
86
137
|
fread(&(s->rho_x), sizeof(scs_float), 1, fin);
|
87
|
-
|
138
|
+
read_int(&(s->max_iters), file_int_sz, 1, fin);
|
88
139
|
fread(&(s->eps_abs), sizeof(scs_float), 1, fin);
|
89
140
|
fread(&(s->eps_rel), sizeof(scs_float), 1, fin);
|
90
141
|
fread(&(s->eps_infeas), sizeof(scs_float), 1, fin);
|
91
142
|
fread(&(s->alpha), sizeof(scs_float), 1, fin);
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
143
|
+
read_int(&(s->verbose), file_int_sz, 1, fin);
|
144
|
+
read_int(&(s->warm_start), file_int_sz, 1, fin);
|
145
|
+
read_int(&(s->acceleration_lookback), file_int_sz, 1, fin);
|
146
|
+
read_int(&(s->acceleration_interval), file_int_sz, 1, fin);
|
147
|
+
read_int(&(s->adaptive_scale), file_int_sz, 1, fin);
|
97
148
|
return s;
|
98
149
|
}
|
99
150
|
|
@@ -106,18 +157,18 @@ static void write_amatrix(const ScsMatrix *A, FILE *fout) {
|
|
106
157
|
fwrite(A->i, sizeof(scs_int), Anz, fout);
|
107
158
|
}
|
108
159
|
|
109
|
-
static ScsMatrix *read_amatrix(FILE *fin) {
|
160
|
+
static ScsMatrix *read_amatrix(FILE *fin, size_t file_int_sz) {
|
110
161
|
scs_int Anz;
|
111
162
|
ScsMatrix *A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
112
|
-
|
113
|
-
|
163
|
+
read_int(&(A->m), file_int_sz, 1, fin);
|
164
|
+
read_int(&(A->n), file_int_sz, 1, fin);
|
114
165
|
A->p = (scs_int *)scs_calloc(A->n + 1, sizeof(scs_int));
|
115
|
-
|
166
|
+
read_int(A->p, file_int_sz, A->n + 1, fin);
|
116
167
|
Anz = A->p[A->n];
|
117
168
|
A->x = (scs_float *)scs_calloc(Anz, sizeof(scs_float));
|
118
169
|
A->i = (scs_int *)scs_calloc(Anz, sizeof(scs_int));
|
119
170
|
fread(A->x, sizeof(scs_float), Anz, fin);
|
120
|
-
|
171
|
+
read_int(A->i, file_int_sz, Anz, fin);
|
121
172
|
return A;
|
122
173
|
}
|
123
174
|
|
@@ -135,19 +186,20 @@ static void write_scs_data(const ScsData *d, FILE *fout) {
|
|
135
186
|
}
|
136
187
|
}
|
137
188
|
|
138
|
-
static ScsData *read_scs_data(FILE *fin) {
|
189
|
+
static ScsData *read_scs_data(FILE *fin, size_t file_int_sz) {
|
139
190
|
scs_int has_p = 0;
|
140
191
|
ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
141
|
-
|
142
|
-
|
192
|
+
|
193
|
+
read_int(&(d->m), file_int_sz, 1, fin);
|
194
|
+
read_int(&(d->n), file_int_sz, 1, fin);
|
143
195
|
d->b = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
144
196
|
d->c = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
145
197
|
fread(d->b, sizeof(scs_float), d->m, fin);
|
146
198
|
fread(d->c, sizeof(scs_float), d->n, fin);
|
147
|
-
d->A = read_amatrix(fin);
|
199
|
+
d->A = read_amatrix(fin, file_int_sz);
|
148
200
|
/* If has_p bit is not set or this hits end of file then has_p = 0 */
|
149
|
-
has_p &=
|
150
|
-
d->P = has_p ? read_amatrix(fin) : SCS_NULL;
|
201
|
+
has_p &= read_int(&has_p, file_int_sz, 1, fin);
|
202
|
+
d->P = has_p ? read_amatrix(fin, file_int_sz) : SCS_NULL;
|
151
203
|
return d;
|
152
204
|
}
|
153
205
|
|
@@ -158,7 +210,6 @@ void SCS(write_data)(const ScsData *d, const ScsCone *k,
|
|
158
210
|
uint32_t scs_float_sz = (uint32_t)sizeof(scs_float);
|
159
211
|
const char *scs_version = SCS_VERSION;
|
160
212
|
uint32_t scs_version_sz = (uint32_t)strlen(scs_version);
|
161
|
-
scs_printf("writing data to %s\n", stgs->write_data_filename);
|
162
213
|
fwrite(&(scs_int_sz), sizeof(uint32_t), 1, fout);
|
163
214
|
fwrite(&(scs_float_sz), sizeof(uint32_t), 1, fout);
|
164
215
|
fwrite(&(scs_version_sz), sizeof(uint32_t), 1, fout);
|
@@ -175,9 +226,11 @@ scs_int SCS(read_data)(const char *filename, ScsData **d, ScsCone **k,
|
|
175
226
|
uint32_t file_float_sz;
|
176
227
|
uint32_t file_version_sz;
|
177
228
|
char file_version[16];
|
229
|
+
errno = 0;
|
178
230
|
FILE *fin = fopen(filename, "rb");
|
179
231
|
if (!fin) {
|
180
232
|
scs_printf("Error reading file %s\n", filename);
|
233
|
+
scs_printf("errno:%i:%s\n", errno, strerror(errno));
|
181
234
|
return -1;
|
182
235
|
}
|
183
236
|
scs_printf("Reading data from %s\n", filename);
|
@@ -185,11 +238,10 @@ scs_int SCS(read_data)(const char *filename, ScsData **d, ScsCone **k,
|
|
185
238
|
fread(&(file_float_sz), sizeof(uint32_t), 1, fin);
|
186
239
|
if (file_int_sz != (uint32_t)sizeof(scs_int)) {
|
187
240
|
scs_printf(
|
188
|
-
"
|
189
|
-
"
|
241
|
+
"Warning, sizeof(file int) is %lu, but scs expects sizeof(int) %lu. "
|
242
|
+
"SCS will attempt to cast the data, which may be slow. "
|
243
|
+
"This message can be avoided by recompiling with the correct flags.\n",
|
190
244
|
(unsigned long)file_int_sz, (unsigned long)sizeof(scs_int));
|
191
|
-
fclose(fin);
|
192
|
-
return -1;
|
193
245
|
}
|
194
246
|
if (file_float_sz != (uint32_t)sizeof(scs_float)) {
|
195
247
|
scs_printf(
|
@@ -209,9 +261,10 @@ scs_int SCS(read_data)(const char *filename, ScsData **d, ScsCone **k,
|
|
209
261
|
"************************************************************\n",
|
210
262
|
file_version, SCS_VERSION);
|
211
263
|
}
|
212
|
-
*k = read_scs_cone(fin);
|
213
|
-
*d = read_scs_data(fin);
|
214
|
-
*stgs = read_scs_stgs(fin);
|
264
|
+
*k = read_scs_cone(fin, file_int_sz);
|
265
|
+
*d = read_scs_data(fin, file_int_sz);
|
266
|
+
*stgs = read_scs_stgs(fin, file_int_sz);
|
267
|
+
scs_printf("Finished reading data.\n");
|
215
268
|
fclose(fin);
|
216
269
|
return 0;
|
217
270
|
}
|
@@ -348,3 +401,5 @@ void SCS(log_data_to_csv)(const ScsCone *k, const ScsSettings *stgs,
|
|
348
401
|
fprintf(fout, "\n");
|
349
402
|
fclose(fout);
|
350
403
|
}
|
404
|
+
|
405
|
+
#endif
|