Skip to main content

antecedent_core/query/
error.rs

1//! Query submodule.
2//!
3//! SPDX-License-Identifier: MIT OR Apache-2.0
4
5use crate::ids::VariableId;
6
7/// Errors from query construction or validation.
8#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
9#[non_exhaustive]
10pub enum QueryError {
11    /// Treatment and outcome are the same variable.
12    #[error("treatment and outcome are the same variable {id}")]
13    TreatmentEqualsOutcome {
14        /// Shared id.
15        id: VariableId,
16    },
17    /// Intervention does not target the declared treatment.
18    #[error("intervention targets {got}, expected treatment {expected}")]
19    InterventionVariableMismatch {
20        /// Expected treatment id.
21        expected: VariableId,
22        /// Actual intervention target.
23        got: VariableId,
24    },
25    /// Intervention sequence has no unique target variable.
26    #[error("intervention does not have a unique target variable")]
27    AmbiguousInterventionTarget,
28    /// Effect modifier overlaps treatment or outcome.
29    #[error("effect modifier overlaps treatment or outcome")]
30    ModifierOverlapsTreatmentOrOutcome,
31    /// Sustained window has `until < from`.
32    #[error("invalid temporal window [{from}, {until}]")]
33    InvalidTemporalWindow {
34        /// Window start.
35        from: i32,
36        /// Window end.
37        until: i32,
38    },
39    /// Horizon must be at least one time step.
40    #[error("horizon_steps must be >= 1")]
41    NonPositiveHorizon,
42    /// Nested intervention failed validation.
43    #[error("invalid intervention: {0}")]
44    InvalidIntervention(String),
45    /// Counterfactual query has no outcomes.
46    #[error("counterfactual query requires at least one outcome")]
47    EmptyCounterfactualOutcomes,
48    /// Anomaly query has no targets.
49    #[error("anomaly attribution requires targets")]
50    EmptyAnomalyTargets,
51    /// Anomaly `max_units` must be ≥ 1.
52    #[error("anomaly max_units must be >= 1")]
53    NonPositiveAnomalyLimit,
54    /// Mediation query has no mediators.
55    #[error("mediation query requires mediators")]
56    EmptyMediators,
57    /// Mediator overlaps treatment or outcome.
58    #[error("mediator overlaps treatment or outcome")]
59    MediatorOverlapsTreatmentOrOutcome,
60    /// Conditional effect requires non-empty modifiers.
61    #[error("conditional effect requires non-empty effect modifiers")]
62    EmptyEffectModifiers,
63    /// Population selector has no rows.
64    #[error("population selector has no rows")]
65    EmptyPopulationRows,
66    /// Named [`crate::query::PredicateExpr`] has an empty registry key.
67    #[error("predicate name must be non-empty")]
68    EmptyPredicateName,
69    /// [`crate::intervention::TemporalPolicy::Dynamic`] has no single treatment origin.
70    #[error("TemporalPolicy::Dynamic has no single treatment offset")]
71    DynamicPolicyHasNoTreatmentOffset,
72    /// Time-range population has `end <= start`.
73    #[error("invalid population time range [{start}, {end})")]
74    InvalidPopulationTimeRange {
75        /// Start.
76        start: usize,
77        /// End.
78        end: usize,
79    },
80    /// Sequential allocation order is empty.
81    #[error("sequential allocation order is empty")]
82    EmptyAllocationOrder,
83    /// Sequential allocation order contains the same component more than once.
84    #[error("sequential allocation order contains duplicate components")]
85    DuplicateAllocationComponent,
86    /// Shapley exact component limit must be ≥ 1.
87    #[error("Shapley max_exact_components must be >= 1")]
88    NonPositiveShapleyLimit,
89    /// Approximate Shapley sample / permutation count must be ≥ 1.
90    #[error("Shapley sample / permutation count must be >= 1")]
91    NonPositiveShapleySamples,
92    /// Change attribution `max_components` must be ≥ 1.
93    #[error("max_components / max_targets must be >= 1")]
94    NonPositiveComponentLimit,
95    /// Mechanism-change query has no targets.
96    #[error("mechanism-change detection requires targets")]
97    EmptyMechanismChangeTargets,
98    /// Significance level must be in (0, 1).
99    #[error("significance level must be in (0, 1)")]
100    InvalidSignificanceLevel,
101    /// Interventional distribution query has no outcomes.
102    #[error("interventional distribution requires at least one outcome")]
103    EmptyDistributionOutcomes,
104    /// Path enumeration `max_paths` / `max_len` must be ≥ 1.
105    #[error("path max_paths / max_len must be >= 1")]
106    NonPositivePathLimit,
107    /// Path node overlaps treatment or outcome.
108    #[error("path node overlaps treatment or outcome")]
109    PathNodeOverlapsTreatmentOrOutcome,
110    /// Distribution conditioning overlaps an outcome or intervention target.
111    #[error("distribution conditioning overlaps outcome or intervention")]
112    ConditioningOverlapsOutcomeOrIntervention,
113    /// Named / custom population requires a [`super::PopulationRegistry`].
114    #[error("named predicate / custom distribution requires a PopulationRegistry")]
115    PopulationRegistryRequired,
116    /// Named predicate is not bound in the registry.
117    #[error("unknown predicate name `{name}`")]
118    UnknownPredicateName {
119        /// Predicate key.
120        name: std::sync::Arc<str>,
121    },
122    /// Custom distribution handle is not bound in the registry.
123    #[error("unknown DistributionRef({id})")]
124    UnknownDistributionRef {
125        /// Raw distribution id.
126        id: u32,
127    },
128    /// Treated / untreated population requires a treatment column.
129    #[error("Treated/Untreated population requires a treatment column")]
130    PopulationNeedsTreatment,
131    /// Treatment column is not binary 0/1.
132    #[error("Treated/Untreated population requires binary 0/1 treatment")]
133    PopulationNonBinaryTreatment,
134    /// Keep-mask / weight length mismatch.
135    #[error("population length mismatch: expected {expected}, got {actual}")]
136    PopulationLengthMismatch {
137        /// Expected length.
138        expected: usize,
139        /// Actual length.
140        actual: usize,
141    },
142    /// Predicate row index ≥ `n`.
143    #[error("population row {row} out of range for n={n}")]
144    PopulationRowOutOfRange {
145        /// Offending row.
146        row: usize,
147        /// Population size.
148        n: usize,
149    },
150    /// Environment-restricted populations need multi-env data (not resolved here).
151    #[error("Environment target population is not resolved by PopulationRegistry")]
152    PopulationEnvironmentUnsupported,
153    /// Distribution weights contain negatives or non-finite values.
154    #[error("custom distribution weights must be finite and non-negative")]
155    InvalidPopulationWeights,
156}