Skip to main content

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 {}