Skip to main content

sva_samples/
error.rs

1// Concern: declares the refusals the sampled half reaches, each with its code | Non-concern: the closed-form crate's own codes (sva-formula), rendering a diagnostic (sva-engine) | IO: none
2
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub enum SampleError {
5    HopOutsideCola {
6        window: usize,
7        hop: usize,
8    },
9    WindowNotPowerOfTwo {
10        window: usize,
11    },
12    WidthMismatch {
13        left: usize,
14        right: usize,
15    },
16    ChannelOutOfRange {
17        k: usize,
18        width: usize,
19    },
20    /// A grid sized from the rate and the fundamental, past what one call may allocate.
21    GridTooLarge {
22        model: &'static str,
23        nodes: usize,
24        ceiling: usize,
25    },
26    /// A string no stable grid at this rate rings at the partials it was asked for.
27    StringPastRate {
28        model: &'static str,
29    },
30    /// A unison whose bridge row leaves its scheme's mass form not provably positive.
31    BridgeUnstable {
32        model: &'static str,
33    },
34    /// A contact whose force solve settled on no value at a sample.
35    ContactUnsettled {
36        model: &'static str,
37        sample: usize,
38    },
39    /// A reading needs a sample this run has not computed yet.
40    ReadsAhead {
41        at: i64,
42    },
43    /// An exactly computed time passed what its integers hold.
44    UnreadablePosition,
45    /// A closed form read at one of the machine's instants has no value there.
46    FormulaUnevaluable {
47        at: i64,
48    },
49    /// A varying parameter outside the range its model holds, at one sample.
50    ArgumentOutOfRange {
51        model: &'static str,
52        name: &'static str,
53        /// The value's bits, which keep the error `Eq`.
54        bits: u64,
55        sample: u64,
56    },
57}
58
59/// What a collapse refuses, per FORMAT 16.3.
60#[derive(Clone, Debug, PartialEq)]
61pub enum CollapseError {
62    /// `by_rate` where the ceiling is the rate's own half, under the profile's.
63    EmptyBand {
64        ceiling: f64,
65        lowest: f64,
66        by_rate: bool,
67    },
68    SingularInCt {
69        at: f64,
70        order: i32,
71    },
72    NotEvaluable(&'static str),
73    /// `terms` is `None` where the count is past what a `usize` holds.
74    NestedSeries {
75        depth: usize,
76        terms: Option<usize>,
77        bound: usize,
78    },
79    LeftAlgebra(&'static str),
80    /// A form in `f` reaches the grid by one transform over a whole extent.
81    NoBlockRow,
82}
83
84impl CollapseError {
85    pub fn code(&self) -> &'static str {
86        match self {
87            CollapseError::EmptyBand { .. } => "collapse.empty_band",
88            CollapseError::SingularInCt { .. } => "collapse.singular_in_ct",
89            CollapseError::NotEvaluable(_) => "collapse.not_evaluable",
90            CollapseError::NestedSeries { .. } => "collapse.series_nesting",
91            CollapseError::LeftAlgebra(_) => "cast.left_algebra",
92            CollapseError::NoBlockRow => "collapse.no_block_row",
93        }
94    }
95}
96
97/// One repair per refusal: no extent brings a line back under a ceiling.
98impl CollapseError {
99    pub fn help(&self) -> &'static str {
100        match self {
101            CollapseError::EmptyBand { by_rate: true, .. } => {
102                "this rate's own half is the ceiling: raise --rate past twice the \
103                 lowest line"
104            }
105            CollapseError::EmptyBand { .. } => {
106                "the profile's ceiling is what no rate raises; read it with \
107                 `--representation lines`, or bring the line into the band"
108            }
109            CollapseError::SingularInCt { .. } => {
110                "write it inside a convolution, or sample the closed form it multiplies"
111            }
112            CollapseError::NestedSeries { .. } => {
113                "write fewer levels, or a narrower band for the terms to clear"
114            }
115            CollapseError::NotEvaluable(_) | CollapseError::LeftAlgebra(_) => {
116                "write the subterm inside sample(...) to leave A deliberately"
117            }
118            CollapseError::NoBlockRow => {
119                "render it to a stated end instead of streaming it, or write it in t"
120            }
121        }
122    }
123}
124
125impl std::fmt::Display for CollapseError {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        match self {
128            CollapseError::EmptyBand {
129                ceiling, lowest, ..
130            } => write!(
131                f,
132                "every line is at or above the {ceiling} Hz ceiling, the lowest at {lowest} Hz"
133            ),
134            CollapseError::SingularInCt { at, order } => write!(
135                f,
136                "a singularity of order {order} at t = {at} has no value on the grid"
137            ),
138            CollapseError::NotEvaluable(what) => {
139                write!(f, "{what} has no value at a point")
140            }
141            CollapseError::NestedSeries {
142                depth,
143                terms,
144                bound,
145            } => match terms {
146                Some(terms) => write!(
147                    f,
148                    "a series nested {depth} deep takes {terms} terms at one instant, past \
149                     the {bound} one expansion holds"
150                ),
151                None => write!(
152                    f,
153                    "a series nested {depth} deep takes more terms at one instant than a \
154                     count holds, past the {bound} one expansion holds"
155                ),
156            },
157            CollapseError::LeftAlgebra(clause) => write!(f, "the closed form left A. {clause}"),
158            CollapseError::NoBlockRow => write!(
159                f,
160                "a closed form in f reaches the grid by one transform over a whole extent, \
161                 so no block of it is read alone"
162            ),
163        }
164    }
165}
166
167impl SampleError {
168    pub fn code(&self) -> &'static str {
169        match self {
170            SampleError::HopOutsideCola { .. } => "samples.hop_outside_cola",
171            SampleError::WindowNotPowerOfTwo { .. } => "samples.window_not_power_of_two",
172            SampleError::WidthMismatch { .. } => "type.width_mismatch",
173            SampleError::ChannelOutOfRange { .. } => "samples.channel_out_of_range",
174            SampleError::GridTooLarge { .. } => "samples.grid_too_large",
175            SampleError::StringPastRate { .. } => "samples.string_past_rate",
176            SampleError::BridgeUnstable { .. } => "samples.bridge_unstable",
177            SampleError::ContactUnsettled { .. } => "samples.contact_unsettled",
178            SampleError::ArgumentOutOfRange { .. } => "samples.argument_out_of_range",
179            SampleError::ReadsAhead { .. } => "engine.reads_ahead",
180            SampleError::UnreadablePosition => "engine.unreadable_position",
181            SampleError::FormulaUnevaluable { .. } => "collapse.not_evaluable",
182        }
183    }
184}
185
186impl std::fmt::Display for SampleError {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188        match self {
189            SampleError::HopOutsideCola { window, hop } => write!(
190                f,
191                "a window of {window} at a hop of {hop} does not overlap-add to a constant. \
192                 write a hop that divides the window"
193            ),
194            SampleError::WindowNotPowerOfTwo { window } => {
195                write!(f, "a window of {window} is not a power of two")
196            }
197            SampleError::WidthMismatch { left, right } => write!(
198                f,
199                "{left} components meet {right}; an elementwise operation needs equal widths, \
200                 or one side mono"
201            ),
202            SampleError::ChannelOutOfRange { k, width } => {
203                write!(f, "component {k} of a value {width} wide")
204            }
205            SampleError::GridTooLarge {
206                model,
207                nodes,
208                ceiling,
209            } => write!(
210                f,
211                "`{model}` sizes a {nodes}-node grid at this rate, past the {ceiling} one \
212                 call may hold. ask for a higher fundamental, or a lower --rate"
213            ),
214            SampleError::StringPastRate { model } => write!(
215                f,
216                "`{model}` has no stable grid at this rate whose first two partials ring where \
217                 asked. ask for a lower fundamental or `b`, or a higher --rate"
218            ),
219            SampleError::BridgeUnstable { model } => write!(
220                f,
221                "`{model}`'s unison is not proven stable on its bridge at this rate: the mass \
222                 form its bridge row leaves is not provably positive. ask for a heavier bridge, \
223                 less frequency-dependent loss, or a higher --rate"
224            ),
225            SampleError::ContactUnsettled { model, sample } => write!(
226                f,
227                "`{model}`'s contact force settled on no value at sample {sample}. ask for a \
228                 lower bow velocity or force, or a higher --rate"
229            ),
230            SampleError::ReadsAhead { at } => write!(
231                f,
232                "a reading needs sample {at} of its source, which is not computed yet: a \
233                 stream reads no output ahead of where it stands"
234            ),
235            SampleError::UnreadablePosition => {
236                write!(f, "an exactly computed time passed what its integers hold")
237            }
238            SampleError::FormulaUnevaluable { at } => write!(
239                f,
240                "a closed form read at sample {at}'s instant has no value there"
241            ),
242            SampleError::ArgumentOutOfRange {
243                model,
244                name,
245                bits,
246                sample,
247            } => write!(
248                f,
249                "`{model}`'s `{name}` is {} at sample {sample}, outside the range it models",
250                f64::from_bits(*bits)
251            ),
252        }
253    }
254}