The duplicate ports neural/jpegai_hyper.rs and neural/jpegai_mans.rs, which the float decode path ran its front half with, are deleted (O10): that path runs the shared driver since the switch. The direct pieces of the exact decoder leave production, test-only (legacy_int): the crate-root mANS port (jpegai_mans), the hyper-scale network (jpegai_synthesis::decode_hyper_scale and its convolution) and the pipeline's skip_mask, rvs_additive, rvs_likely and sigma_index. The calibration tests that read them require legacy_int. jpegai_mans_golden runs on E8 and the scale graph alone; jpegai_e2e (the float chain against the reference PNG) takes its front half from the driver, still checking the dumped RVS additions, masks and residuals; the byte-equality crate drops the neural port and keeps E8 and the direct port. Co-Authored-By: Claude Opus 5.5 <[email protected]>
76 lines
4.1 KiB
Rust
76 lines
4.1 KiB
Rust
//! Byte-exact calibration for the mANS entropy decoder: replay the real JPEG-AI
|
|
//! `SORP` stream (main y-latent) through `MansDecoder::decode_sgm` and require an
|
|
//! EXACT match to the reference `expected` (the golden was produced by the ISO
|
|
//! reference `ans.so`, and this Rust is a faithful port of `decompressor.cpp`).
|
|
//! No ort needed — the fixture carries the transition tables + stream + goldens.
|
|
//!
|
|
//! env: WAI_JPEGAI_MANS_FIXTURE = path to mans_sorp_fixture.json
|
|
//! { dt:[u32; 32*256], bounds:[u8;32], mem:[u8], offsets:[u32],
|
|
//! calls:[{sigma:[u8], mask:[bool], expected:[i16]}] }
|
|
#![cfg(all(feature = "neural_int", feature = "legacy_int"))]
|
|
|
|
use wai::jpegai_mans::MansDecoder;
|
|
|
|
#[test]
|
|
fn mans_sgm_byte_exact_vs_reference() {
|
|
let path = match std::env::var("WAI_JPEGAI_MANS_FIXTURE") {
|
|
Ok(p) if std::path::Path::new(&p).exists() => p,
|
|
_ => { eprintln!("skip: set WAI_JPEGAI_MANS_FIXTURE to mans_sorp_fixture.json"); return; }
|
|
};
|
|
let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap();
|
|
let arr_u32 = |k: &str| v[k].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u32).collect::<Vec<_>>();
|
|
let dt = arr_u32("dt");
|
|
let bounds: Vec<u8> = v["bounds"].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u8).collect();
|
|
let mem: Vec<u8> = v["mem"].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u8).collect();
|
|
let offsets = arr_u32("offsets");
|
|
|
|
let mut dec = MansDecoder::new(&mem, &offsets);
|
|
dec.set_sgm_transitions(&dt, &bounds);
|
|
|
|
let mut total = 0usize;
|
|
let mut mism = 0usize;
|
|
let mut first: Option<(usize, usize, i16, i16)> = None;
|
|
for (ci, call) in v["calls"].as_array().unwrap().iter().enumerate() {
|
|
let sigma: Vec<u8> = call["sigma"].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u8).collect();
|
|
let mask: Vec<bool> = call["mask"].as_array().unwrap().iter().map(|x| x.as_bool().unwrap()).collect();
|
|
let exp: Vec<i16> = call["expected"].as_array().unwrap().iter().map(|x| x.as_i64().unwrap() as i16).collect();
|
|
let mut out = vec![0i16; sigma.len()];
|
|
dec.decode_sgm(&sigma, &mut out, &mask);
|
|
for i in 0..out.len() {
|
|
total += 1;
|
|
if out[i] != exp[i] {
|
|
mism += 1;
|
|
if first.is_none() { first = Some((ci, i, out[i], exp[i])); }
|
|
}
|
|
}
|
|
}
|
|
eprintln!("mANS decode_sgm vs reference: {}/{} exact, {} mismatched", total - mism, total, mism);
|
|
if let Some((ci, i, got, exp)) = first { eprintln!("first mismatch: call {ci} pos {i}: got {got} exp {exp}"); }
|
|
assert_eq!(mism, 0, "mANS decoder must be BYTE-EXACT vs the ISO reference; {mism} mismatches");
|
|
}
|
|
|
|
/// Byte-exact `fac` (factorized z hyper-latent) path vs an oracle roundtrip vector.
|
|
/// env: WAI_JPEGAI_MANS_FAC = path to mans_fac_fixture.json
|
|
/// { cdfs:[u8; channels*63], mem:[u8], offsets:[u32], channels, spc, expected:[u8] }
|
|
#[test]
|
|
fn mans_fac_byte_exact_vs_reference() {
|
|
let path = match std::env::var("WAI_JPEGAI_MANS_FAC") {
|
|
Ok(p) if std::path::Path::new(&p).exists() => p,
|
|
_ => { eprintln!("skip: set WAI_JPEGAI_MANS_FAC to mans_fac_fixture.json"); return; }
|
|
};
|
|
let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap();
|
|
let u8v = |k: &str| v[k].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u8).collect::<Vec<u8>>();
|
|
let cdfs = u8v("cdfs");
|
|
let mem = u8v("mem");
|
|
let offsets: Vec<u32> = v["offsets"].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u32).collect();
|
|
let channels = v["channels"].as_u64().unwrap() as usize;
|
|
let spc = v["spc"].as_u64().unwrap() as usize;
|
|
let expected = u8v("expected");
|
|
|
|
let mut dec = MansDecoder::new(&mem, &offsets);
|
|
let mut out = vec![0u8; channels * spc];
|
|
dec.decode_factorize(&cdfs, &mut out, channels, spc);
|
|
let mism = out.iter().zip(&expected).filter(|(a, b)| a != b).count();
|
|
eprintln!("mANS decode_factorize vs reference: {}/{} exact, {} mismatched", out.len() - mism, out.len(), mism);
|
|
assert_eq!(mism, 0, "mANS fac decoder must be BYTE-EXACT; {mism} mismatches");
|
|
}
|