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]>
48 lines
2.4 KiB
Rust
48 lines
2.4 KiB
Rust
//! Byte-exact calibration for [`wai::jpegai_pipeline::sigma_index`] — the link that
|
|
//! closes the scale path: the hyper-scale decoder's index `i_s` (plus the per-channel
|
|
//! gain and the per-position residual-variance scale) selects the mANS `sgm`
|
|
//! distribution index for every latent position.
|
|
//!
|
|
//! Validated on the real `test256.bin` streams for BOTH planes — the reference
|
|
//! `indexes` come straight out of the reference decoder's entropy fixture (SORP for
|
|
//! luma, SORS for chroma), so a match here means our sigma selection is exactly what
|
|
//! the reference entropy coder consumed.
|
|
//!
|
|
//! env: WAI_JPEGAI_SIGMA_FIXTURE = sigma_index_fixture.json
|
|
//! { y|uv: { channels, i_s:[i64], gain_per_ch:[i64], rvs:[i64], expected_sigma:[u8] } }
|
|
#![cfg(all(feature = "neural_int", feature = "legacy_int"))]
|
|
|
|
use wai::jpegai_pipeline::sigma_index;
|
|
|
|
#[test]
|
|
fn sigma_index_byte_exact_vs_reference() {
|
|
let path = match std::env::var("WAI_JPEGAI_SIGMA_FIXTURE") {
|
|
Ok(p) if std::path::Path::new(&p).exists() => p,
|
|
_ => { eprintln!("skip: set WAI_JPEGAI_SIGMA_FIXTURE to sigma_index_fixture.json"); return; }
|
|
};
|
|
let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap();
|
|
let i64v = |o: &serde_json::Value, k: &str| {
|
|
o[k].as_array().unwrap().iter().map(|x| x.as_i64().unwrap()).collect::<Vec<i64>>()
|
|
};
|
|
|
|
for plane in ["y", "uv"] {
|
|
let o = &v[plane];
|
|
let channels = o["channels"].as_u64().unwrap() as usize;
|
|
let i_s = i64v(o, "i_s");
|
|
let gain_per_ch = i64v(o, "gain_per_ch");
|
|
let rvs = i64v(o, "rvs");
|
|
let expected: Vec<u8> = o["expected_sigma"].as_array().unwrap()
|
|
.iter().map(|x| x.as_u64().unwrap() as u8).collect();
|
|
|
|
let got = sigma_index(&i_s, &gain_per_ch, &rvs, channels);
|
|
assert_eq!(got.len(), expected.len(), "{plane}: sigma length mismatch");
|
|
|
|
let mism = got.iter().zip(&expected).filter(|(a, b)| a != b).count();
|
|
if let Some((i, (a, b))) = got.iter().zip(&expected).enumerate().find(|(_, (a, b))| a != b) {
|
|
eprintln!("{plane}: first mismatch @ {i}: got {a} exp {b}");
|
|
}
|
|
eprintln!("sigma_index [{plane}] vs reference: {}/{} exact, {} mismatched",
|
|
got.len() - mism, got.len(), mism);
|
|
assert_eq!(mism, 0, "{plane}: sigma_index must be BYTE-EXACT vs the reference decoder");
|
|
}
|
|
}
|