scs 0.5.6 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +1 -1
- data/lib/scs/ffi.rb +18 -0
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +2 -3
- data/vendor/scs/CLAUDE.md +115 -0
- data/vendor/scs/CMakeLists.txt +330 -201
- data/vendor/scs/CONTRIBUTING.md +49 -0
- data/vendor/scs/Makefile +90 -43
- data/vendor/scs/README.md +96 -2
- data/vendor/scs/include/aa.h +59 -11
- data/vendor/scs/include/aa_stats.h +47 -0
- data/vendor/scs/include/cones.h +16 -7
- data/vendor/scs/include/glbopts.h +113 -26
- data/vendor/scs/include/linalg.h +5 -1
- data/vendor/scs/include/linsys.h +1 -2
- data/vendor/scs/include/normalize.h +6 -2
- data/vendor/scs/include/rw.h +9 -3
- data/vendor/scs/include/scs.h +17 -1
- data/vendor/scs/include/scs_blas.h +8 -0
- data/vendor/scs/include/scs_types.h +2 -2
- data/vendor/scs/include/scs_work.h +22 -1
- data/vendor/scs/include/util.h +3 -6
- data/vendor/scs/include/util_spectral_cones.h +3 -3
- data/vendor/scs/linsys/accelerate/direct/private.c +126 -0
- data/vendor/scs/linsys/accelerate/direct/private.h +34 -0
- data/vendor/scs/linsys/cpu/dense/private.c +250 -0
- data/vendor/scs/linsys/cpu/dense/private.h +31 -0
- data/vendor/scs/linsys/cpu/direct/private.c +86 -44
- data/vendor/scs/linsys/cpu/indirect/private.c +647 -113
- data/vendor/scs/linsys/cpu/indirect/private.h +28 -0
- data/vendor/scs/linsys/csparse.c +9 -3
- data/vendor/scs/linsys/csparse.h +4 -2
- data/vendor/scs/linsys/cudss/direct/private.c +77 -43
- data/vendor/scs/linsys/cudss/direct/private.h +33 -7
- data/vendor/scs/linsys/gpu/indirect/private.c +6 -2
- data/vendor/scs/linsys/mkl/direct/private.c +63 -31
- data/vendor/scs/linsys/mkl/direct/private.h +0 -1
- data/vendor/scs/linsys/scs_matrix.c +291 -165
- data/vendor/scs/linsys/scs_matrix.h +7 -9
- data/vendor/scs/scs.mk +35 -13
- data/vendor/scs/src/aa.c +673 -166
- data/vendor/scs/src/cones.c +545 -223
- data/vendor/scs/src/ctrlc.c +59 -16
- data/vendor/scs/src/exp_cone.c +70 -50
- data/vendor/scs/src/linalg.c +21 -2
- data/vendor/scs/src/normalize.c +24 -26
- data/vendor/scs/src/rw.c +596 -124
- data/vendor/scs/src/scs.c +990 -513
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +240 -187
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +108 -85
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +62 -63
- data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +85 -78
- data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +92 -97
- data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +39 -28
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +59 -40
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +37 -29
- data/vendor/scs/src/spectral_cones/util_spectral_cones.c +12 -6
- data/vendor/scs/src/util.c +37 -7
- data/vendor/scs/test/mkl_interface_mismatch.c +97 -0
- data/vendor/scs/test/packaging/CMakeLists.txt +21 -0
- data/vendor/scs/test/packaging/consume.c +50 -0
- data/vendor/scs/test/problem_utils.h +9 -2
- data/vendor/scs/test/problems/dense_qp.h +64 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +6 -2
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +10 -2
- data/vendor/scs/test/problems/infeasible_lp.h +66 -0
- data/vendor/scs/test/problems/infeasible_socp.h +75 -0
- data/vendor/scs/test/problems/lp_update.h +110 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -1
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +6 -3
- data/vendor/scs/test/problems/small_qp.h +5 -0
- data/vendor/scs/test/problems/test_box_cone.h +92 -0
- data/vendor/scs/test/problems/test_dual_exp_cone.h +96 -0
- data/vendor/scs/test/problems/test_inaccurate.h +212 -0
- data/vendor/scs/test/problems/test_mixed_cones.h +113 -0
- data/vendor/scs/test/problems/test_normalize_roundtrip.h +279 -0
- data/vendor/scs/test/problems/test_power_cone.h +414 -0
- data/vendor/scs/test/problems/test_psd_metric.h +109 -0
- data/vendor/scs/test/problems/test_psd_n1.h +84 -0
- data/vendor/scs/test/problems/test_root_plus.h +191 -0
- data/vendor/scs/test/problems/test_rw_settings.h +112 -0
- data/vendor/scs/test/problems/test_soc_sizes.h +393 -0
- data/vendor/scs/test/problems/test_solver_options.h +558 -0
- data/vendor/scs/test/problems/test_validation.h +263 -24
- data/vendor/scs/test/problems/test_zero_cone.h +81 -0
- data/vendor/scs/test/problems/unbounded_lp.h +66 -0
- data/vendor/scs/test/problems/unbounded_socp.h +71 -0
- data/vendor/scs/test/run_from_file.c +6 -0
- data/vendor/scs/test/run_tests.c +71 -0
- data/vendor/scs/test/rw_settings.c +7 -0
- data/vendor/scs/test/spectral_cones_problems/test_ell1_and_nuc.h +128 -0
- data/vendor/scs/test/spectral_cones_problems/test_ell1_cone.h +115 -0
- metadata +35 -3
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Dense direct linear system solver using the Gram matrix reduction:
|
|
3
|
+
*
|
|
4
|
+
* [R_x + P A'] [x] [rx]
|
|
5
|
+
* [ A -R_y] [y] = [ry]
|
|
6
|
+
*
|
|
7
|
+
* is reduced to:
|
|
8
|
+
*
|
|
9
|
+
* G x = rx + A' R_y^{-1} ry, where G = R_x + P + A' R_y^{-1} A
|
|
10
|
+
* y = R_y^{-1} (A x - ry)
|
|
11
|
+
*
|
|
12
|
+
* G is n x n symmetric positive definite, factorized via Cholesky (dpotrf).
|
|
13
|
+
* A is stored as a dense m x n matrix for fast dgemv operations.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include "private.h"
|
|
17
|
+
|
|
18
|
+
#include <string.h>
|
|
19
|
+
|
|
20
|
+
/* LAPACK / BLAS prototypes */
|
|
21
|
+
#ifdef __cplusplus
|
|
22
|
+
extern "C" {
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
/* Cholesky factorization */
|
|
26
|
+
void BLAS(potrf)(const char *uplo, blas_int *n, scs_float *a, blas_int *lda,
|
|
27
|
+
blas_int *info);
|
|
28
|
+
/* Cholesky solve */
|
|
29
|
+
void BLAS(potrs)(const char *uplo, blas_int *n, blas_int *nrhs,
|
|
30
|
+
const scs_float *a, blas_int *lda, scs_float *b,
|
|
31
|
+
blas_int *ldb, blas_int *info);
|
|
32
|
+
/* Matrix-vector multiply: y = alpha * op(A) * x + beta * y */
|
|
33
|
+
void BLAS(gemv)(const char *trans, blas_int *m, blas_int *n, scs_float *alpha,
|
|
34
|
+
const scs_float *a, blas_int *lda, const scs_float *x,
|
|
35
|
+
blas_int *incx, scs_float *beta, scs_float *y, blas_int *incy);
|
|
36
|
+
/* Symmetric rank-k update: C = alpha * A' * A + beta * C */
|
|
37
|
+
void BLAS(syrk)(const char *uplo, const char *trans, blas_int *n, blas_int *k,
|
|
38
|
+
scs_float *alpha, const scs_float *a, blas_int *lda,
|
|
39
|
+
scs_float *beta, scs_float *c, blas_int *ldc);
|
|
40
|
+
|
|
41
|
+
#ifdef __cplusplus
|
|
42
|
+
}
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
const char *scs_get_lin_sys_method(void) {
|
|
46
|
+
return "dense-direct-cholesky";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Convert sparse CSC matrix A (m x n) to dense column-major array */
|
|
50
|
+
static void sparse_to_dense(const ScsMatrix *A, scs_float *A_dense) {
|
|
51
|
+
scs_int j, k;
|
|
52
|
+
scs_int m = A->m;
|
|
53
|
+
scs_int n = A->n;
|
|
54
|
+
memset(A_dense, 0, (size_t)m * n * sizeof(scs_float));
|
|
55
|
+
for (j = 0; j < n; ++j) {
|
|
56
|
+
for (k = A->p[j]; k < A->p[j + 1]; ++k) {
|
|
57
|
+
A_dense[j * m + A->i[k]] = A->x[k];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Form Gram matrix G = R_x + P + A' diag(r_y_inv) A (upper triangle).
|
|
63
|
+
* Uses BLAS dsyrk for the A' diag(r_y_inv) A product. */
|
|
64
|
+
static void form_gram(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
65
|
+
scs_int i, j, k;
|
|
66
|
+
scs_int n = p->n;
|
|
67
|
+
scs_int m = p->m;
|
|
68
|
+
scs_float *G = p->G;
|
|
69
|
+
const ScsMatrix *P = p->P;
|
|
70
|
+
|
|
71
|
+
/* Compute r_y_inv = 1 / R_y and sqrt_r_y_inv in tmp_m */
|
|
72
|
+
for (i = 0; i < m; ++i) {
|
|
73
|
+
p->r_y_inv[i] = 1.0 / diag_r[n + i];
|
|
74
|
+
p->tmp_m[i] = SQRTF(p->r_y_inv[i]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Form S = diag(sqrt(r_y_inv)) * A in pre-allocated workspace.
|
|
78
|
+
* S is m x n, stored column-major. */
|
|
79
|
+
scs_float *S = p->S;
|
|
80
|
+
for (j = 0; j < n; ++j) {
|
|
81
|
+
for (i = 0; i < m; ++i) {
|
|
82
|
+
S[j * m + i] = p->tmp_m[i] * p->A_dense[j * m + i];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* G = S' * S = A' diag(r_y_inv) A (upper triangle) */
|
|
87
|
+
{
|
|
88
|
+
blas_int bn = (blas_int)n;
|
|
89
|
+
blas_int bm = (blas_int)m;
|
|
90
|
+
scs_float one = 1.0;
|
|
91
|
+
scs_float zero = 0.0;
|
|
92
|
+
char uplo = 'U';
|
|
93
|
+
char trans = 'T';
|
|
94
|
+
BLAS(syrk)(&uplo, &trans, &bn, &bm, &one, S, &bm, &zero, G, &bn);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Add R_x to diagonal */
|
|
98
|
+
for (i = 0; i < n; ++i) {
|
|
99
|
+
G[i * n + i] += diag_r[i];
|
|
100
|
+
p->diag_p[i] = 0.;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Add P (symmetric, stored upper triangular CSC) */
|
|
104
|
+
if (P) {
|
|
105
|
+
for (j = 0; j < n; ++j) {
|
|
106
|
+
for (k = P->p[j]; k < P->p[j + 1]; ++k) {
|
|
107
|
+
i = P->i[k];
|
|
108
|
+
G[j * n + i] += P->x[k]; /* upper triangle: i <= j */
|
|
109
|
+
if (i == j) {
|
|
110
|
+
p->diag_p[j] = P->x[k];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
118
|
+
const scs_float *diag_r) {
|
|
119
|
+
blas_int info, bn;
|
|
120
|
+
ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
|
|
121
|
+
if (!p) {
|
|
122
|
+
return SCS_NULL;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
p->n = A->n;
|
|
126
|
+
p->m = A->m;
|
|
127
|
+
p->P = P;
|
|
128
|
+
|
|
129
|
+
p->A_dense = (scs_float *)scs_calloc((size_t)A->m * A->n, sizeof(scs_float));
|
|
130
|
+
p->G = (scs_float *)scs_calloc((size_t)A->n * A->n, sizeof(scs_float));
|
|
131
|
+
p->r_y_inv = (scs_float *)scs_calloc(A->m, sizeof(scs_float));
|
|
132
|
+
p->tmp_m = (scs_float *)scs_calloc(A->m, sizeof(scs_float));
|
|
133
|
+
p->S = (scs_float *)scs_calloc((size_t)A->m * A->n, sizeof(scs_float));
|
|
134
|
+
p->diag_p = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
|
|
135
|
+
|
|
136
|
+
if (!p->A_dense || !p->G || !p->r_y_inv || !p->tmp_m || !p->S || !p->diag_p) {
|
|
137
|
+
scs_free_lin_sys_work(p);
|
|
138
|
+
return SCS_NULL;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Convert sparse A to dense once */
|
|
142
|
+
sparse_to_dense(A, p->A_dense);
|
|
143
|
+
|
|
144
|
+
/* Form and factorize Gram matrix */
|
|
145
|
+
form_gram(p, diag_r);
|
|
146
|
+
bn = (blas_int)p->n;
|
|
147
|
+
{
|
|
148
|
+
char uplo = 'U';
|
|
149
|
+
BLAS(potrf)(&uplo, &bn, p->G, &bn, &info);
|
|
150
|
+
}
|
|
151
|
+
if (info != 0) {
|
|
152
|
+
scs_printf("Error in dense Cholesky factorization (dpotrf), info = %d\n",
|
|
153
|
+
(int)info);
|
|
154
|
+
scs_free_lin_sys_work(p);
|
|
155
|
+
return SCS_NULL;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return p;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/*
|
|
162
|
+
* Solve:
|
|
163
|
+
* x = G^{-1} (rx + A' R_y^{-1} ry)
|
|
164
|
+
* y = R_y^{-1} (A x - ry)
|
|
165
|
+
*
|
|
166
|
+
* Input b = [rx; ry], solution stored in b = [x; y].
|
|
167
|
+
*/
|
|
168
|
+
scs_int scs_solve_lin_sys(ScsLinSysWork *p, scs_float *b, const scs_float *s,
|
|
169
|
+
scs_float tol) {
|
|
170
|
+
blas_int bn = (blas_int)p->n;
|
|
171
|
+
blas_int bm = (blas_int)p->m;
|
|
172
|
+
blas_int one = 1;
|
|
173
|
+
blas_int info;
|
|
174
|
+
scs_float alpha, beta;
|
|
175
|
+
scs_int i;
|
|
176
|
+
|
|
177
|
+
scs_float *rx = b;
|
|
178
|
+
scs_float *ry = b + p->n;
|
|
179
|
+
|
|
180
|
+
/* tmp_m = R_y^{-1} ry */
|
|
181
|
+
for (i = 0; i < p->m; ++i) {
|
|
182
|
+
p->tmp_m[i] = p->r_y_inv[i] * ry[i];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* rx += A' * tmp_m (rx = rx + A' R_y^{-1} ry) */
|
|
186
|
+
{
|
|
187
|
+
char trans = 'T';
|
|
188
|
+
alpha = 1.0;
|
|
189
|
+
beta = 1.0;
|
|
190
|
+
BLAS(gemv)(&trans, &bm, &bn, &alpha, p->A_dense, &bm, p->tmp_m, &one,
|
|
191
|
+
&beta, rx, &one);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Solve G x = rx, result in rx (= b[:n]) */
|
|
195
|
+
{
|
|
196
|
+
char uplo = 'U';
|
|
197
|
+
BLAS(potrs)(&uplo, &bn, &one, p->G, &bn, rx, &bn, &info);
|
|
198
|
+
}
|
|
199
|
+
if (info != 0) {
|
|
200
|
+
scs_printf("Error in dense Cholesky solve (dpotrs), info = %d\n",
|
|
201
|
+
(int)info);
|
|
202
|
+
return (scs_int)info;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* ry = A x - ry */
|
|
206
|
+
{
|
|
207
|
+
char trans = 'N';
|
|
208
|
+
alpha = 1.0;
|
|
209
|
+
beta = -1.0;
|
|
210
|
+
BLAS(gemv)(&trans, &bm, &bn, &alpha, p->A_dense, &bm, rx, &one, &beta, ry,
|
|
211
|
+
&one);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* ry = R_y^{-1} (A x - ry) = y */
|
|
215
|
+
for (i = 0; i < p->m; ++i) {
|
|
216
|
+
ry[i] *= p->r_y_inv[i];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* Update diagonal R entries: re-form Gram matrix and re-factorize */
|
|
223
|
+
scs_int scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
224
|
+
blas_int info, bn;
|
|
225
|
+
form_gram(p, diag_r);
|
|
226
|
+
bn = (blas_int)p->n;
|
|
227
|
+
{
|
|
228
|
+
char uplo = 'U';
|
|
229
|
+
BLAS(potrf)(&uplo, &bn, p->G, &bn, &info);
|
|
230
|
+
}
|
|
231
|
+
if (info != 0) {
|
|
232
|
+
scs_printf(
|
|
233
|
+
"Error in dense Cholesky re-factorization (dpotrf), info = %d\n",
|
|
234
|
+
(int)info);
|
|
235
|
+
return (scs_int)info;
|
|
236
|
+
}
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
void scs_free_lin_sys_work(ScsLinSysWork *p) {
|
|
241
|
+
if (p) {
|
|
242
|
+
scs_free(p->A_dense);
|
|
243
|
+
scs_free(p->G);
|
|
244
|
+
scs_free(p->r_y_inv);
|
|
245
|
+
scs_free(p->tmp_m);
|
|
246
|
+
scs_free(p->S);
|
|
247
|
+
scs_free(p->diag_p);
|
|
248
|
+
scs_free(p);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -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 "glbopts.h"
|
|
9
|
+
#include "linsys.h"
|
|
10
|
+
#include "scs_blas.h"
|
|
11
|
+
|
|
12
|
+
struct SCS_LIN_SYS_WORK {
|
|
13
|
+
scs_int n; /* number of QP variables */
|
|
14
|
+
scs_int m; /* number of QP constraints */
|
|
15
|
+
|
|
16
|
+
scs_float *A_dense; /* dense A matrix, m x n column-major */
|
|
17
|
+
scs_float *G; /* Gram matrix R_x + P + A' R_y^{-1} A, n x n col-major */
|
|
18
|
+
scs_float *r_y_inv; /* 1 / R_y diagonal, length m */
|
|
19
|
+
scs_float *tmp_m; /* workspace of length m */
|
|
20
|
+
scs_float *S; /* scratch for scaled A, m x n column-major */
|
|
21
|
+
|
|
22
|
+
/* These are required for matrix updates */
|
|
23
|
+
const ScsMatrix *P; /* does *not* own this memory */
|
|
24
|
+
scs_float *diag_p; /* Diagonal values of P */
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
#ifdef __cplusplus
|
|
28
|
+
}
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
#endif
|
|
@@ -1,30 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
/* ======================== Includes / Types ======================== */
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
return "sparse-direct-amd-qdldl";
|
|
5
|
-
}
|
|
3
|
+
#include "private.h"
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
if (p) {
|
|
9
|
-
SCS(cs_spfree)(p->L);
|
|
10
|
-
SCS(cs_spfree)(p->kkt);
|
|
11
|
-
scs_free(p->diag_p);
|
|
12
|
-
scs_free(p->perm);
|
|
13
|
-
scs_free(p->Dinv);
|
|
14
|
-
scs_free(p->bp);
|
|
15
|
-
scs_free(p->diag_r_idxs);
|
|
16
|
-
scs_free(p->Lnz);
|
|
17
|
-
scs_free(p->iwork);
|
|
18
|
-
scs_free(p->etree);
|
|
19
|
-
scs_free(p->D);
|
|
20
|
-
scs_free(p->bwork);
|
|
21
|
-
scs_free(p->fwork);
|
|
22
|
-
scs_free(p);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
5
|
+
/* ======================== LDL Factorization Internals ======================== */
|
|
25
6
|
|
|
26
7
|
static scs_int _ldl_init(ScsMatrix *A, scs_int *P, scs_float **info) {
|
|
27
8
|
*info = (scs_float *)scs_calloc(AMD_INFO, sizeof(scs_float));
|
|
9
|
+
if (!*info) {
|
|
10
|
+
return -1;
|
|
11
|
+
}
|
|
28
12
|
return amd_order(A->n, A->p, A->i, P, (scs_float *)SCS_NULL, *info);
|
|
29
13
|
}
|
|
30
14
|
|
|
@@ -36,6 +20,9 @@ static scs_int ldl_prepare(ScsLinSysWork *p) {
|
|
|
36
20
|
p->Lnz = (scs_int *)scs_calloc(n, sizeof(scs_int));
|
|
37
21
|
p->iwork = (scs_int *)scs_calloc(3 * n, sizeof(scs_int));
|
|
38
22
|
L->p = (scs_int *)scs_calloc((1 + n), sizeof(scs_int));
|
|
23
|
+
if (!p->etree || !p->Lnz || !p->iwork || !L->p) {
|
|
24
|
+
return -1;
|
|
25
|
+
}
|
|
39
26
|
nzmax = QDLDL_etree(n, kkt->p, kkt->i, p->iwork, p->Lnz, p->etree);
|
|
40
27
|
if (nzmax < 0) {
|
|
41
28
|
scs_printf("Error in elimination tree calculation.\n");
|
|
@@ -53,6 +40,9 @@ static scs_int ldl_prepare(ScsLinSysWork *p) {
|
|
|
53
40
|
p->D = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
|
54
41
|
p->bwork = (QDLDL_bool *)scs_calloc(n, sizeof(QDLDL_bool));
|
|
55
42
|
p->fwork = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
|
43
|
+
if (!L->x || !L->i || !p->Dinv || !p->D || !p->bwork || !p->fwork) {
|
|
44
|
+
return -1;
|
|
45
|
+
}
|
|
56
46
|
return nzmax;
|
|
57
47
|
}
|
|
58
48
|
|
|
@@ -104,6 +94,8 @@ static void _ldl_solve(scs_float *b, ScsMatrix *L, scs_float *Dinv, scs_int *P,
|
|
|
104
94
|
_ldl_permt(n, b, bp, P);
|
|
105
95
|
}
|
|
106
96
|
|
|
97
|
+
/* ======================== KKT Matrix Permutation ======================== */
|
|
98
|
+
|
|
107
99
|
static scs_int *cs_pinv(scs_int const *p, scs_int n) {
|
|
108
100
|
scs_int k, *pinv;
|
|
109
101
|
if (!p) {
|
|
@@ -181,6 +173,8 @@ static ScsMatrix *permute_kkt(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
181
173
|
amd_status = _ldl_init(kkt, p->perm, &info);
|
|
182
174
|
if (amd_status < 0) {
|
|
183
175
|
scs_printf("AMD permutatation error.\n");
|
|
176
|
+
SCS(cs_spfree)(kkt);
|
|
177
|
+
scs_free(info);
|
|
184
178
|
return SCS_NULL;
|
|
185
179
|
}
|
|
186
180
|
#if VERBOSITY > 0
|
|
@@ -189,7 +183,20 @@ static ScsMatrix *permute_kkt(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
189
183
|
#endif
|
|
190
184
|
Pinv = cs_pinv(p->perm, A->n + A->m);
|
|
191
185
|
idx_mapping = (scs_int *)scs_calloc(kkt_nnz, sizeof(scs_int));
|
|
186
|
+
if (!Pinv || !idx_mapping) {
|
|
187
|
+
SCS(cs_spfree)(kkt);
|
|
188
|
+
scs_free(Pinv);
|
|
189
|
+
scs_free(info);
|
|
190
|
+
return SCS_NULL;
|
|
191
|
+
}
|
|
192
192
|
kkt_perm = cs_symperm(kkt, Pinv, idx_mapping, 1);
|
|
193
|
+
if (!kkt_perm) {
|
|
194
|
+
SCS(cs_spfree)(kkt);
|
|
195
|
+
scs_free(Pinv);
|
|
196
|
+
scs_free(info);
|
|
197
|
+
scs_free(idx_mapping);
|
|
198
|
+
return SCS_NULL;
|
|
199
|
+
}
|
|
193
200
|
for (i = 0; i < A->n + A->m; i++) {
|
|
194
201
|
p->diag_r_idxs[i] = idx_mapping[p->diag_r_idxs[i]];
|
|
195
202
|
}
|
|
@@ -200,46 +207,44 @@ static ScsMatrix *permute_kkt(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
200
207
|
return kkt_perm;
|
|
201
208
|
}
|
|
202
209
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
p->kkt->x[p->diag_r_idxs[i]] = p->diag_p[i] + diag_r[i];
|
|
208
|
-
}
|
|
209
|
-
for (i = p->n; i < p->n + p->m; ++i) {
|
|
210
|
-
/* top left is R_x + P, bottom right is -R_y */
|
|
211
|
-
p->kkt->x[p->diag_r_idxs[i]] = -diag_r[i];
|
|
212
|
-
}
|
|
213
|
-
ldl_status = ldl_factor(p, p->n);
|
|
214
|
-
if (ldl_status < 0) {
|
|
215
|
-
scs_printf("Error in LDL factorization when updating.\n");
|
|
216
|
-
/* TODO: this is broken somehow */
|
|
217
|
-
/* SCS(free_lin_sys_work)(p); */
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
210
|
+
/* ======================== Public API ======================== */
|
|
211
|
+
|
|
212
|
+
const char *scs_get_lin_sys_method(void) {
|
|
213
|
+
return "sparse-direct-amd-qdldl";
|
|
220
214
|
}
|
|
221
215
|
|
|
222
216
|
ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
223
217
|
const scs_float *diag_r) {
|
|
224
218
|
ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
|
|
225
|
-
scs_int n_plus_m
|
|
219
|
+
scs_int n_plus_m, ldl_status, ldl_prepare_status;
|
|
220
|
+
if (!p)
|
|
221
|
+
return SCS_NULL;
|
|
222
|
+
n_plus_m = A->n + A->m;
|
|
226
223
|
p->m = A->m;
|
|
227
224
|
p->n = A->n;
|
|
228
225
|
p->diag_p = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
|
|
229
|
-
p->perm = (scs_int *)scs_calloc(sizeof(scs_int)
|
|
226
|
+
p->perm = (scs_int *)scs_calloc(n_plus_m, sizeof(scs_int));
|
|
230
227
|
p->L = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
|
231
228
|
p->bp = (scs_float *)scs_calloc(n_plus_m, sizeof(scs_float));
|
|
232
229
|
p->diag_r_idxs = (scs_int *)scs_calloc(n_plus_m, sizeof(scs_int));
|
|
233
230
|
p->factorizations = 0;
|
|
231
|
+
if (!p->diag_p || !p->perm || !p->L || !p->bp || !p->diag_r_idxs) {
|
|
232
|
+
scs_free_lin_sys_work(p);
|
|
233
|
+
return SCS_NULL;
|
|
234
|
+
}
|
|
234
235
|
p->L->m = n_plus_m;
|
|
235
236
|
p->L->n = n_plus_m;
|
|
236
237
|
p->kkt = permute_kkt(A, P, p, diag_r);
|
|
238
|
+
if (!p->kkt) {
|
|
239
|
+
scs_free_lin_sys_work(p);
|
|
240
|
+
return SCS_NULL;
|
|
241
|
+
}
|
|
237
242
|
ldl_prepare_status = ldl_prepare(p);
|
|
238
|
-
ldl_status =
|
|
243
|
+
ldl_status =
|
|
244
|
+
ldl_prepare_status < 0 ? ldl_prepare_status : ldl_factor(p, A->n);
|
|
239
245
|
if (ldl_prepare_status < 0 || ldl_status < 0) {
|
|
240
246
|
scs_printf("Error in LDL initial factorization.\n");
|
|
241
|
-
|
|
242
|
-
/* SCS(free_lin_sys_work)(p); */
|
|
247
|
+
scs_free_lin_sys_work(p);
|
|
243
248
|
return SCS_NULL;
|
|
244
249
|
}
|
|
245
250
|
return p;
|
|
@@ -252,3 +257,40 @@ scs_int scs_solve_lin_sys(ScsLinSysWork *p, scs_float *b, const scs_float *s,
|
|
|
252
257
|
_ldl_solve(b, p->L, p->Dinv, p->perm, p->bp);
|
|
253
258
|
return 0;
|
|
254
259
|
}
|
|
260
|
+
|
|
261
|
+
scs_int scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
262
|
+
scs_int i, ldl_status;
|
|
263
|
+
for (i = 0; i < p->n; ++i) {
|
|
264
|
+
/* top left is R_x + P, bottom right is -R_y */
|
|
265
|
+
p->kkt->x[p->diag_r_idxs[i]] = p->diag_p[i] + diag_r[i];
|
|
266
|
+
}
|
|
267
|
+
for (i = p->n; i < p->n + p->m; ++i) {
|
|
268
|
+
/* top left is R_x + P, bottom right is -R_y */
|
|
269
|
+
p->kkt->x[p->diag_r_idxs[i]] = -diag_r[i];
|
|
270
|
+
}
|
|
271
|
+
ldl_status = ldl_factor(p, p->n);
|
|
272
|
+
if (ldl_status < 0) {
|
|
273
|
+
scs_printf("Error in LDL factorization when updating.\n");
|
|
274
|
+
return ldl_status;
|
|
275
|
+
}
|
|
276
|
+
return 0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
void scs_free_lin_sys_work(ScsLinSysWork *p) {
|
|
280
|
+
if (p) {
|
|
281
|
+
SCS(cs_spfree)(p->L);
|
|
282
|
+
SCS(cs_spfree)(p->kkt);
|
|
283
|
+
scs_free(p->diag_p);
|
|
284
|
+
scs_free(p->perm);
|
|
285
|
+
scs_free(p->Dinv);
|
|
286
|
+
scs_free(p->bp);
|
|
287
|
+
scs_free(p->diag_r_idxs);
|
|
288
|
+
scs_free(p->Lnz);
|
|
289
|
+
scs_free(p->iwork);
|
|
290
|
+
scs_free(p->etree);
|
|
291
|
+
scs_free(p->D);
|
|
292
|
+
scs_free(p->bwork);
|
|
293
|
+
scs_free(p->fwork);
|
|
294
|
+
scs_free(p);
|
|
295
|
+
}
|
|
296
|
+
}
|