native_neural_network_std 0.2.1

Ergonomic std wrapper for the `native_neural_network` crate (no_std) — std-friendly re-exports and utilities.
Documentation
use native_neural_network_std::std::activations_std::ActivationKind;
use native_neural_network_std::std::engine_std::{
    get_compute_backend, set_compute_backend, ComputeBackend,
};
use native_neural_network_std::std::layers_std::{DenseLayerDesc, LayerSpec};

#[test]
fn cpu_backend_abstraction_real() {
    let previous = get_compute_backend();
    set_compute_backend(ComputeBackend::Cpu);
    assert_eq!(get_compute_backend(), ComputeBackend::Cpu);
    set_compute_backend(previous);
}

#[test]
fn rnn_api_basic_topology_and_pack_run() {
    use native_neural_network_std::std::rnn_std as rstd;

    let topology = &[2usize, 1usize];
    let decoded = rstd::rnn_required_from_topology(topology).expect("required counts");
    assert_eq!(decoded.layers, 1);
    let weights = vec![1.0f32, 1.0f32];
    let biases = vec![0.5f32];
    let mut layer_scratch = vec![
        LayerSpec::Dense(DenseLayerDesc {
            input_size: 0,
            output_size: 0,
            weight_offset: 0,
            bias_offset: 0,
            activation: ActivationKind::Identity
        });
        1
    ];

    let mut out_bytes = vec![0u8; 8192];

    let written = rstd::rnn_pack_v1(
        topology,
        ActivationKind::Identity,
        ActivationKind::Identity,
        &weights,
        &biases,
        &mut layer_scratch,
        &mut out_bytes,
    )
    .expect("pack");

    assert!(written > 0);

    let input = [2.0f32, 3.0f32];
    let mut output = [0f32; 1];
    let infer_scratch_len =
        rstd::rnn_required_infer_scratch_from_specs_std(&layer_scratch).unwrap_or(0);
    let mut weights_scratch = vec![0f32; decoded.weights];
    let mut biases_scratch = vec![0f32; decoded.biases];
    let mut infer_scratch = vec![0f32; infer_scratch_len];

    let res = rstd::rnn_run_v1(
        &out_bytes[..written],
        &input,
        &mut output,
        &mut layer_scratch,
        &mut weights_scratch,
        &mut biases_scratch,
        &mut infer_scratch,
    );
    assert!(res.is_ok());
    assert!((output[0] - (2.0 + 3.0 + 0.5)).abs() < 1e-5);
}

#[test]
fn rnn_validate_topology_and_buffers() {
    use native_neural_network_std::std::rnn_std as rstd;
    let good = vec![2usize, 1usize];
    assert!(rstd::rnn_validate_topology(&good).is_ok());

    let bad = vec![1usize];
    assert!(rstd::rnn_validate_topology(&bad).is_err());

    let cap = rstd::rnn_required_buffers(&good).expect("capacity");
    assert_eq!(cap.layer_specs, 1);
    assert_eq!(cap.weights, 2);
    assert_eq!(cap.biases, 1);
}

#[test]
fn rnn_pack_and_required_counts_roundtrip() {
    use native_neural_network_std::std::rnn_std as rstd;

    let topology = &[2usize, 1usize];
    let weights = vec![1.0f32, 1.0f32];
    let biases = vec![0.5f32];

    let mut layer_scratch = vec![
        LayerSpec::Dense(DenseLayerDesc {
            input_size: 0,
            output_size: 0,
            weight_offset: 0,
            bias_offset: 0,
            activation: ActivationKind::Identity
        });
        1
    ];

    let mut out_bytes = vec![0u8; 8192];
    let written = rstd::rnn_pack_v1(
        topology,
        ActivationKind::Identity,
        ActivationKind::Identity,
        &weights,
        &biases,
        &mut layer_scratch,
        &mut out_bytes,
    )
    .expect("pack");

    let counts = rstd::rnn_required_from_bytes_v1_std(&out_bytes[..written]).expect("counts");
    assert_eq!(counts.layers, 1);
    assert_eq!(counts.weights, 2);
    assert_eq!(counts.biases, 1);
}

