helena 0.1.0

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

#[test]
fn response_curve_of_monotone_sweep_is_straight() {
    let sweep = scalar_sweep(&[0.0, 1.0, 2.0, 3.0]);
    let r = ResponseCurve::measure(&sweep).unwrap();
    assert!((r.net_response() - 3.0).abs() < 1e-6);
    assert!((r.monotonicity() - 1.0).abs() < 1e-6);
    assert_eq!(r.step_count(), 4);
}

#[test]
fn response_curve_penalizes_backtracking() {
    let sweep = scalar_sweep(&[0.0, 2.0, 1.0]);
    let r = ResponseCurve::measure(&sweep).unwrap();
    assert!((r.net_response() - 1.0).abs() < 1e-6);
    assert!((r.monotonicity() - 1.0 / 3.0).abs() < 1e-6);
}

#[test]
fn response_curve_of_flat_sweep_is_unresponsive() {
    let sweep = scalar_sweep(&[2.0, 2.0, 2.0]);
    let r = ResponseCurve::measure(&sweep).unwrap();
    assert_eq!(r.net_response(), 0.0);
    assert_eq!(r.monotonicity(), 0.0);
}

#[test]
fn response_curve_averages_seeds_per_step() {
    let sweep = vec![
        vec![latent([1, 1], vec![-0.5]), latent([1, 1], vec![0.5])],
        vec![latent([1, 1], vec![0.5]), latent([1, 1], vec![1.5])],
        vec![latent([1, 1], vec![1.5]), latent([1, 1], vec![2.5])],
    ];
    let r = ResponseCurve::measure(&sweep).unwrap();
    assert!((r.net_response() - 2.0).abs() < 1e-6);
    assert!((r.monotonicity() - 1.0).abs() < 1e-6);
}

#[test]
fn response_curve_is_straight_in_multiple_dimensions() {
    let sweep = vec![
        vec![latent([2, 1], vec![0.0, 0.0])],
        vec![latent([2, 1], vec![1.0, 1.0])],
        vec![latent([2, 1], vec![2.0, 2.0])],
    ];
    let r = ResponseCurve::measure(&sweep).unwrap();
    assert!((r.net_response() - (8.0f32).sqrt()).abs() < 1e-6);
    assert!((r.monotonicity() - 1.0).abs() < 1e-6);
}

#[test]
fn response_curve_rejects_too_few_steps() {
    assert!(matches!(
        ResponseCurve::measure(&scalar_sweep(&[1.0])),
        Err(Error::Validation(_))
    ));
    assert!(matches!(
        ResponseCurve::measure(&[]),
        Err(Error::Validation(_))
    ));
}

#[test]
fn response_curve_rejects_empty_step_and_shape_mismatch() {
    let with_empty = vec![vec![latent([1, 1], vec![0.0])], vec![]];
    assert!(matches!(
        ResponseCurve::measure(&with_empty),
        Err(Error::Validation(_))
    ));
    let mismatch = vec![
        vec![latent([1, 2], vec![0.0, 1.0])],
        vec![latent([2, 1], vec![0.0, 1.0])],
    ];
    assert!(matches!(
        ResponseCurve::measure(&mismatch),
        Err(Error::Validation(_))
    ));
}

// `response_curve_rejects_tokens` is gone: a sweep of `Latent<Continuous>` cannot
// contain a token latent, so the rejection is unrepresentable.

#[test]
fn sweep_response_reports_controllable_signature() {
    let generator = MockGenerator {
        cond_weight: 2.0,
        seed_weight: 1.0,
    };
    let r = sweep_response(
        &generator,
        &[cond(0.0), cond(1.0), cond(2.0), cond(3.0)],
        &[Seed(1), Seed(2)],
        &params(),
    )
    .unwrap();
    assert!((r.net_response() - 6.0).abs() < 1e-4);
    assert!((r.monotonicity() - 1.0).abs() < 1e-4);
    assert_eq!(r.step_count(), 4);
}

#[test]
fn sweep_response_flags_condition_blind_generator() {
    let generator = MockGenerator {
        cond_weight: 0.0,
        seed_weight: 1.0,
    };
    let r = sweep_response(
        &generator,
        &[cond(0.0), cond(5.0), cond(9.0)],
        &[Seed(3), Seed(4)],
        &params(),
    )
    .unwrap();
    assert_eq!(r.net_response(), 0.0);
    assert_eq!(r.monotonicity(), 0.0);
}

#[test]
fn sweep_response_propagates_and_validates() {
    let ok = MockGenerator {
        cond_weight: 1.0,
        seed_weight: 0.0,
    };
    assert!(matches!(
        sweep_response(&ok, &[cond(0.0)], &[Seed(1)], &params()),
        Err(Error::Validation(_))
    ));
    assert!(matches!(
        sweep_response(&ok, &[cond(0.0), cond(1.0)], &[], &params()),
        Err(Error::Validation(_))
    ));
    assert!(matches!(
        sweep_response(
            &FailingGenerator,
            &[cond(0.0), cond(1.0)],
            &[Seed(1)],
            &params()
        ),
        Err(Error::Validation(_))
    ));
}