use std::path::Path;
use std::path::PathBuf;
use candle_core::DType;
use tempfile::tempdir;
use super::*;
fn npy_bytes(descr: &str, fortran_order: bool, shape: &[usize], data: &[u8]) -> Vec<u8> {
let shape_str = match shape {
[] => "()".to_string(),
[only] => format!("({only},)"),
many => format!(
"({})",
many
.iter()
.map(usize::to_string)
.collect::<Vec<_>>()
.join(", ")
),
};
let dict = format!(
"{{'descr': '{descr}', 'fortran_order': {}, 'shape': {shape_str}, }}\n",
if fortran_order { "True" } else { "False" }
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&MAGIC);
bytes.extend_from_slice(&[1, 0]);
bytes.extend_from_slice(&(dict.len() as u16).to_le_bytes());
bytes.extend_from_slice(dict.as_bytes());
bytes.extend_from_slice(data);
bytes
}
fn write_file(dir: &Path, name: &str, bytes: &[u8]) -> PathBuf {
let path = dir.join(name);
std::fs::write(&path, bytes).unwrap();
path
}
fn le_f32(values: &[f32]) -> Vec<u8> {
values.iter().flat_map(|v| v.to_le_bytes()).collect()
}
#[test]
fn round_trip_through_a_file_this_test_writes_itself() {
let dir = tempdir().unwrap();
let values = [1.0f32, -2.5, 3.25, 4.0, -5.5, 6.75];
let bytes = npy_bytes("<f4", false, &[2, 3], &le_f32(&values));
let path = write_file(dir.path(), "round_trip.npy", &bytes);
let tensor = read(&path).unwrap();
assert_eq!(tensor.dims(), &[2, 3]);
assert_eq!(tensor.dtype(), DType::F32);
assert_eq!(
tensor.to_vec2::<f32>().unwrap(),
vec![vec![1.0, -2.5, 3.25], vec![4.0, -5.5, 6.75]]
);
}
#[test]
fn round_trip_preserves_a_single_byte_integer_dtype() {
let dir = tempdir().unwrap();
let bytes = npy_bytes("|u1", false, &[4], &[0u8, 1, 254, 255]);
let path = write_file(dir.path(), "bytes.npy", &bytes);
let tensor = read(&path).unwrap();
assert_eq!(tensor.dtype(), DType::U8);
assert_eq!(tensor.to_vec1::<u8>().unwrap(), vec![0, 1, 254, 255]);
}
#[test]
fn minicoil_file_byte_count_matches_its_declared_shape() {
const TOTAL_BYTES: usize = 156_672_128;
const STANDARD_HEADER_BYTES: usize = 128;
const INPUT_DIM: usize = 512;
const OUTPUT_DIM: usize = 4;
const F32_BYTES: usize = 4;
let data_bytes = TOTAL_BYTES - STANDARD_HEADER_BYTES;
assert_eq!(data_bytes, 156_672_000);
let floats = data_bytes / F32_BYTES;
assert_eq!(floats, 39_168_000);
assert_eq!(floats % (INPUT_DIM * OUTPUT_DIM), 0);
assert_eq!(floats / (INPUT_DIM * OUTPUT_DIM), 19_125);
}
mod errors;