scs 0.2.2 → 0.3.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 +16 -0
- data/LICENSE.txt +18 -18
- data/README.md +19 -14
- data/lib/scs/ffi.rb +31 -20
- data/lib/scs/solver.rb +32 -9
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +39 -0
- data/vendor/scs/CMakeLists.txt +320 -0
- data/vendor/scs/Makefile +32 -23
- data/vendor/scs/README.md +9 -218
- data/vendor/scs/include/aa.h +67 -23
- data/vendor/scs/include/cones.h +22 -19
- data/vendor/scs/include/glbopts.h +107 -79
- data/vendor/scs/include/linalg.h +3 -4
- data/vendor/scs/include/linsys.h +58 -44
- data/vendor/scs/include/normalize.h +6 -5
- data/vendor/scs/include/rw.h +8 -2
- data/vendor/scs/include/scs.h +257 -141
- data/vendor/scs/include/scs_types.h +34 -0
- data/vendor/scs/include/scs_work.h +83 -0
- data/vendor/scs/include/util.h +3 -15
- data/vendor/scs/linsys/cpu/direct/private.c +241 -232
- data/vendor/scs/linsys/cpu/direct/private.h +13 -7
- data/vendor/scs/linsys/cpu/indirect/private.c +194 -118
- data/vendor/scs/linsys/cpu/indirect/private.h +7 -4
- data/vendor/scs/linsys/csparse.c +87 -0
- data/vendor/scs/linsys/csparse.h +34 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +6 -6
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +6 -1
- data/vendor/scs/linsys/external/amd/amd_internal.h +1 -1
- data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
- data/vendor/scs/linsys/external/qdldl/changes +2 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.c +29 -46
- data/vendor/scs/linsys/external/qdldl/qdldl.h +33 -41
- data/vendor/scs/linsys/external/qdldl/qdldl_types.h +11 -3
- data/vendor/scs/linsys/gpu/gpu.c +58 -21
- data/vendor/scs/linsys/gpu/gpu.h +70 -35
- data/vendor/scs/linsys/gpu/indirect/private.c +394 -157
- data/vendor/scs/linsys/gpu/indirect/private.h +27 -12
- data/vendor/scs/linsys/scs_matrix.c +478 -0
- data/vendor/scs/linsys/scs_matrix.h +70 -0
- data/vendor/scs/scs.mk +14 -10
- data/vendor/scs/src/aa.c +394 -110
- data/vendor/scs/src/cones.c +497 -359
- data/vendor/scs/src/ctrlc.c +15 -5
- data/vendor/scs/src/linalg.c +107 -26
- data/vendor/scs/src/normalize.c +30 -72
- data/vendor/scs/src/rw.c +202 -27
- data/vendor/scs/src/scs.c +769 -571
- data/vendor/scs/src/scs_version.c +11 -3
- data/vendor/scs/src/util.c +37 -106
- data/vendor/scs/test/minunit.h +22 -8
- data/vendor/scs/test/problem_utils.h +180 -25
- data/vendor/scs/test/problems/degenerate.h +130 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +124 -0
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +116 -0
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +100 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +199 -0
- data/vendor/scs/test/problems/random_prob +0 -0
- data/vendor/scs/test/problems/random_prob.h +45 -0
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +188 -31
- data/vendor/scs/test/problems/small_lp.h +14 -13
- data/vendor/scs/test/problems/small_qp.h +352 -0
- data/vendor/scs/test/problems/test_validation.h +43 -0
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +82 -0
- data/vendor/scs/test/random_socp_prob.c +54 -53
- data/vendor/scs/test/rng.h +109 -0
- data/vendor/scs/test/run_from_file.c +20 -11
- data/vendor/scs/test/run_tests.c +35 -2
- metadata +29 -98
- data/vendor/scs/linsys/amatrix.c +0 -305
- data/vendor/scs/linsys/amatrix.h +0 -36
- data/vendor/scs/linsys/amatrix.o +0 -0
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.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/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_version.o +0 -0
- data/vendor/scs/src/util.o +0 -0
- data/vendor/scs/test/data/small_random_socp +0 -0
- data/vendor/scs/test/problems/small_random_socp.h +0 -33
- data/vendor/scs/test/run_tests +0 -2
|
@@ -5,29 +5,44 @@
|
|
|
5
5
|
extern "C" {
|
|
6
6
|
#endif
|
|
7
7
|
|
|
8
|
-
#include "
|
|
8
|
+
#include "csparse.h"
|
|
9
9
|
#include "glbopts.h"
|
|
10
|
+
#include "gpu.h"
|
|
10
11
|
#include "linalg.h"
|
|
11
12
|
#include "scs.h"
|
|
12
13
|
|
|
13
|
-
|
|
14
14
|
struct SCS_LIN_SYS_WORK {
|
|
15
|
+
scs_int n, m; /* linear system dimensions */
|
|
15
16
|
/* reporting */
|
|
16
17
|
scs_int tot_cg_its;
|
|
17
|
-
scs_float
|
|
18
|
+
scs_float *M; /* preconditioner on cpu */
|
|
18
19
|
/* ALL BELOW HOSTED ON THE GPU */
|
|
19
|
-
scs_float *p;
|
|
20
|
-
scs_float *r;
|
|
21
|
-
scs_float *Gp;
|
|
22
|
-
scs_float *bg;
|
|
23
|
-
scs_float *tmp_m;
|
|
24
|
-
scs_float *z;
|
|
25
|
-
scs_float *
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
scs_float *p; /* cg iterate, n */
|
|
21
|
+
scs_float *r; /* cg residual, n */
|
|
22
|
+
scs_float *Gp; /* G * p, n */
|
|
23
|
+
scs_float *bg; /* b, n */
|
|
24
|
+
scs_float *tmp_m; /* m, used in mat_vec */
|
|
25
|
+
scs_float *z; /* preconditioned */
|
|
26
|
+
scs_float *M_gpu; /* preconditioner */
|
|
27
|
+
const ScsMatrix *A; /* does *not* own this memory */
|
|
28
|
+
const ScsMatrix *P; /* does *not* own this memory */
|
|
29
|
+
ScsGpuMatrix *Ag; /* A matrix on GPU */
|
|
30
|
+
ScsGpuMatrix *Agt; /* A trans matrix on GPU */
|
|
31
|
+
ScsGpuMatrix *Pg; /* P matrix on GPU */
|
|
28
32
|
/* CUDA */
|
|
29
33
|
cublasHandle_t cublas_handle;
|
|
30
34
|
cusparseHandle_t cusparse_handle;
|
|
35
|
+
/* CUSPARSE */
|
|
36
|
+
size_t buffer_size;
|
|
37
|
+
void *buffer;
|
|
38
|
+
cusparseDnVecDescr_t dn_vec_m; /* Dense vector of length m */
|
|
39
|
+
cusparseDnVecDescr_t dn_vec_n; /* Dense vector of length n */
|
|
40
|
+
cusparseDnVecDescr_t dn_vec_n_p; /* Dense vector of length n */
|
|
41
|
+
|
|
42
|
+
/* rho terms */
|
|
43
|
+
scs_float *r_x_gpu;
|
|
44
|
+
scs_float *inv_r_y; /* inverse R_y */
|
|
45
|
+
scs_float *inv_r_y_gpu; /* inverse R_y on GPU */
|
|
31
46
|
};
|
|
32
47
|
|
|
33
48
|
#ifdef __cplusplus
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/* contains routines common to direct and indirect sparse solvers */
|
|
2
|
+
#include "scs_matrix.h"
|
|
3
|
+
#include "linalg.h"
|
|
4
|
+
#include "linsys.h"
|
|
5
|
+
#include "util.h"
|
|
6
|
+
|
|
7
|
+
#define MIN_NORMALIZATION_FACTOR (1e-4)
|
|
8
|
+
#define MAX_NORMALIZATION_FACTOR (1e4)
|
|
9
|
+
#define NUM_RUIZ_PASSES (25) /* additional passes don't help much */
|
|
10
|
+
#define NUM_L2_PASSES (1) /* do one or zero, not more since not stable */
|
|
11
|
+
|
|
12
|
+
scs_int SCS(copy_matrix)(ScsMatrix **dstp, const ScsMatrix *src) {
|
|
13
|
+
scs_int Anz = src->p[src->n];
|
|
14
|
+
ScsMatrix *A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
|
15
|
+
if (!A) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
A->n = src->n;
|
|
19
|
+
A->m = src->m;
|
|
20
|
+
/* A values, size: NNZ A */
|
|
21
|
+
A->x = (scs_float *)scs_calloc(Anz, sizeof(scs_float));
|
|
22
|
+
/* A row index, size: NNZ A */
|
|
23
|
+
A->i = (scs_int *)scs_calloc(Anz, sizeof(scs_int));
|
|
24
|
+
/* A column pointer, size: n+1 */
|
|
25
|
+
A->p = (scs_int *)scs_calloc(src->n + 1, sizeof(scs_int));
|
|
26
|
+
if (!A->x || !A->i || !A->p) {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
memcpy(A->x, src->x, sizeof(scs_float) * Anz);
|
|
30
|
+
memcpy(A->i, src->i, sizeof(scs_int) * Anz);
|
|
31
|
+
memcpy(A->p, src->p, sizeof(scs_int) * (src->n + 1));
|
|
32
|
+
*dstp = A;
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
scs_int SCS(validate_lin_sys)(const ScsMatrix *A, const ScsMatrix *P) {
|
|
37
|
+
scs_int i, j, r_max, Anz;
|
|
38
|
+
if (!A->x || !A->i || !A->p) {
|
|
39
|
+
scs_printf("data incompletely specified\n");
|
|
40
|
+
return -1;
|
|
41
|
+
}
|
|
42
|
+
/* detects some errors in A col ptrs: */
|
|
43
|
+
Anz = A->p[A->n];
|
|
44
|
+
if (Anz > 0) {
|
|
45
|
+
for (i = 0; i < A->n; ++i) {
|
|
46
|
+
if (A->p[i] == A->p[i + 1]) {
|
|
47
|
+
scs_printf("WARN: A->p (column pointers) not strictly increasing, "
|
|
48
|
+
"column %li empty\n",
|
|
49
|
+
(long)i);
|
|
50
|
+
} else if (A->p[i] > A->p[i + 1]) {
|
|
51
|
+
scs_printf("ERROR: A->p (column pointers) decreasing\n");
|
|
52
|
+
return -1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (((scs_float)Anz / A->m > A->n) || (Anz < 0)) {
|
|
57
|
+
scs_printf("Anz (nonzeros in A) = %li, outside of valid range\n",
|
|
58
|
+
(long)Anz);
|
|
59
|
+
return -1;
|
|
60
|
+
}
|
|
61
|
+
r_max = 0;
|
|
62
|
+
for (i = 0; i < Anz; ++i) {
|
|
63
|
+
if (A->i[i] > r_max) {
|
|
64
|
+
r_max = A->i[i];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (r_max > A->m - 1) {
|
|
68
|
+
scs_printf("number of rows in A inconsistent with input dimension\n");
|
|
69
|
+
return -1;
|
|
70
|
+
}
|
|
71
|
+
if (P) {
|
|
72
|
+
if (P->n != A->n) {
|
|
73
|
+
scs_printf("P dimension = %li, inconsistent with n = %li\n", (long)P->n,
|
|
74
|
+
(long)A->n);
|
|
75
|
+
return -1;
|
|
76
|
+
}
|
|
77
|
+
if (P->m != P->n) {
|
|
78
|
+
scs_printf("P is not square\n");
|
|
79
|
+
return -1;
|
|
80
|
+
}
|
|
81
|
+
for (j = 0; j < P->n; j++) { /* cols */
|
|
82
|
+
for (i = P->p[j]; i < P->p[j + 1]; i++) {
|
|
83
|
+
if (P->i[i] > j) { /* if row > */
|
|
84
|
+
scs_printf("P is not upper triangular\n");
|
|
85
|
+
return -1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
void SCS(free_scs_matrix)(ScsMatrix *A) {
|
|
94
|
+
if (A) {
|
|
95
|
+
scs_free(A->x);
|
|
96
|
+
scs_free(A->i);
|
|
97
|
+
scs_free(A->p);
|
|
98
|
+
scs_free(A);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static inline scs_float apply_limit(scs_float x) {
|
|
103
|
+
/* need to bound to 1 for cols/rows of all zeros, otherwise blows up */
|
|
104
|
+
x = x < MIN_NORMALIZATION_FACTOR ? 1.0 : x;
|
|
105
|
+
x = x > MAX_NORMALIZATION_FACTOR ? MAX_NORMALIZATION_FACTOR : x;
|
|
106
|
+
return x;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static void compute_ruiz_mats(ScsMatrix *P, ScsMatrix *A, scs_float *b,
|
|
110
|
+
scs_float *c, scs_float *Dt, scs_float *Et,
|
|
111
|
+
scs_float *s, ScsConeWork *cone) {
|
|
112
|
+
scs_int i, j, kk;
|
|
113
|
+
scs_float wrk;
|
|
114
|
+
|
|
115
|
+
/**************************** D ****************************/
|
|
116
|
+
|
|
117
|
+
/* initialize D */
|
|
118
|
+
for (i = 0; i < A->m; ++i) {
|
|
119
|
+
/* Dt[i] = 0.; */
|
|
120
|
+
Dt[i] = ABS(b[i]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* calculate row norms */
|
|
124
|
+
for (i = 0; i < A->n; ++i) {
|
|
125
|
+
for (j = A->p[i]; j < A->p[i + 1]; ++j) {
|
|
126
|
+
Dt[A->i[j]] = MAX(Dt[A->i[j]], ABS(A->x[j]));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* accumulate D across each cone */
|
|
131
|
+
SCS(enforce_cone_boundaries)(cone, Dt, &SCS(norm_inf));
|
|
132
|
+
|
|
133
|
+
/* invert temporary vec to form D */
|
|
134
|
+
for (i = 0; i < A->m; ++i) {
|
|
135
|
+
Dt[i] = SAFEDIV_POS(1.0, SQRTF(apply_limit(Dt[i])));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**************************** E ****************************/
|
|
139
|
+
|
|
140
|
+
/* initialize E */
|
|
141
|
+
for (i = 0; i < A->n; ++i) {
|
|
142
|
+
/* Et[i] = 0.; */
|
|
143
|
+
Et[i] = ABS(c[i]);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* TODO: test not using P to determine scaling */
|
|
147
|
+
if (P) {
|
|
148
|
+
/* compute norm of cols of P (symmetric upper triangular) */
|
|
149
|
+
/* E = norm of cols of P */
|
|
150
|
+
/* Compute maximum across columns */
|
|
151
|
+
/* P(i, j) contributes to col j and col i (row i) due to symmetry */
|
|
152
|
+
for (j = 0; j < P->n; j++) { /* cols */
|
|
153
|
+
for (kk = P->p[j]; kk < P->p[j + 1]; kk++) {
|
|
154
|
+
i = P->i[kk]; /* row */
|
|
155
|
+
wrk = ABS(P->x[kk]);
|
|
156
|
+
Et[j] = MAX(wrk, Et[j]);
|
|
157
|
+
if (i != j) {
|
|
158
|
+
Et[i] = MAX(wrk, Et[i]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* calculate col norms, E */
|
|
165
|
+
for (i = 0; i < A->n; ++i) {
|
|
166
|
+
Et[i] = MAX(Et[i], SCS(norm_inf)(&(A->x[A->p[i]]), A->p[i + 1] - A->p[i]));
|
|
167
|
+
Et[i] = SAFEDIV_POS(1.0, SQRTF(apply_limit(Et[i])));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* calculate s value */
|
|
171
|
+
*s = MAX(SCS(norm_inf)(c, A->n), SCS(norm_inf)(b, A->m));
|
|
172
|
+
*s = SAFEDIV_POS(1.0, SQRTF(apply_limit(*s)));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static void compute_l2_mats(ScsMatrix *P, ScsMatrix *A, scs_float *b,
|
|
176
|
+
scs_float *c, scs_float *Dt, scs_float *Et,
|
|
177
|
+
scs_float *s, ScsConeWork *cone) {
|
|
178
|
+
scs_int i, j, kk;
|
|
179
|
+
scs_float wrk, norm_c, norm_b;
|
|
180
|
+
|
|
181
|
+
/**************************** D ****************************/
|
|
182
|
+
|
|
183
|
+
/* initialize D */
|
|
184
|
+
for (i = 0; i < A->m; ++i) {
|
|
185
|
+
/* Dt[i] = 0.; */
|
|
186
|
+
Dt[i] = b[i] * b[i];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* calculate row norms */
|
|
190
|
+
for (i = 0; i < A->n; ++i) {
|
|
191
|
+
for (j = A->p[i]; j < A->p[i + 1]; ++j) {
|
|
192
|
+
Dt[A->i[j]] += A->x[j] * A->x[j];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
for (i = 0; i < A->m; ++i) {
|
|
196
|
+
Dt[i] = SQRTF(Dt[i]); /* l2 norm of rows */
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* accumulate D across each cone */
|
|
200
|
+
SCS(enforce_cone_boundaries)(cone, Dt, &SCS(mean));
|
|
201
|
+
|
|
202
|
+
for (i = 0; i < A->m; ++i) {
|
|
203
|
+
Dt[i] = SAFEDIV_POS(1.0, SQRTF(apply_limit(Dt[i])));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**************************** E ****************************/
|
|
207
|
+
|
|
208
|
+
/* initialize E */
|
|
209
|
+
for (i = 0; i < A->n; ++i) {
|
|
210
|
+
/* Et[i] = 0.; */
|
|
211
|
+
Et[i] = c[i] * c[i];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* TODO: test not using P to determine scaling */
|
|
215
|
+
if (P) {
|
|
216
|
+
/* compute norm of cols of P (symmetric upper triangular) */
|
|
217
|
+
/* E = norm of cols of P */
|
|
218
|
+
/* Compute maximum across columns */
|
|
219
|
+
/* P(i, j) contributes to col j and col i (row i) due to symmetry */
|
|
220
|
+
for (j = 0; j < P->n; j++) { /* cols */
|
|
221
|
+
for (kk = P->p[j]; kk < P->p[j + 1]; kk++) {
|
|
222
|
+
i = P->i[kk]; /* row */
|
|
223
|
+
wrk = P->x[kk] * P->x[kk];
|
|
224
|
+
Et[j] += wrk;
|
|
225
|
+
if (i != j) {
|
|
226
|
+
Et[i] += wrk;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* calculate col norms, E */
|
|
233
|
+
for (i = 0; i < A->n; ++i) {
|
|
234
|
+
Et[i] += SCS(norm_sq)(&(A->x[A->p[i]]), A->p[i + 1] - A->p[i]);
|
|
235
|
+
Et[i] = SAFEDIV_POS(1.0, SQRTF(apply_limit(SQRTF(Et[i]))));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* calculate s value */
|
|
239
|
+
norm_c = SCS(norm_2)(c, A->n);
|
|
240
|
+
norm_b = SCS(norm_2)(b, A->m);
|
|
241
|
+
*s = SQRTF(norm_c * norm_c + norm_b * norm_b);
|
|
242
|
+
*s = SAFEDIV_POS(1.0, SQRTF(apply_limit(*s)));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
static void rescale(ScsMatrix *P, ScsMatrix *A, scs_float *b, scs_float *c,
|
|
246
|
+
scs_float *Dt, scs_float *Et, scs_float s, ScsScaling *scal,
|
|
247
|
+
ScsConeWork *cone) {
|
|
248
|
+
scs_int i, j;
|
|
249
|
+
/* scale the rows of A with D */
|
|
250
|
+
for (i = 0; i < A->n; ++i) {
|
|
251
|
+
for (j = A->p[i]; j < A->p[i + 1]; ++j) {
|
|
252
|
+
A->x[j] *= Dt[A->i[j]];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* scale the cols of A with E */
|
|
257
|
+
for (i = 0; i < A->n; ++i) {
|
|
258
|
+
SCS(scale_array)(&(A->x[A->p[i]]), Et[i], A->p[i + 1] - A->p[i]);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (P) {
|
|
262
|
+
/* scale the rows of P with E */
|
|
263
|
+
for (i = 0; i < P->n; ++i) {
|
|
264
|
+
for (j = P->p[i]; j < P->p[i + 1]; ++j) {
|
|
265
|
+
P->x[j] *= Et[P->i[j]];
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/* scale the cols of P with E */
|
|
269
|
+
for (i = 0; i < P->n; ++i) {
|
|
270
|
+
SCS(scale_array)(&(P->x[P->p[i]]), Et[i], P->p[i + 1] - P->p[i]);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* scale c */
|
|
275
|
+
for (i = 0; i < A->n; ++i) {
|
|
276
|
+
c[i] *= Et[i];
|
|
277
|
+
}
|
|
278
|
+
/* scale b */
|
|
279
|
+
for (i = 0; i < A->m; ++i) {
|
|
280
|
+
b[i] *= Dt[i];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/* Accumulate scaling */
|
|
284
|
+
for (i = 0; i < A->m; ++i) {
|
|
285
|
+
scal->D[i] *= Dt[i];
|
|
286
|
+
}
|
|
287
|
+
for (i = 0; i < A->n; ++i) {
|
|
288
|
+
scal->E[i] *= Et[i];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* Apply scaling */
|
|
292
|
+
SCS(scale_array)(c, s, A->n);
|
|
293
|
+
SCS(scale_array)(b, s, A->m);
|
|
294
|
+
/* no need to scale P since primal_scale = dual_scale */
|
|
295
|
+
/*
|
|
296
|
+
if (P) {
|
|
297
|
+
SCS(scale_array)(P->x, primal_scale, P->p[P->n]);
|
|
298
|
+
SCS(scale_array)(P->x, 1.0 / dual_scale, P->p[P->n]);
|
|
299
|
+
}
|
|
300
|
+
*/
|
|
301
|
+
|
|
302
|
+
/* Accumulate scaling */
|
|
303
|
+
scal->primal_scale *= s;
|
|
304
|
+
scal->dual_scale *= s;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Will rescale as P -> EPE, A -> DAE, c -> sEc, b -> sDb, in-place.
|
|
308
|
+
* Essentially trying to rescale this matrix:
|
|
309
|
+
*
|
|
310
|
+
* [P A' c] with [E 0 0] on both sides (D, E diagonal)
|
|
311
|
+
* [A 0 b] [0 D 0]
|
|
312
|
+
* [c' b' 0] [0 0 s]
|
|
313
|
+
*
|
|
314
|
+
* which results in:
|
|
315
|
+
*
|
|
316
|
+
* [ EPE EA'D sEc ]
|
|
317
|
+
* [ DAE 0 sDb ]
|
|
318
|
+
* [ sc'E sb'D 0 ]
|
|
319
|
+
*
|
|
320
|
+
* In other words D rescales the rows of A, b
|
|
321
|
+
* E rescales the cols of A and rows/cols of P, c'
|
|
322
|
+
*
|
|
323
|
+
* will repeatedly set: D^-1 ~ norm of rows of [ A b ]
|
|
324
|
+
*
|
|
325
|
+
* E^-1 ~ norm of cols of [ P ]
|
|
326
|
+
* [ A ]
|
|
327
|
+
* [ c']
|
|
328
|
+
*
|
|
329
|
+
* `s` is incorporated into dual_scale and primal_scale
|
|
330
|
+
*
|
|
331
|
+
* The main complication is that D has to respect cone boundaries.
|
|
332
|
+
*
|
|
333
|
+
*/
|
|
334
|
+
ScsScaling *SCS(normalize_a_p)(ScsMatrix *P, ScsMatrix *A, scs_float *b,
|
|
335
|
+
scs_float *c, ScsConeWork *cone) {
|
|
336
|
+
scs_int i;
|
|
337
|
+
scs_float s;
|
|
338
|
+
ScsScaling *scal = (ScsScaling *)scs_calloc(1, sizeof(ScsScaling));
|
|
339
|
+
scs_float *Dt = (scs_float *)scs_calloc(A->m, sizeof(scs_float));
|
|
340
|
+
scs_float *Et = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
|
|
341
|
+
scal->D = (scs_float *)scs_calloc(A->m, sizeof(scs_float));
|
|
342
|
+
scal->E = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
|
|
343
|
+
|
|
344
|
+
#if VERBOSITY > 5
|
|
345
|
+
SCS(timer) normalize_timer;
|
|
346
|
+
SCS(tic)(&normalize_timer);
|
|
347
|
+
scs_printf("normalizing A and P\n");
|
|
348
|
+
#endif
|
|
349
|
+
|
|
350
|
+
/* init D, E */
|
|
351
|
+
scal->m = A->m;
|
|
352
|
+
for (i = 0; i < A->m; ++i) {
|
|
353
|
+
scal->D[i] = 1.;
|
|
354
|
+
}
|
|
355
|
+
scal->n = A->n;
|
|
356
|
+
for (i = 0; i < A->n; ++i) {
|
|
357
|
+
scal->E[i] = 1.;
|
|
358
|
+
}
|
|
359
|
+
scal->primal_scale = 1.;
|
|
360
|
+
scal->dual_scale = 1.;
|
|
361
|
+
for (i = 0; i < NUM_RUIZ_PASSES; ++i) {
|
|
362
|
+
compute_ruiz_mats(P, A, b, c, Dt, Et, &s, cone);
|
|
363
|
+
rescale(P, A, b, c, Dt, Et, s, scal, cone);
|
|
364
|
+
}
|
|
365
|
+
for (i = 0; i < NUM_L2_PASSES; ++i) {
|
|
366
|
+
compute_l2_mats(P, A, b, c, Dt, Et, &s, cone);
|
|
367
|
+
rescale(P, A, b, c, Dt, Et, s, scal, cone);
|
|
368
|
+
}
|
|
369
|
+
scs_free(Dt);
|
|
370
|
+
scs_free(Et);
|
|
371
|
+
|
|
372
|
+
#if VERBOSITY > 5
|
|
373
|
+
scs_printf("finished normalizing A and P, time: %1.2es\n",
|
|
374
|
+
SCS(tocq)(&normalize_timer) / 1e3);
|
|
375
|
+
scs_printf("inf norm A %1.2e\n", SCS(norm_inf)(A->x, A->p[A->n]));
|
|
376
|
+
if (P) {
|
|
377
|
+
scs_printf("inf norm P %1.2e\n", SCS(norm_inf)(P->x, P->p[P->n]));
|
|
378
|
+
}
|
|
379
|
+
scs_printf("primal_scale %g\n", scal->primal_scale);
|
|
380
|
+
scs_printf("dual_scale %g\n", scal->dual_scale);
|
|
381
|
+
scs_printf("norm_b %g\n", SCS(norm_inf)(b, A->m));
|
|
382
|
+
scs_printf("norm_c %g\n", SCS(norm_inf)(c, A->n));
|
|
383
|
+
scs_printf("norm D %g\n", SCS(norm_inf)(scal->D, A->m));
|
|
384
|
+
scs_printf("norm E %g\n", SCS(norm_inf)(scal->E, A->n));
|
|
385
|
+
#endif
|
|
386
|
+
return scal;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
void SCS(un_normalize_a_p)(ScsMatrix *A, ScsMatrix *P, const ScsScaling *scal) {
|
|
390
|
+
scs_int i, j;
|
|
391
|
+
scs_float *D = scal->D;
|
|
392
|
+
scs_float *E = scal->E;
|
|
393
|
+
for (i = 0; i < A->n; ++i) {
|
|
394
|
+
SCS(scale_array)
|
|
395
|
+
(&(A->x[A->p[i]]), 1. / E[i], A->p[i + 1] - A->p[i]);
|
|
396
|
+
}
|
|
397
|
+
for (i = 0; i < A->n; ++i) {
|
|
398
|
+
for (j = A->p[i]; j < A->p[i + 1]; ++j) {
|
|
399
|
+
A->x[j] /= D[A->i[j]];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (P) {
|
|
403
|
+
for (i = 0; i < P->n; ++i) {
|
|
404
|
+
SCS(scale_array)
|
|
405
|
+
(&(P->x[P->p[i]]), 1. / E[i], P->p[i + 1] - P->p[i]);
|
|
406
|
+
}
|
|
407
|
+
for (i = 0; i < P->n; ++i) {
|
|
408
|
+
for (j = P->p[i]; j < P->p[i + 1]; ++j) {
|
|
409
|
+
P->x[j] /= E[P->i[j]];
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
void SCS(accum_by_atrans)(const ScsMatrix *A, const scs_float *x,
|
|
416
|
+
scs_float *y) {
|
|
417
|
+
/* y += A'*x
|
|
418
|
+
A in column compressed format
|
|
419
|
+
parallelizes over columns (rows of A')
|
|
420
|
+
*/
|
|
421
|
+
scs_int p, j;
|
|
422
|
+
scs_int c1, c2;
|
|
423
|
+
scs_float yj;
|
|
424
|
+
scs_int n = A->n;
|
|
425
|
+
scs_int *Ap = A->p;
|
|
426
|
+
scs_int *Ai = A->i;
|
|
427
|
+
scs_float *Ax = A->x;
|
|
428
|
+
#ifdef _OPENMP
|
|
429
|
+
#pragma omp parallel for private(p, c1, c2, yj)
|
|
430
|
+
#endif
|
|
431
|
+
for (j = 0; j < n; j++) {
|
|
432
|
+
yj = y[j];
|
|
433
|
+
c1 = Ap[j];
|
|
434
|
+
c2 = Ap[j + 1];
|
|
435
|
+
for (p = c1; p < c2; p++) {
|
|
436
|
+
yj += Ax[p] * x[Ai[p]];
|
|
437
|
+
}
|
|
438
|
+
y[j] = yj;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
void SCS(accum_by_a)(const ScsMatrix *A, const scs_float *x, scs_float *y) {
|
|
443
|
+
/*y += A*x
|
|
444
|
+
A in column compressed format
|
|
445
|
+
*/
|
|
446
|
+
scs_int p, j, i;
|
|
447
|
+
scs_int n = A->n;
|
|
448
|
+
scs_int *Ap = A->p;
|
|
449
|
+
scs_int *Ai = A->i;
|
|
450
|
+
scs_float *Ax = A->x;
|
|
451
|
+
for (j = 0; j < n; j++) { /* col */
|
|
452
|
+
for (p = Ap[j]; p < Ap[j + 1]; p++) {
|
|
453
|
+
i = Ai[p]; /* row */
|
|
454
|
+
y[i] += Ax[p] * x[j];
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Since P is upper triangular need to be clever here */
|
|
460
|
+
void SCS(accum_by_p)(const ScsMatrix *P, const scs_float *x, scs_float *y) {
|
|
461
|
+
/* returns y += P x */
|
|
462
|
+
scs_int p, j, i;
|
|
463
|
+
scs_int n = P->n;
|
|
464
|
+
scs_int *Pp = P->p;
|
|
465
|
+
scs_int *Pi = P->i;
|
|
466
|
+
scs_float *Px = P->x;
|
|
467
|
+
/* y += P_upper x but skip diagonal entries*/
|
|
468
|
+
for (j = 0; j < n; j++) { /* col */
|
|
469
|
+
for (p = Pp[j]; p < Pp[j + 1]; p++) {
|
|
470
|
+
i = Pi[p]; /* row */
|
|
471
|
+
if (i != j) { /* skip the diagonal */
|
|
472
|
+
y[i] += Px[p] * x[j];
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
/* y += P_lower x */
|
|
477
|
+
SCS(accum_by_atrans)(P, x, y);
|
|
478
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#ifndef SCS_MATRIX_H_GUARD
|
|
2
|
+
#define SCS_MATRIX_H_GUARD
|
|
3
|
+
|
|
4
|
+
#ifdef __cplusplus
|
|
5
|
+
extern "C" {
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#include "glbopts.h"
|
|
9
|
+
#include "scs.h"
|
|
10
|
+
#include "scs_work.h"
|
|
11
|
+
|
|
12
|
+
/* Normalization routines, used if d->NORMALIZE is true */
|
|
13
|
+
/* normalizes A matrix, sets scal->E and scal->D diagonal scaling matrices,
|
|
14
|
+
* A -> D*A*E. D and E must be all positive entries, D must satisfy cone
|
|
15
|
+
* boundaries */
|
|
16
|
+
ScsScaling *SCS(normalize_a_p)(ScsMatrix *P, ScsMatrix *A, scs_float *b,
|
|
17
|
+
scs_float *c, ScsConeWork *cone);
|
|
18
|
+
|
|
19
|
+
/* unnormalizes A matrix, unnormalizes by w->D and w->E */
|
|
20
|
+
void SCS(un_normalize_a_p)(ScsMatrix *A, ScsMatrix *P, const ScsScaling *scal);
|
|
21
|
+
|
|
22
|
+
/* to free the memory allocated in a ScsMatrix (called on A and P at finish) */
|
|
23
|
+
void SCS(free_scs_matrix)(ScsMatrix *A);
|
|
24
|
+
|
|
25
|
+
/* copies A (instead of in-place normalization), returns 0 for failure,
|
|
26
|
+
* allocates memory for dstp */
|
|
27
|
+
scs_int SCS(copy_matrix)(ScsMatrix **dstp, const ScsMatrix *src);
|
|
28
|
+
|
|
29
|
+
scs_float SCS(cumsum)(scs_int *p, scs_int *c, scs_int n);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Validate the linear system inputs, returns < 0 if not valid inputs.
|
|
33
|
+
*
|
|
34
|
+
* @param A A data matrix
|
|
35
|
+
* @param P P data matrix
|
|
36
|
+
* @return status < 0 indicates failure
|
|
37
|
+
*/
|
|
38
|
+
scs_int SCS(validate_lin_sys)(const ScsMatrix *A, const ScsMatrix *P);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Forms y += A^T * x
|
|
42
|
+
*
|
|
43
|
+
* @param A A data matrix
|
|
44
|
+
* @param x Input
|
|
45
|
+
* @param y Output
|
|
46
|
+
*/
|
|
47
|
+
void SCS(accum_by_atrans)(const ScsMatrix *A, const scs_float *x, scs_float *y);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Forms y += A * x
|
|
51
|
+
*
|
|
52
|
+
* @param A Data matrix
|
|
53
|
+
* @param x Input
|
|
54
|
+
* @param y Output
|
|
55
|
+
*/
|
|
56
|
+
void SCS(accum_by_a)(const ScsMatrix *A, const scs_float *x, scs_float *y);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Forms y += P * x
|
|
60
|
+
*
|
|
61
|
+
* @param P P data matrix
|
|
62
|
+
* @param x Input
|
|
63
|
+
* @param y Output
|
|
64
|
+
*/
|
|
65
|
+
void SCS(accum_by_p)(const ScsMatrix *P, const scs_float *x, scs_float *y);
|
|
66
|
+
|
|
67
|
+
#ifdef __cplusplus
|
|
68
|
+
}
|
|
69
|
+
#endif
|
|
70
|
+
#endif
|
data/vendor/scs/scs.mk
CHANGED
|
@@ -99,10 +99,6 @@ SFLOAT = 0
|
|
|
99
99
|
ifneq ($(SFLOAT), 0)
|
|
100
100
|
OPT_FLAGS += -DSFLOAT=$(SFLOAT) # use floats rather than doubles
|
|
101
101
|
endif
|
|
102
|
-
NOVALIDATE = 0
|
|
103
|
-
ifneq ($(NOVALIDATE), 0)
|
|
104
|
-
OPT_FLAGS += -DNOVALIDATE=$(NOVALIDATE)$ # remove data validation step
|
|
105
|
-
endif
|
|
106
102
|
NOTIMER = 0
|
|
107
103
|
ifneq ($(NOTIMER), 0)
|
|
108
104
|
OPT_FLAGS += -DNOTIMER=$(NOTIMER) # no timing, times reported as nan
|
|
@@ -115,12 +111,20 @@ GPU_TRANSPOSE_MAT = 1
|
|
|
115
111
|
ifneq ($(GPU_TRANSPOSE_MAT), 0)
|
|
116
112
|
OPT_FLAGS += -DGPU_TRANSPOSE_MAT=$(GPU_TRANSPOSE_MAT) # tranpose A mat in GPU memory
|
|
117
113
|
endif
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
114
|
+
NOVALIDATE = 0
|
|
115
|
+
ifneq ($(NOVALIDATE), 0)
|
|
116
|
+
OPT_FLAGS += -DNOVALIDATE=$(NOVALIDATE) # perform problem validation or skip
|
|
117
|
+
endif
|
|
118
|
+
### VERBOSITY LEVELS: 0,1,2,...
|
|
119
|
+
VERBOSITY = 0
|
|
120
|
+
ifneq ($(VERBOSITY), 0)
|
|
121
|
+
OPT_FLAGS += -DVERBOSITY=$(VERBOSITY) # verbosity level
|
|
123
122
|
endif
|
|
123
|
+
COVERAGE = 0
|
|
124
|
+
ifneq ($(COVERAGE), 0)
|
|
125
|
+
override CFLAGS += --coverage # generate test coverage data
|
|
126
|
+
endif
|
|
127
|
+
|
|
124
128
|
|
|
125
129
|
############ OPENMP: ############
|
|
126
130
|
# set USE_OPENMP = 1 to allow openmp (multi-threaded matrix multiplies):
|
|
@@ -141,7 +145,7 @@ endif
|
|
|
141
145
|
USE_LAPACK = 1
|
|
142
146
|
ifneq ($(USE_LAPACK), 0)
|
|
143
147
|
# edit these for your setup:
|
|
144
|
-
BLASLDFLAGS = -lblas -
|
|
148
|
+
BLASLDFLAGS = -llapack -lblas # -lgfortran
|
|
145
149
|
LDFLAGS += $(BLASLDFLAGS)
|
|
146
150
|
OPT_FLAGS += -DUSE_LAPACK
|
|
147
151
|
|