1use crate::common::IntegrateFloat;
8use crate::error::IntegrateResult;
9use scirs2_core::ndarray::{Array1, ArrayView1};
10use std::collections::VecDeque;
11
12pub struct AdvancedErrorEstimator<F: IntegrateFloat> {
14 pub tolerance: F,
16 pub max_richardson_order: usize,
18 solution_history: VecDeque<Array1<F>>,
20 step_size_history: VecDeque<F>,
22 error_history: VecDeque<F>,
24}
25
26pub struct RichardsonExtrapolator<F: IntegrateFloat> {
28 pub order: usize,
30 pub step_ratios: Vec<F>,
32 solutions: Vec<Array1<F>>,
34}
35
36pub struct SpectralErrorIndicator<F: IntegrateFloat> {
38 pub window_size: usize,
40 pub decay_threshold: F,
42 history: VecDeque<Array1<F>>,
44}
45
46pub struct DefectCorrector<F: IntegrateFloat> {
48 pub max_iterations: usize,
50 pub tolerance: F,
52 pub iterative: bool,
54}
55
56#[derive(Debug, Clone)]
58pub struct ErrorAnalysisResult<F: IntegrateFloat> {
59 pub primary_estimate: F,
61 pub richardson_error: Option<F>,
63 pub spectral_error: Option<F>,
65 pub defect_error: Option<F>,
67 pub quality_metrics: SolutionQualityMetrics<F>,
69 pub recommended_step_size: F,
71 pub confidence: F,
73 pub error_distribution: ErrorDistribution<F>,
75}
76
77#[derive(Debug, Clone)]
79pub struct SolutionQualityMetrics<F: IntegrateFloat> {
80 pub smoothness: F,
82 pub regularity: F,
84 pub conservation_error: Option<F>,
86 pub monotonicity_violations: usize,
88 pub oscillation_index: F,
90 pub signal_noise_ratio: F,
92}
93
94#[derive(Debug, Clone)]
96pub struct ErrorDistribution<F: IntegrateFloat> {
97 pub mean_error: F,
99 pub std_deviation: F,
101 pub max_error: F,
103 pub skewness: F,
105 pub component_errors: Vec<F>,
107}
108
109impl<F: IntegrateFloat> AdvancedErrorEstimator<F> {
110 pub fn new(tolerance: F, max_richardsonorder: usize) -> Self {
112 Self {
113 tolerance,
114 max_richardson_order: max_richardsonorder,
115 solution_history: VecDeque::new(),
116 step_size_history: VecDeque::new(),
117 error_history: VecDeque::new(),
118 }
119 }
120
121 pub fn analyze_error<Func>(
123 &mut self,
124 current_solution: &Array1<F>,
125 step_size: F,
126 ode_function: Func,
127 embedded_error: Option<F>,
128 ) -> IntegrateResult<ErrorAnalysisResult<F>>
129 where
130 Func: Fn(F, &ArrayView1<F>) -> Array1<F>,
131 {
132 self.solution_history.push_back(current_solution.clone());
134 self.step_size_history.push_back(step_size);
135
136 while self.solution_history.len() > 20 {
138 self.solution_history.pop_front();
139 self.step_size_history.pop_front();
140 }
141
142 let mut result = ErrorAnalysisResult {
143 primary_estimate: embedded_error.unwrap_or(F::from(1e-8).unwrap()),
144 richardson_error: None,
145 spectral_error: None,
146 defect_error: None,
147 quality_metrics: self.assess_solution_quality()?,
148 recommended_step_size: step_size,
149 confidence: F::from(0.5).unwrap(), error_distribution: self.analyze_error_distribution(current_solution)?,
151 };
152
153 if self.solution_history.len() >= 3 {
155 result.richardson_error = self.richardson_extrapolation()?;
156 }
157
158 if self.solution_history.len() >= 5 {
160 result.spectral_error = self.spectral_error_analysis()?;
161 }
162
163 result.defect_error = self.defect_based_error(current_solution, &ode_function)?;
165
166 result.confidence = Self::compute_confidence(&result);
168 result.recommended_step_size = self.recommend_step_size(&result, step_size);
169
170 self.error_history.push_back(result.primary_estimate);
172 while self.error_history.len() > 20 {
173 self.error_history.pop_front();
174 }
175
176 Ok(result)
177 }
178
179 fn richardson_extrapolation(&self) -> IntegrateResult<Option<F>> {
181 if self.solution_history.len() < 3 || self.step_size_history.len() < 3 {
182 return Ok(None);
183 }
184
185 let n = self.solution_history.len();
186 let y2 = &self.solution_history[n - 1]; let y1 = &self.solution_history[n - 2]; let _y0 = &self.solution_history[n - 3]; let h2 = self.step_size_history[n - 1];
191 let h1 = self.step_size_history[n - 2];
192
193 let r = h1 / h2;
195 if (r - F::one()).abs() < F::from(0.1).unwrap() {
196 return Ok(None);
198 }
199
200 let extrapolated_error = (y2 - y1).mapv(|x| x.abs()).sum() / (r.powi(2) - F::one());
202
203 Ok(Some(extrapolated_error))
204 }
205
206 fn spectral_error_analysis(&self) -> IntegrateResult<Option<F>> {
208 if self.solution_history.len() < 5 {
209 return Ok(None);
210 }
211
212 let _n = self.solution_history.len();
213 let recent_solutions = &self.solution_history;
214
215 let mut spectral_norm = F::zero();
217 let mut total_norm = F::zero();
218
219 for component in 0..recent_solutions[0].len() {
220 let values: Vec<F> = recent_solutions.iter().map(|sol| sol[component]).collect();
221
222 if values.len() >= 3 {
224 for i in 1..values.len() - 1 {
225 let second_diff =
226 values[i + 1] - F::from(2.0).unwrap() * values[i] + values[i - 1];
227 spectral_norm += second_diff.abs();
228 total_norm += values[i].abs();
229 }
230 }
231 }
232
233 if total_norm > F::zero() {
234 let spectral_indicator = spectral_norm / total_norm;
235 Ok(Some(spectral_indicator))
236 } else {
237 Ok(None)
238 }
239 }
240
241 fn defect_based_error<Func>(
243 &self,
244 current_solution: &Array1<F>,
245 ode_function: &Func,
246 ) -> IntegrateResult<Option<F>>
247 where
248 Func: Fn(F, &ArrayView1<F>) -> Array1<F>,
249 {
250 if self.solution_history.len() < 2 || self.step_size_history.is_empty() {
251 return Ok(None);
252 }
253
254 let h = *self.step_size_history.back().unwrap();
255 let t = F::zero(); let f_current = ode_function(t, ¤t_solution.view());
260 let defect_norm = f_current.mapv(|x| x.abs()).sum() * h;
261
262 Ok(Some(defect_norm))
263 }
264
265 fn assess_solution_quality(&self) -> IntegrateResult<SolutionQualityMetrics<F>> {
267 let mut metrics = SolutionQualityMetrics {
268 smoothness: F::zero(),
269 regularity: F::zero(),
270 conservation_error: None,
271 monotonicity_violations: 0,
272 oscillation_index: F::zero(),
273 signal_noise_ratio: F::one(),
274 };
275
276 if self.solution_history.len() < 3 {
277 return Ok(metrics);
278 }
279
280 let n = self.solution_history.len();
281 let solutions = &self.solution_history;
282
283 let mut total_variation = F::zero();
285 let mut total_magnitude = F::zero();
286
287 for i in 1..n {
288 let diff = &solutions[i] - &solutions[i - 1];
289 total_variation += diff.mapv(|x| x.abs()).sum();
290 total_magnitude += solutions[i].mapv(|x| x.abs()).sum();
291 }
292
293 if total_magnitude > F::zero() {
294 metrics.smoothness = F::one() / (F::one() + total_variation / total_magnitude);
295 }
296
297 if n >= 3 {
299 let mut oscillations = 0;
300 for comp in 0..solutions[0].len() {
301 for i in 1..n - 1 {
302 let prev = solutions[i - 1][comp];
303 let curr = solutions[i][comp];
304 let next = solutions[i + 1][comp];
305
306 if (curr - prev) * (next - curr) < F::zero() {
308 oscillations += 1;
309 }
310 }
311 }
312 metrics.oscillation_index =
313 F::from(oscillations).unwrap() / F::from(n * solutions[0].len()).unwrap();
314 }
315
316 if n >= 4 {
318 let mut signal_power = F::zero();
319 let mut noise_power = F::zero();
320
321 for comp in 0..solutions[0].len() {
322 let values: Vec<F> = solutions.iter().map(|sol| sol[comp]).collect();
323 let mean = values.iter().fold(F::zero(), |acc, &x| acc + x)
324 / F::from(values.len()).unwrap();
325
326 for &val in &values {
328 signal_power += (val - mean).powi(2);
329 }
330
331 for i in 1..values.len() - 1 {
333 let second_diff =
334 values[i + 1] - F::from(2.0).unwrap() * values[i] + values[i - 1];
335 noise_power += second_diff.powi(2);
336 }
337 }
338
339 if noise_power > F::zero() {
340 metrics.signal_noise_ratio = signal_power / noise_power;
341 }
342 }
343
344 Ok(metrics)
345 }
346
347 fn analyze_error_distribution(
349 &self,
350 solution: &Array1<F>,
351 ) -> IntegrateResult<ErrorDistribution<F>> {
352 let n_components = solution.len();
353 let mut component_errors = vec![F::zero(); n_components];
354
355 if self.solution_history.len() >= 2 {
357 let prev_solution = self.solution_history.back().unwrap();
358 for i in 0..n_components {
359 component_errors[i] = (solution[i] - prev_solution[i]).abs();
360 }
361 }
362
363 let mean_error = component_errors.iter().fold(F::zero(), |acc, &x| acc + x)
365 / F::from(n_components).unwrap();
366
367 let variance = component_errors
368 .iter()
369 .map(|&err| (err - mean_error).powi(2))
370 .fold(F::zero(), |acc, x| acc + x)
371 / F::from(n_components).unwrap();
372
373 let std_deviation = variance.sqrt();
374 let max_error = component_errors
375 .iter()
376 .fold(F::zero(), |acc, &x| acc.max(x));
377
378 let skewness = if std_deviation > F::zero() {
380 component_errors
381 .iter()
382 .map(|&err| ((err - mean_error) / std_deviation).powi(3))
383 .fold(F::zero(), |acc, x| acc + x)
384 / F::from(n_components).unwrap()
385 } else {
386 F::zero()
387 };
388
389 Ok(ErrorDistribution {
390 mean_error,
391 std_deviation,
392 max_error,
393 skewness,
394 component_errors,
395 })
396 }
397
398 fn compute_confidence(result: &ErrorAnalysisResult<F>) -> F {
400 let mut confidence_factors = Vec::new();
401
402 let estimates = [
404 Some(result.primary_estimate),
405 result.richardson_error,
406 result.spectral_error,
407 result.defect_error,
408 ]
409 .iter()
410 .filter_map(|&est| est)
411 .collect::<Vec<_>>();
412
413 if estimates.len() >= 2 {
414 let mean_est = estimates.iter().fold(F::zero(), |acc, &x| acc + x)
415 / F::from(estimates.len()).unwrap();
416 let relative_std = estimates
417 .iter()
418 .map(|&est| ((est - mean_est) / mean_est).abs())
419 .fold(F::zero(), |acc, x| acc + x)
420 / F::from(estimates.len()).unwrap();
421
422 confidence_factors.push(F::one() / (F::one() + relative_std));
424 }
425
426 confidence_factors.push(result.quality_metrics.smoothness);
428 confidence_factors.push(F::one() / (F::one() + result.quality_metrics.oscillation_index));
429
430 if !confidence_factors.is_empty() {
432 confidence_factors.iter().fold(F::zero(), |acc, &x| acc + x)
433 / F::from(confidence_factors.len()).unwrap()
434 } else {
435 F::from(0.5).unwrap() }
437 }
438
439 fn recommend_step_size(&self, result: &ErrorAnalysisResult<F>, currentstep: F) -> F {
441 let target_error = self.tolerance;
442 let current_error = result.primary_estimate;
443
444 if current_error <= F::zero() {
445 return currentstep;
446 }
447
448 let safety_factor = F::from(0.8).unwrap() + F::from(0.15).unwrap() * result.confidence;
450
451 let ratio = (target_error / current_error).powf(F::from(0.5).unwrap());
453 let _basic_recommendation = currentstep * ratio * safety_factor;
454
455 let quality_factor = if result.quality_metrics.oscillation_index > F::from(0.1).unwrap() {
457 F::from(0.7).unwrap() } else if result.quality_metrics.smoothness > F::from(0.8).unwrap() {
459 F::from(1.2).unwrap() } else {
461 F::one()
462 };
463
464 let min_factor = F::from(0.2).unwrap();
466 let max_factor = F::from(5.0).unwrap();
467 let final_factor = (ratio * safety_factor * quality_factor)
468 .max(min_factor)
469 .min(max_factor);
470
471 currentstep * final_factor
472 }
473}
474
475impl<F: IntegrateFloat> RichardsonExtrapolator<F> {
476 pub fn new(order: usize) -> Self {
478 Self {
479 order,
480 step_ratios: vec![F::from(0.5).unwrap(), F::from(0.25).unwrap()],
481 solutions: Vec::new(),
482 }
483 }
484
485 pub fn add_solution(&mut self, solution: Array1<F>) {
487 self.solutions.push(solution);
488 if self.solutions.len() > self.order + 1 {
489 self.solutions.remove(0);
490 }
491 }
492
493 pub fn extrapolate(&self) -> IntegrateResult<Option<Array1<F>>> {
495 if self.solutions.len() < 2 {
496 return Ok(None);
497 }
498
499 let n = self.solutions.len();
500 let mut tableau = Vec::new();
501
502 for sol in &self.solutions {
504 tableau.push(vec![sol.clone()]);
505 }
506
507 for col in 1..n {
509 for row in 0..n - col {
510 let default_ratio = F::from(0.5).unwrap();
511 let r = self.step_ratios.get(col - 1).unwrap_or(&default_ratio);
512 let r_power = r.powi(self.order as i32);
513
514 let numerator = &tableau[row + 1][col - 1] * r_power - &tableau[row][col - 1];
515 let denominator = r_power - F::one();
516
517 if denominator.abs() > F::from(1e-12).unwrap() {
518 let extrapolated = numerator / denominator;
519 tableau[row].push(extrapolated);
520 } else {
521 return Ok(None);
522 }
523 }
524 }
525
526 Ok(Some(tableau[0][n - 1].clone()))
528 }
529}
530
531impl<F: IntegrateFloat> SpectralErrorIndicator<F> {
532 pub fn new(window_size: usize, decaythreshold: F) -> Self {
534 Self {
535 window_size,
536 decay_threshold: decaythreshold,
537 history: VecDeque::new(),
538 }
539 }
540
541 pub fn add_solution(&mut self, solution: Array1<F>) {
543 self.history.push_back(solution);
544 while self.history.len() > self.window_size {
545 self.history.pop_front();
546 }
547 }
548
549 pub fn compute_indicator(&self) -> IntegrateResult<Option<F>> {
551 if self.history.len() < self.window_size {
552 return Ok(None);
553 }
554
555 let mut total_indicator = F::zero();
558 let n_components = self.history[0].len();
559
560 for comp in 0..n_components {
561 let values: Vec<F> = self.history.iter().map(|sol| sol[comp]).collect();
562
563 let mut diff_norms = Vec::new();
565 let mut current_values = values;
566
567 for _order in 0..3 {
568 if current_values.len() < 2 {
570 break;
571 }
572
573 let mut new_values = Vec::new();
574 let mut norm = F::zero();
575
576 for i in 0..current_values.len() - 1 {
577 let diff = current_values[i + 1] - current_values[i];
578 new_values.push(diff);
579 norm += diff.abs();
580 }
581
582 diff_norms.push(norm);
583 current_values = new_values;
584 }
585
586 if diff_norms.len() >= 2 {
588 for i in 1..diff_norms.len() {
589 if diff_norms[i - 1] > F::zero() {
590 let decay_rate = diff_norms[i] / diff_norms[i - 1];
591 if decay_rate > self.decay_threshold {
592 total_indicator += decay_rate;
593 }
594 }
595 }
596 }
597 }
598
599 Ok(Some(total_indicator / F::from(n_components).unwrap()))
600 }
601}
602
603#[cfg(test)]
604mod tests {
605 use super::*;
606
607 #[test]
608 fn test_advanced_error_estimator() {
609 let mut estimator = AdvancedErrorEstimator::<f64>::new(1e-6, 3);
610
611 let solution = Array1::from_vec(vec![1.0, 2.0, 3.0]);
612 let step_size = 0.01;
613 let ode_fn =
614 |_t: f64, y: &ArrayView1<f64>| Array1::from_vec(y.iter().map(|&yi| -yi).collect());
615
616 let result = estimator.analyze_error(&solution, step_size, ode_fn, Some(1e-8));
617 assert!(result.is_ok());
618
619 let error_analysis = result.unwrap();
620 assert!(error_analysis.primary_estimate > 0.0);
621 assert!(error_analysis.confidence >= 0.0 && error_analysis.confidence <= 1.0);
622 }
623
624 #[test]
625 fn test_richardson_extrapolator() {
626 let mut extrapolator = RichardsonExtrapolator::<f64>::new(2);
627
628 extrapolator.add_solution(Array1::from_vec(vec![1.0, 2.0]));
629 extrapolator.add_solution(Array1::from_vec(vec![1.01, 2.01]));
630 extrapolator.add_solution(Array1::from_vec(vec![1.005, 2.005]));
631
632 let result = extrapolator.extrapolate();
633 assert!(result.is_ok());
634 }
635
636 #[test]
637 fn test_spectral_error_indicator() {
638 let mut indicator = SpectralErrorIndicator::<f64>::new(5, 0.5);
639
640 for i in 0..6 {
641 let solution = Array1::from_vec(vec![i as f64, (i as f64).sin()]);
642 indicator.add_solution(solution);
643 }
644
645 let result = indicator.compute_indicator();
646 assert!(result.is_ok());
647 }
648}