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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +1 -1
  4. data/lib/scs/ffi.rb +18 -0
  5. data/lib/scs/version.rb +1 -1
  6. data/vendor/scs/CITATION.cff +2 -3
  7. data/vendor/scs/CLAUDE.md +115 -0
  8. data/vendor/scs/CMakeLists.txt +330 -201
  9. data/vendor/scs/CONTRIBUTING.md +49 -0
  10. data/vendor/scs/Makefile +90 -43
  11. data/vendor/scs/README.md +96 -2
  12. data/vendor/scs/include/aa.h +59 -11
  13. data/vendor/scs/include/aa_stats.h +47 -0
  14. data/vendor/scs/include/cones.h +16 -7
  15. data/vendor/scs/include/glbopts.h +113 -26
  16. data/vendor/scs/include/linalg.h +5 -1
  17. data/vendor/scs/include/linsys.h +1 -2
  18. data/vendor/scs/include/normalize.h +6 -2
  19. data/vendor/scs/include/rw.h +9 -3
  20. data/vendor/scs/include/scs.h +17 -1
  21. data/vendor/scs/include/scs_blas.h +8 -0
  22. data/vendor/scs/include/scs_types.h +2 -2
  23. data/vendor/scs/include/scs_work.h +22 -1
  24. data/vendor/scs/include/util.h +3 -6
  25. data/vendor/scs/include/util_spectral_cones.h +3 -3
  26. data/vendor/scs/linsys/accelerate/direct/private.c +126 -0
  27. data/vendor/scs/linsys/accelerate/direct/private.h +34 -0
  28. data/vendor/scs/linsys/cpu/dense/private.c +250 -0
  29. data/vendor/scs/linsys/cpu/dense/private.h +31 -0
  30. data/vendor/scs/linsys/cpu/direct/private.c +86 -44
  31. data/vendor/scs/linsys/cpu/indirect/private.c +647 -113
  32. data/vendor/scs/linsys/cpu/indirect/private.h +28 -0
  33. data/vendor/scs/linsys/csparse.c +9 -3
  34. data/vendor/scs/linsys/csparse.h +4 -2
  35. data/vendor/scs/linsys/cudss/direct/private.c +77 -43
  36. data/vendor/scs/linsys/cudss/direct/private.h +33 -7
  37. data/vendor/scs/linsys/gpu/indirect/private.c +6 -2
  38. data/vendor/scs/linsys/mkl/direct/private.c +63 -31
  39. data/vendor/scs/linsys/mkl/direct/private.h +0 -1
  40. data/vendor/scs/linsys/scs_matrix.c +291 -165
  41. data/vendor/scs/linsys/scs_matrix.h +7 -9
  42. data/vendor/scs/scs.mk +35 -13
  43. data/vendor/scs/src/aa.c +673 -166
  44. data/vendor/scs/src/cones.c +545 -223
  45. data/vendor/scs/src/ctrlc.c +59 -16
  46. data/vendor/scs/src/exp_cone.c +70 -50
  47. data/vendor/scs/src/linalg.c +21 -2
  48. data/vendor/scs/src/normalize.c +24 -26
  49. data/vendor/scs/src/rw.c +596 -124
  50. data/vendor/scs/src/scs.c +990 -513
  51. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +240 -187
  52. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +108 -85
  53. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +62 -63
  54. data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +85 -78
  55. data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +92 -97
  56. data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +39 -28
  57. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +59 -40
  58. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +37 -29
  59. data/vendor/scs/src/spectral_cones/util_spectral_cones.c +12 -6
  60. data/vendor/scs/src/util.c +37 -7
  61. data/vendor/scs/test/mkl_interface_mismatch.c +97 -0
  62. data/vendor/scs/test/packaging/CMakeLists.txt +21 -0
  63. data/vendor/scs/test/packaging/consume.c +50 -0
  64. data/vendor/scs/test/problem_utils.h +9 -2
  65. data/vendor/scs/test/problems/dense_qp.h +64 -0
  66. data/vendor/scs/test/problems/hs21_tiny_qp.h +6 -2
  67. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +10 -2
  68. data/vendor/scs/test/problems/infeasible_lp.h +66 -0
  69. data/vendor/scs/test/problems/infeasible_socp.h +75 -0
  70. data/vendor/scs/test/problems/lp_update.h +110 -0
  71. data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -1
  72. data/vendor/scs/test/problems/rob_gauss_cov_est.h +6 -3
  73. data/vendor/scs/test/problems/small_qp.h +5 -0
  74. data/vendor/scs/test/problems/test_box_cone.h +92 -0
  75. data/vendor/scs/test/problems/test_dual_exp_cone.h +96 -0
  76. data/vendor/scs/test/problems/test_inaccurate.h +212 -0
  77. data/vendor/scs/test/problems/test_mixed_cones.h +113 -0
  78. data/vendor/scs/test/problems/test_normalize_roundtrip.h +279 -0
  79. data/vendor/scs/test/problems/test_power_cone.h +414 -0
  80. data/vendor/scs/test/problems/test_psd_metric.h +109 -0
  81. data/vendor/scs/test/problems/test_psd_n1.h +84 -0
  82. data/vendor/scs/test/problems/test_root_plus.h +191 -0
  83. data/vendor/scs/test/problems/test_rw_settings.h +112 -0
  84. data/vendor/scs/test/problems/test_soc_sizes.h +393 -0
  85. data/vendor/scs/test/problems/test_solver_options.h +558 -0
  86. data/vendor/scs/test/problems/test_validation.h +263 -24
  87. data/vendor/scs/test/problems/test_zero_cone.h +81 -0
  88. data/vendor/scs/test/problems/unbounded_lp.h +66 -0
  89. data/vendor/scs/test/problems/unbounded_socp.h +71 -0
  90. data/vendor/scs/test/run_from_file.c +6 -0
  91. data/vendor/scs/test/run_tests.c +71 -0
  92. data/vendor/scs/test/rw_settings.c +7 -0
  93. data/vendor/scs/test/spectral_cones_problems/test_ell1_and_nuc.h +128 -0
  94. data/vendor/scs/test/spectral_cones_problems/test_ell1_cone.h +115 -0
  95. 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
- #include "private.h"
1
+ /* ======================== Includes / Types ======================== */
2
2
 
3
- const char *scs_get_lin_sys_method(void) {
4
- return "sparse-direct-amd-qdldl";
5
- }
3
+ #include "private.h"
6
4
 
7
- void scs_free_lin_sys_work(ScsLinSysWork *p) {
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
- void scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
204
- scs_int i, ldl_status;
205
- for (i = 0; i < p->n; ++i) {
206
- /* top left is R_x + P, bottom right is -R_y */
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 = A->n + A->m, ldl_status, ldl_prepare_status;
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), n_plus_m);
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 = ldl_factor(p, A->n);
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
- /* TODO: this is broken somehow */
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
+ }