1use antecedent_core::ExecutionContext;
9use antecedent_estimate::EstimationWorkspace;
10
11use crate::bootstrap_refute::BootstrapRefute;
12use crate::common::{RefutationProblem, RefutationReport};
13use crate::data_subset::DataSubsetRefuter;
14use crate::dummy_outcome::DummyOutcome;
15use crate::error::ValidationError;
16use crate::evalue::EValue;
17use crate::graph_refute::GraphRefuter;
18use crate::overlap::OverlapRefuter;
19use crate::overlap_rule::OverlapRuleRefuter;
20use crate::panel_slice::PanelSliceTemplate;
21use crate::placebo::PlaceboTreatment;
22use crate::rcc::RandomCommonCause;
23use crate::riesz::RieszSensitivity;
24use crate::sensitivity::{LinearSensitivity, NonparametricSensitivity, PartialLinearSensitivity};
25use crate::unobserved_common_cause::UnobservedCommonCause;
26
27mod sealed {
28 pub trait Sealed {}
29}
30
31pub trait Validator<A>: sealed::Sealed {
38 type Prepared;
40 type Report;
42
43 fn prepare(
49 &self,
50 artifact: &A,
51 ctx: &ExecutionContext,
52 ) -> Result<Self::Prepared, ValidationError>;
53
54 fn validate(
60 &self,
61 prepared: &mut Self::Prepared,
62 workspace: &mut EstimationWorkspace,
63 ctx: &ExecutionContext,
64 ) -> Result<Self::Report, ValidationError>;
65}
66
67#[derive(Clone, Debug)]
70pub struct PreparedRefutation<'a> {
71 pub problem: RefutationProblem<'a>,
73 pub panel: Option<PanelSliceTemplate<'a>>,
75}
76
77impl<'a> PreparedRefutation<'a> {
78 pub fn compile(problem: &RefutationProblem<'a>) -> Result<Self, ValidationError> {
85 let panel = match problem.temporal.and_then(|t| t.panel) {
86 Some(p) => Some(PanelSliceTemplate::from_panel(p, problem.data)?),
87 None => None,
88 };
89 Ok(Self { problem: *problem, panel })
90 }
91}
92
93pub fn run_validator<'a, V>(
99 validator: &V,
100 problem: &RefutationProblem<'a>,
101 workspace: &mut EstimationWorkspace,
102 ctx: &ExecutionContext,
103) -> Result<RefutationReport, ValidationError>
104where
105 V: Validator<
106 RefutationProblem<'a>,
107 Prepared = PreparedRefutation<'a>,
108 Report = RefutationReport,
109 >,
110{
111 let mut prepared = validator.prepare(problem, ctx)?;
112 validator.validate(&mut prepared, workspace, ctx)
113}
114
115macro_rules! impl_effect_validator {
116 ($ty:ty, $call:expr) => {
117 impl crate::validator::sealed::Sealed for $ty {}
118 impl<'a> Validator<RefutationProblem<'a>> for $ty {
119 type Prepared = PreparedRefutation<'a>;
120 type Report = RefutationReport;
121
122 fn prepare(
123 &self,
124 artifact: &RefutationProblem<'a>,
125 _ctx: &ExecutionContext,
126 ) -> Result<Self::Prepared, ValidationError> {
127 PreparedRefutation::compile(artifact)
128 }
129
130 fn validate(
131 &self,
132 prepared: &mut Self::Prepared,
133 workspace: &mut EstimationWorkspace,
134 ctx: &ExecutionContext,
135 ) -> Result<Self::Report, ValidationError> {
136 let problem = prepared.problem.with_panel_slices(prepared.panel.as_ref());
137 ($call)(self, &problem, workspace, ctx)
138 }
139 }
140 };
141}
142
143impl_effect_validator!(PlaceboTreatment, |this: &PlaceboTreatment, p, ws, ctx| {
144 this.refute(p, ws, ctx)
145});
146impl_effect_validator!(RandomCommonCause, |this: &RandomCommonCause, p, ws, ctx| {
147 this.refute(p, ws, ctx)
148});
149impl_effect_validator!(BootstrapRefute, |this: &BootstrapRefute, p, ws, ctx| {
150 this.refute(p, ws, ctx)
151});
152impl_effect_validator!(UnobservedCommonCause, |this: &UnobservedCommonCause, p, ws, ctx| {
153 this.refute(p, ws, ctx)
154});
155impl_effect_validator!(DataSubsetRefuter, |this: &DataSubsetRefuter, p, ws, ctx| {
156 this.refute(p, ws, ctx)
157});
158impl_effect_validator!(DummyOutcome, |this: &DummyOutcome, p, ws, ctx| { this.refute(p, ws, ctx) });
159impl_effect_validator!(GraphRefuter, |this: &GraphRefuter, p, ws, ctx| { this.refute(p, ws, ctx) });
160impl_effect_validator!(LinearSensitivity, |this: &LinearSensitivity, p, ws, ctx| {
161 this.refute(p, ws, ctx)
162});
163impl_effect_validator!(PartialLinearSensitivity, |this: &PartialLinearSensitivity, p, ws, ctx| {
164 this.refute(p, ws, ctx)
165});
166impl_effect_validator!(NonparametricSensitivity, |this: &NonparametricSensitivity, p, ws, ctx| {
167 this.refute(p, ws, ctx)
168});
169impl_effect_validator!(RieszSensitivity, |this: &RieszSensitivity, p, ws, ctx| {
170 this.refute(p, ws, ctx)
171});
172
173macro_rules! impl_stateless_effect_validator {
175 ($ty:ty, $call:expr) => {
176 impl crate::validator::sealed::Sealed for $ty {}
177 impl<'a> Validator<RefutationProblem<'a>> for $ty {
178 type Prepared = PreparedRefutation<'a>;
179 type Report = RefutationReport;
180
181 fn prepare(
182 &self,
183 artifact: &RefutationProblem<'a>,
184 _ctx: &ExecutionContext,
185 ) -> Result<Self::Prepared, ValidationError> {
186 PreparedRefutation::compile(artifact)
187 }
188
189 fn validate(
190 &self,
191 prepared: &mut Self::Prepared,
192 _workspace: &mut EstimationWorkspace,
193 _ctx: &ExecutionContext,
194 ) -> Result<Self::Report, ValidationError> {
195 let problem = prepared.problem.with_panel_slices(prepared.panel.as_ref());
196 ($call)(self, &problem)
197 }
198 }
199 };
200}
201
202impl_stateless_effect_validator!(OverlapRefuter, |this: &OverlapRefuter, p| this.refute(p));
203impl_stateless_effect_validator!(OverlapRuleRefuter, |this: &OverlapRuleRefuter, p| {
204 this.refute(p)
205});
206impl_stateless_effect_validator!(EValue, |this: &EValue, p| this.refute(p));