use std::{
ffi::NulError,
fmt::{self, Display, Formatter},
};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use singe_core::impl_enum_conversion;
use singe_cuda::error::Error as CudaError;
use singe_cusolver_sys as sys;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("cuda error: {0}")]
Cuda(#[from] CudaError),
#[error("cusolver error ({code}): {message}")]
Cusolver { code: Status, message: String },
#[error("string contains interior nul byte")]
InteriorNul,
#[error("unexpected null handle")]
NullHandle,
#[error("{name} is out of range")]
OutOfRange { name: String },
#[error("invalid matrix leading dimension")]
InvalidLeadingDimension,
#[error("invalid matrix shape")]
InvalidMatrixShape,
#[error("invalid vector shape")]
InvalidVectorShape,
#[error("invalid eigensolver range")]
InvalidEigRange,
#[error("invalid svd mode")]
InvalidSvdMode,
#[error("invalid precision configuration")]
InvalidPrecisionConfiguration,
#[error("insufficient workspace size: {actual} provided (required {required})")]
InsufficientWorkspaceSize { required: usize, actual: usize },
#[error("invalid residual history")]
InvalidResidualHistory,
#[error("stream belongs to a different cuda context")]
StreamContextMismatch,
}
pub type Result<T> = std::result::Result<T, Error>;
impl From<sys::cusolverStatus_t> for Error {
fn from(status: sys::cusolverStatus_t) -> Self {
debug_assert_ne!(status, sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS);
let message = match status {
sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_INITIALIZED => "library not initialized",
sys::cusolverStatus_t::CUSOLVER_STATUS_ALLOC_FAILED => "allocation failed",
sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_VALUE => "invalid value",
sys::cusolverStatus_t::CUSOLVER_STATUS_ARCH_MISMATCH => "architecture mismatch",
sys::cusolverStatus_t::CUSOLVER_STATUS_MAPPING_ERROR => "mapping error",
sys::cusolverStatus_t::CUSOLVER_STATUS_EXECUTION_FAILED => "execution failed",
sys::cusolverStatus_t::CUSOLVER_STATUS_INTERNAL_ERROR => "internal error",
sys::cusolverStatus_t::CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED => {
"matrix type not supported"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_SUPPORTED => "not supported",
sys::cusolverStatus_t::CUSOLVER_STATUS_ZERO_PIVOT => "zero pivot",
sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_LICENSE => "invalid license",
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED => {
"irs params not initialized"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID => "irs params invalid",
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC => {
"irs params invalid precision"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE => {
"irs params invalid refinement"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER => {
"irs params invalid maxiter"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INTERNAL_ERROR => "irs internal error",
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NOT_SUPPORTED => "irs not supported",
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_OUT_OF_RANGE => "irs out of range",
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES => {
"irs nrhs not supported for refine gmres"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED => {
"irs infos not initialized"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED => {
"irs infos not destroyed"
}
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_MATRIX_SINGULAR => "irs matrix singular",
sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_WORKSPACE => "invalid workspace",
_ => "unknown cusolver error",
};
Self::Cusolver {
code: status.into(),
message: message.to_string(),
}
}
}
impl From<NulError> for Error {
fn from(_: NulError) -> Self {
Self::InteriorNul
}
}
#[macro_export]
macro_rules! try_ffi {
($expr:expr) => {{
let status = { $expr };
if status != singe_cusolver_sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS {
Err($crate::error::Error::from(status))
} else {
Ok(())
}
}};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Status {
Success = sys::cusolverStatus_t::CUSOLVER_STATUS_SUCCESS as _,
NotInitialized = sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_INITIALIZED as _,
AllocFailed = sys::cusolverStatus_t::CUSOLVER_STATUS_ALLOC_FAILED as _,
InvalidValue = sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_VALUE as _,
ArchMismatch = sys::cusolverStatus_t::CUSOLVER_STATUS_ARCH_MISMATCH as _,
MappingError = sys::cusolverStatus_t::CUSOLVER_STATUS_MAPPING_ERROR as _,
ExecutionFailed = sys::cusolverStatus_t::CUSOLVER_STATUS_EXECUTION_FAILED as _,
InternalError = sys::cusolverStatus_t::CUSOLVER_STATUS_INTERNAL_ERROR as _,
MatrixTypeNotSupported = sys::cusolverStatus_t::CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED as _,
NotSupported = sys::cusolverStatus_t::CUSOLVER_STATUS_NOT_SUPPORTED as _,
ZeroPivot = sys::cusolverStatus_t::CUSOLVER_STATUS_ZERO_PIVOT as _,
InvalidLicense = sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_LICENSE as _,
IrsParamsNotInitialized =
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED as _,
IrsParamsInvalid = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID as _,
IrsParamsInvalidPrec = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC as _,
IrsParamsInvalidRefine = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE as _,
IrsParamsInvalidMaxIter =
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER as _,
IrsInternalError = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INTERNAL_ERROR as _,
IrsNotSupported = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NOT_SUPPORTED as _,
IrsOutOfRange = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_OUT_OF_RANGE as _,
IrsNrhsNotSupportedForRefineGmres =
sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES as _,
IrsInfosNotInitialized = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED as _,
IrsInfosNotDestroyed = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED as _,
IrsMatrixSingular = sys::cusolverStatus_t::CUSOLVER_STATUS_IRS_MATRIX_SINGULAR as _,
InvalidWorkspace = sys::cusolverStatus_t::CUSOLVER_STATUS_INVALID_WORKSPACE as _,
}
impl_enum_conversion!(sys::cusolverStatus_t, Status);
impl Status {
pub const fn description(self) -> &'static str {
match self {
Self::Success => "success",
Self::NotInitialized => "library not initialized",
Self::AllocFailed => "allocation failed",
Self::InvalidValue => "invalid value",
Self::ArchMismatch => "architecture mismatch",
Self::MappingError => "mapping error",
Self::ExecutionFailed => "execution failed",
Self::InternalError => "internal error",
Self::MatrixTypeNotSupported => "matrix type not supported",
Self::NotSupported => "not supported",
Self::ZeroPivot => "zero pivot",
Self::InvalidLicense => "invalid license",
Self::IrsParamsNotInitialized => "irs params not initialized",
Self::IrsParamsInvalid => "irs params invalid",
Self::IrsParamsInvalidPrec => "irs params invalid precision",
Self::IrsParamsInvalidRefine => "irs params invalid refinement",
Self::IrsParamsInvalidMaxIter => "irs params invalid maxiter",
Self::IrsInternalError => "irs internal error",
Self::IrsNotSupported => "irs not supported",
Self::IrsOutOfRange => "irs out of range",
Self::IrsNrhsNotSupportedForRefineGmres => "irs nrhs not supported for refine gmres",
Self::IrsInfosNotInitialized => "irs infos not initialized",
Self::IrsInfosNotDestroyed => "irs infos not destroyed",
Self::IrsMatrixSingular => "irs matrix singular",
Self::InvalidWorkspace => "invalid workspace",
}
}
}
impl Display for Status {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Success => write!(f, "CUSOLVER_STATUS_SUCCESS"),
Self::NotInitialized => write!(f, "CUSOLVER_STATUS_NOT_INITIALIZED"),
Self::AllocFailed => write!(f, "CUSOLVER_STATUS_ALLOC_FAILED"),
Self::InvalidValue => write!(f, "CUSOLVER_STATUS_INVALID_VALUE"),
Self::ArchMismatch => write!(f, "CUSOLVER_STATUS_ARCH_MISMATCH"),
Self::MappingError => write!(f, "CUSOLVER_STATUS_MAPPING_ERROR"),
Self::ExecutionFailed => write!(f, "CUSOLVER_STATUS_EXECUTION_FAILED"),
Self::InternalError => write!(f, "CUSOLVER_STATUS_INTERNAL_ERROR"),
Self::MatrixTypeNotSupported => {
write!(f, "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED")
}
Self::NotSupported => write!(f, "CUSOLVER_STATUS_NOT_SUPPORTED"),
Self::ZeroPivot => write!(f, "CUSOLVER_STATUS_ZERO_PIVOT"),
Self::InvalidLicense => write!(f, "CUSOLVER_STATUS_INVALID_LICENSE"),
Self::IrsParamsNotInitialized => {
write!(f, "CUSOLVER_STATUS_IRS_PARAMS_NOT_INITIALIZED")
}
Self::IrsParamsInvalid => write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID"),
Self::IrsParamsInvalidPrec => write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID_PREC"),
Self::IrsParamsInvalidRefine => {
write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID_REFINE")
}
Self::IrsParamsInvalidMaxIter => {
write!(f, "CUSOLVER_STATUS_IRS_PARAMS_INVALID_MAXITER")
}
Self::IrsInternalError => write!(f, "CUSOLVER_STATUS_IRS_INTERNAL_ERROR"),
Self::IrsNotSupported => write!(f, "CUSOLVER_STATUS_IRS_NOT_SUPPORTED"),
Self::IrsOutOfRange => write!(f, "CUSOLVER_STATUS_IRS_OUT_OF_RANGE"),
Self::IrsNrhsNotSupportedForRefineGmres => {
write!(f, "CUSOLVER_STATUS_IRS_NRHS_NOT_SUPPORTED_FOR_REFINE_GMRES")
}
Self::IrsInfosNotInitialized => {
write!(f, "CUSOLVER_STATUS_IRS_INFOS_NOT_INITIALIZED")
}
Self::IrsInfosNotDestroyed => write!(f, "CUSOLVER_STATUS_IRS_INFOS_NOT_DESTROYED"),
Self::IrsMatrixSingular => write!(f, "CUSOLVER_STATUS_IRS_MATRIX_SINGULAR"),
Self::InvalidWorkspace => write!(f, "CUSOLVER_STATUS_INVALID_WORKSPACE"),
}
}
}