sva-samples 0.7.15

Buffers, frames, the f64 machine, the collapse of a law onto a grid, and the measured observations over one
Documentation
// 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

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SampleError {
    HopOutsideCola {
        window: usize,
        hop: usize,
    },
    WindowNotPowerOfTwo {
        window: usize,
    },
    WidthMismatch {
        left: usize,
        right: usize,
    },
    ChannelOutOfRange {
        k: usize,
        width: usize,
    },
    /// A grid sized from the rate and the fundamental, past what one call may allocate.
    GridTooLarge {
        model: &'static str,
        nodes: usize,
        ceiling: usize,
    },
    /// A string no stable grid at this rate rings at the partials it was asked for.
    StringPastRate {
        model: &'static str,
    },
    /// A unison whose bridge row leaves its scheme's mass form not provably positive.
    BridgeUnstable {
        model: &'static str,
    },
    /// A contact whose force solve settled on no value at a sample.
    ContactUnsettled {
        model: &'static str,
        sample: usize,
    },
    /// A reading needs a sample this run has not computed yet.
    ReadsAhead {
        at: i64,
    },
    /// An exactly computed time passed what its integers hold.
    UnreadablePosition,
    /// A closed form read at one of the machine's instants has no value there.
    FormulaUnevaluable {
        at: i64,
    },
    /// A varying parameter outside the range its model holds, at one sample.
    ArgumentOutOfRange {
        model: &'static str,
        name: &'static str,
        /// The value's bits, which keep the error `Eq`.
        bits: u64,
        sample: u64,
    },
}

/// What a collapse refuses, per FORMAT 16.3.
#[derive(Clone, Debug, PartialEq)]
pub enum CollapseError {
    EmptyBand {
        ceiling: f64,
        lowest: f64,
    },
    SingularInCt {
        at: f64,
        order: i32,
    },
    NotEvaluable(&'static str),
    /// `terms` is `None` where the count is past what a `usize` holds.
    NestedSeries {
        depth: usize,
        terms: Option<usize>,
        bound: usize,
    },
    LeftAlgebra(&'static str),
    /// A form in `f` reaches the grid by one transform over a whole extent.
    NoBlockRow,
}

impl CollapseError {
    pub fn code(&self) -> &'static str {
        match self {
            CollapseError::EmptyBand { .. } => "collapse.empty_band",
            CollapseError::SingularInCt { .. } => "collapse.singular_in_ct",
            CollapseError::NotEvaluable(_) => "collapse.not_evaluable",
            CollapseError::NestedSeries { .. } => "collapse.series_nesting",
            CollapseError::LeftAlgebra(_) => "cast.left_algebra",
            CollapseError::NoBlockRow => "collapse.no_block_row",
        }
    }
}

/// One repair per refusal: no extent brings a line back under a ceiling.
impl CollapseError {
    pub fn help(&self) -> &'static str {
        match self {
            CollapseError::EmptyBand { ceiling, .. }
                if *ceiling < sva_formula::AUDIBLE_CEILING_HZ =>
            {
                "this rate's own half is the ceiling: raise --rate past twice the \
                 lowest line"
            }
            CollapseError::EmptyBand { .. } => {
                "the profile's 20 kHz ceiling is what no rate raises; read it with \
                 `--representation lines`, or bring the line into the band"
            }
            CollapseError::SingularInCt { .. } => {
                "write it inside a convolution, or sample the closed form it multiplies"
            }
            CollapseError::NestedSeries { .. } => {
                "write fewer levels, or a narrower band for the terms to clear"
            }
            CollapseError::NotEvaluable(_) | CollapseError::LeftAlgebra(_) => {
                "write the subterm inside sample(...) to leave A deliberately"
            }
            CollapseError::NoBlockRow => {
                "render it to a stated end instead of streaming it, or write it in t"
            }
        }
    }
}

