1use std::{
2 ffi::NulError,
3 fmt::{self, Display, Formatter},
4};
5
6use num_enum::{IntoPrimitive, TryFromPrimitive};
7use singe_core::impl_enum_conversion;
8use singe_cuda::error::Error as CudaError;
9use singe_cusolver_sys as sys;
10use thiserror::Error;
11
12#[derive(Error, Debug)]
13pub enum Error {
14 #[error("cuda error: {0}")]
15 Cuda(#[from] CudaError),
16
17 #[error("cusolver error ({code}): {message}")]
18 Cusolver { code: Status, message: String },
19
20 #[error("string contains interior nul byte")]
21 InteriorNul,
22
23 #[error("unexpected null handle")]
24 NullHandle,
25
26 #[error("{name} is out of range")]
27 OutOfRange { name: String },
28
29 #[error("invalid matrix leading dimension")]
30 InvalidLeadingDimension,
31
32 #[error("invalid matrix shape")]
33 InvalidMatrixShape,
34
35 #[error("invalid vector shape")]
36 InvalidVectorShape,
37
38 #[error("invalid eigensolver range")]
39 InvalidEigRange,
40
41 #[error("invalid svd mode")]
42 InvalidSvdMode,
43
44 #[error("invalid precision configuration")]
45 InvalidPrecisionConfiguration,
46
47 #[error("insufficient workspace size: {actual} provided (required {required})")]
48 InsufficientWorkspaceSize { required: usize, actual: usize },
49
50 #[error("invalid residual history")]
51 InvalidResidualHistory,
52
53 #[error("stream belongs to a different cuda context")]
54 StreamContextMismatch,
55}
56
57pub type Result<T> = std::result::Result<T, Error>;
58
59impl From<sys::cusolverStatus_t> for Error {
60 fn from(status: sys::cusolverStatus_t) -> Self {
61 debug_assert_ne!(status, sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS);
62
63 let message = match status {
64 sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_INITIALIZED => "library not initialized",
65 sys::cusolverStatus_t::CUSOLVER_STATUS_ALLOC_FAILED => "allocation failed",
66 sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_VALUE => "invalid value",
67 sys::cusolverStatus_t::CUSOLVER_STATUS_ARCH_MISMATCH => "architecture mismatch",
68 sys::cusolverStatus_t::CUSOLVER_STATUS_MAPPING_ERROR => "mapping error",
69 sys::cusolverStatus_t::CUSOLVER_STATUS_EXECUTION_FAILED => "execution failed",
70 sys::cusolverStatus_t::CUSOLVER_STATUS_INTERNAL_ERROR => "internal error",
71 sys::cusolverStatus_t::CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED => {
72 "matrix type not supported"
73 }
74 sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_SUPPORTED => "not supported",
75 sys::cusolverStatus_t::CUSOLVER_STATUS_ZERO_PIVOT => "zero pivot",
76 sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_LICENSE => "invalid license",
77 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED => {
78 "irs params not initialized"
79 }
80 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID => "irs params invalid",
81 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC => {
82 "irs params invalid precision"
83 }
84 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE => {
85 "irs params invalid refinement"
86 }
87 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER => {
88 "irs params invalid maxiter"
89 }
90 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INTERNAL_ERROR => "irs internal error",
91 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NOT_SUPPORTED => "irs not supported",
92 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_OUT_OF_RANGE => "irs out of range",
93 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES => {
94 "irs nrhs not supported for refine gmres"
95 }
96 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED => {
97 "irs infos not initialized"
98 }
99 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED => {
100 "irs infos not destroyed"
101 }
102 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_MATRIX_SINGULAR => "irs matrix singular",
103 sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_WORKSPACE => "invalid workspace",
104 _ => "unknown cusolver error",
105 };
106
107 Self::Cusolver {
108 code: status.into(),
109 message: message.to_string(),
110 }
111 }
112}
113
114impl From<NulError> for Error {
115 fn from(_: NulError) -> Self {
116 Self::InteriorNul
117 }
118}
119
120#[macro_export]
121macro_rules! try_ffi {
122 ($expr:expr) => {{
123 let status = { $expr };
124 if status != singe_cusolver_sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS {
125 Err($crate::error::Error::from(status))
126 } else {
127 Ok(())
128 }
129 }};
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive, IntoPrimitive)]
135#[repr(u32)]
136pub enum Status {
137 Success = sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS as _,
139 NotInitialized = sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_INITIALIZED as _,
141 AllocFailed = sys::cusolverStatus_t::CUSOLVER_STATUS_ALLOC_FAILED as _,
143 InvalidValue = sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_VALUE as _,
145 ArchMismatch = sys::cusolverStatus_t::CUSOLVER_STATUS_ARCH_MISMATCH as _,
147 MappingError = sys::cusolverStatus_t::CUSOLVER_STATUS_MAPPING_ERROR as _,
149 ExecutionFailed = sys::cusolverStatus_t::CUSOLVER_STATUS_EXECUTION_FAILED as _,
151 InternalError = sys::cusolverStatus_t::CUSOLVER_STATUS_INTERNAL_ERROR as _,
153 MatrixTypeNotSupported = sys::cusolverStatus_t::CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED as _,
155 NotSupported = sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_SUPPORTED as _,
157 ZeroPivot = sys::cusolverStatus_t::CUSOLVER_STATUS_ZERO_PIVOT as _,
159 InvalidLicense = sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_LICENSE as _,
161 IrsParamsNotInitialized =
163 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED as _,
164 IrsParamsInvalid = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID as _,
166 IrsParamsInvalidPrec = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC as _,
168 IrsParamsInvalidRefine = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE as _,
170 IrsParamsInvalidMaxIter =
172 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER as _,
173 IrsInternalError = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INTERNAL_ERROR as _,
175 IrsNotSupported = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NOT_SUPPORTED as _,
177 IrsOutOfRange = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_OUT_OF_RANGE as _,
179 IrsNrhsNotSupportedForRefineGmres =
181 sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES as _,
182 IrsInfosNotInitialized = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED as _,
184 IrsInfosNotDestroyed = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED as _,
186 IrsMatrixSingular = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_MATRIX_SINGULAR as _,
188 InvalidWorkspace = sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_WORKSPACE as _,
190}
191
192impl_enum_conversion!(sys::cusolverStatus_t, Status);
193
194impl Status {
195 pub const fn description(self) -> &'static str {
196 match self {
197 Self::Success => "success",
198 Self::NotInitialized => "library not initialized",
199 Self::AllocFailed => "allocation failed",
200 Self::InvalidValue => "invalid value",
201 Self::ArchMismatch => "architecture mismatch",
202 Self::MappingError => "mapping error",
203 Self::ExecutionFailed => "execution failed",
204 Self::InternalError => "internal error",
205 Self::MatrixTypeNotSupported => "matrix type not supported",
206 Self::NotSupported => "not supported",
207 Self::ZeroPivot => "zero pivot",
208 Self::InvalidLicense => "invalid license",
209 Self::IrsParamsNotInitialized => "irs params not initialized",
210 Self::IrsParamsInvalid => "irs params invalid",
211 Self::IrsParamsInvalidPrec => "irs params invalid precision",
212 Self::IrsParamsInvalidRefine => "irs params invalid refinement",
213 Self::IrsParamsInvalidMaxIter => "irs params invalid maxiter",
214 Self::IrsInternalError => "irs internal error",
215 Self::IrsNotSupported => "irs not supported",
216 Self::IrsOutOfRange => "irs out of range",
217 Self::IrsNrhsNotSupportedForRefineGmres => "irs nrhs not supported for refine gmres",
218 Self::IrsInfosNotInitialized => "irs infos not initialized",
219 Self::IrsInfosNotDestroyed => "irs infos not destroyed",
220 Self::IrsMatrixSingular => "irs matrix singular",
221 Self::InvalidWorkspace => "invalid workspace",
222 }
223 }
224}
225
226impl Display for Status {
227 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
228 match self {
229 Self::Success => write!(f, "CUSOLVER_STATUS_SUCCESS"),
230 Self::NotInitialized => write!(f, "CUSOLVER_STATUS_NOT_INITIALIZED"),
231 Self::AllocFailed => write!(f, "CUSOLVER_STATUS_ALLOC_FAILED"),
232 Self::InvalidValue => write!(f, "CUSOLVER_STATUS_INVALID_VALUE"),
233 Self::ArchMismatch => write!(f, "CUSOLVER_STATUS_ARCH_MISMATCH"),
234 Self::MappingError => write!(f, "CUSOLVER_STATUS_MAPPING_ERROR"),
235 Self::ExecutionFailed => write!(f, "CUSOLVER_STATUS_EXECUTION_FAILED"),
236 Self::InternalError => write!(f, "CUSOLVER_STATUS_INTERNAL_ERROR"),
237 Self::MatrixTypeNotSupported => {
238 write!(f, "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED")
239 }
240 Self::NotSupported => write!(f, "CUSOLVER_STATUS_NOT_SUPPORTED"),
241 Self::ZeroPivot => write!(f, "CUSOLVER_STATUS_ZERO_PIVOT"),
242 Self::InvalidLicense => write!(f, "CUSOLVER_STATUS_INVALID_LICENSE"),
243 Self::IrsParamsNotInitialized => {
244 write!(f, "CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED")
245 }
246 Self::IrsParamsInvalid => write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID"),
247 Self::IrsParamsInvalidPrec => write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC"),
248 Self::IrsParamsInvalidRefine => {
249 write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE")
250 }
251 Self::IrsParamsInvalidMaxIter => {
252 write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER")
253 }
254 Self::IrsInternalError => write!(f, "CUSOLVER_STATUS_IRS_INTERNAL_ERROR"),
255 Self::IrsNotSupported => write!(f, "CUSOLVER_STATUS_IRS_NOT_SUPPORTED"),
256 Self::IrsOutOfRange => write!(f, "CUSOLVER_STATUS_IRS_OUT_OF_RANGE"),
257 Self::IrsNrhsNotSupportedForRefineGmres => {
258 write!(f, "CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES")
259 }
260 Self::IrsInfosNotInitialized => {
261 write!(f, "CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED")
262 }
263 Self::IrsInfosNotDestroyed => write!(f, "CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED"),
264 Self::IrsMatrixSingular => write!(f, "CUSOLVER_STATUS_IRS_MATRIX_SINGULAR"),
265 Self::InvalidWorkspace => write!(f, "CUSOLVER_STATUS_INVALID_WORKSPACE"),
266 }
267 }
268}