Skip to main content

singe_cusolver/
error.rs

1use std::{ffi::NulError, fmt};
2
3use singe_cuda::error::Error as CudaError;
4use singe_cusolver_sys as sys;
5use thiserror::Error;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[non_exhaustive]
9pub enum Status {
10    /// The operation completed successfully.
11    Success,
12    /// The cuSOLVER library was not initialized.
13    NotInitialized,
14    /// Resource allocation failed.
15    AllocFailed,
16    /// An invalid value was provided.
17    InvalidValue,
18    /// The current device architecture is not supported.
19    ArchitectureMismatch,
20    /// Memory or resource mapping failed.
21    MappingError,
22    /// Kernel execution failed.
23    ExecutionFailed,
24    /// An internal cuSOLVER error occurred.
25    InternalError,
26    /// The matrix type is not supported by the operation.
27    MatrixTypeNotSupported,
28    /// The requested operation is not supported.
29    NotSupported,
30    /// A zero pivot was encountered.
31    ZeroPivot,
32    /// The cuSOLVER license is invalid.
33    InvalidLicense,
34    /// IRS parameters were not initialized.
35    IrsParamsNotInitialized,
36    /// IRS parameters are invalid.
37    IrsParamsInvalid,
38    /// IRS precision parameters are invalid.
39    IrsParamsInvalidPrec,
40    /// IRS refinement parameters are invalid.
41    IrsParamsInvalidRefine,
42    /// IRS max-iteration parameters are invalid.
43    IrsParamsInvalidMaxIter,
44    /// An internal IRS error occurred.
45    IrsInternalError,
46    /// The requested IRS configuration is not supported.
47    IrsNotSupported,
48    /// IRS configuration values are out of range.
49    IrsOutOfRange,
50    /// GMRES refinement does not support the requested number of right-hand sides.
51    IrsNrhsNotSupportedForRefineGmres,
52    /// IRS info structures were not initialized.
53    IrsInfosNotInitialized,
54    /// IRS info structures were not destroyed before reuse.
55    IrsInfosNotDestroyed,
56    /// The IRS system matrix is singular.
57    IrsMatrixSingular,
58    /// The provided workspace is invalid.
59    InvalidWorkspace,
60    /// A status code not known to this version of Singe.
61    Unknown(u32),
62}
63
64impl Status {
65    pub const fn description(self) -> &'static str {
66        match self {
67            Self::Success => "success",
68            Self::NotInitialized => "library not initialized",
69            Self::AllocFailed => "allocation failed",
70            Self::InvalidValue => "invalid value",
71            Self::ArchitectureMismatch => "architecture mismatch",
72            Self::MappingError => "mapping error",
73            Self::ExecutionFailed => "execution failed",
74            Self::InternalError => "internal error",
75            Self::MatrixTypeNotSupported => "matrix type not supported",
76            Self::NotSupported => "not supported",
77            Self::ZeroPivot => "zero pivot",
78            Self::InvalidLicense => "invalid license",
79            Self::IrsParamsNotInitialized => "irs params not initialized",
80            Self::IrsParamsInvalid => "irs params invalid",
81            Self::IrsParamsInvalidPrec => "irs params invalid precision",
82            Self::IrsParamsInvalidRefine => "irs params invalid refinement",
83            Self::IrsParamsInvalidMaxIter => "irs params invalid maxiter",
84            Self::IrsInternalError => "irs internal error",
85            Self::IrsNotSupported => "irs not supported",
86            Self::IrsOutOfRange => "irs out of range",
87            Self::IrsNrhsNotSupportedForRefineGmres => "irs nrhs not supported for refine gmres",
88            Self::IrsInfosNotInitialized => "irs infos not initialized",
89            Self::IrsInfosNotDestroyed => "irs infos not destroyed",
90            Self::IrsMatrixSingular => "irs matrix singular",
91            Self::InvalidWorkspace => "invalid workspace",
92            Self::Unknown(_) => "unknown cusolver error",
93        }
94    }
95
96    pub const fn raw(self) -> u32 {
97        match self {
98            Self::Success => sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS as _,
99            Self::NotInitialized => sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_INITIALIZED as _,
100            Self::AllocFailed => sys::cusolverStatus_t::CUSOLVER_STATUS_ALLOC_FAILED as _,
101            Self::InvalidValue => sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_VALUE as _,
102            Self::ArchitectureMismatch => sys::cusolverStatus_t::CUSOLVER_STATUS_ARCH_MISMATCH as _,
103            Self::MappingError => sys::cusolverStatus_t::CUSOLVER_STATUS_MAPPING_ERROR as _,
104            Self::ExecutionFailed => sys::cusolverStatus_t::CUSOLVER_STATUS_EXECUTION_FAILED as _,
105            Self::InternalError => sys::cusolverStatus_t::CUSOLVER_STATUS_INTERNAL_ERROR as _,
106            Self::MatrixTypeNotSupported => {
107                sys::cusolverStatus_t::CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED as _
108            }
109            Self::NotSupported => sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_SUPPORTED as _,
110            Self::ZeroPivot => sys::cusolverStatus_t::CUSOLVER_STATUS_ZERO_PIVOT as _,
111            Self::InvalidLicense => sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_LICENSE as _,
112            Self::IrsParamsNotInitialized => {
113                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED as _
114            }
115            Self::IrsParamsInvalid => {
116                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID as _
117            }
118            Self::IrsParamsInvalidPrec => {
119                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC as _
120            }
121            Self::IrsParamsInvalidRefine => {
122                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE as _
123            }
124            Self::IrsParamsInvalidMaxIter => {
125                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER as _
126            }
127            Self::IrsInternalError => {
128                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INTERNAL_ERROR as _
129            }
130            Self::IrsNotSupported => sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NOT_SUPPORTED as _,
131            Self::IrsOutOfRange => sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_OUT_OF_RANGE as _,
132            Self::IrsNrhsNotSupportedForRefineGmres => {
133                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES as _
134            }
135            Self::IrsInfosNotInitialized => {
136                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED as _
137            }
138            Self::IrsInfosNotDestroyed => {
139                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED as _
140            }
141            Self::IrsMatrixSingular => {
142                sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_MATRIX_SINGULAR as _
143            }
144            Self::InvalidWorkspace => sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_WORKSPACE as _,
145            Self::Unknown(code) => code,
146        }
147    }
148}
149
150impl TryFrom<u32> for Status {
151    type Error = u32;
152
153    fn try_from(code: u32) -> std::result::Result<Self, Self::Error> {
154        match code {
155            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS as u32 => {
156                Ok(Self::Success)
157            }
158            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_INITIALIZED as u32 => {
159                Ok(Self::NotInitialized)
160            }
161            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_ALLOC_FAILED as u32 => {
162                Ok(Self::AllocFailed)
163            }
164            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_VALUE as u32 => {
165                Ok(Self::InvalidValue)
166            }
167            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_ARCH_MISMATCH as u32 => {
168                Ok(Self::ArchitectureMismatch)
169            }
170            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_MAPPING_ERROR as u32 => {
171                Ok(Self::MappingError)
172            }
173            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_EXECUTION_FAILED as u32 => {
174                Ok(Self::ExecutionFailed)
175            }
176            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_INTERNAL_ERROR as u32 => {
177                Ok(Self::InternalError)
178            }
179            code if code
180                == sys::cusolverStatus_t::CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED as u32 =>
181            {
182                Ok(Self::MatrixTypeNotSupported)
183            }
184            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_SUPPORTED as u32 => {
185                Ok(Self::NotSupported)
186            }
187            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_ZERO_PIVOT as u32 => {
188                Ok(Self::ZeroPivot)
189            }
190            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_LICENSE as u32 => {
191                Ok(Self::InvalidLicense)
192            }
193            code if code
194                == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED as u32 =>
195            {
196                Ok(Self::IrsParamsNotInitialized)
197            }
198            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID as u32 => {
199                Ok(Self::IrsParamsInvalid)
200            }
201            code if code
202                == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC as u32 =>
203            {
204                Ok(Self::IrsParamsInvalidPrec)
205            }
206            code if code
207                == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE as u32 =>
208            {
209                Ok(Self::IrsParamsInvalidRefine)
210            }
211            code if code
212                == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER as u32 =>
213            {
214                Ok(Self::IrsParamsInvalidMaxIter)
215            }
216            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INTERNAL_ERROR as u32 => {
217                Ok(Self::IrsInternalError)
218            }
219            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NOT_SUPPORTED as u32 => {
220                Ok(Self::IrsNotSupported)
221            }
222            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_OUT_OF_RANGE as u32 => {
223                Ok(Self::IrsOutOfRange)
224            }
225            code if code
226                == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES
227                    as u32 =>
228            {
229                Ok(Self::IrsNrhsNotSupportedForRefineGmres)
230            }
231            code if code
232                == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED as u32 =>
233            {
234                Ok(Self::IrsInfosNotInitialized)
235            }
236            code if code
237                == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED as u32 =>
238            {
239                Ok(Self::IrsInfosNotDestroyed)
240            }
241            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_MATRIX_SINGULAR as u32 => {
242                Ok(Self::IrsMatrixSingular)
243            }
244            code if code == sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_WORKSPACE as u32 => {
245                Ok(Self::InvalidWorkspace)
246            }
247            code => Err(code),
248        }
249    }
250}
251
252impl From<sys::cusolverStatus_t> for Status {
253    fn from(status: sys::cusolverStatus_t) -> Self {
254        Self::try_from(status as u32).unwrap_or_else(Self::Unknown)
255    }
256}
257
258impl TryFrom<Status> for sys::cusolverStatus_t {
259    type Error = Status;
260
261    fn try_from(status: Status) -> std::result::Result<Self, Self::Error> {
262        match status {
263            Status::Success => Ok(Self::CUSOLVER_STATUS_SUCCESS),
264            Status::NotInitialized => Ok(Self::CUSOLVER_STATUS_NOT_INITIALIZED),
265            Status::AllocFailed => Ok(Self::CUSOLVER_STATUS_ALLOC_FAILED),
266            Status::InvalidValue => Ok(Self::CUSOLVER_STATUS_INVALID_VALUE),
267            Status::ArchitectureMismatch => Ok(Self::CUSOLVER_STATUS_ARCH_MISMATCH),
268            Status::MappingError => Ok(Self::CUSOLVER_STATUS_MAPPING_ERROR),
269            Status::ExecutionFailed => Ok(Self::CUSOLVER_STATUS_EXECUTION_FAILED),
270            Status::InternalError => Ok(Self::CUSOLVER_STATUS_INTERNAL_ERROR),
271            Status::MatrixTypeNotSupported => Ok(Self::CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED),
272            Status::NotSupported => Ok(Self::CUSOLVER_STATUS_NOT_SUPPORTED),
273            Status::ZeroPivot => Ok(Self::CUSOLVER_STATUS_ZERO_PIVOT),
274            Status::InvalidLicense => Ok(Self::CUSOLVER_STATUS_INVALID_LICENSE),
275            Status::IrsParamsNotInitialized => Ok(Self::CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED),
276            Status::IrsParamsInvalid => Ok(Self::CUSOLVER_STATUS_IRS_PARAMS_INVALID),
277            Status::IrsParamsInvalidPrec => Ok(Self::CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC),
278            Status::IrsParamsInvalidRefine => Ok(Self::CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE),
279            Status::IrsParamsInvalidMaxIter => Ok(Self::CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER),
280            Status::IrsInternalError => Ok(Self::CUSOLVER_STATUS_IRS_INTERNAL_ERROR),
281            Status::IrsNotSupported => Ok(Self::CUSOLVER_STATUS_IRS_NOT_SUPPORTED),
282            Status::IrsOutOfRange => Ok(Self::CUSOLVER_STATUS_IRS_OUT_OF_RANGE),
283            Status::IrsNrhsNotSupportedForRefineGmres => {
284                Ok(Self::CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES)
285            }
286            Status::IrsInfosNotInitialized => Ok(Self::CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED),
287            Status::IrsInfosNotDestroyed => Ok(Self::CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED),
288            Status::IrsMatrixSingular => Ok(Self::CUSOLVER_STATUS_IRS_MATRIX_SINGULAR),
289            Status::InvalidWorkspace => Ok(Self::CUSOLVER_STATUS_INVALID_WORKSPACE),
290            Status::Unknown(_) => Err(status),
291        }
292    }
293}
294
295impl fmt::Display for Status {
296    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297        match self {
298            Self::Success => f.write_str("CUSOLVER_STATUS_SUCCESS"),
299            Self::NotInitialized => f.write_str("CUSOLVER_STATUS_NOT_INITIALIZED"),
300            Self::AllocFailed => f.write_str("CUSOLVER_STATUS_ALLOC_FAILED"),
301            Self::InvalidValue => f.write_str("CUSOLVER_STATUS_INVALID_VALUE"),
302            Self::ArchitectureMismatch => f.write_str("CUSOLVER_STATUS_ARCH_MISMATCH"),
303            Self::MappingError => f.write_str("CUSOLVER_STATUS_MAPPING_ERROR"),
304            Self::ExecutionFailed => f.write_str("CUSOLVER_STATUS_EXECUTION_FAILED"),
305            Self::InternalError => f.write_str("CUSOLVER_STATUS_INTERNAL_ERROR"),
306            Self::MatrixTypeNotSupported => {
307                f.write_str("CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED")
308            }
309            Self::NotSupported => f.write_str("CUSOLVER_STATUS_NOT_SUPPORTED"),
310            Self::ZeroPivot => f.write_str("CUSOLVER_STATUS_ZERO_PIVOT"),
311            Self::InvalidLicense => f.write_str("CUSOLVER_STATUS_INVALID_LICENSE"),
312            Self::IrsParamsNotInitialized => {
313                f.write_str("CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED")
314            }
315            Self::IrsParamsInvalid => f.write_str("CUSOLVER_STATUS_IRS_PARAMS_INVALID"),
316            Self::IrsParamsInvalidPrec => f.write_str("CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC"),
317            Self::IrsParamsInvalidRefine => {
318                f.write_str("CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE")
319            }
320            Self::IrsParamsInvalidMaxIter => {
321                f.write_str("CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER")
322            }
323            Self::IrsInternalError => f.write_str("CUSOLVER_STATUS_IRS_INTERNAL_ERROR"),
324            Self::IrsNotSupported => f.write_str("CUSOLVER_STATUS_IRS_NOT_SUPPORTED"),
325            Self::IrsOutOfRange => f.write_str("CUSOLVER_STATUS_IRS_OUT_OF_RANGE"),
326            Self::IrsNrhsNotSupportedForRefineGmres => {
327                f.write_str("CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES")
328            }
329            Self::IrsInfosNotInitialized => {
330                f.write_str("CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED")
331            }
332            Self::IrsInfosNotDestroyed => f.write_str("CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED"),
333            Self::IrsMatrixSingular => f.write_str("CUSOLVER_STATUS_IRS_MATRIX_SINGULAR"),
334            Self::InvalidWorkspace => f.write_str("CUSOLVER_STATUS_INVALID_WORKSPACE"),
335            Self::Unknown(code) => write!(f, "UNKNOWN_CUSOLVER_STATUS({code})"),
336        }
337    }
338}
339
340#[derive(Error, Debug)]
341#[non_exhaustive]
342pub enum Error {
343    #[error("cuda error: {0}")]
344    Cuda(#[from] CudaError),
345
346    #[error("cusolver error ({code}): {message}")]
347    Cusolver { code: Status, message: String },
348
349    #[error("string contains interior nul byte")]
350    InteriorNul,
351
352    #[error("unexpected null handle")]
353    NullHandle,
354
355    #[error("`{name}` is out of range")]
356    OutOfRange { name: String },
357
358    #[error("invalid matrix leading dimension")]
359    InvalidLeadingDimension,
360
361    #[error("invalid matrix shape")]
362    InvalidMatrixShape,
363
364    #[error("invalid vector shape")]
365    InvalidVectorShape,
366
367    #[error("invalid eigensolver range")]
368    InvalidEigenRange,
369
370    #[error("invalid svd mode")]
371    InvalidSvdMode,
372
373    #[error("invalid precision configuration")]
374    InvalidPrecisionConfiguration,
375
376    #[error("insufficient workspace size: {actual} provided (required {required})")]
377    InsufficientWorkspaceSize { required: usize, actual: usize },
378
379    #[error("invalid residual history")]
380    InvalidResidualHistory,
381
382    #[error("stream belongs to a different cuda context")]
383    StreamContextMismatch,
384}
385
386pub type Result<T> = std::result::Result<T, Error>;
387
388impl From<sys::cusolverStatus_t> for Error {
389    fn from(code: sys::cusolverStatus_t) -> Self {
390        let status = Status::from(code);
391        Self::from(status)
392    }
393}
394
395impl From<Status> for Error {
396    fn from(code: Status) -> Self {
397        Self::Cusolver {
398            code,
399            message: code.description().to_string(),
400        }
401    }
402}
403
404impl From<NulError> for Error {
405    fn from(_: NulError) -> Self {
406        Self::InteriorNul
407    }
408}
409
410#[macro_export]
411macro_rules! try_ffi {
412    ($expr:expr) => {{
413        let status = { $expr };
414        if status != singe_cusolver_sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS {
415            Err($crate::error::Error::from(status))
416        } else {
417            Ok(())
418        }
419    }};
420}