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