1use crate::traits::*;
7use crate::{InterpolateError, InterpolateResult};
8use scirs2_core::ndarray::{ArrayView1, ArrayView2};
9
10pub mod factory_pattern {
36 use super::*;
37
38 #[derive(Debug, Clone)]
40 pub struct StandardConfig<T: InterpolationFloat> {
41 pub smoothing: Option<T>,
43
44 pub regularization: Option<T>,
46
47 pub max_iterations: usize,
49
50 pub tolerance: T,
52 }
53
54 impl<T: InterpolationFloat> Default for StandardConfig<T> {
55 fn default() -> Self {
56 Self {
57 smoothing: None,
58 regularization: None,
59 max_iterations: 100,
60 tolerance: T::default_tolerance(),
61 }
62 }
63 }
64
65 impl<T: InterpolationFloat> InterpolationConfig for StandardConfig<T> {
66 fn validate(&self) -> InterpolateResult<()> {
67 if self.max_iterations == 0 {
68 return Err(InterpolateError::invalid_input(
69 "max_iterations must be greater than 0",
70 ));
71 }
72
73 if let Some(s) = self.smoothing {
74 if s <= T::zero() {
75 return Err(InterpolateError::invalid_input(
76 "smoothing parameter must be positive",
77 ));
78 }
79 }
80
81 Ok(())
82 }
83
84 fn default() -> Self {
85 <Self as std::default::Default>::default()
86 }
87 }
88}
89
90pub mod builder_pattern {
104 use super::*;
105 use crate::api_standards::factory_pattern::StandardConfig;
106
107 #[derive(Debug, Clone)]
109 pub struct StandardInterpolatorBuilder<T: InterpolationFloat> {
110 config_factory_pattern: StandardConfig<T>,
111 }
112
113 impl<T: InterpolationFloat> StandardInterpolatorBuilder<T> {
114 pub fn new() -> Self {
116 Self {
117 config_factory_pattern: Default::default(),
118 }
119 }
120
121 pub fn with_smoothing(mut self, smoothing: T) -> Self {
123 self.config_factory_pattern.smoothing = Some(smoothing);
124 self
125 }
126
127 pub fn with_regularization(mut self, regularization: T) -> Self {
129 self.config_factory_pattern.regularization = Some(regularization);
130 self
131 }
132
133 pub fn with_max_iterations(mut self, maxiterations: usize) -> Self {
135 self.config_factory_pattern.max_iterations = maxiterations;
136 self
137 }
138
139 pub fn with_tolerance(mut self, tolerance: T) -> Self {
141 self.config_factory_pattern.tolerance = tolerance;
142 self
143 }
144
145 pub fn build<I>(
147 self,
148 points: &ArrayView2<T>,
149 values: &ArrayView1<T>,
150 ) -> InterpolateResult<I>
151 where
152 for<'a> I: From<(
153 ArrayView2<'a, T>,
154 ArrayView1<'a, T>,
155 factory_pattern::StandardConfig<T>,
156 )>,
157 {
158 validation::validate_data_consistency(points, values)?;
159 self.config_factory_pattern.validate()?;
160
161 Ok(I::from((
162 points.view(),
163 values.view(),
164 self.config_factory_pattern,
165 )))
166 }
167 }
168
169 impl<T: InterpolationFloat> Default for StandardInterpolatorBuilder<T> {
170 fn default() -> Self {
171 Self::new()
172 }
173 }
174}
175
176pub mod evaluation_pattern {
180 use super::*;
181
182 pub fn evaluate_batch<T, I>(
184 interpolator: &I,
185 query_points: &ArrayView2<T>,
186 options: Option<EvaluationOptions>,
187 ) -> InterpolateResult<BatchEvaluationResult<T>>
188 where
189 T: InterpolationFloat,
190 I: Interpolator<T>,
191 {
192 let _options = options.unwrap_or_default();
193
194 let values = interpolator.evaluate(query_points)?;
199
200 Ok(BatchEvaluationResult {
201 values,
202 uncertainties: None,
203 out_of_bounds: Vec::new(),
204 })
205 }
206}
207
208pub mod error_handling {
212 use crate::InterpolateError;
213
214 pub fn dimension_mismatch(expected: usize, actual: usize, context: &str) -> InterpolateError {
216 InterpolateError::dimension_mismatch(expected, actual, context)
217 }
218
219 pub fn empty_data(context: &str) -> InterpolateError {
221 InterpolateError::empty_data(context)
222 }
223
224 pub fn invalid_parameter<T: std::fmt::Display>(
226 param: &str,
227 expected: &str,
228 actual: T,
229 context: &str,
230 ) -> InterpolateError {
231 InterpolateError::invalid_parameter(param, expected, actual, context)
232 }
233
234 pub fn convergence_failure(method: &str, iterations: usize) -> InterpolateError {
236 InterpolateError::convergence_failure(method, iterations)
237 }
238
239 pub fn numerical_instability(context: &str, details: &str) -> InterpolateError {
241 InterpolateError::numerical_instability(context, details)
242 }
243
244 pub fn insufficient_points(
246 _required: usize,
247 provided: usize,
248 method: &str,
249 ) -> InterpolateError {
250 InterpolateError::insufficient_points(_required, provided, method)
251 }
252}
253
254pub mod input_validation {
258 use crate::{traits::InterpolationFloat, InterpolateError, InterpolateResult};
259 use scirs2_core::ndarray::{ArrayView1, ArrayView2};
260
261 pub fn validate_finite_data<T: InterpolationFloat>(
263 points: &ArrayView2<T>,
264 values: &ArrayView1<T>,
265 context: &str,
266 ) -> InterpolateResult<()> {
267 for (i, point_slice) in points.outer_iter().enumerate() {
269 for (j, &val) in point_slice.iter().enumerate() {
270 if !val.is_finite() {
271 return Err(InterpolateError::InvalidInput {
272 message: format!(
273 "Non-finite value found in {context} points at position ({i}, {j}): {val}"
274 ),
275 });
276 }
277 }
278 }
279
280 for (i, &val) in values.iter().enumerate() {
282 if !val.is_finite() {
283 return Err(InterpolateError::InvalidInput {
284 message: format!(
285 "Non-finite value found in {context} values at position {i}: {val}"
286 ),
287 });
288 }
289 }
290
291 Ok(())
292 }
293
294 pub fn validate_sufficient_points<T: InterpolationFloat>(
296 points: &ArrayView2<T>,
297 _values: &ArrayView1<T>,
298 minimum_required: usize,
299 method_name: &str,
300 ) -> InterpolateResult<()> {
301 let n_points = points.nrows();
302 if n_points < minimum_required {
303 return Err(InterpolateError::insufficient_points(
304 minimum_required,
305 n_points,
306 method_name,
307 ));
308 }
309 Ok(())
310 }
311
312 pub fn validate_query_points<T: InterpolationFloat>(
314 query_points: &ArrayView2<T>,
315 expected_dim: usize,
316 context: &str,
317 ) -> InterpolateResult<()> {
318 if query_points.ncols() != expected_dim {
319 return Err(InterpolateError::dimension_mismatch(
320 expected_dim,
321 query_points.ncols(),
322 &format!("{context} query _points"),
323 ));
324 }
325
326 for (i, point_slice) in query_points.outer_iter().enumerate() {
328 for (j, &val) in point_slice.iter().enumerate() {
329 if !val.is_finite() {
330 return Err(InterpolateError::InvalidInput {
331 message: format!(
332 "Non-finite value found in {context} query _points at position ({i}, {j}): {val}"
333 ),
334 });
335 }
336 }
337 }
338
339 Ok(())
340 }
341
342 pub fn validate_positive<T: InterpolationFloat>(
344 value: T,
345 param_name: &str,
346 context: &str,
347 ) -> InterpolateResult<()> {
348 if value <= T::zero() {
349 return Err(InterpolateError::invalid_parameter(
350 param_name,
351 "positive value",
352 value,
353 context,
354 ));
355 }
356 Ok(())
357 }
358
359 pub fn validate_non_negative<T: InterpolationFloat>(
361 value: T,
362 param_name: &str,
363 context: &str,
364 ) -> InterpolateResult<()> {
365 if value < T::zero() {
366 return Err(InterpolateError::invalid_parameter(
367 param_name,
368 "non-negative value",
369 value,
370 context,
371 ));
372 }
373 Ok(())
374 }
375
376 pub fn validate_range<T: InterpolationFloat>(
378 value: T,
379 min: T,
380 max: T,
381 param_name: &str,
382 context: &str,
383 ) -> InterpolateResult<()> {
384 if value < min || value > max {
385 return Err(InterpolateError::invalid_parameter(
386 param_name,
387 format!("value between {min} and {max}"),
388 value,
389 context,
390 ));
391 }
392 Ok(())
393 }
394}
395
396pub mod migration_examples {
400 use super::*;
401
402 #[derive(Debug, Clone)]
412 pub struct RBFConfig<T: InterpolationFloat> {
413 pub kernel: RBFKernel,
414 pub epsilon: T,
415 }
416
417 #[derive(Debug, Clone)]
418 pub enum RBFKernel {
419 Gaussian,
420 Multiquadric,
421 InverseMultiquadric,
422 ThinPlate,
423 }
424
425 impl<T: InterpolationFloat> Default for RBFConfig<T> {
426 fn default() -> Self {
427 Self {
428 kernel: RBFKernel::Gaussian,
429 epsilon: T::from_f64(1.0).expect("Operation failed"),
430 }
431 }
432 }
433
434 impl<T: InterpolationFloat> InterpolationConfig for RBFConfig<T> {
435 fn validate(&self) -> InterpolateResult<()> {
436 if self.epsilon <= T::zero() {
437 return Err(InterpolateError::invalid_input("epsilon must be positive"));
438 }
439 Ok(())
440 }
441
442 fn default() -> Self {
443 <Self as std::default::Default>::default()
444 }
445 }
446
447 pub fn make_rbf_interpolator<T: InterpolationFloat, I>(
449 points: &ArrayView2<T>,
450 values: &ArrayView1<T>,
451 config: Option<RBFConfig<T>>,
452 ) -> InterpolateResult<I>
453 where
454 for<'a> I: From<(ArrayView2<'a, T>, ArrayView1<'a, T>, RBFConfig<T>)>,
455 {
456 validation::validate_data_consistency(points, values)?;
457
458 let config = config.unwrap_or_default();
459 config.validate()?;
460
461 Ok(I::from((points.view(), values.view(), config)))
462 }
463}