impl std::fmt::Display for CollapseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            CollapseError::EmptyBand { ceiling, lowest } => write!(
                f,
                "every line is at or above the {ceiling} Hz ceiling, the lowest at {lowest} Hz"
            ),
            CollapseError::SingularInCt { at, order } => write!(
                f,
                "a singularity of order {order} at t = {at} has no value on the grid"
            ),
            CollapseError::NotEvaluable(what) => {
                write!(f, "{what} has no value at a point")
            }
            CollapseError::NestedSeries {
                depth,
                terms,
                bound,
            } => match terms {
                Some(terms) => write!(
                    f,
                    "a series nested {depth} deep takes {terms} terms at one instant, past \
                     the {bound} one expansion holds"
                ),
                None => write!(
                    f,
                    "a series nested {depth} deep takes more terms at one instant than a \
                     count holds, past the {bound} one expansion holds"
                ),
            },
            CollapseError::LeftAlgebra(clause) => write!(f, "the closed form left A. {clause}"),
            CollapseError::NoBlockRow => write!(
                f,
                "a closed form in f reaches the grid by one transform over a whole extent, \
                 so no block of it is read alone"
            ),
        }
    }
}

impl SampleError {
    pub fn code(&self) -> &'static str {
        match self {
            SampleError::HopOutsideCola { .. } => "samples.hop_outside_cola",
            SampleError::WindowNotPowerOfTwo { .. } => "samples.window_not_power_of_two",
            SampleError::WidthMismatch { .. } => "type.width_mismatch",
            SampleError::ChannelOutOfRange { .. } => "samples.channel_out_of_range",
            SampleError::GridTooLarge { .. } => "samples.grid_too_large",
            SampleError::StringPastRate { .. } => "samples.string_past_rate",
            SampleError::BridgeUnstable { .. } => "samples.bridge_unstable",
            SampleError::ContactUnsettled { .. } => "samples.contact_unsettled",
            SampleError::ArgumentOutOfRange { .. } => "samples.argument_out_of_range",
            SampleError::ReadsAhead { .. } => "engine.reads_ahead",
            SampleError::UnreadablePosition => "engine.unreadable_position",
            SampleError::FormulaUnevaluable { .. } => "collapse.not_evaluable",
        }
    }
}

impl std::fmt::Display for SampleError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SampleError::HopOutsideCola { window, hop } => write!(
                f,
                "a window of {window} at a hop of {hop} does not overlap-add to a constant. \
                 write a hop that divides the window"
            ),
            SampleError::WindowNotPowerOfTwo { window } => {
                write!(f, "a window of {window} is not a power of two")
            }
            SampleError::WidthMismatch { left, right } => write!(
                f,
                "{left} components meet {right}; an elementwise operation needs equal widths, \
                 or one side mono"
            ),
            SampleError::ChannelOutOfRange { k, width } => {
                write!(f, "component {k} of a value {width} wide")
            }
            SampleError::GridTooLarge {
                model,
                nodes,
                ceiling,
            } => write!(
                f,
                "`{model}` sizes a {nodes}-node grid at this rate, past the {ceiling} one \
                 call may hold. ask for a higher fundamental, or a lower --rate"
            ),
            SampleError::StringPastRate { model } => write!(
                f,
                "`{model}` has no stable grid at this rate whose first two partials ring where \
                 asked. ask for a lower fundamental or `b`, or a higher --rate"
            ),
            SampleError::BridgeUnstable { model } => write!(
                f,
                "`{model}`'s unison is not proven stable on its bridge at this rate: the mass \
                 form its bridge row leaves is not provably positive. ask for a heavier bridge, \
                 less frequency-dependent loss, or a higher --rate"
            ),
            SampleError::ContactUnsettled { model, sample } => write!(
                f,
                "`{model}`'s contact force settled on no value at sample {sample}. ask for a \
                 lower bow velocity or force, or a higher --rate"
            ),
            SampleError::ReadsAhead { at } => write!(
                f,
                "a reading needs sample {at} of its source, which is not computed yet: a \
                 stream reads no output ahead of where it stands"
            ),
            SampleError::UnreadablePosition => {
                write!(f, "an exactly computed time passed what its integers hold")
            }
            SampleError::FormulaUnevaluable { at } => write!(
                f,
                "a closed form read at sample {at}'s instant has no value there"
            ),
            SampleError::ArgumentOutOfRange {
                model,
                name,
                bits,
                sample,
            } => write!(
                f,
                "`{model}`'s `{name}` is {} at sample {sample}, outside the range it models",
                f64::from_bits(*bits)
            ),
        }
    }
}