mod parity_metrics;
use brain2qwerty::model::conv_conformer::ConvConformer;
use brain2qwerty::tensor::load_tensor_bin;
use parity_metrics::compare_slices;
fn refs_dir() -> std::path::PathBuf {
brain2qwerty::parity_refs_dir()
}
fn skip() -> bool {
!refs_dir().join("input_neuros.bin").is_file()
|| !brain2qwerty::data_paths::encoder_weights_path().is_file()
}
#[test]
fn test_encoder_vs_python_refs() {
if skip() {
eprintln!("SKIP: parity refs / encoder weights not found");
return;
}
let weights = brain2qwerty::data_paths::encoder_weights_path();
let model = ConvConformer::from_tiny_weights(&weights.to_string_lossy()).unwrap();
let neuros = load_tensor_bin(&refs_dir().join("input_neuros.bin")).unwrap();
let chan_pos = load_tensor_bin(&refs_dir().join("input_chan_pos.bin")).unwrap();
let days = load_tensor_bin(&refs_dir().join("input_days.bin")).unwrap();
let subject_ids: Vec<usize> = days.data.iter().map(|&x| x as usize).collect();
let out = model.forward(&neuros, &subject_ids, Some(&chan_pos));
for name in ["z_enc", "z_final", "c_out", "z_aux"] {
let path = refs_dir().join(format!("{name}.bin"));
if !path.is_file() {
continue;
}
let reference = load_tensor_bin(&path).unwrap();
let actual = match name {
"z_enc" => &out.z_enc,
"z_final" => &out.z_final,
"c_out" => &out.c_out,
"z_aux" => out.z_aux.as_ref().unwrap(),
_ => unreachable!(),
};
compare_slices(&actual.data, &reference.data).assert_full_parity(name);
}
}