scs 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +42 -13
- data/lib/scs/ffi.rb +1 -7
- 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 +1 -1
- data/vendor/scs/CMakeLists.txt +55 -7
- data/vendor/scs/Makefile +9 -9
- data/vendor/scs/README.md +4 -1
- data/vendor/scs/include/aa.h +1 -1
- data/vendor/scs/include/cones.h +17 -12
- data/vendor/scs/include/glbopts.h +27 -66
- data/vendor/scs/include/linalg.h +2 -1
- data/vendor/scs/include/linsys.h +13 -13
- data/vendor/scs/include/normalize.h +7 -5
- data/vendor/scs/include/rw.h +3 -3
- data/vendor/scs/include/scs.h +85 -106
- data/vendor/scs/include/scs_types.h +34 -0
- data/vendor/scs/include/scs_work.h +80 -0
- data/vendor/scs/include/util.h +3 -1
- data/vendor/scs/linsys/cpu/direct/private.c +86 -73
- data/vendor/scs/linsys/cpu/direct/private.h +2 -2
- data/vendor/scs/linsys/cpu/indirect/private.c +42 -33
- data/vendor/scs/linsys/cpu/indirect/private.h +1 -2
- data/vendor/scs/linsys/csparse.c +3 -3
- data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +9 -7
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +1 -1
- data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
- data/vendor/scs/linsys/gpu/gpu.h +8 -11
- data/vendor/scs/linsys/gpu/indirect/private.c +72 -49
- data/vendor/scs/linsys/gpu/indirect/private.h +14 -13
- data/vendor/scs/linsys/scs_matrix.c +55 -104
- data/vendor/scs/linsys/scs_matrix.h +5 -4
- data/vendor/scs/scs.mk +1 -5
- data/vendor/scs/src/aa.c +13 -8
- data/vendor/scs/src/cones.c +197 -108
- data/vendor/scs/src/linalg.c +25 -0
- data/vendor/scs/src/normalize.c +75 -26
- data/vendor/scs/src/rw.c +74 -30
- data/vendor/scs/src/scs.c +300 -264
- data/vendor/scs/src/scs_version.c +8 -6
- data/vendor/scs/src/util.c +27 -13
- data/vendor/scs/test/minunit.h +6 -1
- data/vendor/scs/test/problem_utils.h +28 -35
- data/vendor/scs/test/problems/degenerate.h +2 -1
- data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +6 -2
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +2 -1
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +5 -4
- data/vendor/scs/test/problems/random_prob.h +6 -2
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +9 -2
- data/vendor/scs/test/problems/small_lp.h +7 -2
- data/vendor/scs/test/problems/small_qp.h +387 -0
- data/vendor/scs/test/problems/{test_fails.h → test_validation.h} +7 -4
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +4 -4
- data/vendor/scs/test/random_socp_prob.c +4 -2
- data/vendor/scs/test/run_from_file.c +16 -4
- data/vendor/scs/test/run_tests.c +23 -14
- metadata +10 -35
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
- data/vendor/scs/linsys/csparse.o +0 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
- data/vendor/scs/linsys/scs_matrix.o +0 -0
- data/vendor/scs/src/aa.o +0 -0
- data/vendor/scs/src/cones.o +0 -0
- data/vendor/scs/src/ctrlc.o +0 -0
- data/vendor/scs/src/linalg.o +0 -0
- data/vendor/scs/src/normalize.o +0 -0
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.o +0 -0
- data/vendor/scs/src/scs_indir.o +0 -0
- data/vendor/scs/src/scs_version.o +0 -0
- data/vendor/scs/src/util.o +0 -0
data/vendor/scs/src/cones.c
CHANGED
|
@@ -10,18 +10,15 @@
|
|
|
10
10
|
#define BOX_CONE_MAX_ITERS (25)
|
|
11
11
|
#define POW_CONE_MAX_ITERS (20)
|
|
12
12
|
|
|
13
|
-
/* In the box cone projection we penalize the `t` term additionally by this
|
|
14
|
-
* factor. This encourages the `t` term to stay close to the incoming `t` term,
|
|
15
|
-
* which should provide better convergence since typically the `t` term does
|
|
16
|
-
* not appear in the linear system other than `t = 1`. Setting to 1 is
|
|
17
|
-
* the vanilla projection.
|
|
18
|
-
*/
|
|
19
|
-
#define BOX_T_SCALE (1.)
|
|
20
|
-
|
|
21
13
|
/* Box cone limits (+ or -) taken to be INF */
|
|
22
14
|
#define MAX_BOX_VAL (1e15)
|
|
23
15
|
|
|
24
16
|
#ifdef USE_LAPACK
|
|
17
|
+
|
|
18
|
+
#ifdef __cplusplus
|
|
19
|
+
extern "C" {
|
|
20
|
+
#endif
|
|
21
|
+
|
|
25
22
|
void BLAS(syev)(const char *jobz, const char *uplo, blas_int *n, scs_float *a,
|
|
26
23
|
blas_int *lda, scs_float *w, scs_float *work, blas_int *lwork,
|
|
27
24
|
blas_int *info);
|
|
@@ -31,34 +28,94 @@ blas_int BLAS(syrk)(const char *uplo, const char *trans, const blas_int *n,
|
|
|
31
28
|
const scs_float *beta, scs_float *c, const blas_int *ldc);
|
|
32
29
|
void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
|
|
33
30
|
const blas_int *incx);
|
|
31
|
+
|
|
32
|
+
#ifdef __cplusplus
|
|
33
|
+
}
|
|
34
|
+
#endif
|
|
35
|
+
|
|
34
36
|
#endif
|
|
35
37
|
|
|
38
|
+
void SCS(free_cone)(ScsCone *k) {
|
|
39
|
+
if (k) {
|
|
40
|
+
if (k->bu)
|
|
41
|
+
scs_free(k->bu);
|
|
42
|
+
if (k->bl)
|
|
43
|
+
scs_free(k->bl);
|
|
44
|
+
if (k->q)
|
|
45
|
+
scs_free(k->q);
|
|
46
|
+
if (k->s)
|
|
47
|
+
scs_free(k->s);
|
|
48
|
+
if (k->p)
|
|
49
|
+
scs_free(k->p);
|
|
50
|
+
scs_free(k);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void SCS(deep_copy_cone)(ScsCone *dest, const ScsCone *src) {
|
|
55
|
+
memcpy(dest, src, sizeof(ScsCone));
|
|
56
|
+
/* copy bu, bl */
|
|
57
|
+
if (src->bsize > 1) {
|
|
58
|
+
dest->bu = (scs_float *)scs_calloc(src->bsize - 1, sizeof(scs_float));
|
|
59
|
+
memcpy(dest->bu, src->bu, (src->bsize - 1) * sizeof(scs_float));
|
|
60
|
+
dest->bl = (scs_float *)scs_calloc(src->bsize - 1, sizeof(scs_float));
|
|
61
|
+
memcpy(dest->bl, src->bl, (src->bsize - 1) * sizeof(scs_float));
|
|
62
|
+
} else {
|
|
63
|
+
dest->bu = SCS_NULL;
|
|
64
|
+
dest->bl = SCS_NULL;
|
|
65
|
+
}
|
|
66
|
+
/* copy SOC */
|
|
67
|
+
if (src->qsize > 0) {
|
|
68
|
+
dest->q = (scs_int *)scs_calloc(src->qsize, sizeof(scs_int));
|
|
69
|
+
memcpy(dest->q, src->q, src->qsize * sizeof(scs_int));
|
|
70
|
+
} else {
|
|
71
|
+
dest->q = SCS_NULL;
|
|
72
|
+
}
|
|
73
|
+
/* copy PSD cone */
|
|
74
|
+
if (src->ssize > 0) {
|
|
75
|
+
dest->s = (scs_int *)scs_calloc(src->ssize, sizeof(scs_int));
|
|
76
|
+
memcpy(dest->s, src->s, src->ssize * sizeof(scs_int));
|
|
77
|
+
} else {
|
|
78
|
+
dest->s = SCS_NULL;
|
|
79
|
+
}
|
|
80
|
+
/* copy power cone */
|
|
81
|
+
if (src->psize > 0) {
|
|
82
|
+
dest->p = (scs_float *)scs_calloc(src->psize, sizeof(scs_float));
|
|
83
|
+
memcpy(dest->p, src->p, src->psize * sizeof(scs_float));
|
|
84
|
+
} else {
|
|
85
|
+
dest->p = SCS_NULL;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
36
89
|
/* set the vector of rho y terms, based on scale and cones */
|
|
37
|
-
void SCS(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
for (i = 0; i < k->z; ++i) {
|
|
90
|
+
void SCS(set_r_y)(const ScsConeWork *c, scs_float scale, scs_float *r_y) {
|
|
91
|
+
scs_int i;
|
|
92
|
+
/* z cone */
|
|
93
|
+
for (i = 0; i < c->k->z; ++i) {
|
|
42
94
|
/* set rho_y small for z, similar to rho_x term, since z corresponds to
|
|
43
95
|
* dual free cone, this effectively decreases penalty on those entries
|
|
44
96
|
* and lets them be determined almost entirely by the linear system solve
|
|
45
97
|
*/
|
|
46
|
-
|
|
98
|
+
r_y[i] = 1.0 / (1000. * scale);
|
|
47
99
|
}
|
|
48
|
-
count += k->z;
|
|
49
100
|
/* others */
|
|
50
|
-
for (i =
|
|
51
|
-
|
|
101
|
+
for (i = c->k->z; i < c->m; ++i) {
|
|
102
|
+
r_y[i] = 1.0 / scale;
|
|
52
103
|
}
|
|
104
|
+
}
|
|
53
105
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
106
|
+
/* the function f aggregates the entries within each cone */
|
|
107
|
+
void SCS(enforce_cone_boundaries)(const ScsConeWork *c, scs_float *vec,
|
|
108
|
+
scs_float (*f)(const scs_float *, scs_int)) {
|
|
109
|
+
scs_int i, j, delta;
|
|
110
|
+
scs_int count = c->cone_boundaries[0];
|
|
111
|
+
scs_float wrk;
|
|
112
|
+
for (i = 1; i < c->cone_boundaries_len; ++i) {
|
|
113
|
+
delta = c->cone_boundaries[i];
|
|
114
|
+
wrk = f(&(vec[count]), delta);
|
|
115
|
+
for (j = count; j < count + delta; ++j) {
|
|
116
|
+
vec[j] = wrk;
|
|
117
|
+
}
|
|
118
|
+
count += delta;
|
|
62
119
|
}
|
|
63
120
|
}
|
|
64
121
|
|
|
@@ -71,7 +128,7 @@ static inline scs_int get_sd_cone_size(scs_int s) {
|
|
|
71
128
|
* cone boundaries, boundaries[0] is starting index for cones of size strictly
|
|
72
129
|
* larger than 1, boundaries malloc-ed here so should be freed.
|
|
73
130
|
*/
|
|
74
|
-
|
|
131
|
+
void set_cone_boundaries(const ScsCone *k, ScsConeWork *c) {
|
|
75
132
|
scs_int i, s_cone_sz, count = 0;
|
|
76
133
|
scs_int cone_boundaries_len =
|
|
77
134
|
1 + k->qsize + k->ssize + k->ed + k->ep + k->psize;
|
|
@@ -99,8 +156,8 @@ scs_int SCS(set_cone_boundaries)(const ScsCone *k, scs_int **cone_boundaries) {
|
|
|
99
156
|
}
|
|
100
157
|
count += k->psize;
|
|
101
158
|
/* other cones */
|
|
102
|
-
|
|
103
|
-
|
|
159
|
+
c->cone_boundaries = b;
|
|
160
|
+
c->cone_boundaries_len = cone_boundaries_len;
|
|
104
161
|
}
|
|
105
162
|
|
|
106
163
|
static scs_int get_full_cone_dims(const ScsCone *k) {
|
|
@@ -121,7 +178,7 @@ static scs_int get_full_cone_dims(const ScsCone *k) {
|
|
|
121
178
|
if (k->ep) {
|
|
122
179
|
c += 3 * k->ep;
|
|
123
180
|
}
|
|
124
|
-
if (k->
|
|
181
|
+
if (k->psize) {
|
|
125
182
|
c += 3 * k->psize;
|
|
126
183
|
}
|
|
127
184
|
return c;
|
|
@@ -216,15 +273,12 @@ void SCS(finish_cone)(ScsConeWork *c) {
|
|
|
216
273
|
scs_free(c->work);
|
|
217
274
|
}
|
|
218
275
|
#endif
|
|
276
|
+
if (c->cone_boundaries) {
|
|
277
|
+
scs_free(c->cone_boundaries);
|
|
278
|
+
}
|
|
219
279
|
if (c->s) {
|
|
220
280
|
scs_free(c->s);
|
|
221
281
|
}
|
|
222
|
-
if (c->bu) {
|
|
223
|
-
scs_free(c->bu);
|
|
224
|
-
}
|
|
225
|
-
if (c->bl) {
|
|
226
|
-
scs_free(c->bl);
|
|
227
|
-
}
|
|
228
282
|
if (c) {
|
|
229
283
|
scs_free(c);
|
|
230
284
|
}
|
|
@@ -484,7 +538,7 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
|
484
538
|
/* Solve eigenproblem, reuse workspaces */
|
|
485
539
|
BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
|
|
486
540
|
if (info != 0) {
|
|
487
|
-
scs_printf("WARN: LAPACK syev error, info = %i\n", info);
|
|
541
|
+
scs_printf("WARN: LAPACK syev error, info = %i\n", (int)info);
|
|
488
542
|
if (info < 0) {
|
|
489
543
|
return info;
|
|
490
544
|
}
|
|
@@ -571,52 +625,56 @@ static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
|
|
|
571
625
|
* { (t', s') | t' * l' <= s' <= t' u', t >= 0 } = K'
|
|
572
626
|
* where l' = D l / d0, u' = D u / d0.
|
|
573
627
|
*/
|
|
574
|
-
static void normalize_box_cone(
|
|
628
|
+
static void normalize_box_cone(ScsCone *k, scs_float *D, scs_int bsize) {
|
|
575
629
|
scs_int j;
|
|
576
630
|
for (j = 0; j < bsize - 1; j++) {
|
|
577
|
-
if (
|
|
578
|
-
|
|
631
|
+
if (k->bu[j] >= MAX_BOX_VAL) {
|
|
632
|
+
k->bu[j] = INFINITY;
|
|
579
633
|
} else {
|
|
580
|
-
|
|
634
|
+
k->bu[j] = D ? D[j + 1] * k->bu[j] / D[0] : k->bu[j];
|
|
581
635
|
}
|
|
582
|
-
if (
|
|
583
|
-
|
|
636
|
+
if (k->bl[j] <= -MAX_BOX_VAL) {
|
|
637
|
+
k->bl[j] = -INFINITY;
|
|
584
638
|
} else {
|
|
585
|
-
|
|
639
|
+
k->bl[j] = D ? D[j + 1] * k->bl[j] / D[0] : k->bl[j];
|
|
586
640
|
}
|
|
587
641
|
}
|
|
588
642
|
}
|
|
589
643
|
|
|
590
|
-
/*
|
|
591
|
-
tx = [t; s], total length = bsize
|
|
592
|
-
uses Moreau since \Pi_K*(tx) = \Pi_K(-tx) + tx
|
|
644
|
+
/* Project onto { (t, s) | t * l <= s <= t * u, t >= 0 }, Newton's method on t
|
|
645
|
+
tx = [t; s], total length = bsize, under Euclidean metric 1/r_box.
|
|
593
646
|
*/
|
|
594
647
|
static scs_float proj_box_cone(scs_float *tx, const scs_float *bl,
|
|
595
648
|
const scs_float *bu, scs_int bsize,
|
|
596
|
-
scs_float t_warm_start) {
|
|
649
|
+
scs_float t_warm_start, scs_float *r_box) {
|
|
597
650
|
scs_float *x, gt, ht, t_prev, t = t_warm_start;
|
|
651
|
+
scs_float rho_t = 1, *rho = SCS_NULL, r;
|
|
598
652
|
scs_int iter, j;
|
|
599
653
|
|
|
600
654
|
if (bsize == 1) { /* special case */
|
|
601
655
|
tx[0] = MAX(tx[0], 0.0);
|
|
602
656
|
return tx[0];
|
|
603
657
|
}
|
|
604
|
-
|
|
605
658
|
x = &(tx[1]);
|
|
606
659
|
|
|
660
|
+
if (r_box) {
|
|
661
|
+
rho_t = 1.0 / r_box[0];
|
|
662
|
+
rho = &(r_box[1]);
|
|
663
|
+
}
|
|
664
|
+
|
|
607
665
|
/* should only require about 5 or so iterations, 1 or 2 if warm-started */
|
|
608
666
|
for (iter = 0; iter < BOX_CONE_MAX_ITERS; iter++) {
|
|
609
667
|
t_prev = t;
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
ht = BOX_T_SCALE; /* hessian */
|
|
668
|
+
gt = rho_t * (t - tx[0]); /* gradient */
|
|
669
|
+
ht = rho_t; /* hessian */
|
|
613
670
|
for (j = 0; j < bsize - 1; j++) {
|
|
671
|
+
r = rho ? 1.0 / rho[j] : 1.;
|
|
614
672
|
if (x[j] > t * bu[j]) {
|
|
615
|
-
gt += (t * bu[j] - x[j]) * bu[j]; /* gradient */
|
|
616
|
-
ht += bu[j] * bu[j]; /* hessian */
|
|
673
|
+
gt += r * (t * bu[j] - x[j]) * bu[j]; /* gradient */
|
|
674
|
+
ht += r * bu[j] * bu[j]; /* hessian */
|
|
617
675
|
} else if (x[j] < t * bl[j]) {
|
|
618
|
-
gt += (t * bl[j] - x[j]) * bl[j]; /* gradient */
|
|
619
|
-
ht += bl[j] * bl[j]; /* hessian */
|
|
676
|
+
gt += r * (t * bl[j] - x[j]) * bl[j]; /* gradient */
|
|
677
|
+
ht += r * bl[j] * bl[j]; /* hessian */
|
|
620
678
|
}
|
|
621
679
|
}
|
|
622
680
|
t = MAX(t - gt / MAX(ht, 1e-8), 0.); /* newton step */
|
|
@@ -647,6 +705,7 @@ static scs_float proj_box_cone(scs_float *tx, const scs_float *bl,
|
|
|
647
705
|
/* x[j] unchanged otherwise */
|
|
648
706
|
}
|
|
649
707
|
tx[0] = t;
|
|
708
|
+
|
|
650
709
|
#if VERBOSITY > 3
|
|
651
710
|
scs_printf("box cone iters %i\n", (int)iter + 1);
|
|
652
711
|
#endif
|
|
@@ -718,18 +777,22 @@ static void proj_power_cone(scs_float *v, scs_float a) {
|
|
|
718
777
|
}
|
|
719
778
|
|
|
720
779
|
/* project onto the primal K cone in the paper */
|
|
780
|
+
/* the r_y vector determines the INVERSE metric, ie, project under the
|
|
781
|
+
* diag(r_y)^-1 norm.
|
|
782
|
+
*/
|
|
721
783
|
static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
722
|
-
scs_int normalize) {
|
|
784
|
+
scs_int normalize, scs_float *r_y) {
|
|
723
785
|
scs_int i, status;
|
|
724
786
|
scs_int count = 0;
|
|
787
|
+
scs_float *r_box = SCS_NULL;
|
|
725
788
|
|
|
726
|
-
if (k->z) {
|
|
789
|
+
if (k->z) { /* doesn't use r_y */
|
|
727
790
|
/* project onto primal zero / dual free cone */
|
|
728
791
|
memset(x, 0, k->z * sizeof(scs_float));
|
|
729
792
|
count += k->z;
|
|
730
793
|
}
|
|
731
794
|
|
|
732
|
-
if (k->l) {
|
|
795
|
+
if (k->l) { /* doesn't use r_y */
|
|
733
796
|
/* project onto positive orthant */
|
|
734
797
|
for (i = count; i < count + k->l; ++i) {
|
|
735
798
|
x[i] = MAX(x[i], 0.0);
|
|
@@ -737,19 +800,17 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
737
800
|
count += k->l;
|
|
738
801
|
}
|
|
739
802
|
|
|
740
|
-
if (k->bsize) {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
c->box_t_warm_start = proj_box_cone(&(x[count]), c->bl, c->bu, k->bsize,
|
|
744
|
-
c->box_t_warm_start);
|
|
745
|
-
} else {
|
|
746
|
-
c->box_t_warm_start = proj_box_cone(&(x[count]), k->bl, k->bu, k->bsize,
|
|
747
|
-
c->box_t_warm_start);
|
|
803
|
+
if (k->bsize) { /* DOES use r_y */
|
|
804
|
+
if (r_y) {
|
|
805
|
+
r_box = &(r_y[count]);
|
|
748
806
|
}
|
|
807
|
+
/* project onto box cone */
|
|
808
|
+
c->box_t_warm_start = proj_box_cone(&(x[count]), k->bl, k->bu, k->bsize,
|
|
809
|
+
c->box_t_warm_start, r_box);
|
|
749
810
|
count += k->bsize; /* since b = (t,s), len(s) = bsize - 1 */
|
|
750
811
|
}
|
|
751
812
|
|
|
752
|
-
if (k->qsize && k->q) {
|
|
813
|
+
if (k->qsize && k->q) { /* doesn't use r_y */
|
|
753
814
|
/* project onto second-order cones */
|
|
754
815
|
for (i = 0; i < k->qsize; ++i) {
|
|
755
816
|
proj_soc(&(x[count]), k->q[i]);
|
|
@@ -757,7 +818,7 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
757
818
|
}
|
|
758
819
|
}
|
|
759
820
|
|
|
760
|
-
if (k->ssize && k->s) {
|
|
821
|
+
if (k->ssize && k->s) { /* doesn't use r_y */
|
|
761
822
|
/* project onto PSD cones */
|
|
762
823
|
for (i = 0; i < k->ssize; ++i) {
|
|
763
824
|
status = proj_semi_definite_cone(&(x[count]), k->s[i], c);
|
|
@@ -768,13 +829,13 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
768
829
|
}
|
|
769
830
|
}
|
|
770
831
|
|
|
771
|
-
if (k->ep) {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
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
|
+
*/
|
|
778
839
|
#ifdef _OPENMP
|
|
779
840
|
#pragma omp parallel for
|
|
780
841
|
#endif
|
|
@@ -784,7 +845,8 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
784
845
|
count += 3 * k->ep;
|
|
785
846
|
}
|
|
786
847
|
|
|
787
|
-
|
|
848
|
+
/* dual exponential cone */
|
|
849
|
+
if (k->ed) { /* doesn't use r_y */
|
|
788
850
|
/*
|
|
789
851
|
* exponential cone is not self dual, if s \in K
|
|
790
852
|
* then y \in K^* and so if K is the primal cone
|
|
@@ -812,7 +874,7 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
812
874
|
count += 3 * k->ed;
|
|
813
875
|
}
|
|
814
876
|
|
|
815
|
-
if (k->psize && k->p) {
|
|
877
|
+
if (k->psize && k->p) { /* doesn't use r_y */
|
|
816
878
|
scs_float v[3];
|
|
817
879
|
scs_int idx;
|
|
818
880
|
/* don't use openmp for power cone
|
|
@@ -820,7 +882,7 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
820
882
|
pragma omp parallel for private(v, idx)
|
|
821
883
|
endif
|
|
822
884
|
*/
|
|
823
|
-
for (i = 0; i < k->psize; ++i) {
|
|
885
|
+
for (i = 0; i < k->psize; ++i) { /* doesn't use r_y */
|
|
824
886
|
idx = count + 3 * i;
|
|
825
887
|
if (k->p[i] >= 0) {
|
|
826
888
|
/* primal power cone */
|
|
@@ -844,23 +906,13 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
844
906
|
return 0;
|
|
845
907
|
}
|
|
846
908
|
|
|
847
|
-
ScsConeWork *SCS(init_cone)(
|
|
848
|
-
scs_int cone_len) {
|
|
909
|
+
ScsConeWork *SCS(init_cone)(ScsCone *k, scs_int m) {
|
|
849
910
|
ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
|
|
850
|
-
c->
|
|
851
|
-
c->
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
c->bu = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
|
|
856
|
-
c->bl = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
|
|
857
|
-
memcpy(c->bu, k->bu, (k->bsize - 1) * sizeof(scs_float));
|
|
858
|
-
memcpy(c->bl, k->bl, (k->bsize - 1) * sizeof(scs_float));
|
|
859
|
-
/* also does some sanitizing */
|
|
860
|
-
normalize_box_cone(c, scal ? &(scal->D[k->z + k->l]) : SCS_NULL,
|
|
861
|
-
k->bsize);
|
|
862
|
-
}
|
|
863
|
-
}
|
|
911
|
+
c->k = k;
|
|
912
|
+
c->m = m;
|
|
913
|
+
c->scaled_cones = 0;
|
|
914
|
+
set_cone_boundaries(k, c);
|
|
915
|
+
c->s = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
|
864
916
|
if (k->ssize && k->s) {
|
|
865
917
|
if (set_up_sd_cone_work_space(c, k) < 0) {
|
|
866
918
|
SCS(finish_cone)(c);
|
|
@@ -870,20 +922,57 @@ ScsConeWork *SCS(init_cone)(const ScsCone *k, const ScsScaling *scal,
|
|
|
870
922
|
return c;
|
|
871
923
|
}
|
|
872
924
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
925
|
+
void scale_box_cone(ScsCone *k, ScsConeWork *c, ScsScaling *scal) {
|
|
926
|
+
if (k->bsize && k->bu && k->bl) {
|
|
927
|
+
c->box_t_warm_start = 1.;
|
|
928
|
+
if (scal) {
|
|
929
|
+
/* also does some sanitizing */
|
|
930
|
+
normalize_box_cone(k, &(scal->D[k->z + k->l]), k->bsize);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/* Outward facing cone projection routine, performs projection in-place.
|
|
936
|
+
If normalize > 0 then will use normalized (equilibrated) cones if applicable.
|
|
937
|
+
|
|
938
|
+
Moreau decomposition for R-norm projections:
|
|
939
|
+
|
|
940
|
+
`x + R^{-1} \Pi_{C^*}^{R^{-1}} ( - R x ) = \Pi_C^R ( x )`
|
|
941
|
+
|
|
942
|
+
where \Pi^R_C is the projection onto C under the R-norm:
|
|
943
|
+
|
|
944
|
+
`||x||_R = \sqrt{x ' R x}`.
|
|
945
|
+
|
|
876
946
|
*/
|
|
877
|
-
scs_int SCS(proj_dual_cone)(scs_float *x,
|
|
878
|
-
|
|
879
|
-
scs_int status;
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
947
|
+
scs_int SCS(proj_dual_cone)(scs_float *x, ScsConeWork *c, ScsScaling *scal,
|
|
948
|
+
scs_float *r_y) {
|
|
949
|
+
scs_int status, i;
|
|
950
|
+
ScsCone *k = c->k;
|
|
951
|
+
|
|
952
|
+
if (!c->scaled_cones) {
|
|
953
|
+
scale_box_cone(k, c, scal);
|
|
954
|
+
c->scaled_cones = 1;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/* copy s = x */
|
|
958
|
+
memcpy(c->s, x, c->m * sizeof(scs_float));
|
|
959
|
+
|
|
960
|
+
/* x -> - Rx */
|
|
961
|
+
for (i = 0; i < c->m; ++i) {
|
|
962
|
+
x[i] *= r_y ? -r_y[i] : -1;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/* project -x onto cone, x -> \Pi_{C^*}^{R^{-1}}(-x) under r_y metric */
|
|
966
|
+
status = proj_cone(x, k, c, scal ? 1 : 0, r_y);
|
|
967
|
+
|
|
968
|
+
/* return x + R^{-1} \Pi_{C^*}^{R^{-1}} ( -x ) */
|
|
969
|
+
for (i = 0; i < c->m; ++i) {
|
|
970
|
+
if (r_y) {
|
|
971
|
+
x[i] = x[i] / r_y[i] + c->s[i];
|
|
972
|
+
} else {
|
|
973
|
+
x[i] += c->s[i];
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
888
977
|
return status;
|
|
889
978
|
}
|
data/vendor/scs/src/linalg.c
CHANGED
|
@@ -83,9 +83,22 @@ void SCS(add_scaled_array)(scs_float *a, const scs_float *b, scs_int n,
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
scs_float SCS(mean)(const scs_float *x, scs_int n) {
|
|
87
|
+
scs_int i;
|
|
88
|
+
scs_float mean = 0.;
|
|
89
|
+
for (i = 0; i < n; ++i) {
|
|
90
|
+
mean += x[i];
|
|
91
|
+
}
|
|
92
|
+
return mean / n;
|
|
93
|
+
}
|
|
94
|
+
|
|
86
95
|
#else
|
|
87
96
|
/* If we have BLAS / LAPACK we may as well use them */
|
|
88
97
|
|
|
98
|
+
#ifdef __cplusplus
|
|
99
|
+
extern "C" {
|
|
100
|
+
#endif
|
|
101
|
+
|
|
89
102
|
scs_float BLAS(nrm2)(blas_int *n, const scs_float *x, blas_int *incx);
|
|
90
103
|
scs_float BLAS(dot)(const blas_int *n, const scs_float *x, const blas_int *incx,
|
|
91
104
|
const scs_float *y, const blas_int *incy);
|
|
@@ -96,6 +109,10 @@ void BLAS(axpy)(blas_int *n, const scs_float *a, const scs_float *x,
|
|
|
96
109
|
void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
|
|
97
110
|
const blas_int *incx);
|
|
98
111
|
|
|
112
|
+
#ifdef __cplusplus
|
|
113
|
+
}
|
|
114
|
+
#endif
|
|
115
|
+
|
|
99
116
|
/* a *= b */
|
|
100
117
|
void SCS(scale_array)(scs_float *a, const scs_float b, scs_int len) {
|
|
101
118
|
blas_int bone = 1;
|
|
@@ -137,4 +154,12 @@ void SCS(add_scaled_array)(scs_float *a, const scs_float *b, scs_int len,
|
|
|
137
154
|
BLAS(axpy)(&blen, &sc, b, &bone, a, &bone);
|
|
138
155
|
}
|
|
139
156
|
|
|
157
|
+
scs_float SCS(mean)(const scs_float *x, scs_int n) {
|
|
158
|
+
blas_int bone = 1;
|
|
159
|
+
blas_int bzero = 0;
|
|
160
|
+
blas_int blen = (blas_int)n;
|
|
161
|
+
scs_float y = 1.0;
|
|
162
|
+
return BLAS(dot)(&blen, x, &bone, &y, &bzero) / n;
|
|
163
|
+
}
|
|
164
|
+
|
|
140
165
|
#endif
|
data/vendor/scs/src/normalize.c
CHANGED
|
@@ -3,49 +3,98 @@
|
|
|
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;
|
|
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
|
+
sigma = MAX(SCS(norm_inf)(c, scal->n), SCS(norm_inf)(b, scal->m));
|
|
42
|
+
sigma = sigma < MIN_NORMALIZATION_FACTOR ? 1.0 : sigma;
|
|
43
|
+
sigma = sigma > MAX_NORMALIZATION_FACTOR ? MAX_NORMALIZATION_FACTOR : sigma;
|
|
44
|
+
sigma = SAFEDIV_POS(1.0, sigma);
|
|
45
|
+
|
|
46
|
+
/* Scale b, c */
|
|
47
|
+
SCS(scale_array)(c, sigma, scal->n);
|
|
48
|
+
SCS(scale_array)(b, sigma, scal->m);
|
|
49
|
+
|
|
50
|
+
/* We assume that primal_scale = dual_scale, otherwise need to refactorize */
|
|
51
|
+
scal->primal_scale = sigma;
|
|
52
|
+
scal->dual_scale = sigma;
|
|
53
|
+
}
|
|
54
|
+
|
|
6
55
|
/* needed for normalizing the warm-start */
|
|
7
|
-
void SCS(normalize_sol)(
|
|
56
|
+
void SCS(normalize_sol)(ScsScaling *scal, ScsSolution *sol) {
|
|
8
57
|
scs_int i;
|
|
9
|
-
scs_float *D =
|
|
10
|
-
scs_float *E =
|
|
11
|
-
for (i = 0; i <
|
|
12
|
-
sol->x[i] /= (E[i] /
|
|
58
|
+
scs_float *D = scal->D;
|
|
59
|
+
scs_float *E = scal->E;
|
|
60
|
+
for (i = 0; i < scal->n; ++i) {
|
|
61
|
+
sol->x[i] /= (E[i] / scal->dual_scale);
|
|
13
62
|
}
|
|
14
|
-
for (i = 0; i <
|
|
15
|
-
sol->y[i] /= (D[i] /
|
|
63
|
+
for (i = 0; i < scal->m; ++i) {
|
|
64
|
+
sol->y[i] /= (D[i] / scal->primal_scale);
|
|
16
65
|
}
|
|
17
|
-
for (i = 0; i <
|
|
18
|
-
sol->s[i] *= (D[i] *
|
|
66
|
+
for (i = 0; i < scal->m; ++i) {
|
|
67
|
+
sol->s[i] *= (D[i] * scal->dual_scale);
|
|
19
68
|
}
|
|
20
69
|
}
|
|
21
70
|
|
|
22
|
-
void SCS(un_normalize_sol)(
|
|
71
|
+
void SCS(un_normalize_sol)(ScsScaling *scal, ScsSolution *sol) {
|
|
23
72
|
scs_int i;
|
|
24
|
-
scs_float *D =
|
|
25
|
-
scs_float *E =
|
|
26
|
-
for (i = 0; i <
|
|
27
|
-
sol->x[i] *= (E[i] /
|
|
73
|
+
scs_float *D = scal->D;
|
|
74
|
+
scs_float *E = scal->E;
|
|
75
|
+
for (i = 0; i < scal->n; ++i) {
|
|
76
|
+
sol->x[i] *= (E[i] / scal->dual_scale);
|
|
28
77
|
}
|
|
29
|
-
for (i = 0; i <
|
|
30
|
-
sol->y[i] *= (D[i] /
|
|
78
|
+
for (i = 0; i < scal->m; ++i) {
|
|
79
|
+
sol->y[i] *= (D[i] / scal->primal_scale);
|
|
31
80
|
}
|
|
32
|
-
for (i = 0; i <
|
|
33
|
-
sol->s[i] /= (D[i] *
|
|
81
|
+
for (i = 0; i < scal->m; ++i) {
|
|
82
|
+
sol->s[i] /= (D[i] * scal->dual_scale);
|
|
34
83
|
}
|
|
35
84
|
}
|
|
36
85
|
|
|
37
|
-
void SCS(un_normalize_primal)(
|
|
86
|
+
void SCS(un_normalize_primal)(ScsScaling *scal, scs_float *r) {
|
|
38
87
|
scs_int i;
|
|
39
|
-
scs_float *D =
|
|
40
|
-
for (i = 0; i <
|
|
41
|
-
r[i] /= (D[i] *
|
|
88
|
+
scs_float *D = scal->D;
|
|
89
|
+
for (i = 0; i < scal->m; ++i) {
|
|
90
|
+
r[i] /= (D[i] * scal->dual_scale);
|
|
42
91
|
}
|
|
43
92
|
}
|
|
44
93
|
|
|
45
|
-
void SCS(un_normalize_dual)(
|
|
94
|
+
void SCS(un_normalize_dual)(ScsScaling *scal, scs_float *r) {
|
|
46
95
|
scs_int i;
|
|
47
|
-
scs_float *E =
|
|
48
|
-
for (i = 0; i <
|
|
49
|
-
r[i] /= (E[i] *
|
|
96
|
+
scs_float *E = scal->E;
|
|
97
|
+
for (i = 0; i < scal->n; ++i) {
|
|
98
|
+
r[i] /= (E[i] * scal->primal_scale);
|
|
50
99
|
}
|
|
51
100
|
}
|