scs 0.3.2 → 0.4.1
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 +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +35 -6
- data/lib/scs/matrix.rb +72 -0
- data/lib/scs/solver.rb +19 -26
- data/lib/scs/version.rb +1 -1
- data/lib/scs.rb +1 -0
- data/vendor/scs/CITATION.cff +2 -2
- data/vendor/scs/CMakeLists.txt +285 -169
- data/vendor/scs/Makefile +43 -18
- data/vendor/scs/README.md +3 -1
- data/vendor/scs/include/cones.h +5 -3
- data/vendor/scs/include/glbopts.h +35 -17
- data/vendor/scs/include/linsys.h +8 -8
- data/vendor/scs/include/normalize.h +1 -0
- data/vendor/scs/include/rw.h +3 -3
- data/vendor/scs/include/scs.h +51 -24
- data/vendor/scs/include/scs_types.h +3 -1
- data/vendor/scs/include/scs_work.h +13 -15
- data/vendor/scs/include/util.h +4 -2
- 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/external/amd/LICENSE.txt +0 -897
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +4 -2
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +0 -5
- 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 +49 -72
- data/vendor/scs/linsys/scs_matrix.h +4 -3
- data/vendor/scs/scs.mk +39 -30
- data/vendor/scs/src/aa.c +0 -4
- data/vendor/scs/src/cones.c +78 -184
- data/vendor/scs/src/exp_cone.c +399 -0
- data/vendor/scs/src/normalize.c +51 -0
- data/vendor/scs/src/rw.c +139 -76
- data/vendor/scs/src/scs.c +275 -202
- data/vendor/scs/src/util.c +36 -13
- data/vendor/scs/test/minunit.h +2 -1
- data/vendor/scs/test/problem_utils.h +5 -4
- data/vendor/scs/test/problems/degenerate.h +1 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +13 -4
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +1 -0
- data/vendor/scs/test/problems/max_ent +0 -0
- data/vendor/scs/test/problems/max_ent.h +8 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/random_prob.h +2 -39
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +15 -3
- data/vendor/scs/test/problems/small_lp.h +4 -1
- data/vendor/scs/test/problems/small_qp.h +42 -7
- 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/problems/test_validation.h +4 -1
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +3 -3
- data/vendor/scs/test/random_socp_prob.c +3 -1
- data/vendor/scs/test/run_from_file.c +22 -4
- data/vendor/scs/test/run_tests.c +22 -9
- metadata +12 -4
@@ -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
@@ -3,6 +3,57 @@
|
|
3
3
|
#include "linalg.h"
|
4
4
|
#include "scs.h"
|
5
5
|
|
6
|
+
/* copied from linsys/scs_matrix.c */
|
7
|
+
#define MIN_NORMALIZATION_FACTOR (1e-4)
|
8
|
+
#define MAX_NORMALIZATION_FACTOR (1e4)
|
9
|
+
|
10
|
+
/* Given D, E in scaling normalize b, c and compute primal / dual scales.
|
11
|
+
*
|
12
|
+
* Recall that the normalization routine is performing:
|
13
|
+
*
|
14
|
+
* [P A' c] with [E 0 0] on both sides (D, E diagonal)
|
15
|
+
* [A 0 b] [0 D 0]
|
16
|
+
* [c' b' 0] [0 0 s]
|
17
|
+
*
|
18
|
+
* which results in:
|
19
|
+
*
|
20
|
+
* [ EPE EA'D sEc ]
|
21
|
+
* [ DAE 0 sDb ]
|
22
|
+
* [ sc'E sb'D 0 ]
|
23
|
+
*
|
24
|
+
* `s` is incorporated into dual_scale and primal_scale
|
25
|
+
*
|
26
|
+
*/
|
27
|
+
void SCS(normalize_b_c)(ScsScaling *scal, scs_float *b, scs_float *c) {
|
28
|
+
scs_int i;
|
29
|
+
scs_float sigma, nm_c, nm_b;
|
30
|
+
|
31
|
+
/* scale c */
|
32
|
+
for (i = 0; i < scal->n; ++i) {
|
33
|
+
c[i] *= scal->E[i];
|
34
|
+
}
|
35
|
+
/* scale b */
|
36
|
+
for (i = 0; i < scal->m; ++i) {
|
37
|
+
b[i] *= scal->D[i];
|
38
|
+
}
|
39
|
+
|
40
|
+
/* calculate primal and dual scales */
|
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);
|
44
|
+
sigma = sigma < MIN_NORMALIZATION_FACTOR ? 1.0 : sigma;
|
45
|
+
sigma = sigma > MAX_NORMALIZATION_FACTOR ? MAX_NORMALIZATION_FACTOR : sigma;
|
46
|
+
sigma = SAFEDIV_POS(1.0, sigma);
|
47
|
+
|
48
|
+
/* Scale b, c */
|
49
|
+
SCS(scale_array)(c, sigma, scal->n);
|
50
|
+
SCS(scale_array)(b, sigma, scal->m);
|
51
|
+
|
52
|
+
/* We assume that primal_scale = dual_scale, otherwise need to refactorize */
|
53
|
+
scal->primal_scale = sigma;
|
54
|
+
scal->dual_scale = sigma;
|
55
|
+
}
|
56
|
+
|
6
57
|
/* needed for normalizing the warm-start */
|
7
58
|
void SCS(normalize_sol)(ScsScaling *scal, ScsSolution *sol) {
|
8
59
|
scs_int i;
|