antecedent_graph/error.rs
1//! Graph construction and validation errors.
2//!
3//! SPDX-License-Identifier: MIT OR Apache-2.0
4
5use antecedent_core::{Lag, VariableId};
6use thiserror::Error;
7
8/// Graph-layer errors.
9#[derive(Clone, Debug, Eq, PartialEq, Error)]
10#[non_exhaustive]
11pub enum GraphError {
12 /// Unknown dense node.
13 #[error("unknown dense node {id}")]
14 UnknownNode {
15 /// Dense id.
16 id: u32,
17 },
18 /// Unknown variable name at an API boundary.
19 #[error("unknown variable name '{name}'")]
20 UnknownVariableName {
21 /// Requested name.
22 name: String,
23 },
24 /// Edge would introduce a directed cycle.
25 #[error("edge {from}->{to} would create a cycle")]
26 Cycle {
27 /// Source dense id.
28 from: u32,
29 /// Target dense id.
30 to: u32,
31 },
32 /// Invalid endpoint combination for this graph class.
33 #[error("invalid endpoints: {message}")]
34 InvalidEndpoints {
35 /// Explanation.
36 message: &'static str,
37 },
38 /// Contemporaneous self-edge is invalid.
39 #[error("contemporaneous self-edge on {variable}")]
40 ContemporaneousSelfEdge {
41 /// Variable.
42 variable: VariableId,
43 },
44 /// Duplicate edge.
45 #[error("duplicate edge {from}->{to}")]
46 DuplicateEdge {
47 /// From.
48 from: u32,
49 /// To.
50 to: u32,
51 },
52 /// Lagged self-edge with lag 0.
53 #[error("invalid lag {lag}")]
54 InvalidLag {
55 /// Lag value.
56 lag: Lag,
57 },
58 /// Edge points from the future into the past (source lag nearer the present
59 /// than target lag).
60 #[error("edge {from}->{to} points from the future ({from_lag}) into the past ({to_lag})")]
61 FutureToPast {
62 /// Source dense id.
63 from: u32,
64 /// Target dense id.
65 to: u32,
66 /// Source lag.
67 from_lag: Lag,
68 /// Target lag.
69 to_lag: Lag,
70 },
71 /// Node capacity exceeded.
72 #[error("too many nodes")]
73 TooManyNodes,
74 /// Invalid selection-diagram metadata.
75 #[error("invalid selection diagram: {message}")]
76 InvalidSelectionDiagram {
77 /// Explanation.
78 message: String,
79 },
80 /// Bounded path search hit `max_paths` or `max_len` before exploring all candidates.
81 ///
82 /// Returned when m-separation would otherwise conclude "separated" after an incomplete
83 /// search (an unexplored active path may still exist). Finding an active path remains
84 /// conclusive even under truncation.
85 #[error("path search budget exhausted (max_paths={max_paths}, max_len={max_len})")]
86 SearchBudgetExhausted {
87 /// Path-count budget.
88 max_paths: usize,
89 /// Path-length budget.
90 max_len: usize,
91 },
92}