scs 0.2.2 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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
@@ -1,221 +1,223 @@
|
|
1
1
|
#include "private.h"
|
2
|
+
#include "linsys.h"
|
2
3
|
|
3
|
-
|
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;
|
4
|
+
const char *SCS(get_lin_sys_method)() {
|
5
|
+
return "sparse-direct";
|
18
6
|
}
|
19
7
|
|
8
|
+
/*
|
20
9
|
char *SCS(get_lin_sys_summary)(ScsLinSysWork *p, const ScsInfo *info) {
|
21
10
|
char *str = (char *)scs_malloc(sizeof(char) * 128);
|
22
11
|
scs_int n = p->L->n;
|
23
|
-
sprintf(str, "
|
24
|
-
(long)(p->L->p[n] + n), p->total_solve_time / (info->iter + 1) / 1e3);
|
25
|
-
p->total_solve_time = 0;
|
12
|
+
sprintf(str, "lin-sys: nnz(L): %li\n", (long)(p->L->p[n] + n));
|
26
13
|
return str;
|
27
14
|
}
|
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
|
-
}
|
15
|
+
*/
|
46
16
|
|
47
17
|
void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
|
48
18
|
if (p) {
|
49
|
-
cs_spfree(p->L);
|
50
|
-
|
19
|
+
SCS(cs_spfree)(p->L);
|
20
|
+
SCS(cs_spfree)(p->kkt);
|
21
|
+
scs_free(p->diag_p);
|
22
|
+
scs_free(p->perm);
|
51
23
|
scs_free(p->Dinv);
|
52
24
|
scs_free(p->bp);
|
25
|
+
scs_free(p->diag_r_idxs);
|
26
|
+
scs_free(p->Lnz);
|
27
|
+
scs_free(p->iwork);
|
28
|
+
scs_free(p->etree);
|
29
|
+
scs_free(p->D);
|
30
|
+
scs_free(p->bwork);
|
31
|
+
scs_free(p->fwork);
|
53
32
|
scs_free(p);
|
54
33
|
}
|
55
34
|
}
|
56
35
|
|
57
|
-
static
|
58
|
-
|
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) {
|
36
|
+
static csc *form_kkt(const ScsMatrix *A, const ScsMatrix *P, scs_float *diag_p,
|
37
|
+
const scs_float *diag_r, scs_int *diag_r_idxs) {
|
110
38
|
/* ONLY UPPER TRIANGULAR PART IS STUFFED
|
111
|
-
* forms column compressed
|
39
|
+
* forms column compressed kkt matrix
|
112
40
|
* assumes column compressed form A matrix
|
113
41
|
*
|
114
|
-
* forms upper triangular part of [I A'; A -I]
|
42
|
+
* forms upper triangular part of [(I + P) A'; A -I]
|
43
|
+
* P : n x n, A: m x n.
|
115
44
|
*/
|
116
|
-
scs_int
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
45
|
+
scs_int h, i, j, count;
|
46
|
+
csc *Kcsc, *K;
|
47
|
+
scs_int n = A->n;
|
48
|
+
scs_int m = A->m;
|
49
|
+
scs_int Anz = A->p[n];
|
50
|
+
scs_int Knzmax;
|
51
|
+
scs_int *idx_mapping;
|
52
|
+
if (P) {
|
53
|
+
/* Upper bound P + I upper triangular component as Pnz + n */
|
54
|
+
Knzmax = n + m + Anz + P->p[n];
|
55
|
+
} else {
|
56
|
+
Knzmax = n + m + Anz;
|
57
|
+
}
|
58
|
+
K = SCS(cs_spalloc)(m + n, m + n, Knzmax, 1, 1);
|
122
59
|
|
123
|
-
#if
|
124
|
-
scs_printf("forming
|
60
|
+
#if VERBOSITY > 0
|
61
|
+
scs_printf("forming kkt\n");
|
125
62
|
#endif
|
126
|
-
|
63
|
+
/* Here we generate a triplet matrix and then compress to CSC */
|
127
64
|
if (!K) {
|
128
65
|
return SCS_NULL;
|
129
66
|
}
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
67
|
+
|
68
|
+
count = 0; /* element counter */
|
69
|
+
if (P) {
|
70
|
+
/* R_x + P in top left */
|
71
|
+
for (j = 0; j < n; j++) { /* cols */
|
72
|
+
diag_p[j] = 0.;
|
73
|
+
/* empty column, add diagonal */
|
74
|
+
if (P->p[j] == P->p[j + 1]) {
|
75
|
+
K->i[count] = j;
|
76
|
+
K->p[count] = j;
|
77
|
+
K->x[count] = diag_r[j];
|
78
|
+
diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
|
79
|
+
count++;
|
80
|
+
}
|
81
|
+
for (h = P->p[j]; h < P->p[j + 1]; h++) {
|
82
|
+
i = P->i[h]; /* row */
|
83
|
+
if (i > j) { /* only upper triangular needed */
|
84
|
+
break;
|
85
|
+
}
|
86
|
+
K->i[count] = i;
|
87
|
+
K->p[count] = j;
|
88
|
+
K->x[count] = P->x[h];
|
89
|
+
if (i == j) {
|
90
|
+
/* P has diagonal element */
|
91
|
+
diag_p[j] = P->x[h];
|
92
|
+
K->x[count] += diag_r[j];
|
93
|
+
diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
|
94
|
+
}
|
95
|
+
count++;
|
96
|
+
/* reached the end without adding diagonal, do it now */
|
97
|
+
if ((i < j) && (h + 1 == P->p[j + 1] || P->i[h + 1] > j)) {
|
98
|
+
K->i[count] = j;
|
99
|
+
K->p[count] = j;
|
100
|
+
K->x[count] = diag_r[j];
|
101
|
+
diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
|
102
|
+
count++;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
} else {
|
107
|
+
/* R_x in top left */
|
108
|
+
for (j = 0; j < n; j++) {
|
109
|
+
diag_p[j] = 0.;
|
110
|
+
K->i[count] = j;
|
111
|
+
K->p[count] = j;
|
112
|
+
K->x[count] = diag_r[j];
|
113
|
+
diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
|
114
|
+
count++;
|
115
|
+
}
|
136
116
|
}
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
K->
|
142
|
-
K->
|
143
|
-
|
117
|
+
|
118
|
+
/* A^T at top right */
|
119
|
+
for (j = 0; j < n; j++) {
|
120
|
+
for (h = A->p[j]; h < A->p[j + 1]; h++) {
|
121
|
+
K->p[count] = A->i[h] + n;
|
122
|
+
K->i[count] = j;
|
123
|
+
K->x[count] = A->x[h];
|
124
|
+
count++;
|
144
125
|
}
|
145
126
|
}
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
K->
|
150
|
-
K->
|
151
|
-
|
127
|
+
|
128
|
+
/* -R_y at bottom right */
|
129
|
+
for (j = 0; j < m; j++) {
|
130
|
+
K->i[count] = j + n;
|
131
|
+
K->p[count] = j + n;
|
132
|
+
K->x[count] = -diag_r[j + n];
|
133
|
+
diag_r_idxs[j + n] = count; /* store the indices where diag_r occurs */
|
134
|
+
count++;
|
135
|
+
}
|
136
|
+
|
137
|
+
K->nz = count;
|
138
|
+
idx_mapping = (scs_int *)scs_calloc(K->nz, sizeof(scs_int));
|
139
|
+
Kcsc = SCS(cs_compress)(K, idx_mapping);
|
140
|
+
for (i = 0; i < m + n; i++) {
|
141
|
+
diag_r_idxs[i] = idx_mapping[diag_r_idxs[i]];
|
152
142
|
}
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
cs_spfree(K);
|
157
|
-
return K_cs;
|
143
|
+
SCS(cs_spfree)(K);
|
144
|
+
scs_free(idx_mapping);
|
145
|
+
return Kcsc;
|
158
146
|
}
|
159
147
|
|
160
|
-
static scs_int _ldl_init(
|
161
|
-
*info = (scs_float *)
|
148
|
+
static scs_int _ldl_init(csc *A, scs_int *P, scs_float **info) {
|
149
|
+
*info = (scs_float *)scs_calloc(AMD_INFO, sizeof(scs_float));
|
162
150
|
return amd_order(A->n, A->p, A->i, P, (scs_float *)SCS_NULL, *info);
|
163
151
|
}
|
164
152
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
scs_int
|
169
|
-
|
170
|
-
|
171
|
-
scs_int *
|
172
|
-
|
173
|
-
|
174
|
-
if (
|
153
|
+
/* call only once */
|
154
|
+
static scs_int ldl_prepare(ScsLinSysWork *p) {
|
155
|
+
csc *kkt = p->kkt, *L = p->L;
|
156
|
+
scs_int n = kkt->n;
|
157
|
+
p->etree = (scs_int *)scs_calloc(n, sizeof(scs_int));
|
158
|
+
p->Lnz = (scs_int *)scs_calloc(n, sizeof(scs_int));
|
159
|
+
p->iwork = (scs_int *)scs_calloc(3 * n, sizeof(scs_int));
|
160
|
+
L->p = (scs_int *)scs_calloc((1 + n), sizeof(scs_int));
|
161
|
+
L->nzmax = QDLDL_etree(n, kkt->p, kkt->i, p->iwork, p->Lnz, p->etree);
|
162
|
+
if (L->nzmax < 0) {
|
175
163
|
scs_printf("Error in elimination tree calculation.\n");
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
164
|
+
if (L->nzmax == -1) {
|
165
|
+
scs_printf("Matrix is not perfectly upper triangular.\n");
|
166
|
+
} else if (L->nzmax == -2) {
|
167
|
+
scs_printf("Integer overflow in L nonzero count.\n");
|
168
|
+
}
|
169
|
+
return L->nzmax;
|
181
170
|
}
|
182
171
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
D = (scs_float *)
|
187
|
-
bwork = (scs_int *)
|
188
|
-
fwork = (scs_float *)
|
172
|
+
L->x = (scs_float *)scs_calloc(L->nzmax, sizeof(scs_float));
|
173
|
+
L->i = (scs_int *)scs_calloc(L->nzmax, sizeof(scs_int));
|
174
|
+
p->Dinv = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
175
|
+
p->D = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
176
|
+
p->bwork = (scs_int *)scs_calloc(n, sizeof(scs_int));
|
177
|
+
p->fwork = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
178
|
+
return L->nzmax;
|
179
|
+
}
|
189
180
|
|
190
|
-
|
181
|
+
/* can call many times */
|
182
|
+
static scs_int ldl_factor(ScsLinSysWork *p, scs_int num_vars) {
|
183
|
+
scs_int factor_status;
|
184
|
+
csc *kkt = p->kkt, *L = p->L;
|
185
|
+
#if VERBOSITY > 0
|
191
186
|
scs_printf("numeric factorization\n");
|
192
187
|
#endif
|
193
|
-
factor_status =
|
194
|
-
|
195
|
-
|
196
|
-
|
188
|
+
factor_status =
|
189
|
+
QDLDL_factor(kkt->n, kkt->p, kkt->i, kkt->x, L->p, L->i, L->x, p->D,
|
190
|
+
p->Dinv, p->Lnz, p->etree, p->bwork, p->iwork, p->fwork);
|
191
|
+
#if VERBOSITY > 0
|
192
|
+
scs_printf("finished numeric factorization.\n");
|
197
193
|
#endif
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
194
|
+
if (factor_status < 0) {
|
195
|
+
scs_printf("Error in LDL factorization when computing the nonzero "
|
196
|
+
"elements. There are zeros in the diagonal matrix.\n");
|
197
|
+
} else if (factor_status < num_vars) {
|
198
|
+
scs_printf("Error in LDL factorization when computing the nonzero "
|
199
|
+
"elements. The problem seems to be non-convex.\n");
|
200
|
+
scs_printf("factor_status: %li, num_vars: %li\n", (long)factor_status,
|
201
|
+
(long)num_vars);
|
202
|
+
return -1;
|
203
|
+
}
|
204
|
+
p->factorizations++;
|
205
205
|
return factor_status;
|
206
206
|
}
|
207
207
|
|
208
208
|
static void _ldl_perm(scs_int n, scs_float *x, scs_float *b, scs_int *P) {
|
209
209
|
scs_int j;
|
210
|
-
for (j = 0; j < n; j++)
|
210
|
+
for (j = 0; j < n; j++)
|
211
|
+
x[j] = b[P[j]];
|
211
212
|
}
|
212
213
|
|
213
214
|
static void _ldl_permt(scs_int n, scs_float *x, scs_float *b, scs_int *P) {
|
214
215
|
scs_int j;
|
215
|
-
for (j = 0; j < n; j++)
|
216
|
+
for (j = 0; j < n; j++)
|
217
|
+
x[P[j]] = b[j];
|
216
218
|
}
|
217
219
|
|
218
|
-
static void _ldl_solve(scs_float *b,
|
220
|
+
static void _ldl_solve(scs_float *b, csc *L, scs_float *Dinv, scs_int *P,
|
219
221
|
scs_float *bp) {
|
220
222
|
/* solves PLDL'P' x = b for x */
|
221
223
|
scs_int n = L->n;
|
@@ -224,41 +226,34 @@ static void _ldl_solve(scs_float *b, _cs *L, scs_float *Dinv, scs_int *P,
|
|
224
226
|
_ldl_permt(n, b, bp, P);
|
225
227
|
}
|
226
228
|
|
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
229
|
static scs_int *cs_pinv(scs_int const *p, scs_int n) {
|
238
230
|
scs_int k, *pinv;
|
239
231
|
if (!p) {
|
240
232
|
return SCS_NULL;
|
241
233
|
} /* p = SCS_NULL denotes identity */
|
242
|
-
pinv = (scs_int *)
|
234
|
+
pinv = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* allocate result */
|
243
235
|
if (!pinv) {
|
244
236
|
return SCS_NULL;
|
245
|
-
}
|
246
|
-
for (k = 0; k < n; k++)
|
247
|
-
|
237
|
+
} /* out of memory */
|
238
|
+
for (k = 0; k < n; k++)
|
239
|
+
pinv[p[k]] = k; /* invert the permutation */
|
240
|
+
return pinv; /* return result */
|
248
241
|
}
|
249
242
|
|
250
|
-
static
|
243
|
+
static csc *cs_symperm(const csc *A, const scs_int *pinv, scs_int *idx_mapping,
|
244
|
+
scs_int values) {
|
251
245
|
scs_int i, j, p, q, i2, j2, n, *Ap, *Ai, *Cp, *Ci, *w;
|
252
246
|
scs_float *Cx, *Ax;
|
253
|
-
|
247
|
+
csc *C;
|
254
248
|
n = A->n;
|
255
249
|
Ap = A->p;
|
256
250
|
Ai = A->i;
|
257
251
|
Ax = A->x;
|
258
|
-
C = cs_spalloc(n, n, Ap[n], values && (Ax != SCS_NULL),
|
252
|
+
C = SCS(cs_spalloc)(n, n, Ap[n], values && (Ax != SCS_NULL),
|
253
|
+
0); /* alloc result*/
|
259
254
|
w = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* get workspace */
|
260
255
|
if (!C || !w) {
|
261
|
-
return cs_done(C, w, SCS_NULL, 0);
|
256
|
+
return SCS(cs_done)(C, w, SCS_NULL, 0);
|
262
257
|
} /* out of memory */
|
263
258
|
Cp = C->p;
|
264
259
|
Ci = C->i;
|
@@ -288,79 +283,93 @@ static _cs *cs_symperm(const _cs *A, const scs_int *pinv, scs_int values) {
|
|
288
283
|
if (Cx) {
|
289
284
|
Cx[q] = Ax[p];
|
290
285
|
}
|
286
|
+
idx_mapping[p] = q; /* old to new indices */
|
291
287
|
}
|
292
288
|
}
|
293
|
-
return cs_done(C, w, SCS_NULL,
|
289
|
+
return SCS(cs_done)(C, w, SCS_NULL,
|
290
|
+
1); /* success; free workspace, return C */
|
294
291
|
}
|
295
292
|
|
296
|
-
static
|
297
|
-
|
293
|
+
static csc *permute_kkt(const ScsMatrix *A, const ScsMatrix *P,
|
294
|
+
ScsLinSysWork *p, const scs_float *diag_r) {
|
298
295
|
scs_float *info;
|
299
|
-
scs_int *Pinv, amd_status,
|
300
|
-
|
301
|
-
if (!
|
302
|
-
return
|
296
|
+
scs_int *Pinv, amd_status, *idx_mapping, i;
|
297
|
+
csc *kkt_perm, *kkt = form_kkt(A, P, p->diag_p, diag_r, p->diag_r_idxs);
|
298
|
+
if (!kkt) {
|
299
|
+
return SCS_NULL;
|
303
300
|
}
|
304
|
-
amd_status = _ldl_init(
|
301
|
+
amd_status = _ldl_init(kkt, p->perm, &info);
|
305
302
|
if (amd_status < 0) {
|
306
|
-
|
307
|
-
|
308
|
-
#if EXTRA_VERBOSE > 0
|
309
|
-
if (stgs->verbose) {
|
310
|
-
scs_printf("Matrix factorization info:\n");
|
311
|
-
amd_info(info);
|
303
|
+
scs_printf("AMD permutatation error.\n");
|
304
|
+
return SCS_NULL;
|
312
305
|
}
|
306
|
+
#if VERBOSITY > 0
|
307
|
+
scs_printf("Matrix factorization info:\n");
|
308
|
+
amd_info(info);
|
313
309
|
#endif
|
314
|
-
Pinv = cs_pinv(p->
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
310
|
+
Pinv = cs_pinv(p->perm, A->n + A->m);
|
311
|
+
idx_mapping = (scs_int *)scs_calloc(kkt->nzmax, sizeof(scs_int));
|
312
|
+
kkt_perm = cs_symperm(kkt, Pinv, idx_mapping, 1);
|
313
|
+
for (i = 0; i < A->n + A->m; i++) {
|
314
|
+
p->diag_r_idxs[i] = idx_mapping[p->diag_r_idxs[i]];
|
315
|
+
}
|
316
|
+
SCS(cs_spfree)(kkt);
|
319
317
|
scs_free(Pinv);
|
320
318
|
scs_free(info);
|
321
|
-
|
319
|
+
scs_free(idx_mapping);
|
320
|
+
return kkt_perm;
|
322
321
|
}
|
323
322
|
|
324
|
-
|
325
|
-
|
323
|
+
void SCS(update_lin_sys_diag_r)(ScsLinSysWork *p, const scs_float *diag_r) {
|
324
|
+
scs_int i, ldl_status;
|
325
|
+
for (i = 0; i < p->n; ++i) {
|
326
|
+
/* top left is R_x + P, bottom right is -R_y */
|
327
|
+
p->kkt->x[p->diag_r_idxs[i]] = p->diag_p[i] + diag_r[i];
|
328
|
+
}
|
329
|
+
for (i = p->n; i < p->n + p->m; ++i) {
|
330
|
+
/* top left is R_x + P, bottom right is -R_y */
|
331
|
+
p->kkt->x[p->diag_r_idxs[i]] = -diag_r[i];
|
332
|
+
}
|
333
|
+
ldl_status = ldl_factor(p, p->n);
|
334
|
+
if (ldl_status < 0) {
|
335
|
+
scs_printf("Error in LDL factorization when updating.\n");
|
336
|
+
/* TODO: this is broken somehow */
|
337
|
+
/* SCS(free_lin_sys_work)(p); */
|
338
|
+
return;
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A, const ScsMatrix *P,
|
343
|
+
const scs_float *diag_r) {
|
326
344
|
ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
|
327
|
-
scs_int n_plus_m = A->n + A->m;
|
328
|
-
p->
|
329
|
-
p->
|
330
|
-
p->
|
345
|
+
scs_int n_plus_m = A->n + A->m, ldl_status, ldl_prepare_status;
|
346
|
+
p->m = A->m;
|
347
|
+
p->n = A->n;
|
348
|
+
p->diag_p = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
|
349
|
+
p->perm = (scs_int *)scs_calloc(sizeof(scs_int), n_plus_m);
|
350
|
+
p->L = (csc *)scs_calloc(1, sizeof(csc));
|
351
|
+
p->bp = (scs_float *)scs_calloc(n_plus_m, sizeof(scs_float));
|
352
|
+
p->diag_r_idxs = (scs_int *)scs_calloc(n_plus_m, sizeof(scs_int));
|
353
|
+
p->factorizations = 0;
|
331
354
|
p->L->m = n_plus_m;
|
332
355
|
p->L->n = n_plus_m;
|
333
356
|
p->L->nz = -1;
|
334
|
-
|
335
|
-
|
336
|
-
|
357
|
+
p->kkt = permute_kkt(A, P, p, diag_r);
|
358
|
+
ldl_prepare_status = ldl_prepare(p);
|
359
|
+
ldl_status = ldl_factor(p, A->n);
|
360
|
+
if (ldl_prepare_status < 0 || ldl_status < 0) {
|
361
|
+
scs_printf("Error in LDL initial factorization.\n");
|
362
|
+
/* TODO: this is broken somehow */
|
363
|
+
/* SCS(free_lin_sys_work)(p); */
|
337
364
|
return SCS_NULL;
|
338
365
|
}
|
339
|
-
p->total_solve_time = 0.0;
|
340
366
|
return p;
|
341
367
|
}
|
342
368
|
|
343
|
-
scs_int SCS(solve_lin_sys)(
|
344
|
-
|
345
|
-
scs_int iter) {
|
369
|
+
scs_int SCS(solve_lin_sys)(ScsLinSysWork *p, scs_float *b, const scs_float *s,
|
370
|
+
scs_float tol) {
|
346
371
|
/* returns solution to linear system */
|
347
372
|
/* Ax = b with solution stored in b */
|
348
|
-
|
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
|
373
|
+
_ldl_solve(b, p->L, p->Dinv, p->perm, p->bp);
|
355
374
|
return 0;
|
356
375
|
}
|
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
|
-
}
|
@@ -5,19 +5,25 @@
|
|
5
5
|
extern "C" {
|
6
6
|
#endif
|
7
7
|
|
8
|
-
#include "
|
8
|
+
#include "csparse.h"
|
9
9
|
#include "external/amd/amd.h"
|
10
10
|
#include "external/qdldl/qdldl.h"
|
11
11
|
#include "glbopts.h"
|
12
12
|
#include "scs.h"
|
13
|
+
#include "scs_matrix.h"
|
13
14
|
|
14
|
-
typedef struct SPARSE_MATRIX _cs;
|
15
15
|
struct SCS_LIN_SYS_WORK {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
scs_float
|
16
|
+
scs_int m, n; /* linear system dimensions */
|
17
|
+
csc *kkt, *L; /* KKT, and factorization matrix L resp. */
|
18
|
+
scs_float *Dinv; /* inverse diagonal matrix of factorization */
|
19
|
+
scs_int *perm; /* permutation of KKT matrix for factorization */
|
20
|
+
scs_float *bp; /* workspace memory for solves */
|
21
|
+
scs_int *diag_r_idxs;
|
22
|
+
scs_int factorizations;
|
23
|
+
/* ldl factorization workspace */
|
24
|
+
scs_float *D, *fwork;
|
25
|
+
scs_int *etree, *iwork, *Lnz, *bwork;
|
26
|
+
scs_float *diag_p;
|
21
27
|
};
|
22
28
|
|
23
29
|
#ifdef __cplusplus
|