helena 0.1.0

Core types and component interfaces for helena, a latent data-to-waveform generation platform.
Documentation
use super::*;

#[test]
fn new_rejects_bad_statistics() {
    // Unequal mean/std lengths: a validation failure (the two vectors are not a
    // shape mismatch of one tensor — they are two malformed inputs).
    assert!(matches!(
        LatentNorm::new(vec![0.0, 0.0], vec![1.0], LatentNorm::DEFAULT_EPS),
        Err(Error::Validation(_))
    ));
    assert!(matches!(
        LatentNorm::new(
            Vec::<f32>::new(),
            Vec::<f32>::new(),
            LatentNorm::DEFAULT_EPS
        ),
        Err(Error::Validation(_))
    ));
    // A non-positive std is not rejected — it floors at eps; a *non-finite* one
    // is rejected, as is a non-finite mean.
    assert_eq!(
        LatentNorm::new(vec![0.0], vec![0.0], LatentNorm::DEFAULT_EPS)
            .unwrap()
            .std()[0],
        LatentNorm::DEFAULT_EPS
    );
    assert!(matches!(
        LatentNorm::new(vec![f32::NAN], vec![1.0], LatentNorm::DEFAULT_EPS),
        Err(Error::Validation(_))
    ));
    assert!(matches!(
        LatentNorm::new(vec![0.0], vec![f32::NAN], LatentNorm::DEFAULT_EPS),
        Err(Error::Validation(_))
    ));
}

#[test]
fn new_and_fit_reject_bad_eps() {
    // eps moved from `finish` into the construction path (`new` / `fit`);
    // the rejection follows it.
    let latent = seq(2, 1, vec![0.0, 1.0]);
    for bad in [0.0, -1.0, f32::NAN, f32::INFINITY] {
        assert!(matches!(
            LatentNorm::new(vec![0.0], vec![1.0], bad),
            Err(Error::Validation(_))
        ));
        assert!(matches!(
            LatentNorm::fit([&latent], bad),
            Err(Error::Validation(_))
        ));
    }
}

#[test]
fn fit_rejects_empty_set() {
    // The token, non-finite, and zero-width cases the old test also covered are
    // gone: a `FrameSeq` is continuous, finite, and `dim ≥ 1` by construction,
    // so none of those latents can be built to hand to `fit` in the first place.
    let none: [&FrameSeq; 0] = [];
    assert!(matches!(
        LatentNorm::fit(none, LatentNorm::DEFAULT_EPS),
        Err(Error::Validation(_))
    ));
    // A sequence with zero frames contributes nothing: still rejected.
    let empty = seq(0, 2, vec![]);
    assert!(matches!(
        LatentNorm::fit([&empty], LatentNorm::DEFAULT_EPS),
        Err(Error::Validation(_))
    ));
}

#[test]
fn fit_rejects_bad_eps_before_consuming_latents() {
    // An iterator that panics the moment it is polled: a bad eps must be
    // rejected before any (possibly expensive or side-effectful) latent is read.
    struct PanicOnPoll;
    impl Iterator for PanicOnPoll {
        type Item = &'static FrameSeq;
        fn next(&mut self) -> Option<Self::Item> {
            panic!("fit polled the latent iterator despite an invalid eps");
        }
    }
    for bad in [0.0, -1.0, f32::NAN, f32::INFINITY] {
        assert!(matches!(
            LatentNorm::fit(PanicOnPoll, bad),
            Err(Error::Validation(_))
        ));
    }
}

#[test]
fn fit_rejects_dim_mismatch() {
    let a = seq(1, 2, vec![0.0, 0.0]);
    let b = seq(1, 3, vec![0.0, 0.0, 0.0]);
    assert!(matches!(
        LatentNorm::fit([&a, &b], LatentNorm::DEFAULT_EPS),
        Err(Error::Shape { expected, actual }) if expected == vec![1, 2] && actual == vec![1, 3]
    ));
}

#[test]
fn apply_rejects_mismatched_dim() {
    // The old token and zero-width apply-rejection cases are unrepresentable:
    // `standardize`/`unstandardize` take a `FrameSeq`, which is never a token
    // grid and never zero-width. Only a width disagreement remains, and it is
    // an `Error::Shape` carrying the two `[frames, dim]` shapes.
    let norm = LatentNorm::new(vec![0.0, 0.0], vec![1.0, 1.0], LatentNorm::DEFAULT_EPS).unwrap();
    let wrong_dim = seq(1, 3, vec![0.0, 0.0, 0.0]);
    assert!(matches!(
        norm.standardize(&wrong_dim),
        Err(Error::Shape { expected, actual }) if expected == vec![1, 2] && actual == vec![1, 3]
    ));
    assert!(matches!(
        norm.unstandardize(&wrong_dim),
        Err(Error::Shape { expected, actual }) if expected == vec![1, 2] && actual == vec![1, 3]
    ));
}