use crate::numerical_stability_modules;
pub use crate::numerical_stability_modules::{
analyze_boundary_conditions, analyze_data_points, analyze_function_values,
analyze_interpolation_data, analyze_interpolation_edge_cases, analyze_sampling_density,
apply_adaptive_regularization, apply_preconditioning, apply_tikhonov_regularization,
assess_matrix_condition, check_diagonal_dominance, check_safe_division, check_symmetry,
classify_stability, count_zero_diagonal_elements, detect_edge_cases, estimate_condition_number,
iterative_refinement, machine_epsilon, safe_reciprocal, solve_with_enhanced_monitoring,
solve_with_stability_monitoring, suggest_data_based_regularization, BoundaryAnalysis,
BoundaryTreatment, ConditionReport, ConvergenceInfo, DataPointsAnalysis, DataScalingAnalysis,
DenoisingStrategy, EdgeCaseAnalysis, EdgeCaseReport, EdgeCaseTreatment,
EnhancedStabilityReport, ExtrapolationRisk, FunctionValuesAnalysis, InterpolationDataReport,
InterpolationMethod, InterpolationMethodRecommendation, NoiseAnalysis, PreconditionerType,
SamplingDensityAnalysis, SamplingStrategy, SolveStrategy, StabilityDiagnostics, StabilityLevel,
};
pub use crate::numerical_stability_modules::prelude::*;
use crate::error::{InterpolateError, InterpolateResult};
use scirs2_core::ndarray::{Array1, ArrayView1, ArrayView2};
use scirs2_core::numeric::{Float, FromPrimitive};
use std::fmt::{Debug, Display};
use std::ops::{AddAssign, SubAssign};
pub type ConditionReportF32 = ConditionReport<f32>;
pub type ConditionReportF64 = ConditionReport<f64>;
pub fn quick_condition_check(matrix: &ArrayView2<f64>) -> InterpolateResult<bool> {
let report = assess_matrix_condition(matrix)?;
Ok(report.is_well_conditioned)
}
pub fn quick_stable_solve(
matrix: &ArrayView2<f64>,
rhs: &ArrayView1<f64>,
) -> InterpolateResult<Array1<f64>> {
solve_with_stability_monitoring(matrix, rhs)
}
pub mod info {
pub use crate::numerical_stability_modules::info::*;
}
#[cfg(test)]
mod tests {
use super::*;
use scirs2_core::ndarray::Array2;
#[test]
fn test_quick_condition_check() {
let well_conditioned = Array2::<f64>::eye(3);
assert!(quick_condition_check(&well_conditioned.view()).expect("Operation failed"));
let ill_conditioned = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, 1.0 + 1e-15])
.expect("Operation failed");
assert!(!quick_condition_check(&ill_conditioned.view()).expect("Operation failed"));
}
#[test]
fn test_quick_stable_solve() {
let matrix =
Array2::from_shape_vec((2, 2), vec![2.0, 1.0, 1.0, 3.0]).expect("Operation failed");
let rhs = Array1::from_vec(vec![1.0, 2.0]);
let solution = quick_stable_solve(&matrix.view(), &rhs.view()).expect("Operation failed");
assert_eq!(solution.len(), 2);
let verification = matrix.dot(&solution);
for i in 0..rhs.len() {
assert!((verification[i] - rhs[i]).abs() < 1e-10);
}
}
#[test]
fn test_modular_api_integration() {
let matrix =
Array2::from_shape_vec((3, 3), vec![4.0, 1.0, 0.0, 1.0, 4.0, 1.0, 0.0, 1.0, 4.0])
.expect("Operation failed");
let rhs = Array1::from_vec(vec![5.0, 6.0, 5.0]);
let condition_report = assess_matrix_condition(&matrix.view()).expect("Operation failed");
assert!(condition_report.is_well_conditioned);
assert_eq!(condition_report.stability_level, StabilityLevel::Excellent);
let (solution, enhanced_report) =
solve_with_enhanced_monitoring(&matrix.view(), &rhs.view()).expect("Operation failed");
assert_eq!(solution.len(), 3);
assert!(enhanced_report.condition_report.is_well_conditioned);
let edge_report = detect_edge_cases(&matrix.view()).expect("Operation failed");
assert!(!edge_report.is_nearly_singular);
assert!(edge_report.has_diagonal_dominance);
}
#[test]
fn test_interpolation_data_analysis() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 3.0, 9.0, 4.0, 16.0],
)
.expect("Operation failed");
let values = Array1::from_vec(vec![0.0, 1.0, 4.0, 9.0, 16.0]);
let analysis = analyze_interpolation_edge_cases(&points.view(), &values.view())
.expect("Operation failed");
assert!(analysis.is_solvable);
assert!(analysis.function_values.is_smooth);
assert!(analysis.function_values.is_monotonic);
let data_report =
analyze_interpolation_data(&points.view(), &values.view()).expect("Operation failed");
assert!(matches!(
data_report
.interpolation_method_recommendation
.primary_method,
InterpolationMethod::CubicSpline
| InterpolationMethod::BSpline
| InterpolationMethod::Linear
));
}
#[test]
fn test_regularization_workflow() {
let ill_conditioned = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, 1.0 + 1e-15])
.expect("Operation failed");
let condition_report =
assess_matrix_condition(&ill_conditioned.view()).expect("Operation failed");
assert!(!condition_report.is_well_conditioned);
assert!(condition_report.recommended_regularization.is_some());
let reg_param = condition_report
.recommended_regularization
.expect("Operation failed");
let regularized = apply_tikhonov_regularization(&ill_conditioned.view(), reg_param)
.expect("Operation failed");
let regularized_report =
assess_matrix_condition(®ularized.view()).expect("Operation failed");
assert!(regularized_report.condition_number < condition_report.condition_number);
}
#[test]
fn test_safe_arithmetic() {
assert!(check_safe_division(1.0, 2.0).is_ok());
assert!(check_safe_division(1.0, 1e-20).is_err());
assert!(safe_reciprocal(2.0).is_ok());
assert_eq!(safe_reciprocal(2.0).expect("Operation failed"), 0.5);
assert!(safe_reciprocal(1e-20).is_err());
}
#[test]
fn test_machine_epsilon() {
let eps_f32 = machine_epsilon::<f32>();
let eps_f64 = machine_epsilon::<f64>();
assert!(eps_f32 > 0.0);
assert!(eps_f64 > 0.0);
assert!(eps_f32 > eps_f64 as f32); }
#[test]
fn test_stability_classification() {
assert_eq!(classify_stability(1e10_f64), StabilityLevel::Excellent);
assert_eq!(classify_stability(1e13_f64), StabilityLevel::Good);
assert_eq!(classify_stability(1e15_f64), StabilityLevel::Marginal);
assert_eq!(classify_stability(1e17_f64), StabilityLevel::Poor);
}
#[test]
fn test_data_analysis_features() {
let uniform_points =
Array2::from_shape_vec((4, 2), vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0])
.expect("Operation failed");
let smooth_values = Array1::from_vec(vec![0.0, 1.0, 2.0, 3.0]);
let data_analysis = analyze_data_points(&uniform_points.view()).expect("Operation failed");
assert!(!data_analysis.is_collinear);
assert!(data_analysis.clustering_score < 0.5);
let function_analysis =
analyze_function_values(&smooth_values.view()).expect("Operation failed");
assert!(function_analysis.is_smooth);
assert!(function_analysis.is_monotonic);
assert!(!function_analysis.has_outliers);
let boundary_analysis =
analyze_boundary_conditions(&uniform_points.view(), &smooth_values.view())
.expect("Operation failed");
assert!(matches!(
boundary_analysis.extrapolation_risk,
ExtrapolationRisk::Low | ExtrapolationRisk::Medium
));
}
#[test]
fn test_sampling_density_analysis() {
let sparse_points =
Array2::from_shape_vec((3, 1), vec![0.0, 5.0, 10.0]).expect("Operation failed");
let analysis =
analyze_sampling_density(&sparse_points.view(), 0.1).expect("Operation failed");
assert!(analysis.current_density > 0.0);
assert!(analysis.recommended_density >= analysis.current_density);
assert!(matches!(
analysis.sampling_strategy,
SamplingStrategy::Uniform | SamplingStrategy::Adaptive
));
}
#[test]
fn test_preconditioning() {
use super::numerical_stability_modules::regularization::PreconditionerType;
let matrix =
Array2::from_shape_vec((2, 2), vec![4.0, 1.0, 1.0, 9.0]).expect("Operation failed");
let (precond, inv_precond) =
apply_preconditioning(&matrix.view(), PreconditionerType::Diagonal)
.expect("Operation failed");
assert_eq!(precond.nrows(), 2);
assert_eq!(precond.ncols(), 2);
assert_eq!(inv_precond.nrows(), 2);
assert_eq!(inv_precond.ncols(), 2);
assert!((precond[(0, 0)] - 2.0).abs() < 1e-10); assert!((precond[(1, 1)] - 3.0).abs() < 1e-10); }
}