scs 0.4.0 → 0.4.2
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 +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);
|