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
|
@@ -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
|