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