scs 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/scs/ffi.rb +2 -2
- data/lib/scs/version.rb +1 -1
- data/lib/scs.rb +3 -3
- data/vendor/scs/CITATION.cff +2 -2
- data/vendor/scs/CMakeLists.txt +305 -171
- data/vendor/scs/Makefile +44 -19
- data/vendor/scs/README.md +1 -1
- data/vendor/scs/include/glbopts.h +34 -14
- data/vendor/scs/include/linsys.h +8 -8
- data/vendor/scs/include/scs.h +6 -2
- data/vendor/scs/include/scs_blas.h +4 -0
- 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 +40 -27
- data/vendor/scs/src/cones.c +17 -161
- data/vendor/scs/src/exp_cone.c +399 -0
- data/vendor/scs/src/linalg.c +17 -3
- data/vendor/scs/src/normalize.c +4 -2
- data/vendor/scs/src/rw.c +107 -38
- data/vendor/scs/src/scs.c +103 -69
- 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/mpc_bug.h +19 -0
- data/vendor/scs/test/problems/mpc_bug1 +0 -0
- data/vendor/scs/test/problems/mpc_bug2 +0 -0
- data/vendor/scs/test/problems/mpc_bug3 +0 -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 +73 -0
- data/vendor/scs/test/run_from_file.c +7 -1
- data/vendor/scs/test/run_tests.c +25 -9
- metadata +14 -3
data/vendor/scs/src/cones.c
CHANGED
@@ -4,10 +4,8 @@
|
|
4
4
|
#include "scs_blas.h" /* contains BLAS(X) macros and type info */
|
5
5
|
#include "util.h"
|
6
6
|
|
7
|
-
#define CONE_TOL (1e-9)
|
8
|
-
#define CONE_THRESH (1e-8)
|
9
|
-
#define EXP_CONE_MAX_ITERS (100)
|
10
7
|
#define BOX_CONE_MAX_ITERS (25)
|
8
|
+
#define POW_CONE_TOL (1e-9)
|
11
9
|
#define POW_CONE_MAX_ITERS (20)
|
12
10
|
|
13
11
|
/* Box cone limits (+ or -) taken to be INF */
|
@@ -35,6 +33,11 @@ void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
|
|
35
33
|
|
36
34
|
#endif
|
37
35
|
|
36
|
+
/* Forward declare exponential cone projection routine.
|
37
|
+
* Implemented in exp_cone.c.
|
38
|
+
*/
|
39
|
+
scs_float SCS(proj_pd_exp_cone)(scs_float *v0, scs_int primal);
|
40
|
+
|
38
41
|
void SCS(free_cone)(ScsCone *k) {
|
39
42
|
if (k) {
|
40
43
|
if (k->bu)
|
@@ -285,7 +288,7 @@ void SCS(finish_cone)(ScsConeWork *c) {
|
|
285
288
|
}
|
286
289
|
|
287
290
|
char *SCS(get_cone_header)(const ScsCone *k) {
|
288
|
-
char *tmp = (char *)scs_malloc(sizeof(char)
|
291
|
+
char *tmp = (char *)scs_malloc(512); /* sizeof(char) = 1 */
|
289
292
|
scs_int i, soc_vars, sd_vars;
|
290
293
|
sprintf(tmp, "cones: ");
|
291
294
|
if (k->z) {
|
@@ -325,122 +328,10 @@ char *SCS(get_cone_header)(const ScsCone *k) {
|
|
325
328
|
return tmp;
|
326
329
|
}
|
327
330
|
|
328
|
-
static scs_float exp_newton_one_d(scs_float rho, scs_float y_hat,
|
329
|
-
scs_float z_hat, scs_float w) {
|
330
|
-
scs_float t_prev, t = MAX(w - z_hat, MAX(-z_hat, 1e-9));
|
331
|
-
scs_float f = 1., fp = 1.;
|
332
|
-
scs_int i;
|
333
|
-
for (i = 0; i < EXP_CONE_MAX_ITERS; ++i) {
|
334
|
-
t_prev = t;
|
335
|
-
f = t * (t + z_hat) / rho / rho - y_hat / rho + log(t / rho) + 1;
|
336
|
-
fp = (2 * t + z_hat) / rho / rho + 1 / t;
|
337
|
-
|
338
|
-
t = t - f / fp;
|
339
|
-
|
340
|
-
if (t <= -z_hat) {
|
341
|
-
t = -z_hat;
|
342
|
-
break;
|
343
|
-
} else if (t <= 0) {
|
344
|
-
t = 0;
|
345
|
-
break;
|
346
|
-
} else if (ABS(t - t_prev) < CONE_TOL) {
|
347
|
-
break;
|
348
|
-
} else if (SQRTF(f * f / fp) < CONE_TOL) {
|
349
|
-
break;
|
350
|
-
}
|
351
|
-
}
|
352
|
-
if (i == EXP_CONE_MAX_ITERS) {
|
353
|
-
scs_printf("warning: exp cone newton step hit maximum %i iters\n", (int)i);
|
354
|
-
scs_printf("rho=%1.5e; y_hat=%1.5e; z_hat=%1.5e; w=%1.5e; f=%1.5e, "
|
355
|
-
"fp=%1.5e, t=%1.5e, t_prev= %1.5e\n",
|
356
|
-
rho, y_hat, z_hat, w, f, fp, t, t_prev);
|
357
|
-
}
|
358
|
-
return t + z_hat;
|
359
|
-
}
|
360
|
-
|
361
|
-
static void exp_solve_for_x_with_rho(const scs_float *v, scs_float *x,
|
362
|
-
scs_float rho, scs_float w) {
|
363
|
-
x[2] = exp_newton_one_d(rho, v[1], v[2], w);
|
364
|
-
x[1] = (x[2] - v[2]) * x[2] / rho;
|
365
|
-
x[0] = v[0] - rho;
|
366
|
-
}
|
367
|
-
|
368
|
-
static scs_float exp_calc_grad(const scs_float *v, scs_float *x, scs_float rho,
|
369
|
-
scs_float w) {
|
370
|
-
exp_solve_for_x_with_rho(v, x, rho, w);
|
371
|
-
if (x[1] <= 1e-12) {
|
372
|
-
return x[0];
|
373
|
-
}
|
374
|
-
return x[0] + x[1] * log(x[1] / x[2]);
|
375
|
-
}
|
376
|
-
|
377
|
-
static void exp_get_rho_ub(const scs_float *v, scs_float *x, scs_float *ub,
|
378
|
-
scs_float *lb) {
|
379
|
-
*lb = 0;
|
380
|
-
*ub = 0.125;
|
381
|
-
while (exp_calc_grad(v, x, *ub, v[1]) > 0) {
|
382
|
-
*lb = *ub;
|
383
|
-
(*ub) *= 2;
|
384
|
-
}
|
385
|
-
}
|
386
|
-
|
387
|
-
/* project onto the exponential cone, v has dimension *exactly* 3 */
|
388
|
-
static scs_int proj_exp_cone(scs_float *v) {
|
389
|
-
scs_int i;
|
390
|
-
scs_float ub, lb, rho, g, x[3];
|
391
|
-
scs_float r = v[0], s = v[1], t = v[2];
|
392
|
-
|
393
|
-
/* v in cl(Kexp) */
|
394
|
-
if ((s * exp(r / s) - t <= CONE_THRESH && s > 0) ||
|
395
|
-
(r <= 0 && s == 0 && t >= 0)) {
|
396
|
-
return 0;
|
397
|
-
}
|
398
|
-
|
399
|
-
/* -v in Kexp^* */
|
400
|
-
if ((r > 0 && r * exp(s / r) + exp(1) * t <= CONE_THRESH) ||
|
401
|
-
(r == 0 && s <= 0 && t <= 0)) {
|
402
|
-
memset(v, 0, 3 * sizeof(scs_float));
|
403
|
-
return 0;
|
404
|
-
}
|
405
|
-
|
406
|
-
/* special case with analytical solution */
|
407
|
-
if (r < 0 && s < 0) {
|
408
|
-
v[1] = 0.0;
|
409
|
-
v[2] = MAX(v[2], 0);
|
410
|
-
return 0;
|
411
|
-
}
|
412
|
-
|
413
|
-
/* iterative procedure to find projection, bisects on dual variable: */
|
414
|
-
exp_get_rho_ub(v, x, &ub, &lb); /* get starting upper and lower bounds */
|
415
|
-
for (i = 0; i < EXP_CONE_MAX_ITERS; ++i) {
|
416
|
-
rho = (ub + lb) / 2; /* halfway between upper and lower bounds */
|
417
|
-
g = exp_calc_grad(v, x, rho, x[1]); /* calculates gradient wrt dual var */
|
418
|
-
if (g > 0) {
|
419
|
-
lb = rho;
|
420
|
-
} else {
|
421
|
-
ub = rho;
|
422
|
-
}
|
423
|
-
if (ub - lb < CONE_TOL) {
|
424
|
-
break;
|
425
|
-
}
|
426
|
-
}
|
427
|
-
#if VERBOSITY > 10
|
428
|
-
scs_printf("exponential cone proj iters %i\n", (int)i);
|
429
|
-
#endif
|
430
|
-
if (i == EXP_CONE_MAX_ITERS) {
|
431
|
-
scs_printf("warning: exp cone outer step hit maximum %i iters\n", (int)i);
|
432
|
-
scs_printf("r=%1.5e; s=%1.5e; t=%1.5e\n", r, s, t);
|
433
|
-
}
|
434
|
-
v[0] = x[0];
|
435
|
-
v[1] = x[1];
|
436
|
-
v[2] = x[2];
|
437
|
-
return 0;
|
438
|
-
}
|
439
|
-
|
440
331
|
static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
441
332
|
scs_int i;
|
442
333
|
#ifdef USE_LAPACK
|
443
|
-
blas_int n_max =
|
334
|
+
blas_int n_max = 1;
|
444
335
|
blas_int neg_one = -1;
|
445
336
|
blas_int info = 0;
|
446
337
|
scs_float wkopt = 0.0;
|
@@ -465,7 +356,7 @@ static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
465
356
|
&info);
|
466
357
|
|
467
358
|
if (info != 0) {
|
468
|
-
scs_printf("FATAL: syev failure, info = %li\n", (long)info);
|
359
|
+
scs_printf("FATAL: syev workspace query failure, info = %li\n", (long)info);
|
469
360
|
return -1;
|
470
361
|
}
|
471
362
|
c->lwork = (blas_int)(wkopt + 1); /* +1 for int casting safety */
|
@@ -741,13 +632,13 @@ static void proj_power_cone(scs_float *v, scs_float a) {
|
|
741
632
|
scs_int i;
|
742
633
|
/* v in K_a */
|
743
634
|
if (xh >= 0 && yh >= 0 &&
|
744
|
-
|
635
|
+
POW_CONE_TOL + POWF(xh, a) * POWF(yh, (1 - a)) >= rh) {
|
745
636
|
return;
|
746
637
|
}
|
747
638
|
|
748
639
|
/* -v in K_a^* */
|
749
640
|
if (xh <= 0 && yh <= 0 &&
|
750
|
-
|
641
|
+
POW_CONE_TOL + POWF(-xh, a) * POWF(-yh, 1 - a) >=
|
751
642
|
rh * POWF(a, a) * POWF(1 - a, 1 - a)) {
|
752
643
|
v[0] = v[1] = v[2] = 0;
|
753
644
|
return;
|
@@ -760,7 +651,7 @@ static void proj_power_cone(scs_float *v, scs_float a) {
|
|
760
651
|
y = pow_calc_x(r, yh, rh, 1 - a);
|
761
652
|
|
762
653
|
f = pow_calc_f(x, y, r, a);
|
763
|
-
if (ABS(f) <
|
654
|
+
if (ABS(f) < POW_CONE_TOL) {
|
764
655
|
break;
|
765
656
|
}
|
766
657
|
|
@@ -829,51 +720,16 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
829
720
|
}
|
830
721
|
}
|
831
722
|
|
832
|
-
if (k->ep) { /* doesn't use r_y */
|
833
|
-
/*
|
834
|
-
* exponential cone is not self dual, if s \in K
|
835
|
-
* then y \in K^* and so if K is the primal cone
|
836
|
-
* here we project onto K^*, via Moreau
|
837
|
-
* \Pi_C^*(y) = y + \Pi_C(-y)
|
838
|
-
*/
|
723
|
+
if (k->ep || k->ed) { /* doesn't use r_y */
|
839
724
|
#ifdef _OPENMP
|
840
725
|
#pragma omp parallel for
|
841
726
|
#endif
|
842
|
-
for (i = 0; i < k->ep; ++i) {
|
843
|
-
|
727
|
+
for (i = 0; i < k->ep + k->ed; ++i) {
|
728
|
+
/* provided in exp_cone.c */
|
729
|
+
SCS(proj_pd_exp_cone)(&(x[count + 3 * i]), i < k->ep);
|
844
730
|
}
|
845
|
-
count += 3 * k->ep;
|
731
|
+
count += 3 * (k->ep + k->ed);
|
846
732
|
}
|
847
|
-
|
848
|
-
/* dual exponential cone */
|
849
|
-
if (k->ed) { /* doesn't use r_y */
|
850
|
-
/*
|
851
|
-
* exponential cone is not self dual, if s \in K
|
852
|
-
* then y \in K^* and so if K is the primal cone
|
853
|
-
* here we project onto K^*, via Moreau
|
854
|
-
* \Pi_C^*(y) = y + \Pi_C(-y)
|
855
|
-
*/
|
856
|
-
scs_int idx;
|
857
|
-
scs_float r, s, t;
|
858
|
-
SCS(scale_array)(&(x[count]), -1, 3 * k->ed); /* x = -x; */
|
859
|
-
#ifdef _OPENMP
|
860
|
-
#pragma omp parallel for private(r, s, t, idx)
|
861
|
-
#endif
|
862
|
-
for (i = 0; i < k->ed; ++i) {
|
863
|
-
idx = count + 3 * i;
|
864
|
-
r = x[idx];
|
865
|
-
s = x[idx + 1];
|
866
|
-
t = x[idx + 2];
|
867
|
-
|
868
|
-
proj_exp_cone(&(x[idx]));
|
869
|
-
|
870
|
-
x[idx] -= r;
|
871
|
-
x[idx + 1] -= s;
|
872
|
-
x[idx + 2] -= t;
|
873
|
-
}
|
874
|
-
count += 3 * k->ed;
|
875
|
-
}
|
876
|
-
|
877
733
|
if (k->psize && k->p) { /* doesn't use r_y */
|
878
734
|
scs_float v[3];
|
879
735
|
scs_int idx;
|
@@ -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/linalg.c
CHANGED
@@ -102,12 +102,16 @@ extern "C" {
|
|
102
102
|
scs_float BLAS(nrm2)(blas_int *n, const scs_float *x, blas_int *incx);
|
103
103
|
scs_float BLAS(dot)(const blas_int *n, const scs_float *x, const blas_int *incx,
|
104
104
|
const scs_float *y, const blas_int *incy);
|
105
|
-
scs_float BLAS(lange)(const char *norm, const blas_int *m, const blas_int *n,
|
106
|
-
const scs_float *a, blas_int *lda, scs_float *work);
|
107
105
|
void BLAS(axpy)(blas_int *n, const scs_float *a, const scs_float *x,
|
108
106
|
blas_int *incx, scs_float *y, blas_int *incy);
|
109
107
|
void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
|
110
108
|
const blas_int *incx);
|
109
|
+
blas_int BLASI(amax)(blas_int *n, const scs_float *x, blas_int *incx);
|
110
|
+
|
111
|
+
/* Possibly not working correctly on all platforms.
|
112
|
+
scs_float BLAS(lange)(const char *norm, const blas_int *m, const blas_int *n,
|
113
|
+
const scs_float *a, blas_int *lda, scs_float *work);
|
114
|
+
*/
|
111
115
|
|
112
116
|
#ifdef __cplusplus
|
113
117
|
}
|
@@ -140,10 +144,20 @@ scs_float SCS(norm_2)(const scs_float *v, scs_int len) {
|
|
140
144
|
return BLAS(nrm2)(&blen, v, &bone);
|
141
145
|
}
|
142
146
|
|
147
|
+
/* Possibly not working correctly on all platforms.
|
148
|
+
scs_float SCS(norm_inf)(const scs_float *a, scs_int len) {
|
149
|
+
blas_int bone = 1;
|
150
|
+
blas_int blen = (blas_int)len;
|
151
|
+
return BLAS(lange)("Max", &blen, &bone, a, &blen, SCS_NULL);
|
152
|
+
}
|
153
|
+
*/
|
154
|
+
|
143
155
|
scs_float SCS(norm_inf)(const scs_float *a, scs_int len) {
|
144
156
|
blas_int bone = 1;
|
145
157
|
blas_int blen = (blas_int)len;
|
146
|
-
|
158
|
+
scs_int idx = (scs_int)BLASI(amax)(&blen, a, &bone);
|
159
|
+
/* Returned idx is 1-based. */
|
160
|
+
return ABS(a[idx - 1]);
|
147
161
|
}
|
148
162
|
|
149
163
|
/* axpy a += sc*b */
|
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);
|