#![allow(clippy::too_many_arguments)]
#![allow(dead_code)]
use crate::error::{MetricsError, Result};
use scirs2_core::ndarray::{Array1, Array2, ArrayView1, ArrayView2};
use scirs2_core::numeric::Float;
use std::collections::HashMap;
pub mod advanced;
pub mod bayesian;
pub mod calibration;
pub mod conformal;
pub mod core;
pub mod rng;
pub use core::{
AleatoricUncertainty, BrierDecomposition, CalibrationMetrics, ConfidenceScores,
EpistemicUncertainty, OODScores, PredictionIntervals, RandomNumberGenerator,
UncertaintyAnalysis, UncertaintyQuantifier,
};
pub use rng::{ChaChaRng, LcgRng, PcgRng, RandomNumberGeneratorTrait, XorshiftRng};
pub use bayesian::{
BayesianUncertainty, MCMCDiagnostics, PriorParameters, VariationalParams,
VariationalUncertainty,
};
pub use conformal::{ConformalPrediction, PredictionSet};
pub use calibration::{DeepEnsembleUncertainty, TemperatureScaling};
pub use advanced::{
AdvancedUncertaintyAnalysis, CoverageAnalysis, MultiscaleUncertainty, UncertaintyDecomposition,
};
pub struct UncertaintyQuantificationSuite<F: Float> {
pub quantifier: UncertaintyQuantifier<F>,
pub bayesian: Option<BayesianUncertainty<F>>,
pub conformal: Option<ConformalPrediction<F>>,
pub temperature_scaling: Option<TemperatureScaling<F>>,
pub deep_ensemble: Option<DeepEnsembleUncertainty<F>>,
pub advanced_analysis: Option<AdvancedUncertaintyAnalysis<F>>,
}
impl<
F: Float
+ scirs2_core::numeric::FromPrimitive
+ std::iter::Sum
+ scirs2_core::ndarray::ScalarOperand,
> UncertaintyQuantificationSuite<F>
{
pub fn new(quantifier: UncertaintyQuantifier<F>) -> Self {
Self {
quantifier,
bayesian: None,
conformal: None,
temperature_scaling: None,
deep_ensemble: None,
advanced_analysis: None,
}
}
pub fn with_all_methods(quantifier: UncertaintyQuantifier<F>) -> Self {
Self {
quantifier,
bayesian: Some(BayesianUncertainty::new(1000, 10)),
conformal: Some(ConformalPrediction::new(
F::from(0.95).expect("Failed to convert constant to float"),
)),
temperature_scaling: Some(TemperatureScaling::new()),
deep_ensemble: Some(DeepEnsembleUncertainty::new(5)),
advanced_analysis: Some(AdvancedUncertaintyAnalysis::new()),
}
}
pub fn with_bayesian(mut self, n_samples: usize, n_params: usize) -> Self {
self.bayesian = Some(BayesianUncertainty::new(n_samples, n_params));
self
}
pub fn with_conformal(mut self, confidence_level: F) -> Self {
self.conformal = Some(ConformalPrediction::new(confidence_level));
self
}
pub fn with_temperature_scaling(mut self) -> Self {
self.temperature_scaling = Some(TemperatureScaling::new());
self
}
pub fn with_deep_ensemble(mut self, ensemble_size: usize) -> Self {
self.deep_ensemble = Some(DeepEnsembleUncertainty::new(ensemble_size));
self
}
pub fn with_advanced_analysis(mut self) -> Self {
self.advanced_analysis = Some(AdvancedUncertaintyAnalysis::new());
self
}
pub fn analyze(
&self,
predictions: &ArrayView2<F>,
ground_truth: Option<&ArrayView1<F>>,
model_outputs: Option<&[ArrayView2<F>]>,
) -> Result<ComprehensiveUncertaintyResults<F>> {
let core_analysis =
self.quantifier
.analyze_uncertainty(predictions, ground_truth, model_outputs)?;
let bayesian_results = if let Some(_bayesian) = &self.bayesian {
None
} else {
None
};
let conformal_results = if let Some(_conformal) = &self.conformal {
None
} else {
None
};
let calibration_results = if let Some(_temp_scaling) = &self.temperature_scaling {
None
} else {
None
};
let ensemble_results = if let Some(_ensemble) = &self.deep_ensemble {
None
} else {
None
};
let advanced_results = if let Some(_advanced) = &self.advanced_analysis {
None
} else {
None
};
Ok(ComprehensiveUncertaintyResults {
core_analysis,
bayesian_results,
conformal_results,
calibration_results,
ensemble_results,
advanced_results,
})
}
pub fn config_summary(&self) -> UncertaintyConfigSummary<F> {
UncertaintyConfigSummary {
bayesian_enabled: self.bayesian.is_some(),
conformal_enabled: self.conformal.is_some(),
temperature_scaling_enabled: self.temperature_scaling.is_some(),
deep_ensemble_enabled: self.deep_ensemble.is_some(),
advanced_analysis_enabled: self.advanced_analysis.is_some(),
mc_samples: self.quantifier.n_mc_samples,
confidence_level: self.quantifier.confidence_level,
}
}
}
#[derive(Debug, Clone)]
pub struct ComprehensiveUncertaintyResults<F: Float> {
pub core_analysis: UncertaintyAnalysis<F>,
pub bayesian_results: Option<BayesianUncertainty<F>>,
pub conformal_results: Option<Vec<PredictionSet<F>>>,
pub calibration_results: Option<TemperatureScaling<F>>,
pub ensemble_results: Option<DeepEnsembleUncertainty<F>>,
pub advanced_results: Option<AdvancedUncertaintyAnalysis<F>>,
}
#[derive(Debug, Clone)]
pub struct UncertaintyConfigSummary<F: Float> {
pub bayesian_enabled: bool,
pub conformal_enabled: bool,
pub temperature_scaling_enabled: bool,
pub deep_ensemble_enabled: bool,
pub advanced_analysis_enabled: bool,
pub mc_samples: usize,
pub confidence_level: F,
}
pub struct UncertaintyMetricsComputer<F: Float> {
suite: UncertaintyQuantificationSuite<F>,
}
impl<
F: Float
+ scirs2_core::numeric::FromPrimitive
+ std::iter::Sum
+ scirs2_core::ndarray::ScalarOperand,
> UncertaintyMetricsComputer<F>
{
pub fn new(suite: UncertaintyQuantificationSuite<F>) -> Self {
Self { suite }
}
pub fn compute_metrics(
&self,
predictions: &ArrayView2<F>,
ground_truth: Option<&ArrayView1<F>>,
model_outputs: Option<&[ArrayView2<F>]>,
) -> Result<ComprehensiveUncertaintyResults<F>> {
self.suite.analyze(predictions, ground_truth, model_outputs)
}
pub fn summary_statistics(
&self,
results: &ComprehensiveUncertaintyResults<F>,
) -> UncertaintySummaryStats<F> {
let core = &results.core_analysis;
UncertaintySummaryStats {
mean_epistemic_uncertainty: core
.epistemic_uncertainty
.model_variance
.mean()
.unwrap_or(F::zero()),
mean_aleatoric_uncertainty: core
.aleatoric_uncertainty
.data_variance
.mean()
.unwrap_or(F::zero()),
mean_confidence: core
.confidence_scores
.max_probability
.mean()
.unwrap_or(F::zero()),
calibration_error: core.calibration_metrics.expected_calibration_error,
coverage: F::from(0.95).expect("Failed to convert constant to float"), }
}
}
#[derive(Debug, Clone)]
pub struct UncertaintySummaryStats<F: Float> {
pub mean_epistemic_uncertainty: F,
pub mean_aleatoric_uncertainty: F,
pub mean_confidence: F,
pub calibration_error: F,
pub coverage: F,
}
impl<
F: Float
+ scirs2_core::numeric::FromPrimitive
+ std::iter::Sum
+ scirs2_core::ndarray::ScalarOperand,
> Default for UncertaintyQuantificationSuite<F>
{
fn default() -> Self {
Self::new(UncertaintyQuantifier::new())
}
}