use scirs2_core::error::{CoreError, ErrorContext, ErrorLocation};
use thiserror::Error;
#[derive(Error, Debug, Clone)]
pub enum StatsError {
#[error("Computation error: {0}")]
ComputationError(String),
#[error("Domain error: {0}")]
DomainError(String),
#[error("Dimension mismatch error: {0}")]
DimensionMismatch(String),
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("Not implemented: {0}")]
NotImplementedError(String),
#[error("Convergence error: {0}")]
ConvergenceError(String),
#[error("Insufficient data: {0}")]
InsufficientData(String),
#[error("Invalid input: {0}")]
InvalidInput(String),
#[error("Not implemented: {0}")]
NotImplemented(String),
#[error("{0}")]
CoreError(#[from] CoreError),
#[error("Random distribution error: {0}")]
DistributionError(String),
}
pub trait StatsErrorExt {
fn context<S: Into<String>>(self, context: S) -> Self;
fn suggestion<S: Into<String>>(self, suggestion: S) -> Self;
}
impl StatsError {
pub fn computation<S: Into<String>>(message: S) -> Self {
StatsError::ComputationError(message.into())
}
pub fn domain<S: Into<String>>(message: S) -> Self {
StatsError::DomainError(message.into())
}
pub fn dimension_mismatch<S: Into<String>>(message: S) -> Self {
StatsError::DimensionMismatch(message.into())
}
pub fn invalid_argument<S: Into<String>>(message: S) -> Self {
StatsError::InvalidArgument(message.into())
}
pub fn not_implemented<S: Into<String>>(message: S) -> Self {
StatsError::NotImplementedError(message.into())
}
pub fn insufficientdata<S: Into<String>>(message: S) -> Self {
StatsError::InsufficientData(message.into())
}
pub fn invalid_input<S: Into<String>>(message: S) -> Self {
StatsError::InvalidInput(message.into())
}
pub fn with_suggestion(&self) -> String {
match self {
StatsError::DomainError(msg) => {
if msg.contains("must be positive") {
format!(
"{msg}
Suggestion: Ensure the value is greater than 0"
)
} else if msg.contains("probability") {
format!(
"{msg}
Suggestion: Probability values must be between 0 and 1 (inclusive)"
)
} else if msg.contains("degrees of freedom") {
format!(
"{msg}
Suggestion: Degrees of freedom must be a positive value"
)
} else {
msg.clone()
}
}
StatsError::DimensionMismatch(msg) => {
if msg.contains("same length") {
format!(
"{msg}
Suggestion: Ensure both arrays have the same number of elements"
)
} else if msg.contains("square matrix") {
format!(
"{msg}
Suggestion: The input matrix must have equal number of rows and columns"
)
} else {
format!(
"{msg}
Suggestion: Check that input dimensions match the function requirements"
)
}
}
StatsError::InvalidArgument(msg) => {
if msg.contains("empty") {
format!(
"{msg}
Suggestion: Provide a non-empty array or collection"
)
} else if msg.contains("NaN") || msg.contains("nan") {
format!(
"{msg}
Suggestion: Remove or handle NaN values before computation"
)
} else if msg.contains("infinite") || msg.contains("inf") {
format!(
"{msg}
Suggestion: Check for and handle infinite values in your data"
)
} else {
format!(
"{msg}
Suggestion: Verify that all input arguments meet the function requirements"
)
}
}
StatsError::NotImplementedError(msg) => {
format!("{msg}
Suggestion: This feature is not yet available. Consider using an alternative method or check for updates")
}
StatsError::ComputationError(msg) => {
if msg.contains("overflow") {
format!(
"{msg}
Suggestion: Try scaling your input data or using a more numerically stable algorithm"
)
} else if msg.contains("convergence") {
format!(
"{msg}
Suggestion: Try adjusting convergence parameters or using different initial values"
)
} else {
format!(
"{msg}
Suggestion: Check input data for numerical issues or extreme values"
)
}
}
StatsError::ConvergenceError(msg) => {
format!("{msg}
Suggestion: Try adjusting convergence parameters, using different initial values, or increasing the maximum number of iterations")
}
StatsError::InsufficientData(msg) => {
format!(
"{msg}
Suggestion: Increase sample size or use methods designed for small datasets"
)
}
StatsError::InvalidInput(msg) => {
format!(
"{msg}
Suggestion: Check input format and ensure data meets function requirements"
)
}
StatsError::NotImplemented(msg) => {
format!("{msg}
Suggestion: This feature is not yet available. Consider using an alternative method or check for updates")
}
StatsError::CoreError(err) => {
format!(
"{err}
Suggestion: {}",
"Refer to the core error for more details"
)
}
StatsError::DistributionError(msg) => {
format!(
"{msg}
Suggestion: Check distribution parameters and ensure they are within valid ranges"
)
}
}
}
}
pub type StatsResult<T> = Result<T, StatsError>;
#[allow(dead_code)]
pub fn convert_to_validation_error<T, S: Into<String>>(
result: StatsResult<T>,
message: S,
) -> Result<T, CoreError> {
match result {
Ok(val) => Ok(val),
Err(err) => Err(CoreError::ValidationError(
ErrorContext::new(format!("{}: {err}", message.into()))
.with_location(ErrorLocation::new(file!(), line!())),
)),
}
}