scs 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/ext/scs/Rakefile +11 -0
- data/lib/scs/ffi.rb +117 -0
- data/lib/scs/solver.rb +178 -0
- data/lib/scs/version.rb +3 -0
- data/lib/scs.rb +17 -0
- data/vendor/scs/LICENSE.txt +21 -0
- data/vendor/scs/Makefile +164 -0
- data/vendor/scs/README.md +220 -0
- data/vendor/scs/include/aa.h +56 -0
- data/vendor/scs/include/cones.h +46 -0
- data/vendor/scs/include/ctrlc.h +33 -0
- data/vendor/scs/include/glbopts.h +177 -0
- data/vendor/scs/include/linalg.h +26 -0
- data/vendor/scs/include/linsys.h +64 -0
- data/vendor/scs/include/normalize.h +18 -0
- data/vendor/scs/include/rw.h +17 -0
- data/vendor/scs/include/scs.h +161 -0
- data/vendor/scs/include/scs_blas.h +51 -0
- data/vendor/scs/include/util.h +65 -0
- data/vendor/scs/linsys/amatrix.c +305 -0
- data/vendor/scs/linsys/amatrix.h +36 -0
- data/vendor/scs/linsys/amatrix.o +0 -0
- data/vendor/scs/linsys/cpu/direct/private.c +366 -0
- data/vendor/scs/linsys/cpu/direct/private.h +26 -0
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.c +256 -0
- data/vendor/scs/linsys/cpu/indirect/private.h +31 -0
- data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
- data/vendor/scs/linsys/external/amd/LICENSE.txt +934 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +469 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +254 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
- data/vendor/scs/linsys/external/amd/amd.h +400 -0
- data/vendor/scs/linsys/external/amd/amd_1.c +180 -0
- data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_2.c +1842 -0
- data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_aat.c +184 -0
- data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_control.c +64 -0
- data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.c +37 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_dump.c +179 -0
- data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_global.c +16 -0
- data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_info.c +119 -0
- data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_internal.h +304 -0
- data/vendor/scs/linsys/external/amd/amd_order.c +199 -0
- data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.c +120 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.c +206 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.c +118 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_valid.c +92 -0
- data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
- data/vendor/scs/linsys/external/amd/changes +11 -0
- data/vendor/scs/linsys/external/qdldl/LICENSE +201 -0
- data/vendor/scs/linsys/external/qdldl/README.md +120 -0
- data/vendor/scs/linsys/external/qdldl/changes +4 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.c +298 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.h +177 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
- data/vendor/scs/linsys/external/qdldl/qdldl_types.h +21 -0
- data/vendor/scs/linsys/gpu/gpu.c +41 -0
- data/vendor/scs/linsys/gpu/gpu.h +85 -0
- data/vendor/scs/linsys/gpu/indirect/private.c +304 -0
- data/vendor/scs/linsys/gpu/indirect/private.h +36 -0
- data/vendor/scs/scs.mk +181 -0
- data/vendor/scs/src/aa.c +224 -0
- data/vendor/scs/src/aa.o +0 -0
- data/vendor/scs/src/cones.c +802 -0
- data/vendor/scs/src/cones.o +0 -0
- data/vendor/scs/src/ctrlc.c +77 -0
- data/vendor/scs/src/ctrlc.o +0 -0
- data/vendor/scs/src/linalg.c +84 -0
- data/vendor/scs/src/linalg.o +0 -0
- data/vendor/scs/src/normalize.c +93 -0
- data/vendor/scs/src/normalize.o +0 -0
- data/vendor/scs/src/rw.c +167 -0
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.c +975 -0
- data/vendor/scs/src/scs.o +0 -0
- data/vendor/scs/src/scs_version.c +5 -0
- data/vendor/scs/src/scs_version.o +0 -0
- data/vendor/scs/src/util.c +196 -0
- data/vendor/scs/src/util.o +0 -0
- data/vendor/scs/test/data/small_random_socp +0 -0
- data/vendor/scs/test/minunit.h +13 -0
- data/vendor/scs/test/problem_utils.h +93 -0
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +85 -0
- data/vendor/scs/test/problems/small_lp.h +50 -0
- data/vendor/scs/test/problems/small_random_socp.h +33 -0
- data/vendor/scs/test/random_socp_prob.c +171 -0
- data/vendor/scs/test/run_from_file.c +69 -0
- data/vendor/scs/test/run_tests +2 -0
- data/vendor/scs/test/run_tests.c +32 -0
- metadata +203 -0
@@ -0,0 +1,366 @@
|
|
1
|
+
#include "private.h"
|
2
|
+
|
3
|
+
struct SPARSE_MATRIX /* matrix in compressed-column or triplet form */
|
4
|
+
{
|
5
|
+
scs_int nzmax; /* maximum number of entries */
|
6
|
+
scs_int m; /* number of rows */
|
7
|
+
scs_int n; /* number of columns */
|
8
|
+
scs_int *p; /* column pointers (size n+1) or col indices (size nzmax) */
|
9
|
+
scs_int *i; /* row indices, size nzmax */
|
10
|
+
scs_float *x; /* numerical values, size nzmax */
|
11
|
+
scs_int nz; /* # of entries in triplet matrix, -1 for compressed-col */
|
12
|
+
};
|
13
|
+
|
14
|
+
char *SCS(get_lin_sys_method)(const ScsMatrix *A, const ScsSettings *stgs) {
|
15
|
+
char *tmp = (char *)scs_malloc(sizeof(char) * 128);
|
16
|
+
sprintf(tmp, "sparse-direct, nnz in A = %li", (long)A->p[A->n]);
|
17
|
+
return tmp;
|
18
|
+
}
|
19
|
+
|
20
|
+
char *SCS(get_lin_sys_summary)(ScsLinSysWork *p, const ScsInfo *info) {
|
21
|
+
char *str = (char *)scs_malloc(sizeof(char) * 128);
|
22
|
+
scs_int n = p->L->n;
|
23
|
+
sprintf(str, "\tLin-sys: nnz in L factor: %li, avg solve time: %1.2es\n",
|
24
|
+
(long)(p->L->p[n] + n), p->total_solve_time / (info->iter + 1) / 1e3);
|
25
|
+
p->total_solve_time = 0;
|
26
|
+
return str;
|
27
|
+
}
|
28
|
+
|
29
|
+
/* wrapper for free */
|
30
|
+
static void *cs_free(void *p) {
|
31
|
+
if (p) {
|
32
|
+
scs_free(p);
|
33
|
+
} /* free p if it is not already SCS_NULL */
|
34
|
+
return SCS_NULL; /* return SCS_NULL to simplify the use of cs_free */
|
35
|
+
}
|
36
|
+
|
37
|
+
static _cs *cs_spfree(_cs *A) {
|
38
|
+
if (!A) {
|
39
|
+
return SCS_NULL;
|
40
|
+
} /* do nothing if A already SCS_NULL */
|
41
|
+
cs_free(A->p);
|
42
|
+
cs_free(A->i);
|
43
|
+
cs_free(A->x);
|
44
|
+
return (_cs *)cs_free(A); /* free the _cs struct and return SCS_NULL */
|
45
|
+
}
|
46
|
+
|
47
|
+
void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
|
48
|
+
if (p) {
|
49
|
+
cs_spfree(p->L);
|
50
|
+
scs_free(p->P);
|
51
|
+
scs_free(p->Dinv);
|
52
|
+
scs_free(p->bp);
|
53
|
+
scs_free(p);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
static _cs *cs_spalloc(scs_int m, scs_int n, scs_int nzmax, scs_int values,
|
58
|
+
scs_int triplet) {
|
59
|
+
_cs *A = (_cs *)scs_calloc(1, sizeof(_cs)); /* allocate the _cs struct */
|
60
|
+
if (!A) {
|
61
|
+
return SCS_NULL;
|
62
|
+
} /* out of memory */
|
63
|
+
A->m = m; /* define dimensions and nzmax */
|
64
|
+
A->n = n;
|
65
|
+
A->nzmax = nzmax = MAX(nzmax, 1);
|
66
|
+
A->nz = triplet ? 0 : -1; /* allocate triplet or comp.col */
|
67
|
+
A->p = (scs_int *)scs_malloc((triplet ? nzmax : n + 1) * sizeof(scs_int));
|
68
|
+
A->i = (scs_int *)scs_malloc(nzmax * sizeof(scs_int));
|
69
|
+
A->x = values ? (scs_float *)scs_malloc(nzmax * sizeof(scs_float)) : SCS_NULL;
|
70
|
+
return (!A->p || !A->i || (values && !A->x)) ? cs_spfree(A) : A;
|
71
|
+
}
|
72
|
+
|
73
|
+
static _cs *cs_done(_cs *C, void *w, void *x, scs_int ok) {
|
74
|
+
cs_free(w); /* free workspace */
|
75
|
+
cs_free(x);
|
76
|
+
return ok ? C : cs_spfree(C); /* return result if OK, else free it */
|
77
|
+
}
|
78
|
+
|
79
|
+
/* C = compressed-column form of a triplet matrix T */
|
80
|
+
static _cs *cs_compress(const _cs *T) {
|
81
|
+
scs_int m, n, nz, p, k, *Cp, *Ci, *w, *Ti, *Tj;
|
82
|
+
scs_float *Cx, *Tx;
|
83
|
+
_cs *C;
|
84
|
+
m = T->m;
|
85
|
+
n = T->n;
|
86
|
+
Ti = T->i;
|
87
|
+
Tj = T->p;
|
88
|
+
Tx = T->x;
|
89
|
+
nz = T->nz;
|
90
|
+
C = cs_spalloc(m, n, nz, Tx != SCS_NULL, 0); /* allocate result */
|
91
|
+
w = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* get workspace */
|
92
|
+
if (!C || !w) {
|
93
|
+
return cs_done(C, w, SCS_NULL, 0);
|
94
|
+
} /* out of memory */
|
95
|
+
Cp = C->p;
|
96
|
+
Ci = C->i;
|
97
|
+
Cx = C->x;
|
98
|
+
for (k = 0; k < nz; k++) w[Tj[k]]++; /* column counts */
|
99
|
+
SCS(cumsum)(Cp, w, n); /* column pointers */
|
100
|
+
for (k = 0; k < nz; k++) {
|
101
|
+
Ci[p = w[Tj[k]]++] = Ti[k]; /* A(i,j) is the pth entry in C */
|
102
|
+
if (Cx) {
|
103
|
+
Cx[p] = Tx[k];
|
104
|
+
}
|
105
|
+
}
|
106
|
+
return cs_done(C, w, SCS_NULL, 1); /* success; free w and return C */
|
107
|
+
}
|
108
|
+
|
109
|
+
static _cs *form_kkt(const ScsMatrix *A, const ScsSettings *s) {
|
110
|
+
/* ONLY UPPER TRIANGULAR PART IS STUFFED
|
111
|
+
* forms column compressed KKT matrix
|
112
|
+
* assumes column compressed form A matrix
|
113
|
+
*
|
114
|
+
* forms upper triangular part of [I A'; A -I]
|
115
|
+
*/
|
116
|
+
scs_int j, k, kk;
|
117
|
+
_cs *K_cs;
|
118
|
+
/* I at top left */
|
119
|
+
const scs_int Anz = A->p[A->n];
|
120
|
+
const scs_int Knzmax = A->n + A->m + Anz;
|
121
|
+
_cs *K = cs_spalloc(A->m + A->n, A->m + A->n, Knzmax, 1, 1);
|
122
|
+
|
123
|
+
#if EXTRA_VERBOSE > 0
|
124
|
+
scs_printf("forming KKT\n");
|
125
|
+
#endif
|
126
|
+
|
127
|
+
if (!K) {
|
128
|
+
return SCS_NULL;
|
129
|
+
}
|
130
|
+
kk = 0;
|
131
|
+
for (k = 0; k < A->n; k++) {
|
132
|
+
K->i[kk] = k;
|
133
|
+
K->p[kk] = k;
|
134
|
+
K->x[kk] = s->rho_x;
|
135
|
+
kk++;
|
136
|
+
}
|
137
|
+
/* A^T at top right : CCS: */
|
138
|
+
for (j = 0; j < A->n; j++) {
|
139
|
+
for (k = A->p[j]; k < A->p[j + 1]; k++) {
|
140
|
+
K->p[kk] = A->i[k] + A->n;
|
141
|
+
K->i[kk] = j;
|
142
|
+
K->x[kk] = A->x[k];
|
143
|
+
kk++;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
/* -I at bottom right */
|
147
|
+
for (k = 0; k < A->m; k++) {
|
148
|
+
K->i[kk] = k + A->n;
|
149
|
+
K->p[kk] = k + A->n;
|
150
|
+
K->x[kk] = -1;
|
151
|
+
kk++;
|
152
|
+
}
|
153
|
+
/* assert kk == Knzmax */
|
154
|
+
K->nz = Knzmax;
|
155
|
+
K_cs = cs_compress(K);
|
156
|
+
cs_spfree(K);
|
157
|
+
return K_cs;
|
158
|
+
}
|
159
|
+
|
160
|
+
static scs_int _ldl_init(_cs *A, scs_int *P, scs_float **info) {
|
161
|
+
*info = (scs_float *)scs_malloc(AMD_INFO * sizeof(scs_float));
|
162
|
+
return amd_order(A->n, A->p, A->i, P, (scs_float *)SCS_NULL, *info);
|
163
|
+
}
|
164
|
+
|
165
|
+
static scs_int _ldl_factor(_cs *A, _cs **L, scs_float **Dinv) {
|
166
|
+
scs_int factor_status, n = A->n;
|
167
|
+
scs_int *etree = (scs_int *)scs_malloc(n * sizeof(scs_int));
|
168
|
+
scs_int *Lnz = (scs_int *)scs_malloc(n * sizeof(scs_int));
|
169
|
+
scs_int *iwork = (scs_int *)scs_malloc(3 * n * sizeof(scs_int));
|
170
|
+
scs_float *D, *fwork;
|
171
|
+
scs_int *bwork;
|
172
|
+
(*L)->p = (scs_int *)scs_malloc((1 + n) * sizeof(scs_int));
|
173
|
+
(*L)->nzmax = QDLDL_etree(n, A->p, A->i, iwork, Lnz, etree);
|
174
|
+
if ((*L)->nzmax < 0) {
|
175
|
+
scs_printf("Error in elimination tree calculation.\n");
|
176
|
+
scs_free(Lnz);
|
177
|
+
scs_free(iwork);
|
178
|
+
scs_free(etree);
|
179
|
+
scs_free((*L)->p);
|
180
|
+
return (*L)->nzmax;
|
181
|
+
}
|
182
|
+
|
183
|
+
(*L)->x = (scs_float *)scs_malloc((*L)->nzmax * sizeof(scs_float));
|
184
|
+
(*L)->i = (scs_int *)scs_malloc((*L)->nzmax * sizeof(scs_int));
|
185
|
+
*Dinv = (scs_float *)scs_malloc(n * sizeof(scs_float));
|
186
|
+
D = (scs_float *)scs_malloc(n * sizeof(scs_float));
|
187
|
+
bwork = (scs_int *)scs_malloc(n * sizeof(scs_int));
|
188
|
+
fwork = (scs_float *)scs_malloc(n * sizeof(scs_float));
|
189
|
+
|
190
|
+
#if EXTRA_VERBOSE > 0
|
191
|
+
scs_printf("numeric factorization\n");
|
192
|
+
#endif
|
193
|
+
factor_status = QDLDL_factor(n, A->p, A->i, A->x, (*L)->p, (*L)->i, (*L)->x,
|
194
|
+
D, *Dinv, Lnz, etree, bwork, iwork, fwork);
|
195
|
+
#if EXTRA_VERBOSE > 0
|
196
|
+
scs_printf("finished numeric factorization\n");
|
197
|
+
#endif
|
198
|
+
|
199
|
+
scs_free(Lnz);
|
200
|
+
scs_free(iwork);
|
201
|
+
scs_free(etree);
|
202
|
+
scs_free(D);
|
203
|
+
scs_free(bwork);
|
204
|
+
scs_free(fwork);
|
205
|
+
return factor_status;
|
206
|
+
}
|
207
|
+
|
208
|
+
static void _ldl_perm(scs_int n, scs_float *x, scs_float *b, scs_int *P) {
|
209
|
+
scs_int j;
|
210
|
+
for (j = 0; j < n; j++) x[j] = b[P[j]];
|
211
|
+
}
|
212
|
+
|
213
|
+
static void _ldl_permt(scs_int n, scs_float *x, scs_float *b, scs_int *P) {
|
214
|
+
scs_int j;
|
215
|
+
for (j = 0; j < n; j++) x[P[j]] = b[j];
|
216
|
+
}
|
217
|
+
|
218
|
+
static void _ldl_solve(scs_float *b, _cs *L, scs_float *Dinv, scs_int *P,
|
219
|
+
scs_float *bp) {
|
220
|
+
/* solves PLDL'P' x = b for x */
|
221
|
+
scs_int n = L->n;
|
222
|
+
_ldl_perm(n, bp, b, P);
|
223
|
+
QDLDL_solve(n, L->p, L->i, L->x, Dinv, bp);
|
224
|
+
_ldl_permt(n, b, bp, P);
|
225
|
+
}
|
226
|
+
|
227
|
+
void SCS(accum_by_atrans)(const ScsMatrix *A, ScsLinSysWork *p,
|
228
|
+
const scs_float *x, scs_float *y) {
|
229
|
+
SCS(_accum_by_atrans)(A->n, A->x, A->i, A->p, x, y);
|
230
|
+
}
|
231
|
+
|
232
|
+
void SCS(accum_by_a)(const ScsMatrix *A, ScsLinSysWork *p, const scs_float *x,
|
233
|
+
scs_float *y) {
|
234
|
+
SCS(_accum_by_a)(A->n, A->x, A->i, A->p, x, y);
|
235
|
+
}
|
236
|
+
|
237
|
+
static scs_int *cs_pinv(scs_int const *p, scs_int n) {
|
238
|
+
scs_int k, *pinv;
|
239
|
+
if (!p) {
|
240
|
+
return SCS_NULL;
|
241
|
+
} /* p = SCS_NULL denotes identity */
|
242
|
+
pinv = (scs_int *)scs_malloc(n * sizeof(scs_int)); /* allocate result */
|
243
|
+
if (!pinv) {
|
244
|
+
return SCS_NULL;
|
245
|
+
} /* out of memory */
|
246
|
+
for (k = 0; k < n; k++) pinv[p[k]] = k; /* invert the permutation */
|
247
|
+
return pinv; /* return result */
|
248
|
+
}
|
249
|
+
|
250
|
+
static _cs *cs_symperm(const _cs *A, const scs_int *pinv, scs_int values) {
|
251
|
+
scs_int i, j, p, q, i2, j2, n, *Ap, *Ai, *Cp, *Ci, *w;
|
252
|
+
scs_float *Cx, *Ax;
|
253
|
+
_cs *C;
|
254
|
+
n = A->n;
|
255
|
+
Ap = A->p;
|
256
|
+
Ai = A->i;
|
257
|
+
Ax = A->x;
|
258
|
+
C = cs_spalloc(n, n, Ap[n], values && (Ax != SCS_NULL), 0); /* alloc result*/
|
259
|
+
w = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* get workspace */
|
260
|
+
if (!C || !w) {
|
261
|
+
return cs_done(C, w, SCS_NULL, 0);
|
262
|
+
} /* out of memory */
|
263
|
+
Cp = C->p;
|
264
|
+
Ci = C->i;
|
265
|
+
Cx = C->x;
|
266
|
+
for (j = 0; j < n; j++) /* count entries in each column of C */
|
267
|
+
{
|
268
|
+
j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */
|
269
|
+
for (p = Ap[j]; p < Ap[j + 1]; p++) {
|
270
|
+
i = Ai[p];
|
271
|
+
if (i > j) {
|
272
|
+
continue;
|
273
|
+
} /* skip lower triangular part of A */
|
274
|
+
i2 = pinv ? pinv[i] : i; /* row i of A is row i2 of C */
|
275
|
+
w[MAX(i2, j2)]++; /* column count of C */
|
276
|
+
}
|
277
|
+
}
|
278
|
+
SCS(cumsum)(Cp, w, n); /* compute column pointers of C */
|
279
|
+
for (j = 0; j < n; j++) {
|
280
|
+
j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */
|
281
|
+
for (p = Ap[j]; p < Ap[j + 1]; p++) {
|
282
|
+
i = Ai[p];
|
283
|
+
if (i > j) {
|
284
|
+
continue;
|
285
|
+
} /* skip lower triangular part of A*/
|
286
|
+
i2 = pinv ? pinv[i] : i; /* row i of A is row i2 of C */
|
287
|
+
Ci[q = w[MAX(i2, j2)]++] = MIN(i2, j2);
|
288
|
+
if (Cx) {
|
289
|
+
Cx[q] = Ax[p];
|
290
|
+
}
|
291
|
+
}
|
292
|
+
}
|
293
|
+
return cs_done(C, w, SCS_NULL, 1); /* success; free workspace, return C */
|
294
|
+
}
|
295
|
+
|
296
|
+
static scs_int factorize(const ScsMatrix *A, const ScsSettings *stgs,
|
297
|
+
ScsLinSysWork *p) {
|
298
|
+
scs_float *info;
|
299
|
+
scs_int *Pinv, amd_status, ldl_status;
|
300
|
+
_cs *C, *K = form_kkt(A, stgs);
|
301
|
+
if (!K) {
|
302
|
+
return -1;
|
303
|
+
}
|
304
|
+
amd_status = _ldl_init(K, p->P, &info);
|
305
|
+
if (amd_status < 0) {
|
306
|
+
return amd_status;
|
307
|
+
}
|
308
|
+
#if EXTRA_VERBOSE > 0
|
309
|
+
if (stgs->verbose) {
|
310
|
+
scs_printf("Matrix factorization info:\n");
|
311
|
+
amd_info(info);
|
312
|
+
}
|
313
|
+
#endif
|
314
|
+
Pinv = cs_pinv(p->P, A->n + A->m);
|
315
|
+
C = cs_symperm(K, Pinv, 1);
|
316
|
+
ldl_status = _ldl_factor(C, &p->L, &p->Dinv);
|
317
|
+
cs_spfree(C);
|
318
|
+
cs_spfree(K);
|
319
|
+
scs_free(Pinv);
|
320
|
+
scs_free(info);
|
321
|
+
return ldl_status;
|
322
|
+
}
|
323
|
+
|
324
|
+
ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A,
|
325
|
+
const ScsSettings *stgs) {
|
326
|
+
ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
|
327
|
+
scs_int n_plus_m = A->n + A->m;
|
328
|
+
p->P = (scs_int *)scs_malloc(sizeof(scs_int) * n_plus_m);
|
329
|
+
p->L = (_cs *)scs_malloc(sizeof(_cs));
|
330
|
+
p->bp = (scs_float *)scs_malloc(n_plus_m * sizeof(scs_float));
|
331
|
+
p->L->m = n_plus_m;
|
332
|
+
p->L->n = n_plus_m;
|
333
|
+
p->L->nz = -1;
|
334
|
+
|
335
|
+
if (factorize(A, stgs, p) < 0) {
|
336
|
+
SCS(free_lin_sys_work)(p);
|
337
|
+
return SCS_NULL;
|
338
|
+
}
|
339
|
+
p->total_solve_time = 0.0;
|
340
|
+
return p;
|
341
|
+
}
|
342
|
+
|
343
|
+
scs_int SCS(solve_lin_sys)(const ScsMatrix *A, const ScsSettings *stgs,
|
344
|
+
ScsLinSysWork *p, scs_float *b, const scs_float *s,
|
345
|
+
scs_int iter) {
|
346
|
+
/* returns solution to linear system */
|
347
|
+
/* Ax = b with solution stored in b */
|
348
|
+
SCS(timer) linsys_timer;
|
349
|
+
SCS(tic)(&linsys_timer);
|
350
|
+
_ldl_solve(b, p->L, p->Dinv, p->P, p->bp);
|
351
|
+
p->total_solve_time += SCS(tocq)(&linsys_timer);
|
352
|
+
#if EXTRA_VERBOSE > 0
|
353
|
+
scs_printf("linsys solve time: %1.2es\n", SCS(tocq)(&linsys_timer) / 1e3);
|
354
|
+
#endif
|
355
|
+
return 0;
|
356
|
+
}
|
357
|
+
|
358
|
+
void SCS(normalize_a)(ScsMatrix *A, const ScsSettings *stgs, const ScsCone *k,
|
359
|
+
ScsScaling *scal) {
|
360
|
+
SCS(_normalize_a)(A, stgs, k, scal);
|
361
|
+
}
|
362
|
+
|
363
|
+
void SCS(un_normalize_a)(ScsMatrix *A, const ScsSettings *stgs,
|
364
|
+
const ScsScaling *scal) {
|
365
|
+
SCS(_un_normalize_a)(A, stgs, scal);
|
366
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#ifndef PRIV_H_GUARD
|
2
|
+
#define PRIV_H_GUARD
|
3
|
+
|
4
|
+
#ifdef __cplusplus
|
5
|
+
extern "C" {
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#include "amatrix.h"
|
9
|
+
#include "external/amd/amd.h"
|
10
|
+
#include "external/qdldl/qdldl.h"
|
11
|
+
#include "glbopts.h"
|
12
|
+
#include "scs.h"
|
13
|
+
|
14
|
+
typedef struct SPARSE_MATRIX _cs;
|
15
|
+
struct SCS_LIN_SYS_WORK {
|
16
|
+
_cs *L; /* KKT, and factorization matrix L resp. */
|
17
|
+
scs_float *Dinv; /* inverse diagonal matrix of factorization */
|
18
|
+
scs_int *P; /* permutation of KKT matrix for factorization */
|
19
|
+
scs_float *bp; /* workspace memory for solves */
|
20
|
+
scs_float total_solve_time; /* reporting */
|
21
|
+
};
|
22
|
+
|
23
|
+
#ifdef __cplusplus
|
24
|
+
}
|
25
|
+
#endif
|
26
|
+
#endif
|
Binary file
|
@@ -0,0 +1,256 @@
|
|
1
|
+
#include "private.h"
|
2
|
+
|
3
|
+
#define CG_BEST_TOL 1e-9
|
4
|
+
#define CG_MIN_TOL 1e-1
|
5
|
+
|
6
|
+
char *SCS(get_lin_sys_method)(const ScsMatrix *A, const ScsSettings *stgs) {
|
7
|
+
char *str = (char *)scs_malloc(sizeof(char) * 128);
|
8
|
+
sprintf(str, "sparse-indirect, nnz in A = %li, CG tol ~ 1/iter^(%2.2f)",
|
9
|
+
(long)A->p[A->n], stgs->cg_rate);
|
10
|
+
return str;
|
11
|
+
}
|
12
|
+
|
13
|
+
char *SCS(get_lin_sys_summary)(ScsLinSysWork *p, const ScsInfo *info) {
|
14
|
+
char *str = (char *)scs_malloc(sizeof(char) * 128);
|
15
|
+
sprintf(str,
|
16
|
+
"\tLin-sys: avg # CG iterations: %2.2f, avg solve time: %1.2es\n",
|
17
|
+
(scs_float)p->tot_cg_its / (info->iter + 1),
|
18
|
+
p->total_solve_time / (info->iter + 1) / 1e3);
|
19
|
+
p->tot_cg_its = 0;
|
20
|
+
p->total_solve_time = 0;
|
21
|
+
return str;
|
22
|
+
}
|
23
|
+
|
24
|
+
/* M = inv ( diag ( RHO_X * I + A'A ) ) */
|
25
|
+
static void get_preconditioner(const ScsMatrix *A, const ScsSettings *stgs,
|
26
|
+
ScsLinSysWork *p) {
|
27
|
+
scs_int i;
|
28
|
+
scs_float *M = p->M;
|
29
|
+
|
30
|
+
#if EXTRA_VERBOSE > 0
|
31
|
+
scs_printf("getting pre-conditioner\n");
|
32
|
+
#endif
|
33
|
+
|
34
|
+
for (i = 0; i < A->n; ++i) {
|
35
|
+
M[i] = 1 / (stgs->rho_x +
|
36
|
+
SCS(norm_sq)(&(A->x[A->p[i]]), A->p[i + 1] - A->p[i]));
|
37
|
+
/* M[i] = 1; */
|
38
|
+
}
|
39
|
+
|
40
|
+
#if EXTRA_VERBOSE > 0
|
41
|
+
scs_printf("finished getting pre-conditioner\n");
|
42
|
+
#endif
|
43
|
+
}
|
44
|
+
|
45
|
+
static void transpose(const ScsMatrix *A, ScsLinSysWork *p) {
|
46
|
+
scs_int *Ci = p->At->i;
|
47
|
+
scs_int *Cp = p->At->p;
|
48
|
+
scs_float *Cx = p->At->x;
|
49
|
+
scs_int m = A->m;
|
50
|
+
scs_int n = A->n;
|
51
|
+
|
52
|
+
scs_int *Ap = A->p;
|
53
|
+
scs_int *Ai = A->i;
|
54
|
+
scs_float *Ax = A->x;
|
55
|
+
|
56
|
+
scs_int i, j, q, *z, c1, c2;
|
57
|
+
#if EXTRA_VERBOSE > 0
|
58
|
+
SCS(timer) transpose_timer;
|
59
|
+
scs_printf("transposing A\n");
|
60
|
+
SCS(tic)(&transpose_timer);
|
61
|
+
#endif
|
62
|
+
|
63
|
+
z = (scs_int *)scs_calloc(m, sizeof(scs_int));
|
64
|
+
for (i = 0; i < Ap[n]; i++) z[Ai[i]]++; /* row counts */
|
65
|
+
SCS(cumsum)(Cp, z, m); /* row pointers */
|
66
|
+
|
67
|
+
for (j = 0; j < n; j++) {
|
68
|
+
c1 = Ap[j];
|
69
|
+
c2 = Ap[j + 1];
|
70
|
+
for (i = c1; i < c2; i++) {
|
71
|
+
q = z[Ai[i]];
|
72
|
+
Ci[q] = j; /* place A(i,j) as entry C(j,i) */
|
73
|
+
Cx[q] = Ax[i];
|
74
|
+
z[Ai[i]]++;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
scs_free(z);
|
78
|
+
|
79
|
+
#if EXTRA_VERBOSE > 0
|
80
|
+
scs_printf("finished transposing A, time: %1.2es\n",
|
81
|
+
SCS(tocq)(&transpose_timer) / 1e3);
|
82
|
+
#endif
|
83
|
+
}
|
84
|
+
|
85
|
+
void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
|
86
|
+
if (p) {
|
87
|
+
scs_free(p->p);
|
88
|
+
scs_free(p->r);
|
89
|
+
scs_free(p->Gp);
|
90
|
+
scs_free(p->tmp);
|
91
|
+
if (p->At) {
|
92
|
+
scs_free(p->At->i);
|
93
|
+
scs_free(p->At->x);
|
94
|
+
scs_free(p->At->p);
|
95
|
+
scs_free(p->At);
|
96
|
+
}
|
97
|
+
scs_free(p->z);
|
98
|
+
scs_free(p->M);
|
99
|
+
scs_free(p);
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
/*y = (RHO_X * I + A'A)x */
|
104
|
+
static void mat_vec(const ScsMatrix *A, const ScsSettings *s, ScsLinSysWork *p,
|
105
|
+
const scs_float *x, scs_float *y) {
|
106
|
+
scs_float *tmp = p->tmp;
|
107
|
+
memset(tmp, 0, A->m * sizeof(scs_float));
|
108
|
+
SCS(accum_by_a)(A, p, x, tmp);
|
109
|
+
memset(y, 0, A->n * sizeof(scs_float));
|
110
|
+
SCS(accum_by_atrans)(A, p, tmp, y);
|
111
|
+
SCS(add_scaled_array)(y, x, A->n, s->rho_x);
|
112
|
+
}
|
113
|
+
|
114
|
+
void SCS(accum_by_atrans)(const ScsMatrix *A, ScsLinSysWork *p,
|
115
|
+
const scs_float *x, scs_float *y) {
|
116
|
+
SCS(_accum_by_atrans)(A->n, A->x, A->i, A->p, x, y);
|
117
|
+
}
|
118
|
+
|
119
|
+
void SCS(accum_by_a)(const ScsMatrix *A, ScsLinSysWork *p, const scs_float *x,
|
120
|
+
scs_float *y) {
|
121
|
+
SCS(_accum_by_atrans)(p->At->n, p->At->x, p->At->i, p->At->p, x, y);
|
122
|
+
}
|
123
|
+
|
124
|
+
static void apply_pre_conditioner(scs_float *M, scs_float *z, scs_float *r,
|
125
|
+
scs_int n, scs_float *ipzr) {
|
126
|
+
scs_int i;
|
127
|
+
*ipzr = 0;
|
128
|
+
for (i = 0; i < n; ++i) {
|
129
|
+
z[i] = r[i] * M[i];
|
130
|
+
*ipzr += z[i] * r[i];
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A,
|
135
|
+
const ScsSettings *stgs) {
|
136
|
+
ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
|
137
|
+
p->p = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
|
138
|
+
p->r = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
|
139
|
+
p->Gp = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
|
140
|
+
p->tmp = (scs_float *)scs_malloc((A->m) * sizeof(scs_float));
|
141
|
+
|
142
|
+
/* memory for A transpose */
|
143
|
+
p->At = (ScsMatrix *)scs_malloc(sizeof(ScsMatrix));
|
144
|
+
p->At->m = A->n;
|
145
|
+
p->At->n = A->m;
|
146
|
+
p->At->i = (scs_int *)scs_malloc((A->p[A->n]) * sizeof(scs_int));
|
147
|
+
p->At->p = (scs_int *)scs_malloc((A->m + 1) * sizeof(scs_int));
|
148
|
+
p->At->x = (scs_float *)scs_malloc((A->p[A->n]) * sizeof(scs_float));
|
149
|
+
transpose(A, p);
|
150
|
+
|
151
|
+
/* preconditioner memory */
|
152
|
+
p->z = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
|
153
|
+
p->M = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
|
154
|
+
get_preconditioner(A, stgs, p);
|
155
|
+
|
156
|
+
p->total_solve_time = 0;
|
157
|
+
p->tot_cg_its = 0;
|
158
|
+
if (!p->p || !p->r || !p->Gp || !p->tmp || !p->At || !p->At->i || !p->At->p ||
|
159
|
+
!p->At->x) {
|
160
|
+
SCS(free_lin_sys_work)(p);
|
161
|
+
return SCS_NULL;
|
162
|
+
}
|
163
|
+
return p;
|
164
|
+
}
|
165
|
+
|
166
|
+
/* solves (I+A'A)x = b, s warm start, solution stored in b */
|
167
|
+
static scs_int pcg(const ScsMatrix *A, const ScsSettings *stgs,
|
168
|
+
ScsLinSysWork *pr, const scs_float *s, scs_float *b,
|
169
|
+
scs_int max_its, scs_float tol) {
|
170
|
+
scs_int i, n = A->n;
|
171
|
+
scs_float ipzr, ipzr_old, alpha;
|
172
|
+
scs_float *p = pr->p; /* cg direction */
|
173
|
+
scs_float *Gp = pr->Gp; /* updated CG direction */
|
174
|
+
scs_float *r = pr->r; /* cg residual */
|
175
|
+
scs_float *z = pr->z; /* for preconditioning */
|
176
|
+
scs_float *M = pr->M; /* inverse diagonal preconditioner */
|
177
|
+
|
178
|
+
if (s == SCS_NULL) {
|
179
|
+
memcpy(r, b, n * sizeof(scs_float));
|
180
|
+
memset(b, 0, n * sizeof(scs_float));
|
181
|
+
} else {
|
182
|
+
mat_vec(A, stgs, pr, s, r);
|
183
|
+
SCS(add_scaled_array)(r, b, n, -1);
|
184
|
+
SCS(scale_array)(r, -1, n);
|
185
|
+
memcpy(b, s, n * sizeof(scs_float));
|
186
|
+
}
|
187
|
+
|
188
|
+
/* check to see if we need to run CG at all */
|
189
|
+
if (SCS(norm)(r, n) < MIN(tol, 1e-18)) {
|
190
|
+
return 0;
|
191
|
+
}
|
192
|
+
|
193
|
+
apply_pre_conditioner(M, z, r, n, &ipzr);
|
194
|
+
memcpy(p, z, n * sizeof(scs_float));
|
195
|
+
|
196
|
+
for (i = 0; i < max_its; ++i) {
|
197
|
+
mat_vec(A, stgs, pr, p, Gp);
|
198
|
+
alpha = ipzr / SCS(dot)(p, Gp, n);
|
199
|
+
SCS(add_scaled_array)(b, p, n, alpha);
|
200
|
+
SCS(add_scaled_array)(r, Gp, n, -alpha);
|
201
|
+
|
202
|
+
if (SCS(norm)(r, n) < tol) {
|
203
|
+
#if EXTRA_VERBOSE > 0
|
204
|
+
scs_printf("tol: %.4e, resid: %.4e, iters: %li\n", tol, SCS(norm)(r, n),
|
205
|
+
(long)i + 1);
|
206
|
+
#endif
|
207
|
+
return i + 1;
|
208
|
+
}
|
209
|
+
ipzr_old = ipzr;
|
210
|
+
apply_pre_conditioner(M, z, r, n, &ipzr);
|
211
|
+
|
212
|
+
SCS(scale_array)(p, ipzr / ipzr_old, n);
|
213
|
+
SCS(add_scaled_array)(p, z, n, 1);
|
214
|
+
}
|
215
|
+
return i;
|
216
|
+
}
|
217
|
+
|
218
|
+
scs_int SCS(solve_lin_sys)(const ScsMatrix *A, const ScsSettings *stgs,
|
219
|
+
ScsLinSysWork *p, scs_float *b, const scs_float *s,
|
220
|
+
scs_int iter) {
|
221
|
+
scs_int cg_its;
|
222
|
+
SCS(timer) linsys_timer;
|
223
|
+
scs_float cg_tol =
|
224
|
+
SCS(norm)(b, A->n) *
|
225
|
+
(iter < 0 ? CG_BEST_TOL
|
226
|
+
: CG_MIN_TOL / POWF((scs_float)iter + 1, stgs->cg_rate));
|
227
|
+
|
228
|
+
SCS(tic)(&linsys_timer);
|
229
|
+
/* solves Mx = b, for x but stores result in b */
|
230
|
+
/* s contains warm-start (if available) */
|
231
|
+
SCS(accum_by_atrans)(A, p, &(b[A->n]), b);
|
232
|
+
/* solves (I+A'A)x = b, s warm start, solution stored in b */
|
233
|
+
cg_its = pcg(A, stgs, p, s, b, A->n, MAX(cg_tol, CG_BEST_TOL));
|
234
|
+
SCS(scale_array)(&(b[A->n]), -1, A->m);
|
235
|
+
SCS(accum_by_a)(A, p, b, &(b[A->n]));
|
236
|
+
|
237
|
+
if (iter >= 0) {
|
238
|
+
p->tot_cg_its += cg_its;
|
239
|
+
}
|
240
|
+
|
241
|
+
p->total_solve_time += SCS(tocq)(&linsys_timer);
|
242
|
+
#if EXTRA_VERBOSE > 0
|
243
|
+
scs_printf("linsys solve time: %1.2es\n", SCS(tocq)(&linsys_timer) / 1e3);
|
244
|
+
#endif
|
245
|
+
return 0;
|
246
|
+
}
|
247
|
+
|
248
|
+
void SCS(normalize_a)(ScsMatrix *A, const ScsSettings *stgs, const ScsCone *k,
|
249
|
+
ScsScaling *scal) {
|
250
|
+
SCS(_normalize_a)(A, stgs, k, scal);
|
251
|
+
}
|
252
|
+
|
253
|
+
void SCS(un_normalize_a)(ScsMatrix *A, const ScsSettings *stgs,
|
254
|
+
const ScsScaling *scal) {
|
255
|
+
SCS(_un_normalize_a)(A, stgs, scal);
|
256
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#ifndef PRIV_H_GUARD
|
2
|
+
#define PRIV_H_GUARD
|
3
|
+
|
4
|
+
#ifdef __cplusplus
|
5
|
+
extern "C" {
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#include <math.h>
|
9
|
+
#include "amatrix.h"
|
10
|
+
#include "glbopts.h"
|
11
|
+
#include "linalg.h"
|
12
|
+
#include "scs.h"
|
13
|
+
|
14
|
+
struct SCS_LIN_SYS_WORK {
|
15
|
+
scs_float *p; /* cg iterate */
|
16
|
+
scs_float *r; /* cg residual */
|
17
|
+
scs_float *Gp;
|
18
|
+
scs_float *tmp;
|
19
|
+
ScsMatrix *At;
|
20
|
+
/* preconditioning */
|
21
|
+
scs_float *z;
|
22
|
+
scs_float *M;
|
23
|
+
/* reporting */
|
24
|
+
scs_int tot_cg_its;
|
25
|
+
scs_float total_solve_time;
|
26
|
+
};
|
27
|
+
|
28
|
+
#ifdef __cplusplus
|
29
|
+
}
|
30
|
+
#endif
|
31
|
+
#endif
|
Binary file
|