#[test]
fn rnn_run_errors_on_small_buffers() {
    use native_neural_network_std::std::rnn_std as rstd;

    let topology = &[2usize, 1usize];
    let weights = vec![1.0f32, 1.0f32];
    let biases = vec![0.5f32];

    let mut layer_scratch = vec![
        LayerSpec::Dense(DenseLayerDesc {
            input_size: 0,
            output_size: 0,
            weight_offset: 0,
            bias_offset: 0,
            activation: ActivationKind::Identity
        });
        1
    ];

    let mut out_bytes = vec![0u8; 8192];
    let written = rstd::rnn_pack_v1(
        topology,
        ActivationKind::Identity,
        ActivationKind::Identity,
        &weights,
        &biases,
        &mut layer_scratch,
        &mut out_bytes,
    )
    .expect("pack");

    let input = [1.0f32, 1.0f32];
    let mut output = [0f32; 1];

    let mut weights_scratch = vec![0f32; 0];
    let mut biases_scratch = vec![0f32; 0];
    let mut infer_scratch = vec![0f32; 0];

    let res = rstd::rnn_run_v1(
        &out_bytes[..written],
        &input,
        &mut output,
        &mut layer_scratch,
        &mut weights_scratch,
        &mut biases_scratch,
        &mut infer_scratch,
    );
    assert!(res.is_err());
}

#[test]
fn rnn_pack_invalid_topology_errors() {
    use native_neural_network_std::std::rnn_std as rstd;

    let bad_topology = &[1usize];
    let weights = vec![];
    let biases = vec![];
    let mut layer_scratch: Vec<LayerSpec> = Vec::new();
    let mut out_bytes = vec![0u8; 16];

    let res = rstd::rnn_pack_v1(
        bad_topology,
        ActivationKind::Identity,
        ActivationKind::Identity,
        &weights,
        &biases,
        &mut layer_scratch,
        &mut out_bytes,
    );
    assert!(res.is_err());
}

#[test]
fn rnn_required_from_topology_bad() {
    use native_neural_network_std::std::rnn_std as rstd;
    let bad = &[0usize];
    assert!(rstd::rnn_required_from_topology(bad).is_err());
}

#[test]
fn rnn_unpack_truncated_bytes_errors() {
    use native_neural_network_std::std::rnn_std as rstd;
    let bytes = [0u8, 1u8, 2u8];
    let res = rstd::rnn_unpack_v1_std(&bytes);
    assert!(res.is_err());
}

#[test]
fn rnn_required_from_bytes_bad_magic() {
    use native_neural_network_std::std::rnn_std as rstd;
    let bad = [0u8; 4];
    assert!(rstd::rnn_required_from_bytes_v1_std(&bad).is_err());
}

#[test]
fn rnn_concurrent_pack_and_run_smoketest() {
    use native_neural_network_std::std::rnn_std as rstd;
    use std::thread;

    let mut handles = Vec::new();
    for _ in 0..4 {
        handles.push(thread::spawn(|| {
            let topology = &[2usize, 1usize];
            let weights = vec![1.0f32, 1.0f32];
            let biases = vec![0.5f32];
            let mut layer_scratch = vec![
                LayerSpec::Dense(DenseLayerDesc {
                    input_size: 0,
                    output_size: 0,
                    weight_offset: 0,
                    bias_offset: 0,
                    activation: ActivationKind::Identity
                });
                1
            ];
            let mut out_bytes = vec![0u8; 8192];
            let written = rstd::rnn_pack_v1(
                topology,
                ActivationKind::Identity,
                ActivationKind::Identity,
                &weights,
                &biases,
                &mut layer_scratch,
                &mut out_bytes,
            )
            .expect("pack");

            let input = [1.0f32, 2.0f32];
            let mut out = [0f32; 1];
            let mut weights_scratch = vec![0f32; 2];
            let mut biases_scratch = vec![0f32; 1];
            let mut infer_scratch =
                vec![
                    0f32;
                    rstd::rnn_required_infer_scratch_from_specs_std(&layer_scratch).unwrap_or(0)
                ];
            let r = rstd::rnn_run_v1(
                &out_bytes[..written],
                &input,
                &mut out,
                &mut layer_scratch,
                &mut weights_scratch,
                &mut biases_scratch,
                &mut infer_scratch,
            );
            assert!(r.is_ok());
        }));
    }
    for h in handles {
        h.join().unwrap();
    }
}