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