sim_lib_numbers_signal/error.rs
1//! Errors shared by transform planning and execution.
2
3use std::{error::Error, fmt};
4
5/// Error returned when a transform plan or signal buffer is invalid.
6#[derive(Clone, Debug, PartialEq)]
7pub enum SignalError {
8 /// A transform length was zero or too short for its definition.
9 InvalidLength {
10 /// Requested logical transform length.
11 len: usize,
12 /// Definition-level requirement that was not met.
13 reason: &'static str,
14 },
15 /// A policy combination is contradictory or unsupported.
16 InvalidPolicy {
17 /// Name of the policy that was rejected.
18 policy: &'static str,
19 /// Reason the policy cannot be used.
20 reason: &'static str,
21 },
22 /// A stride step of zero was requested.
23 ZeroStride,
24 /// Offset/stride arithmetic overflowed `usize`.
25 StrideOverflow,
26 /// The selected logical input length disagrees with the plan.
27 LengthMismatch {
28 /// Length required by the plan.
29 expected: usize,
30 /// Length available through the selected view.
31 actual: usize,
32 },
33 /// A tensor shape or physical layout is not a valid non-overlapping view.
34 InvalidTensorView {
35 /// View invariant that was not satisfied.
36 reason: &'static str,
37 },
38 /// A requested transform axis does not exist in the tensor rank.
39 AxisOutOfBounds {
40 /// Requested axis.
41 axis: usize,
42 /// Number of tensor dimensions.
43 rank: usize,
44 },
45 /// A transform axis appeared more than once.
46 DuplicateAxis {
47 /// Repeated axis.
48 axis: usize,
49 },
50 /// A bounded transform plan would exceed the caller's scratch limit.
51 ScratchLimit {
52 /// Peak scratch bytes required by the selected plan.
53 required: usize,
54 /// Caller-declared scratch-byte ceiling.
55 maximum: usize,
56 },
57 /// A spectral estimator would exceed its declared deterministic work limit.
58 WorkLimit {
59 /// Conservative work units required by the selected plan.
60 required: u64,
61 /// Caller-declared work-unit ceiling.
62 maximum: u64,
63 },
64 /// Burg recursion encountered a zero-energy or numerically singular stage.
65 SingularModel {
66 /// One-based autoregressive order at which the recursion became singular.
67 order: usize,
68 },
69 /// An autoregressive reflection coefficient crossed the declared stability margin.
70 UnstableModel {
71 /// One-based autoregressive order at which stability was lost.
72 order: usize,
73 },
74 /// A numerical system had no pivot above its declared singularity threshold.
75 SingularSystem {
76 /// Operation whose system was rejected.
77 operation: &'static str,
78 /// Zero-based elimination step.
79 step: usize,
80 /// Largest candidate pivot magnitude at the rejected step.
81 pivot_magnitude: f64,
82 /// Absolute pivot threshold required by the numerical policy.
83 threshold: f64,
84 },
85 /// A sampled-data input repeated an abscissa under reject policy.
86 DuplicateCoordinate {
87 /// Index of the repeated coordinate in the supplied input.
88 index: usize,
89 /// Repeated abscissa.
90 value: f64,
91 },
92 /// A query lies outside a finite sampled-data domain under reject policy.
93 OutOfDomain {
94 /// Query index.
95 index: usize,
96 /// Rejected coordinate.
97 value: f64,
98 /// Smallest admitted coordinate.
99 minimum: f64,
100 /// Largest admitted coordinate.
101 maximum: f64,
102 },
103 /// Recursive prediction exceeded its declared finite-amplitude bound.
104 PredictionLimit {
105 /// Zero-based predicted sample that first crossed the bound.
106 index: usize,
107 },
108 /// A Table/Dir block-store operation failed or returned invalid data.
109 BlockStore {
110 /// Operation being performed.
111 operation: &'static str,
112 /// Backend or encoding diagnostic.
113 message: String,
114 },
115 /// A transform received real data where complex data was required, or the
116 /// reverse.
117 InputKind {
118 /// Input representation required by the plan.
119 expected: &'static str,
120 /// Input representation supplied by the caller.
121 actual: &'static str,
122 },
123 /// A signal contains a NaN or infinity.
124 NonFinite {
125 /// Logical signal position containing the invalid component.
126 index: usize,
127 /// Component name (`real`, `imag`, or `value`).
128 component: &'static str,
129 },
130 /// A requested normalization has a zero or non-finite divisor.
131 DegenerateNormalization {
132 /// Name of the normalization whose divisor was unusable.
133 normalization: &'static str,
134 },
135}
136
137impl fmt::Display for SignalError {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match self {
140 Self::InvalidLength { len, reason } => {
141 write!(f, "invalid transform length {len}: {reason}")
142 }
143 Self::InvalidPolicy { policy, reason } => {
144 write!(f, "invalid {policy} policy: {reason}")
145 }
146 Self::ZeroStride => write!(f, "signal stride must be nonzero"),
147 Self::StrideOverflow => write!(f, "signal offset/stride arithmetic overflowed"),
148 Self::LengthMismatch { expected, actual } => {
149 write!(
150 f,
151 "signal length mismatch: expected {expected}, got {actual}"
152 )
153 }
154 Self::InvalidTensorView { reason } => write!(f, "invalid tensor view: {reason}"),
155 Self::AxisOutOfBounds { axis, rank } => {
156 write!(f, "transform axis {axis} is outside tensor rank {rank}")
157 }
158 Self::DuplicateAxis { axis } => {
159 write!(f, "transform axis {axis} was declared more than once")
160 }
161 Self::ScratchLimit { required, maximum } => {
162 write!(
163 f,
164 "transform needs {required} scratch bytes, exceeding limit {maximum}"
165 )
166 }
167 Self::WorkLimit { required, maximum } => {
168 write!(
169 f,
170 "spectral estimator needs {required} work units, exceeding limit {maximum}"
171 )
172 }
173 Self::SingularModel { order } => {
174 write!(f, "autoregressive model is singular at order {order}")
175 }
176 Self::UnstableModel { order } => {
177 write!(f, "autoregressive model is unstable at order {order}")
178 }
179 Self::SingularSystem {
180 operation,
181 step,
182 pivot_magnitude,
183 threshold,
184 } => write!(
185 f,
186 "{operation} system is singular at step {step}: pivot {pivot_magnitude} <= {threshold}"
187 ),
188 Self::DuplicateCoordinate { index, value } => {
189 write!(f, "sample coordinate {index} repeats x={value}")
190 }
191 Self::OutOfDomain {
192 index,
193 value,
194 minimum,
195 maximum,
196 } => write!(
197 f,
198 "query coordinate {index} ({value}) is outside [{minimum}, {maximum}]"
199 ),
200 Self::PredictionLimit { index } => {
201 write!(
202 f,
203 "autoregressive prediction crossed its bound at sample {index}"
204 )
205 }
206 Self::BlockStore { operation, message } => {
207 write!(f, "block store {operation} failed: {message}")
208 }
209 Self::InputKind { expected, actual } => {
210 write!(f, "transform expects {expected} input, got {actual}")
211 }
212 Self::NonFinite { index, component } => {
213 write!(
214 f,
215 "signal {component} component at index {index} is not finite"
216 )
217 }
218 Self::DegenerateNormalization { normalization } => {
219 write!(f, "{normalization} normalization has a degenerate divisor")
220 }
221 }
222 }
223}
224
225impl Error for SignalError {}