Skip to main content

scirs2_stats/
error_messages.rs

1//! Standardized error messages and error creation helpers
2//!
3//! This module provides consistent error messages and helper functions
4//! for creating errors throughout the statistics module.
5
6use crate::error::{StatsError, StatsResult};
7
8/// Standard error messages for common validation failures
9#[allow(dead_code)]
10pub mod messages {
11    /// Domain errors
12    pub const POSITIVE_REQUIRED: &str = "Value must be positive (> 0)";
13    pub const NON_NEGATIVE_REQUIRED: &str = "Value must be non-negative (>= 0)";
14    pub const PROBABILITY_RANGE: &str = "Probability must be between 0 and 1 (inclusive)";
15    pub const DEGREES_OF_FREEDOM_POSITIVE: &str = "Degrees of freedom must be positive";
16    pub const SCALE_POSITIVE: &str = "Scale parameter must be positive";
17    pub const SHAPE_POSITIVE: &str = "Shape parameter must be positive";
18    pub const RATE_POSITIVE: &str = "Rate parameter must be positive";
19
20    /// Dimension errors
21    pub const ARRAYS_SAME_LENGTH: &str = "Input arrays must have the same length";
22    pub const ARRAY_EMPTY: &str = "Input array cannot be empty";
23    pub const MATRIX_SQUARE: &str = "Matrix must be square";
24    pub const INSUFFICIENT_DATA: &str = "Insufficient data for calculation";
25
26    /// Computation errors
27    pub const NUMERICAL_OVERFLOW: &str = "Numerical overflow occurred during computation";
28    pub const CONVERGENCE_FAILED: &str = "Algorithm failed to converge";
29    pub const SINGULAR_MATRIX: &str = "Matrix is singular or near-singular";
30
31    /// Not implemented
32    pub const FEATURE_NOT_IMPLEMENTED: &str = "This feature is not yet implemented";
33}
34
35/// Helper functions for creating standardized errors
36#[allow(dead_code)]
37pub mod helpers {
38    use super::*;
39
40    /// Create a domain error for a parameter that must be positive
41    pub fn positive_required(_paramname: &str, value: impl std::fmt::Display) -> StatsError {
42        StatsError::domain(format!("{_paramname} must be positive (> 0), got {value}"))
43    }
44
45    /// Create a domain error for a parameter that must be non-negative
46    pub fn non_negative_required(_paramname: &str, value: impl std::fmt::Display) -> StatsError {
47        StatsError::domain(format!(
48            "{_paramname} must be non-negative (>= 0), got {value}"
49        ))
50    }
51
52    /// Create a domain error for a probability parameter
53    pub fn probability_range(_paramname: &str, value: impl std::fmt::Display) -> StatsError {
54        StatsError::domain(format!(
55            "{_paramname} must be between 0 and 1 (inclusive), got {value}"
56        ))
57    }
58
59    /// Create a dimension mismatch error for arrays that should have the same length
60    pub fn arrays_length_mismatch(len1: usize, len2: usize) -> StatsError {
61        StatsError::dimension_mismatch(format!(
62            "Arrays must have the same length, got {len1} and {len2}"
63        ))
64    }
65
66    /// Create an invalid argument error for empty arrays
67    pub fn array_empty(_arrayname: &str) -> StatsError {
68        StatsError::invalid_argument(format!("{_arrayname} cannot be empty"))
69    }
70
71    /// Create an invalid argument error for insufficient data
72    pub fn insufficientdata(required: usize, actual: usize, context: &str) -> StatsError {
73        StatsError::invalid_argument(format!(
74            "Insufficient data for {context}: requires at least {required} samples, got {actual}"
75        ))
76    }
77
78    /// Create a computation error for numerical issues
79    pub fn numerical_error(context: &str) -> StatsError {
80        StatsError::computation(format!(
81            "Numerical error in {context}: check for extreme values or scaling issues"
82        ))
83    }
84
85    /// Create a not implemented error with feature name
86    pub fn not_implemented(feature: &str) -> StatsError {
87        StatsError::not_implemented(format!("{feature} is not yet implemented"))
88    }
89}
90
91/// Validation helpers that return standardized errors
92#[allow(dead_code)]
93pub mod validation {
94    use super::*;
95    use scirs2_core::numeric::Float;
96
97    /// Validate that a value is positive
98    pub fn ensure_positive<F: Float + std::fmt::Display>(
99        value: F,
100        param_name: &str,
101    ) -> StatsResult<F> {
102        if value <= F::zero() {
103            Err(helpers::positive_required(param_name, value))
104        } else {
105            Ok(value)
106        }
107    }
108
109    /// Validate that a value is non-negative
110    pub fn ensure_non_negative<F: Float + std::fmt::Display>(
111        value: F,
112        param_name: &str,
113    ) -> StatsResult<F> {
114        if value < F::zero() {
115            Err(helpers::non_negative_required(param_name, value))
116        } else {
117            Ok(value)
118        }
119    }
120
121    /// Validate that a value is a valid probability [0, 1]
122    pub fn ensure_probability<F: Float + std::fmt::Display>(
123        value: F,
124        param_name: &str,
125    ) -> StatsResult<F> {
126        if value < F::zero() || value > F::one() {
127            Err(helpers::probability_range(param_name, value))
128        } else {
129            Ok(value)
130        }
131    }
132
133    /// Validate that arrays have the same length
134    pub fn ensure_same_length<T, U>(arr1: &[T], arr2: &[U]) -> StatsResult<()> {
135        if arr1.len() != arr2.len() {
136            Err(helpers::arrays_length_mismatch(arr1.len(), arr2.len()))
137        } else {
138            Ok(())
139        }
140    }
141
142    /// Validate that an array is not empty
143    pub fn ensure_not_empty<T>(_arr: &[T], arrayname: &str) -> StatsResult<()> {
144        if _arr.is_empty() {
145            Err(helpers::array_empty(arrayname))
146        } else {
147            Ok(())
148        }
149    }
150
151    /// Validate that we have sufficient data
152    pub fn ensure_sufficientdata(actual: usize, required: usize, context: &str) -> StatsResult<()> {
153        if actual < required {
154            Err(helpers::insufficientdata(required, actual, context))
155        } else {
156            Ok(())
157        }
158    }
159}