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
|
@@ -25,6 +25,34 @@ struct SCS_LIN_SYS_WORK {
|
|
|
25
25
|
/* preconditioning */
|
|
26
26
|
scs_float *z;
|
|
27
27
|
scs_float *M;
|
|
28
|
+
/* eigCG deflation (Stathopoulos & Orginos 2010). During the deep
|
|
29
|
+
* solve for g = K^{-1}h (cold, run to CG_BEST_TOL, once per metric
|
|
30
|
+
* change) the CG recurrence is observed -- never perturbed -- and
|
|
31
|
+
* approximate eigenvectors of the smallest eigenvalues of the
|
|
32
|
+
* preconditioned operator are extracted by thick-restarted Lanczos on
|
|
33
|
+
* CG's own scalars. Later warm solves Galerkin-project their initial
|
|
34
|
+
* residual against this near-invariant subspace, which removes the
|
|
35
|
+
* slowly-converging components; because the subspace is
|
|
36
|
+
* near-invariant, CG does not reintroduce them. Discarded whenever
|
|
37
|
+
* the metric changes; the deep re-solve re-harvests. */
|
|
38
|
+
scs_float *dfl_p; /* W: harvested eigenvectors, n x dfl_max */
|
|
39
|
+
scs_float *dfl_Ap; /* A W images, n x dfl_max */
|
|
40
|
+
scs_float *dfl_G; /* Cholesky factor of W'AW, dfl_max x dfl_max */
|
|
41
|
+
scs_float *dfl_c; /* projection coefficients, dfl_max */
|
|
42
|
+
scs_int dfl_max, dfl_count, dfl_harvest;
|
|
43
|
+
/* eigCG window state (live only while harvesting) */
|
|
44
|
+
scs_float *eig_V; /* n x eig_win basis (Lanczos / locked Ritz) */
|
|
45
|
+
scs_float *eig_T; /* eig_win x eig_win projected operator */
|
|
46
|
+
scs_float *eig_E; /* eig_win x eig_win syev scratch */
|
|
47
|
+
scs_float *eig_w; /* eigenvalue scratch */
|
|
48
|
+
scs_float *eig_S; /* eig_win x 2 dfl_max restart stack */
|
|
49
|
+
scs_float *eig_TS; /* eig_win x 2 dfl_max scratch */
|
|
50
|
+
scs_float *eig_H; /* 2 dfl_max x 2 dfl_max small projection */
|
|
51
|
+
scs_float *eig_G; /* eig_win x 2 dfl_max restart transform */
|
|
52
|
+
scs_float *eig_VS; /* n x 2 dfl_max basis-update scratch */
|
|
53
|
+
scs_float *eig_work; /* syev workspace */
|
|
54
|
+
scs_int eig_win, eig_j, eig_jd, eig_step, eig_have_prev, eig_dead, eig_lwork;
|
|
55
|
+
scs_float eig_pa, eig_pb; /* previous iteration's alpha / beta */
|
|
28
56
|
/* reporting */
|
|
29
57
|
scs_int tot_cg_its;
|
|
30
58
|
const scs_float *diag_r;
|
data/vendor/scs/linsys/csparse.c
CHANGED
|
@@ -205,11 +205,17 @@ ScsMatrix *SCS(form_kkt)(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
idx_mapping = (scs_int *)scs_calloc(count, sizeof(scs_int));
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
if (!idx_mapping) {
|
|
209
|
+
SCS(cs_spfree)(K);
|
|
210
|
+
return SCS_NULL;
|
|
211
211
|
}
|
|
212
|
+
Kcsc = SCS(cs_compress)(K, count, idx_mapping);
|
|
212
213
|
SCS(cs_spfree)(K);
|
|
214
|
+
if (Kcsc) {
|
|
215
|
+
for (i = 0; i < m + n; i++) {
|
|
216
|
+
diag_r_idxs[i] = idx_mapping[diag_r_idxs[i]];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
213
219
|
scs_free(idx_mapping);
|
|
214
220
|
return Kcsc;
|
|
215
221
|
}
|
data/vendor/scs/linsys/csparse.h
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/*
|
|
2
|
+
* Sparse matrix utilities adapted from CSparse (T. Davis).
|
|
3
|
+
* Provides allocation, triplet-to-CSC compression, and KKT matrix formation.
|
|
4
|
+
*/
|
|
2
5
|
|
|
3
6
|
#ifndef CS_H_GUARD
|
|
4
7
|
#define CS_H_GUARD
|
|
@@ -8,7 +11,6 @@ extern "C" {
|
|
|
8
11
|
#endif
|
|
9
12
|
|
|
10
13
|
#include "glbopts.h"
|
|
11
|
-
#include "scs.h"
|
|
12
14
|
|
|
13
15
|
ScsMatrix *SCS(cs_spalloc)(scs_int m, scs_int n, scs_int nzmax, scs_int values,
|
|
14
16
|
scs_int triplet);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "private.h"
|
|
2
2
|
#include "linsys.h"
|
|
3
|
+
#include <string.h>
|
|
3
4
|
|
|
4
5
|
/* In case of error abort freeing p */
|
|
5
6
|
#define CUDSS_CHECK_ABORT(call, p, fname) \
|
|
@@ -31,7 +32,23 @@ const char *scs_get_lin_sys_method() {
|
|
|
31
32
|
/* Free allocated resources for the linear system solver */
|
|
32
33
|
void scs_free_lin_sys_work(ScsLinSysWork *p) {
|
|
33
34
|
if (p) {
|
|
34
|
-
/* Free
|
|
35
|
+
/* Free cuDSS resources first, before freeing the GPU memory they reference */
|
|
36
|
+
if (p->solver_data && p->handle)
|
|
37
|
+
cudssDataDestroy(p->handle, p->solver_data);
|
|
38
|
+
if (p->solver_config)
|
|
39
|
+
cudssConfigDestroy(p->solver_config);
|
|
40
|
+
|
|
41
|
+
if (p->d_kkt_mat)
|
|
42
|
+
cudssMatrixDestroy(p->d_kkt_mat);
|
|
43
|
+
if (p->d_b_mat)
|
|
44
|
+
cudssMatrixDestroy(p->d_b_mat);
|
|
45
|
+
if (p->d_sol_mat)
|
|
46
|
+
cudssMatrixDestroy(p->d_sol_mat);
|
|
47
|
+
|
|
48
|
+
if (p->handle)
|
|
49
|
+
cudssDestroy(p->handle);
|
|
50
|
+
|
|
51
|
+
/* Free GPU memory */
|
|
35
52
|
if (p->d_kkt_val)
|
|
36
53
|
cudaFree(p->d_kkt_val);
|
|
37
54
|
if (p->d_kkt_row_ptr)
|
|
@@ -43,26 +60,15 @@ void scs_free_lin_sys_work(ScsLinSysWork *p) {
|
|
|
43
60
|
if (p->d_sol)
|
|
44
61
|
cudaFree(p->d_sol);
|
|
45
62
|
|
|
46
|
-
/* Free
|
|
47
|
-
if (p->
|
|
48
|
-
|
|
49
|
-
if (p->
|
|
50
|
-
|
|
51
|
-
if (p->d_sol_mat)
|
|
52
|
-
cudssMatrixDestroy(p->d_sol_mat);
|
|
53
|
-
|
|
54
|
-
if (p->solver_config)
|
|
55
|
-
cudssConfigDestroy(p->solver_config);
|
|
56
|
-
if (p->solver_data && p->handle)
|
|
57
|
-
cudssDataDestroy(p->handle, p->solver_data);
|
|
58
|
-
if (p->handle)
|
|
59
|
-
cudssDestroy(p->handle);
|
|
63
|
+
/* Free pinned host memory */
|
|
64
|
+
if (p->h_b_pinned)
|
|
65
|
+
cudaFreeHost(p->h_b_pinned);
|
|
66
|
+
if (p->h_sol_pinned)
|
|
67
|
+
cudaFreeHost(p->h_sol_pinned);
|
|
60
68
|
|
|
61
69
|
/* Free CPU resources */
|
|
62
70
|
if (p->kkt)
|
|
63
71
|
SCS(cs_spfree)(p->kkt);
|
|
64
|
-
if (p->sol)
|
|
65
|
-
scs_free(p->sol);
|
|
66
72
|
if (p->diag_r_idxs)
|
|
67
73
|
scs_free(p->diag_r_idxs);
|
|
68
74
|
if (p->diag_p)
|
|
@@ -85,12 +91,6 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
85
91
|
p->n_plus_m = p->n + p->m;
|
|
86
92
|
|
|
87
93
|
/* Allocate CPU memory */
|
|
88
|
-
p->sol = (scs_float *)scs_malloc(sizeof(scs_float) * p->n_plus_m);
|
|
89
|
-
if (!p->sol) {
|
|
90
|
-
scs_free_lin_sys_work(p);
|
|
91
|
-
return SCS_NULL;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
94
|
p->diag_r_idxs = (scs_int *)scs_calloc(p->n_plus_m, sizeof(scs_int));
|
|
95
95
|
if (!p->diag_r_idxs) {
|
|
96
96
|
scs_free_lin_sys_work(p);
|
|
@@ -112,9 +112,6 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
112
112
|
return SCS_NULL;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
cudssStatus_t status;
|
|
116
|
-
cudaError_t cuda_error;
|
|
117
|
-
|
|
118
115
|
/* Create cuDSS handle */
|
|
119
116
|
CUDSS_CHECK_ABORT(cudssCreate(&p->handle), p, "cudssCreate");
|
|
120
117
|
/* Creating cuDSS solver configuration and data objects */
|
|
@@ -154,11 +151,23 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
154
151
|
cudssMatrixType_t mtype = CUDSS_MTYPE_SYMMETRIC;
|
|
155
152
|
cudssMatrixViewType_t mview = CUDSS_MVIEW_LOWER;
|
|
156
153
|
cudssIndexBase_t base = CUDSS_BASE_ZERO;
|
|
154
|
+
/* cuDSS 0.8.0+ added an offsetType parameter before indexType. The two
|
|
155
|
+
* arrays use the same scs_int type for us, so we pass SCS_CUDA_INDEX
|
|
156
|
+
* twice. */
|
|
157
|
+
#if SCS_CUDSS_NEW_API
|
|
158
|
+
CUDSS_CHECK_ABORT(cudssMatrixCreateCsr(
|
|
159
|
+
&p->d_kkt_mat, p->kkt->m, p->kkt->n, nnz,
|
|
160
|
+
p->d_kkt_row_ptr, NULL, p->d_kkt_col_ind, p->d_kkt_val,
|
|
161
|
+
SCS_CUDA_INDEX, SCS_CUDA_INDEX, SCS_CUDA_FLOAT,
|
|
162
|
+
mtype, mview, base),
|
|
163
|
+
p, "cudssMatrixCreateCsr");
|
|
164
|
+
#else
|
|
157
165
|
CUDSS_CHECK_ABORT(cudssMatrixCreateCsr(
|
|
158
166
|
&p->d_kkt_mat, p->kkt->m, p->kkt->n, nnz,
|
|
159
167
|
p->d_kkt_row_ptr, NULL, p->d_kkt_col_ind, p->d_kkt_val,
|
|
160
168
|
SCS_CUDA_INDEX, SCS_CUDA_FLOAT, mtype, mview, base),
|
|
161
169
|
p, "cudssMatrixCreateCsr");
|
|
170
|
+
#endif
|
|
162
171
|
|
|
163
172
|
/* Allocate device memory for vectors */
|
|
164
173
|
CUDA_CHECK_ABORT(
|
|
@@ -168,6 +177,14 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
168
177
|
cudaMalloc((void **)&p->d_sol, p->n_plus_m * sizeof(scs_float)), p,
|
|
169
178
|
"cudaMalloc: sol");
|
|
170
179
|
|
|
180
|
+
/* Allocate pinned host memory for faster H<->D transfers in solve loop */
|
|
181
|
+
CUDA_CHECK_ABORT(
|
|
182
|
+
cudaMallocHost((void **)&p->h_b_pinned, p->n_plus_m * sizeof(scs_float)),
|
|
183
|
+
p, "cudaMallocHost: b");
|
|
184
|
+
CUDA_CHECK_ABORT(cudaMallocHost((void **)&p->h_sol_pinned,
|
|
185
|
+
p->n_plus_m * sizeof(scs_float)),
|
|
186
|
+
p, "cudaMallocHost: sol");
|
|
187
|
+
|
|
171
188
|
/* Create RHS and solution matrix descriptors */
|
|
172
189
|
scs_int nrhs = 1;
|
|
173
190
|
CUDSS_CHECK_ABORT(cudssMatrixCreateDn(&p->d_b_mat, p->n_plus_m, nrhs,
|
|
@@ -191,24 +208,39 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
191
208
|
p->d_sol_mat, p->d_b_mat),
|
|
192
209
|
p, "cudssExecute: factorization");
|
|
193
210
|
|
|
211
|
+
/* Inertia check: verify P is PSD by checking positive eigenvalue count */
|
|
212
|
+
{
|
|
213
|
+
scs_int inertia[2]; /* [0] = positive, [1] = negative */
|
|
214
|
+
size_t inertia_written;
|
|
215
|
+
CUDSS_CHECK_ABORT(
|
|
216
|
+
cudssDataGet(p->handle, p->solver_data, CUDSS_DATA_INERTIA, inertia,
|
|
217
|
+
sizeof(inertia), &inertia_written),
|
|
218
|
+
p, "cudssDataGet: inertia");
|
|
219
|
+
if (inertia[0] < p->n) {
|
|
220
|
+
scs_printf("KKT matrix has < n positive eigenvalues. P not PSD.");
|
|
221
|
+
scs_free_lin_sys_work(p);
|
|
222
|
+
return SCS_NULL;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
194
226
|
return p;
|
|
195
227
|
}
|
|
196
228
|
|
|
197
229
|
/* Solve the linear system for a given RHS b */
|
|
198
230
|
scs_int scs_solve_lin_sys(ScsLinSysWork *p, scs_float *b, const scs_float *ws,
|
|
199
231
|
scs_float tol) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
232
|
+
size_t vec_bytes = p->n_plus_m * sizeof(scs_float);
|
|
233
|
+
|
|
234
|
+
/* Copy RHS to pinned staging buffer, then to device */
|
|
235
|
+
memcpy(p->h_b_pinned, b, vec_bytes);
|
|
236
|
+
cudaError_t custatus =
|
|
237
|
+
cudaMemcpy(p->d_b, p->h_b_pinned, vec_bytes, cudaMemcpyHostToDevice);
|
|
203
238
|
if (custatus != cudaSuccess) {
|
|
204
|
-
scs_printf("scs_solve_lin_sys: Error copying
|
|
239
|
+
scs_printf("scs_solve_lin_sys: Error copying b to device: %d\n",
|
|
205
240
|
(int)custatus);
|
|
206
241
|
return custatus;
|
|
207
242
|
}
|
|
208
243
|
|
|
209
|
-
// is this really needed?
|
|
210
|
-
cudssMatrixSetValues(p->d_b_mat, p->d_b);
|
|
211
|
-
|
|
212
244
|
/* Solve the system */
|
|
213
245
|
cudssStatus_t status =
|
|
214
246
|
cudssExecute(p->handle, CUDSS_PHASE_SOLVE, p->solver_config,
|
|
@@ -219,20 +251,21 @@ scs_int scs_solve_lin_sys(ScsLinSysWork *p, scs_float *b, const scs_float *ws,
|
|
|
219
251
|
return status;
|
|
220
252
|
}
|
|
221
253
|
|
|
222
|
-
/* Copy solution
|
|
223
|
-
custatus =
|
|
224
|
-
|
|
225
|
-
if (
|
|
254
|
+
/* Copy solution from device to pinned staging buffer, then to output */
|
|
255
|
+
custatus =
|
|
256
|
+
cudaMemcpy(p->h_sol_pinned, p->d_sol, vec_bytes, cudaMemcpyDeviceToHost);
|
|
257
|
+
if (custatus != cudaSuccess) {
|
|
226
258
|
scs_printf("scs_solve_lin_sys: Error copying d_sol to host: %d\n",
|
|
227
|
-
(int)
|
|
228
|
-
return
|
|
259
|
+
(int)custatus);
|
|
260
|
+
return custatus;
|
|
229
261
|
}
|
|
262
|
+
memcpy(b, p->h_sol_pinned, vec_bytes);
|
|
230
263
|
|
|
231
264
|
return 0; /* Success */
|
|
232
265
|
}
|
|
233
266
|
|
|
234
267
|
/* Update the KKT matrix when R changes */
|
|
235
|
-
|
|
268
|
+
scs_int scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
236
269
|
scs_int i;
|
|
237
270
|
|
|
238
271
|
/* Update KKT matrix on CPU */
|
|
@@ -253,7 +286,7 @@ void scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
|
253
286
|
scs_printf(
|
|
254
287
|
"scs_update_lin_sys_diag_r: Error copying kkt->x to device: %d\n",
|
|
255
288
|
(int)custatus);
|
|
256
|
-
return;
|
|
289
|
+
return (scs_int)custatus;
|
|
257
290
|
}
|
|
258
291
|
|
|
259
292
|
/* Update the matrix values in cuDSS */
|
|
@@ -264,7 +297,7 @@ void scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
|
264
297
|
scs_printf(
|
|
265
298
|
"scs_update_lin_sys_diag_r: Error updating kkt matrix on device: %d\n",
|
|
266
299
|
(int)status);
|
|
267
|
-
return;
|
|
300
|
+
return (scs_int)status;
|
|
268
301
|
}
|
|
269
302
|
|
|
270
303
|
/* Perform Refactorization with the updated matrix */
|
|
@@ -274,6 +307,7 @@ void scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
|
274
307
|
if (status != CUDSS_STATUS_SUCCESS) {
|
|
275
308
|
scs_printf("scs_update_lin_sys_diag_r: Error during re-factorization: %d\n",
|
|
276
309
|
(int)status);
|
|
277
|
-
return;
|
|
310
|
+
return (scs_int)status;
|
|
278
311
|
}
|
|
312
|
+
return 0;
|
|
279
313
|
}
|
|
@@ -5,22 +5,45 @@
|
|
|
5
5
|
extern "C" {
|
|
6
6
|
#endif
|
|
7
7
|
|
|
8
|
+
#include "csparse.h"
|
|
9
|
+
#include "linsys.h"
|
|
10
|
+
#include <cuda_runtime.h>
|
|
11
|
+
#include <cudss.h>
|
|
12
|
+
|
|
13
|
+
/* cuDSS 0.8.0 renamed cudaDataType_t to cudssDataType_t (so CUDA_R_* enum
|
|
14
|
+
* values become CUDSS_R_*) and added an offsetType parameter to
|
|
15
|
+
* cudssMatrixCreateCsr. cudss.h exposes CUDSS_VERSION = MAJOR*10000 +
|
|
16
|
+
* MINOR*100 + PATCH; gate on that so the same source still builds against
|
|
17
|
+
* older cuDSS (<=0.7.x). */
|
|
18
|
+
#if defined(CUDSS_VERSION) && CUDSS_VERSION >= 800
|
|
19
|
+
#define SCS_CUDSS_NEW_API 1
|
|
20
|
+
#else
|
|
21
|
+
#define SCS_CUDSS_NEW_API 0
|
|
22
|
+
#endif
|
|
23
|
+
|
|
24
|
+
#if SCS_CUDSS_NEW_API
|
|
25
|
+
#ifndef SFLOAT
|
|
26
|
+
#define SCS_CUDA_FLOAT CUDSS_R_64F
|
|
27
|
+
#else
|
|
28
|
+
#define SCS_CUDA_FLOAT CUDSS_R_32F
|
|
29
|
+
#endif
|
|
30
|
+
#ifndef DLONG
|
|
31
|
+
#define SCS_CUDA_INDEX CUDSS_R_32I
|
|
32
|
+
#else
|
|
33
|
+
#define SCS_CUDA_INDEX CUDSS_R_64I
|
|
34
|
+
#endif
|
|
35
|
+
#else
|
|
8
36
|
#ifndef SFLOAT
|
|
9
37
|
#define SCS_CUDA_FLOAT CUDA_R_64F
|
|
10
38
|
#else
|
|
11
39
|
#define SCS_CUDA_FLOAT CUDA_R_32F
|
|
12
40
|
#endif
|
|
13
|
-
|
|
14
41
|
#ifndef DLONG
|
|
15
42
|
#define SCS_CUDA_INDEX CUDA_R_32I
|
|
16
43
|
#else
|
|
17
44
|
#define SCS_CUDA_INDEX CUDA_R_64I
|
|
18
45
|
#endif
|
|
19
|
-
|
|
20
|
-
#include "csparse.h"
|
|
21
|
-
#include "linsys.h"
|
|
22
|
-
#include <cuda_runtime.h>
|
|
23
|
-
#include <cudss.h>
|
|
46
|
+
#endif
|
|
24
47
|
|
|
25
48
|
struct SCS_LIN_SYS_WORK {
|
|
26
49
|
/* General problem dimensions */
|
|
@@ -30,7 +53,6 @@ struct SCS_LIN_SYS_WORK {
|
|
|
30
53
|
|
|
31
54
|
/* CPU matrices and vectors */
|
|
32
55
|
ScsMatrix *kkt; /* KKT matrix in CSR format */
|
|
33
|
-
scs_float *sol; /* solution to the KKT system */
|
|
34
56
|
|
|
35
57
|
/* cuDSS handle and descriptors */
|
|
36
58
|
cudssHandle_t handle; /* cuDSS library handle */
|
|
@@ -47,6 +69,10 @@ struct SCS_LIN_SYS_WORK {
|
|
|
47
69
|
scs_float *d_b; /* device copy of right-hand side */
|
|
48
70
|
scs_float *d_sol; /* device copy of solution */
|
|
49
71
|
|
|
72
|
+
/* Pinned host memory for faster H<->D transfers */
|
|
73
|
+
scs_float *h_b_pinned; /* pinned host staging buffer for RHS */
|
|
74
|
+
scs_float *h_sol_pinned; /* pinned host staging buffer for solution */
|
|
75
|
+
|
|
50
76
|
/* These are required for matrix updates */
|
|
51
77
|
scs_int *diag_r_idxs; /* indices where R appears in the KKT matrix */
|
|
52
78
|
scs_float *diag_p; /* Diagonal values of P */
|
|
@@ -66,7 +66,7 @@ static void set_preconditioner(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/* no need to update anything in this case */
|
|
69
|
-
|
|
69
|
+
scs_int scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
70
70
|
scs_int i;
|
|
71
71
|
|
|
72
72
|
/* R_x to gpu */
|
|
@@ -81,6 +81,7 @@ void scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
|
81
81
|
|
|
82
82
|
/* set preconditioner M on gpu */
|
|
83
83
|
set_preconditioner(p, diag_r);
|
|
84
|
+
return 0;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
void scs_free_lin_sys_work(ScsLinSysWork *p) {
|
|
@@ -141,7 +142,7 @@ static void mat_vec(ScsLinSysWork *p, const scs_float *x, scs_float *y) {
|
|
|
141
142
|
cusparseDnVecSetValues(p->dn_vec_n_p, (void *)y);
|
|
142
143
|
|
|
143
144
|
/* y = x */
|
|
144
|
-
cudaMemcpy(y, x, p->n * sizeof(scs_float),
|
|
145
|
+
cudaMemcpy(y, x, p->n * sizeof(scs_float), cudaMemcpyDeviceToDevice);
|
|
145
146
|
/* y = R_x * x */
|
|
146
147
|
scale_by_diag(p->cublas_handle, p->r_x_gpu, y, p->n);
|
|
147
148
|
|
|
@@ -430,6 +431,9 @@ static scs_int pcg(ScsLinSysWork *pr, const scs_float *s, scs_float *bg,
|
|
|
430
431
|
ztr_prev = ztr;
|
|
431
432
|
/* ztr = z'r */
|
|
432
433
|
CUBLAS(dot)(cublas_handle, n, r, 1, z, 1, &ztr);
|
|
434
|
+
if (ztr_prev == 0.) {
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
433
437
|
beta = ztr / ztr_prev;
|
|
434
438
|
/* p = beta * p, where beta = ztr / ztr_prev */
|
|
435
439
|
CUBLAS(scal)(cublas_handle, n, &beta, p, 1);
|
|
@@ -5,25 +5,56 @@
|
|
|
5
5
|
#define PARDISO_SOLVE (33)
|
|
6
6
|
#define PARDISO_CLEANUP (-1)
|
|
7
7
|
|
|
8
|
-
/* TODO: is it necessary to use pardiso_64 and MKL_Set_Interface_Layer ? */
|
|
9
8
|
/*
|
|
9
|
+
* MKL interface layer constants. MKL has two integer interfaces:
|
|
10
|
+
*
|
|
11
|
+
* LP64 (MKL_INTERFACE_LP64 = 0): BLAS/LAPACK use 32-bit integers (int).
|
|
12
|
+
* ILP64 (MKL_INTERFACE_ILP64 = 1): BLAS/LAPACK use 64-bit integers (long long).
|
|
13
|
+
*
|
|
14
|
+
* These affect the standard BLAS/LAPACK symbols (dgemm, dpotrf, etc.).
|
|
15
|
+
* PARDISO has separate entry points for each integer width:
|
|
16
|
+
*
|
|
17
|
+
* pardiso — 32-bit integer indices (used when !DLONG)
|
|
18
|
+
* pardiso_64 — 64-bit integer indices (used when DLONG)
|
|
19
|
+
*
|
|
20
|
+
* The pardiso/pardiso_64 choice is independent of the interface layer; each is
|
|
21
|
+
* a distinct symbol that always uses its own integer width regardless of what
|
|
22
|
+
* MKL_Set_Interface_Layer says.
|
|
23
|
+
*
|
|
24
|
+
* The BLAS integer width is controlled by the use_blas64 meson option:
|
|
25
|
+
*
|
|
26
|
+
* use_blas64=false (default) -> links mkl-dynamic-lp64-*, expects LP64
|
|
27
|
+
* use_blas64=true -> links mkl-dynamic-ilp64-*, expects ILP64
|
|
28
|
+
*
|
|
29
|
+
* See meson.build for the linkage logic. The MKL-specific initialization in
|
|
30
|
+
* src/scs.c uses BLAS64 to pick the right expected interface layer.
|
|
31
|
+
*
|
|
32
|
+
* PARDISO is independent: pardiso_64 always uses 64-bit ints regardless of
|
|
33
|
+
* the interface layer or BLAS64 setting.
|
|
34
|
+
*/
|
|
10
35
|
#define MKL_INTERFACE_LP64 0
|
|
11
36
|
#define MKL_INTERFACE_ILP64 1
|
|
12
|
-
|
|
37
|
+
|
|
13
38
|
#ifdef DLONG
|
|
14
39
|
#define _PARDISO pardiso_64
|
|
15
40
|
#else
|
|
16
41
|
#define _PARDISO pardiso
|
|
17
42
|
#endif
|
|
18
43
|
|
|
19
|
-
/* Prototypes for Pardiso functions */
|
|
44
|
+
/* Prototypes for Pardiso and MKL service functions. */
|
|
20
45
|
void _PARDISO(void **pt, const scs_int *maxfct, const scs_int *mnum,
|
|
21
46
|
const scs_int *mtype, const scs_int *phase, const scs_int *n,
|
|
22
47
|
const scs_float *a, const scs_int *ia, const scs_int *ja,
|
|
23
48
|
scs_int *perm, const scs_int *nrhs, scs_int *iparm,
|
|
24
49
|
const scs_int *msglvl, scs_float *b, scs_float *x,
|
|
25
50
|
scs_int *error);
|
|
26
|
-
/*
|
|
51
|
+
/* BLAS64 requires DLONG for MKL builds: the interface layer (ILP64) set by
|
|
52
|
+
* MKL_Set_Interface_Layer must match the PARDISO entry point (pardiso_64).
|
|
53
|
+
* Without DLONG, pardiso (32-bit) is used but ILP64 makes its internal BLAS
|
|
54
|
+
* calls expect 64-bit integers, causing hangs or memory corruption. */
|
|
55
|
+
#if defined(BLAS64) && !defined(DLONG)
|
|
56
|
+
#error "MKL PARDISO requires DLONG when BLAS64 is set (pardiso_64 needs 64-bit ints)"
|
|
57
|
+
#endif
|
|
27
58
|
|
|
28
59
|
const char *scs_get_lin_sys_method() {
|
|
29
60
|
return "sparse-direct-mkl-pardiso";
|
|
@@ -31,18 +62,21 @@ const char *scs_get_lin_sys_method() {
|
|
|
31
62
|
|
|
32
63
|
void scs_free_lin_sys_work(ScsLinSysWork *p) {
|
|
33
64
|
if (p) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
65
|
+
/* Pardiso cleanup needs the KKT index arrays; on early allocation
|
|
66
|
+
* failures the workspace may be freed before the KKT matrix (or
|
|
67
|
+
* the factorization) ever existed, so gate the solver teardown on
|
|
68
|
+
* what was actually initialized. */
|
|
69
|
+
if (p->kkt) {
|
|
70
|
+
p->phase = PARDISO_CLEANUP;
|
|
71
|
+
_PARDISO(p->pt, &(p->maxfct), &(p->mnum), &(p->mtype), &(p->phase),
|
|
72
|
+
&(p->n_plus_m), SCS_NULL, p->kkt->p, p->kkt->i, SCS_NULL,
|
|
73
|
+
&(p->nrhs), p->iparm, &(p->msglvl), SCS_NULL, SCS_NULL,
|
|
74
|
+
&(p->error));
|
|
75
|
+
if (p->error != 0) {
|
|
76
|
+
scs_printf("Error during MKL Pardiso cleanup: %d", (int)p->error);
|
|
77
|
+
}
|
|
43
78
|
SCS(cs_spfree)(p->kkt);
|
|
44
|
-
|
|
45
|
-
scs_free(p->sol);
|
|
79
|
+
}
|
|
46
80
|
if (p->diag_r_idxs)
|
|
47
81
|
scs_free(p->diag_r_idxs);
|
|
48
82
|
if (p->diag_p)
|
|
@@ -55,24 +89,18 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
55
89
|
const scs_float *diag_r) {
|
|
56
90
|
scs_int i;
|
|
57
91
|
ScsLinSysWork *p = scs_calloc(1, sizeof(ScsLinSysWork));
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/* Set MKL interface layer */
|
|
61
|
-
/*
|
|
62
|
-
#ifdef DLONG
|
|
63
|
-
MKL_Set_Interface_Layer(MKL_INTERFACE_ILP64);
|
|
64
|
-
#else
|
|
65
|
-
MKL_Set_Interface_Layer(MKL_INTERFACE_LP64);
|
|
66
|
-
#endif
|
|
67
|
-
*/
|
|
92
|
+
if (!p)
|
|
93
|
+
return SCS_NULL;
|
|
68
94
|
p->n = A->n;
|
|
69
95
|
p->m = A->m;
|
|
70
96
|
p->n_plus_m = p->n + p->m;
|
|
71
97
|
|
|
72
|
-
/* Even though we overwrite rhs with sol pardiso requires the memory */
|
|
73
|
-
p->sol = (scs_float *)scs_malloc(sizeof(scs_float) * p->n_plus_m);
|
|
74
98
|
p->diag_r_idxs = (scs_int *)scs_calloc(p->n_plus_m, sizeof(scs_int));
|
|
75
99
|
p->diag_p = (scs_float *)scs_calloc(p->n, sizeof(scs_float));
|
|
100
|
+
if (!p->diag_r_idxs || !p->diag_p) {
|
|
101
|
+
scs_free_lin_sys_work(p);
|
|
102
|
+
return SCS_NULL;
|
|
103
|
+
}
|
|
76
104
|
|
|
77
105
|
/* MKL pardiso requires upper triangular CSR matrices. The KKT matrix stuffed
|
|
78
106
|
* as CSC lower triangular is equivalent. Pass upper=0. */
|
|
@@ -101,7 +129,9 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
101
129
|
p->iparm[1] = 3; /* Fill-in reordering from OpenMP */
|
|
102
130
|
p->iparm[5] = 1; /* Write solution into b */
|
|
103
131
|
p->iparm[7] = 0; /* Automatic iterative refinement calculation */
|
|
104
|
-
p->iparm[9] =
|
|
132
|
+
p->iparm[9] = 13; /* Perturb the pivot elements with 1E-13 (default) */
|
|
133
|
+
p->iparm[23] = 1; /* Two-level scheduling for parallel factorization */
|
|
134
|
+
p->iparm[24] = 1; /* Parallel forward/backward solve */
|
|
105
135
|
p->iparm[34] = 1; /* Use C-style indexing for indices */
|
|
106
136
|
/* p->iparm[36] = -80; */ /* Form block sparse matrices */
|
|
107
137
|
|
|
@@ -135,6 +165,7 @@ ScsLinSysWork *scs_init_lin_sys_work(const ScsMatrix *A, const ScsMatrix *P,
|
|
|
135
165
|
|
|
136
166
|
if (p->iparm[21] < p->n) {
|
|
137
167
|
scs_printf("KKT matrix has < n positive eigenvalues. P not PSD.");
|
|
168
|
+
scs_free_lin_sys_work(p);
|
|
138
169
|
return SCS_NULL;
|
|
139
170
|
}
|
|
140
171
|
|
|
@@ -148,7 +179,7 @@ scs_int scs_solve_lin_sys(ScsLinSysWork *p, scs_float *b, const scs_float *ws,
|
|
|
148
179
|
p->phase = PARDISO_SOLVE;
|
|
149
180
|
_PARDISO(p->pt, &(p->maxfct), &(p->mnum), &(p->mtype), &(p->phase),
|
|
150
181
|
&(p->n_plus_m), p->kkt->x, p->kkt->p, p->kkt->i, SCS_NULL,
|
|
151
|
-
&(p->nrhs), p->iparm, &(p->msglvl), b,
|
|
182
|
+
&(p->nrhs), p->iparm, &(p->msglvl), b, SCS_NULL, &(p->error));
|
|
152
183
|
if (p->error != 0) {
|
|
153
184
|
scs_printf("Error during linear system solution: %d", (int)p->error);
|
|
154
185
|
}
|
|
@@ -156,7 +187,7 @@ scs_int scs_solve_lin_sys(ScsLinSysWork *p, scs_float *b, const scs_float *ws,
|
|
|
156
187
|
}
|
|
157
188
|
|
|
158
189
|
/* Update factorization when R changes */
|
|
159
|
-
|
|
190
|
+
scs_int scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
160
191
|
scs_int i;
|
|
161
192
|
|
|
162
193
|
for (i = 0; i < p->n; ++i) {
|
|
@@ -177,6 +208,7 @@ void scs_update_lin_sys_diag_r(ScsLinSysWork *p, const scs_float *diag_r) {
|
|
|
177
208
|
if (p->error != 0) {
|
|
178
209
|
scs_printf("Error in PARDISO factorization when updating: %d.\n",
|
|
179
210
|
(int)p->error);
|
|
180
|
-
|
|
211
|
+
return (scs_int)p->error;
|
|
181
212
|
}
|
|
213
|
+
return 0;
|
|
182
214
|
}
|