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
//! Error types for the tenferro runtime crate.
//!
//! # Examples
//!
//! ```rust
//! use tenferro_runtime::error::Error;
//!
//! let err = Error::InvalidSubscripts("bad label".into());
//! assert!(err.to_string().contains("bad label"));
//! ```
use std::sync::atomic::{AtomicUsize, Ordering};
use tenferro_tensor::DType;
static NEXT_CONTEXT_ID: AtomicUsize = AtomicUsize::new(1);
/// Errors produced by einsum, eval, and other tenferro operations.
///
/// # Examples
///
/// ```rust
/// use tenferro_runtime::error::Error;
///
/// let err = Error::InvalidSubscripts("rank mismatch".into());
/// ```
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Einsum subscript string is invalid or cannot be parsed.
#[error("invalid subscripts: {0}")]
InvalidSubscripts(String),
/// Contraction optimization failed (shape mismatch, bad path, etc.).
#[error("contraction error: {0}")]
ContractionError(String),
/// A required input tensor is missing from the inputs map.
#[error("missing input: {0}")]
MissingInput(String),
/// Reverse-mode gradient requires a scalar output.
#[error("grad requires a scalar output, got shape {shape:?}")]
NonScalarGrad { shape: Vec<usize> },
/// Runtime tensor execution failed in the backend layer.
#[error(transparent)]
TensorRuntime(#[from] tenferro_tensor::Error),
/// A `TracedTensor` passed to graph-executor input bindings is not a
/// placeholder (has attached data).
#[error(
"binding #{binding_index} is not a placeholder; \
only tensors built via input_concrete_shape / input_symbolic_shape \
can be bound"
)]
UnexpectedBinding { binding_index: usize },
/// A placeholder appearing in the graph has no binding supplied.
#[error("placeholder {input_key} has no runtime input binding")]
UnboundPlaceholder { input_key: String },
/// The same placeholder was bound more than once in the `bindings` slice.
#[error("placeholder {input_key} was bound more than once")]
DuplicateBinding { input_key: String },
/// A binding tensor's dtype does not match the placeholder's dtype.
#[error("binding dtype mismatch for placeholder: expected {expected:?}, got {actual:?}")]
PlaceholderDtypeMismatch { expected: DType, actual: DType },
/// A binding tensor's shape does not match an `input_concrete_shape`
/// placeholder's fixed shape.
#[error(
"binding shape mismatch for concrete-shape placeholder: \
expected {expected:?}, got {actual:?}"
)]
PlaceholderShapeMismatch {
expected: Vec<usize>,
actual: Vec<usize>,
},
/// A binding tensor's rank does not match an `input_symbolic_shape`
/// placeholder's declared rank.
#[error(
"binding rank mismatch for symbolic-shape placeholder: \
expected rank {expected}, got rank {actual}"
)]
PlaceholderRankMismatch { expected: usize, actual: usize },
/// Operation attempted to mix tensors from different eager contexts.
#[error(
"tensors belong to different eager AD contexts ({lhs} vs {rhs}); \
detach into the target context before combining them"
)]
ContextMismatch { lhs: ContextId, rhs: ContextId },
/// Traced graph construction rejected an invalid operation configuration.
#[error("{op}: invalid traced graph build: {message}")]
InvalidGraphBuild {
/// Public operation name.
op: &'static str,
/// Validation failure details.
message: String,
},
/// An AD transform requires a primitive or extension rule that is not
/// registered for the requested operation.
#[error("unsupported {transform} AD rule for {op}")]
UnsupportedAdRule {
/// AD transform that requested the rule, such as `grad` or `backward`.
transform: &'static str,
/// Operation or extension family identifier that has no applicable rule.
op: String,
},
/// Lowering rejected an inconsistent compiled graph.
#[error("invalid compiled graph: {message}")]
InvalidCompiledGraph {
/// Validation failure details.
message: String,
},
/// An unexpected internal error.
#[error("internal error: {0}")]
Internal(String),
}
/// Opaque identifier for an eager AD runtime, used in [`Error::ContextMismatch`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ContextId(usize);
impl ContextId {
/// Generate a fresh opaque runtime context identifier.
///
/// Runtime implementations use this when constructing a new execution
/// context. The value is intentionally opaque and is only useful in error
/// reporting and equality checks.
pub fn fresh() -> Self {
let id = NEXT_CONTEXT_ID.fetch_add(1, Ordering::Relaxed);
Self(id)
}
}
impl std::fmt::Display for ContextId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ctx@{:x}", self.0)
}
}
/// Result type alias for tenferro operations.
pub type Result<T> = std::result::Result<T, Error>;