use antecedent_core::{AverageEffectQuery, Intervention, PopulationRegistry, TargetPopulation};
use antecedent_expr::{EstimandMethod, IdentifiedEstimand};
use crate::adjustment::intervention_f64;
use crate::error::EstimationError;
pub fn require_method(
estimand: &IdentifiedEstimand,
allowed: &[EstimandMethod],
message: &'static str,
) -> Result<EstimandMethod, EstimationError> {
let kind = estimand.method_kind().map_err(EstimationError::data_msg)?;
if !allowed.contains(&kind) {
return Err(EstimationError::IncompatibleEstimand { message });
}
Ok(kind)
}
pub fn validate_ate_query_with_targets(query: &AverageEffectQuery) -> Result<(), EstimationError> {
query.validate()?;
if !query.effect_modifiers.is_empty() {
return Err(EstimationError::EffectModifiers);
}
if !matches!(
query.target_population,
TargetPopulation::AllObserved
| TargetPopulation::Treated
| TargetPopulation::Untreated
| TargetPopulation::Predicate(_)
) {
return Err(EstimationError::TargetPopulation);
}
Ok(())
}
pub(crate) fn intersect_predicate_mask(
row_mask: &mut [bool],
target: &TargetPopulation,
n_full: usize,
registry: Option<&PopulationRegistry>,
) -> Result<(), EstimationError> {
if !matches!(target, TargetPopulation::Predicate(_)) {
return Ok(());
}
let sel = target
.resolve(n_full, None, registry)
.map_err(|e| EstimationError::data_msg(e.to_string()))?;
for (i, slot) in row_mask.iter_mut().enumerate() {
*slot = *slot && sel.keep.get(i).copied().unwrap_or(false);
}
Ok(())
}
pub fn validate_simple_ate_query(query: &AverageEffectQuery) -> Result<(), EstimationError> {
query.validate()?;
if !query.effect_modifiers.is_empty() {
return Err(EstimationError::EffectModifiers);
}
if query.target_population != TargetPopulation::AllObserved {
return Err(EstimationError::TargetPopulation);
}
Ok(())
}
pub fn treatment_contrast(
active: &Intervention,
control: &Intervention,
) -> Result<(f64, f64, f64), EstimationError> {
let a = intervention_f64(active)?;
let c = intervention_f64(control)?;
let delta = a - c;
if delta == 0.0 {
return Err(EstimationError::unsupported(
"active and control treatment levels must differ",
));
}
Ok((a, c, delta))
}