1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
//! Error types for LOESS operations.
//!
//! This module defines error conditions that can occur during LOESS smoothing,
//! including input validation, parameter constraints, and adapter limitations.
// Feature-gated imports
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::error::Error;
#[cfg(feature = "std")]
use std::string::String;
#[cfg(feature = "std")]
use std::vec::Vec;
// External dependencies
use core::fmt::{Display, Formatter, Result};
// Error type for LOESS operations.
#[derive(Debug, Clone, PartialEq)]
pub enum LoessError {
// Input arrays are empty; LOESS requires at least 2 points.
EmptyInput,
// Generic invalid input error with a descriptive message.
InvalidInput(String),
// `x` and `y` arrays must have the same number of elements.
MismatchedInputs {
// Number of elements in the `x` array.
x_len: usize,
// Number of elements in the `y` array.
y_len: usize,
},
// Input data contains NaN or infinite values.
InvalidNumericValue(String),
// Number of points is below the minimum requirement for the selected parameters.
TooFewPoints {
// Number of points provided.
got: usize,
// Minimum required points.
min: usize,
},
// Smoothing fraction must be in the range (0, 1].
InvalidFraction(f64),
// Robustness iterations (0 means initial fit only).
InvalidIterations(usize),
// Interval coverage level must be strictly between 0 and 1.
InvalidIntervals(f64),
// Convergence tolerance must be positive and finite.
InvalidTolerance(f64),
// Chunk size must be large enough to accommodate the minimum window.
InvalidChunkSize {
// The chunk size provided.
got: usize,
// Minimum required chunk size.
min: usize,
},
// Overlap must be strictly less than the chunk size to ensure progress.
InvalidOverlap {
// The overlap provided.
overlap: usize,
// The chunk size.
chunk_size: usize,
},
// Window capacity must be large enough for the requested smoothing parameters.
InvalidWindowCapacity {
// The window capacity provided.
got: usize,
// Minimum required window capacity.
min: usize,
},
// Minimum points must be at least 2 and at most the window capacity.
InvalidMinPoints {
// The min_points provided.
got: usize,
// The window capacity.
window_capacity: usize,
},
// Selected adapter does not support the requested feature (e.g., cross-validation).
UnsupportedFeature {
// Name of the adapter (e.g., "Streaming", "Online").
adapter: &'static str,
// Name of the unsupported feature.
feature: &'static str,
},
// Parameter was set multiple times in the builder.
DuplicateParameter {
// Name of the parameter that was set multiple times.
parameter: &'static str,
},
// Runtime execution error.
RuntimeError(String),
// Cell size must be in the range (0, 1].
InvalidCell(f64),
// Interpolation cell size requires more vertices than allowed limit.
InsufficientVertices {
// Estimated number of vertices required.
required: usize,
// Maximum number of vertices allowed.
limit: usize,
// The cell size that caused the overflow.
cell: f64,
// Whether the cell size was explicitly provided by the user.
cell_provided: bool,
// Whether the limit was explicitly provided by the user.
limit_provided: bool,
},
// An invalid string value was passed for a configuration option.
InvalidOption {
// The name of the configuration option.
option: &'static str,
// The invalid value that was provided.
value: String,
// Comma-separated list of valid values for the option.
valid: &'static str,
},
// Multiple invalid string option values were passed to the builder.
//
// Collects all parse errors from string builder methods and reports them together at `build()`.
ParseErrors(Vec<LoessError>),
}
impl Display for LoessError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Self::EmptyInput => write!(f, "Input arrays are empty"),
Self::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
Self::MismatchedInputs { x_len, y_len } => {
write!(f, "Length mismatch: x has {x_len} points, y has {y_len}")
}
Self::InvalidNumericValue(s) => write!(f, "Invalid numeric value: {s}"),
Self::TooFewPoints { got, min } => {
write!(f, "Too few points: got {got}, need at least {min}")
}
Self::InvalidFraction(frac) => {
write!(f, "Invalid fraction: {frac} (must be > 0 and <= 1)")
}
Self::InvalidIterations(iter) => {
write!(f, "Invalid iterations: {iter} (must be in [0, 1000])")
}
Self::InvalidIntervals(level) => {
write!(f, "Invalid interval level: {level} (must be > 0 and < 1)")
}
Self::InvalidTolerance(tol) => {
write!(f, "Invalid tolerance: {tol} (must be > 0 and finite)")
}
Self::InvalidChunkSize { got, min } => {
write!(f, "Invalid chunk_size: {got} (must be at least {min})")
}
Self::InvalidOverlap {
overlap,
chunk_size,
} => {
write!(
f,
"Invalid overlap: {overlap} (must be less than chunk_size {chunk_size})"
)
}
Self::InvalidWindowCapacity { got, min } => {
write!(f, "Invalid window_capacity: {got} (must be at least {min})")
}
Self::InvalidMinPoints {
got,
window_capacity,
} => {
write!(
f,
"Invalid min_points: {got} (must be between 2 and window_capacity {window_capacity})"
)
}
Self::UnsupportedFeature { adapter, feature } => {
write!(f, "Adapter '{adapter}' does not support feature: {feature}")
}
Self::DuplicateParameter { parameter } => {
write!(
f,
"Parameter '{parameter}' was set multiple times. Each parameter can only be configured once."
)
}
Self::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
Self::InvalidCell(cell) => {
write!(f, "Invalid cell size: {cell} (must be in range (0, 1])")
}
Self::InsufficientVertices {
required,
limit,
cell,
cell_provided,
limit_provided,
} => {
let cell_desc = if *cell_provided {
format!("user-provided cell size {cell}")
} else {
format!("default cell size {cell}")
};
let limit_desc = if *limit_provided {
format!("user-provided limit {limit}")
} else {
format!("default limit (N = {limit})")
};
if !*cell_provided && *limit_provided {
write!(
f,
"Insufficient vertices: {cell_desc} does not work with {limit_desc}. Try passing a larger cell size manually."
)
} else {
write!(
f,
"Insufficient vertices: {cell_desc} requires ~{required} vertices, but {limit_desc} is too small"
)
}
}
Self::InvalidOption {
option,
value,
valid,
} => {
write!(
f,
"Invalid value '{value}' for '{option}'. Valid options: {valid}"
)
}
Self::ParseErrors(errors) => {
write!(f, "Multiple configuration errors ({} total):", errors.len())?;
for (i, e) in errors.iter().enumerate() {
write!(f, " [{i}] {e}")?;
}
Ok(())
}
}
}
}
#[cfg(feature = "std")]
impl Error for LoessError {}