use antecedent_core::ExecutionContext;
use antecedent_estimate::EstimationWorkspace;
use crate::bootstrap_refute::BootstrapRefute;
use crate::common::{RefutationProblem, RefutationReport};
use crate::data_subset::DataSubsetRefuter;
use crate::dummy_outcome::DummyOutcome;
use crate::error::ValidationError;
use crate::evalue::EValue;
use crate::graph_refute::GraphRefuter;
use crate::overlap::OverlapRefuter;
use crate::overlap_rule::OverlapRuleRefuter;
use crate::panel_slice::PanelSliceTemplate;
use crate::placebo::PlaceboTreatment;
use crate::rcc::RandomCommonCause;
use crate::riesz::RieszSensitivity;
use crate::sensitivity::{LinearSensitivity, NonparametricSensitivity, PartialLinearSensitivity};
use crate::unobserved_common_cause::UnobservedCommonCause;
mod sealed {
pub trait Sealed {}
}
pub trait Validator<A>: sealed::Sealed {
type Prepared;
type Report;
fn prepare(
&self,
artifact: &A,
ctx: &ExecutionContext,
) -> Result<Self::Prepared, ValidationError>;
fn validate(
&self,
prepared: &mut Self::Prepared,
workspace: &mut EstimationWorkspace,
ctx: &ExecutionContext,
) -> Result<Self::Report, ValidationError>;
}
#[derive(Clone, Debug)]
pub struct PreparedRefutation<'a> {
pub problem: RefutationProblem<'a>,
pub panel: Option<PanelSliceTemplate<'a>>,
}
impl<'a> PreparedRefutation<'a> {
pub fn compile(problem: &RefutationProblem<'a>) -> Result<Self, ValidationError> {
let panel = match problem.temporal.and_then(|t| t.panel) {
Some(p) => Some(PanelSliceTemplate::from_panel(p, problem.data)?),
None => None,
};
Ok(Self { problem: *problem, panel })
}
}
pub fn run_validator<'a, V>(
validator: &V,
problem: &RefutationProblem<'a>,
workspace: &mut EstimationWorkspace,
ctx: &ExecutionContext,
) -> Result<RefutationReport, ValidationError>
where
V: Validator<
RefutationProblem<'a>,
Prepared = PreparedRefutation<'a>,
Report = RefutationReport,
>,
{
let mut prepared = validator.prepare(problem, ctx)?;
validator.validate(&mut prepared, workspace, ctx)
}
macro_rules! impl_effect_validator {
($ty:ty, $call:expr) => {
impl crate::validator::sealed::Sealed for $ty {}
impl<'a> Validator<RefutationProblem<'a>> for $ty {
type Prepared = PreparedRefutation<'a>;
type Report = RefutationReport;
fn prepare(
&self,
artifact: &RefutationProblem<'a>,
_ctx: &ExecutionContext,
) -> Result<Self::Prepared, ValidationError> {
PreparedRefutation::compile(artifact)
}
fn validate(
&self,
prepared: &mut Self::Prepared,
workspace: &mut EstimationWorkspace,
ctx: &ExecutionContext,
) -> Result<Self::Report, ValidationError> {
let problem = prepared.problem.with_panel_slices(prepared.panel.as_ref());
($call)(self, &problem, workspace, ctx)
}
}
};
}
impl_effect_validator!(PlaceboTreatment, |this: &PlaceboTreatment, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(RandomCommonCause, |this: &RandomCommonCause, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(BootstrapRefute, |this: &BootstrapRefute, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(UnobservedCommonCause, |this: &UnobservedCommonCause, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(DataSubsetRefuter, |this: &DataSubsetRefuter, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(DummyOutcome, |this: &DummyOutcome, p, ws, ctx| { this.refute(p, ws, ctx) });
impl_effect_validator!(GraphRefuter, |this: &GraphRefuter, p, ws, ctx| { this.refute(p, ws, ctx) });
impl_effect_validator!(LinearSensitivity, |this: &LinearSensitivity, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(PartialLinearSensitivity, |this: &PartialLinearSensitivity, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(NonparametricSensitivity, |this: &NonparametricSensitivity, p, ws, ctx| {
this.refute(p, ws, ctx)
});
impl_effect_validator!(RieszSensitivity, |this: &RieszSensitivity, p, ws, ctx| {
this.refute(p, ws, ctx)
});
macro_rules! impl_stateless_effect_validator {
($ty:ty, $call:expr) => {
impl crate::validator::sealed::Sealed for $ty {}
impl<'a> Validator<RefutationProblem<'a>> for $ty {
type Prepared = PreparedRefutation<'a>;
type Report = RefutationReport;
fn prepare(
&self,
artifact: &RefutationProblem<'a>,
_ctx: &ExecutionContext,
) -> Result<Self::Prepared, ValidationError> {
PreparedRefutation::compile(artifact)
}
fn validate(
&self,
prepared: &mut Self::Prepared,
_workspace: &mut EstimationWorkspace,
_ctx: &ExecutionContext,
) -> Result<Self::Report, ValidationError> {
let problem = prepared.problem.with_panel_slices(prepared.panel.as_ref());
($call)(self, &problem)
}
}
};
}
impl_stateless_effect_validator!(OverlapRefuter, |this: &OverlapRefuter, p| this.refute(p));
impl_stateless_effect_validator!(OverlapRuleRefuter, |this: &OverlapRuleRefuter, p| {
this.refute(p)
});
impl_stateless_effect_validator!(EValue, |this: &EValue, p| this.refute(p));