Skip to main content

svod_tensor/
error.rs

1use snafu::Snafu;
2use svod_ir::shape::Shape;
3
4#[derive(Debug, Snafu)]
5#[snafu(visibility(pub))]
6pub enum Error {
7    // =========================================================================
8    // IR Layer Errors
9    // =========================================================================
10    #[snafu(display("IR operation error: {source}"))]
11    UOp { source: svod_ir::Error },
12
13    // =========================================================================
14    // Shape Errors
15    // =========================================================================
16    #[snafu(display("Tensor shape is unknown (symbolic or not yet inferred)"))]
17    ShapeUnknown,
18
19    #[snafu(display("Operation '{operation}' does not support symbolic shapes"))]
20    SymbolicShapeUnsupported { operation: String },
21
22    #[snafu(display("Axis {axis} is out of range for tensor with {ndim} dimensions"))]
23    AxisOutOfRange { axis: isize, ndim: usize },
24
25    #[snafu(display("Permutation length mismatch: expected {expected} axes, got {got}"))]
26    PermutationLengthMismatch { expected: usize, got: usize },
27
28    #[snafu(display("Invalid permutation: axes {axes:?} is not a valid permutation"))]
29    InvalidPermutation { axes: Vec<isize> },
30
31    #[snafu(display("Multiple -1 dimensions in reshape are not allowed"))]
32    MultipleInferDimensions,
33
34    #[snafu(display("Negative dimension {dim} is not allowed (except -1 for inference)"))]
35    NegativeDimension { dim: isize },
36
37    #[snafu(display("Reshape size mismatch during {operation}"))]
38    ReshapeSizeMismatch { operation: String },
39
40    #[snafu(display(
41        "Expand dimension mismatch: current shape has {current_dims} dims, target has {target_dims} dims"
42    ))]
43    ExpandDimensionMismatch { current_dims: usize, target_dims: usize },
44
45    #[snafu(display("Cannot squeeze dimension {dim}: size is {size}, not 1"))]
46    SqueezeDimensionNotOne { dim: usize, size: usize },
47
48    // =========================================================================
49    // NN Input Validation Errors
50    // =========================================================================
51    #[snafu(display("{op} requires exactly {expected}D input, got {actual}D"))]
52    NdimExact { op: &'static str, expected: usize, actual: usize },
53
54    #[snafu(display("{op} requires at least {min}D input, got {actual}D"))]
55    NdimMinimum { op: &'static str, min: usize, actual: usize },
56
57    #[snafu(display("{op}: {lhs_name} ({lhs}) must be divisible by {rhs_name} ({rhs})"))]
58    Divisibility { op: &'static str, lhs_name: &'static str, lhs: usize, rhs_name: &'static str, rhs: usize },
59
60    #[snafu(display("{op}: {param} = {value} is invalid, expected {constraint}"))]
61    ParamRange { op: &'static str, param: &'static str, value: String, constraint: &'static str },
62
63    // =========================================================================
64    // Reduction Errors
65    // =========================================================================
66    #[snafu(display("Cannot specify both 'dtype' and 'promote=true' in reduction operation"))]
67    ConflictingReductionOptions,
68
69    // =========================================================================
70    // Matrix Multiplication Errors
71    // =========================================================================
72    #[snafu(display(
73        "Matrix multiplication requires tensors with at least 1 dimension, got lhs: {lhs_dims}D, rhs: {rhs_dims}D"
74    ))]
75    DotDimensionError { lhs_dims: usize, rhs_dims: usize },
76
77    #[snafu(display(
78        "Matrix multiplication shape mismatch: cannot multiply shapes {lhs_shape:?} and {rhs_shape:?} (contraction dimension mismatch)"
79    ))]
80    DotShapeMismatch { lhs_shape: Box<Shape>, rhs_shape: Box<Shape> },
81
82    // =========================================================================
83    // Broadcasting Errors
84    // =========================================================================
85    #[snafu(display(
86        "Cannot broadcast to fewer dimensions: tensor has {from_dims} dimensions, target has {to_dims} dimensions"
87    ))]
88    BroadcastFewerDimensions { from_dims: usize, to_dims: usize },
89
90    #[snafu(display(
91        "Incompatible dimension {dim} for broadcasting: cannot broadcast size {from_size} to size {to_size}"
92    ))]
93    BroadcastIncompatible { dim: usize, from_size: usize, to_size: usize },
94
95    // =========================================================================
96    // Codegen Errors (from device traits that wrap codegen)
97    // =========================================================================
98    #[snafu(display("Failed to render kernel: {source}"))]
99    RenderKernel { source: svod_device::Error },
100
101    #[snafu(display("Failed to compile kernel: {source}"))]
102    CompileKernel { source: svod_device::Error },
103
104    // =========================================================================
105    // Schedule/Pipeline Errors
106    // =========================================================================
107    #[snafu(display("Rangeify failed: {source}"))]
108    Rangeify { source: svod_ir::Error },
109
110    #[snafu(display("Optimization error: {source}"))]
111    Optimize { source: svod_schedule::OptError },
112
113    #[snafu(display("No kernels found after scheduling pipeline"))]
114    NoKernelsFound,
115
116    #[snafu(display("Schedule contains dependency cycles"))]
117    DependencyCycles,
118
119    #[snafu(display("Empty schedule"))]
120    EmptySchedule,
121
122    #[snafu(display("Batch output count mismatch: expected {expected}, got {actual}"))]
123    BatchOutputMismatch { expected: usize, actual: usize },
124
125    #[snafu(display("Expected CALL operation"))]
126    ExpectedCallableOp,
127
128    // =========================================================================
129    // Runtime Errors
130    // =========================================================================
131    #[snafu(display("Execution failed: {source}"))]
132    Execution { source: svod_runtime::Error },
133
134    #[snafu(display("Failed to create program: {source}"))]
135    CreateProgram { source: svod_device::Error },
136
137    #[snafu(display("Failed to get device: {source}"))]
138    DeviceFactory { source: svod_runtime::Error },
139
140    #[snafu(display("Buffer for UOp {} not found in registry", uop_id))]
141    BufferNotFound { uop_id: u64 },
142
143    #[snafu(display("Device error: {source}"))]
144    Device { source: svod_device::Error },
145
146    // =========================================================================
147    // Type Errors
148    // =========================================================================
149    #[snafu(display("Expected Ptr dtype for {context}, got {actual:?}"))]
150    ExpectedPtrDtype { context: &'static str, actual: svod_dtype::DType },
151
152    #[snafu(display("Buffer Ptr dtype has no size"))]
153    BufferPtrNoSize,
154
155    #[snafu(display("Tensor has no buffer (unrealized tensor?)"))]
156    NoBuffer,
157
158    #[snafu(display("Tensor has no shape"))]
159    NoShape,
160
161    #[snafu(display("Shape mismatch for '{context}': expected {expected}, got {actual}"))]
162    ShapeMismatch { context: String, expected: String, actual: String },
163
164    #[snafu(display("IR construction error: {details}"))]
165    IrConstruction { details: String },
166
167    #[snafu(display("Type mismatch: expected {expected:?}, got {actual:?}"))]
168    TypeMismatch { expected: svod_dtype::DType, actual: svod_dtype::DType },
169
170    #[snafu(display("{op} requires floating-point dtype for {arg}, got {dtype:?}"))]
171    FloatDTypeRequired { op: &'static str, arg: &'static str, dtype: svod_dtype::DType },
172
173    #[snafu(display("Failed to create ndarray: {source}"))]
174    NdarrayShape { source: ndarray::ShapeError },
175
176    // =========================================================================
177    // Variable Errors
178    // =========================================================================
179    #[snafu(display("Variable '{name}' value {val} out of range [{min}, {max}]"))]
180    VariableOutOfRange { name: String, val: i64, min: i64, max: i64 },
181
182    #[snafu(display("Cannot read data from tensor with symbolic shape — reduce or slice to concrete shape first"))]
183    SymbolicShape,
184}
185
186pub type Result<T> = std::result::Result<T, Error>;