use alloc::format;
use deep_causality_algebra::RealField;
use deep_causality_core::EffectLog;
use deep_causality_haft::LogAddEntry;
use deep_causality_num::FromPrimitive;
use deep_causality_uncertain::{MaybeUncertain, ProbabilisticType, UncertainError};
use super::dropout_verbosity::DropoutVerbosity;
#[derive(Debug, Clone, Copy)]
pub struct UncertainBoundarySource<R> {
threshold: f64,
confidence: f64,
epsilon: f64,
max_samples: usize,
collapse_samples: usize,
default_value: R,
verbosity: DropoutVerbosity,
qmc_collapse_seed: Option<u64>,
}
impl<R> UncertainBoundarySource<R>
where
R: RealField + FromPrimitive + ProbabilisticType + core::fmt::Debug,
{
pub fn new(default_value: R) -> Self {
Self {
threshold: 0.5,
confidence: 0.95,
epsilon: 0.05,
max_samples: 1000,
collapse_samples: 1000,
default_value,
verbosity: DropoutVerbosity::EachDropout,
qmc_collapse_seed: None,
}
}
pub fn with_presence_gate(
mut self,
threshold: f64,
confidence: f64,
epsilon: f64,
max_samples: usize,
) -> Self {
self.threshold = threshold;
self.confidence = confidence;
self.epsilon = epsilon;
self.max_samples = max_samples;
self
}
pub fn with_collapse_samples(mut self, collapse_samples: usize) -> Self {
self.collapse_samples = collapse_samples;
self
}
pub fn with_qmc_collapse(mut self, base_seed: u64) -> Self {
self.qmc_collapse_seed = Some(base_seed);
self
}
pub fn with_verbosity(mut self, verbosity: DropoutVerbosity) -> Self {
self.verbosity = verbosity;
self
}
pub fn default_value(&self) -> R {
self.default_value
}
pub fn verbosity(&self) -> DropoutVerbosity {
self.verbosity
}
pub fn resolve(
&self,
sample: &MaybeUncertain<R>,
last_good: &mut R,
) -> Result<(R, bool), UncertainError> {
match sample.lift_to_uncertain(
self.threshold,
self.confidence,
self.epsilon,
self.max_samples,
) {
Ok(present) => {
let collapsed = match self.qmc_collapse_seed {
Some(base) => present.expected_value_qmc(
self.collapse_samples,
base.wrapping_add(present.id() as u64),
),
None => present.expected_value(self.collapse_samples),
};
match collapsed {
Ok(mean) if mean.is_finite() => {
*last_good = mean;
Ok((mean, false))
}
Ok(_) => Ok((*last_good, true)),
Err(e) => Err(e),
}
}
Err(UncertainError::PresenceError(_)) => Ok((*last_good, true)),
Err(e) => Err(e),
}
}
pub fn record(
&self,
logs: &mut EffectLog,
step: usize,
dropout: bool,
in_dropout: bool,
value: R,
) {
match self.verbosity {
DropoutVerbosity::EachDropout => {
if dropout {
logs.add_entry(&format!(
"uncertain boundary source: dropout at step {step} (fallback {value:?})"
));
}
}
DropoutVerbosity::Transitions => {
if dropout && !in_dropout {
logs.add_entry(&format!(
"uncertain boundary source: dropout ONSET at step {step} (fallback {value:?})"
));
} else if !dropout && in_dropout {
logs.add_entry(&format!(
"uncertain boundary source: RECOVERY at step {step} (sensor present again)"
));
}
}
}
}
}