open-standards/wai/wai-rs/tests/jpegai_reconstruct_calibration.rs
Transaction Science e6453a9566 wai: gate the direct-network tests on legacy_int in their files too
Gate 7 made these seven tests require `legacy_int` in Cargo.toml, but their files
were still gated on `neural_int` or `neural` alone, which `check-tests-in-ci.py`
reports: a file's `#![cfg]` must name what its `[[test]]` requires. Each file is
now gated on `all(..., feature = "legacy_int")`, as `jpegai_ops.rs` is.

Three test comments named the design's appendix and a plan item. They now name
the text's sections (§11's `role_profiles`, §13.6.2's table).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 02:41:38 -04:00

63 lines
2.8 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Calibration for [`wai::jpegai_pipeline::reconstruct_yhat`] — the SGMM
//! autoregressive spine — on REAL `test256.bin` data: rebuild the synthesis-input
//! latent `y_hat` from the reference's dequantized residual (`resi_dq_y`) and hyper
//! params (`psi_y`), and compare against the reference `yhat_y`.
//!
//! This closes the last structural gap in the decode chain: entropy → dequant →
//! **reconstruct** → synthesis. The float reference loop reproduces `yhat_y` to
//! ~139 dB (float round-off); our Q16 integer MCM stages carry the 16-bit PTQ floor
//! of the MCM nets themselves (~61–74 dB per stage), so we assert well above that.
//!
//! env: WAI_JPEGAI_RECON_FIXTURE = recon_fixture.json {resi_dq_y, psi_y, yhat_y, c, h2, w2}
//! WAI_JPEGAI_MCM_WEIGHTS_DIR = dir with mcm_stage0..3_y.json
#![cfg(all(feature = "neural_int", feature = "legacy_int"))]
use wai::jpegai_pipeline::reconstruct_yhat;
use wai::jpegai_synthesis::Weights;
fn q16(f: &[f64]) -> Vec<i64> { f.iter().map(|&x| (x * 65536.0).round() as i64).collect() }
#[test]
fn reconstruct_yhat_on_real_reference_data() {
let fx = match std::env::var("WAI_JPEGAI_RECON_FIXTURE") {
Ok(p) if std::path::Path::new(&p).exists() => p,
_ => { eprintln!("skip: set WAI_JPEGAI_RECON_FIXTURE"); return; }
};
let wdir = match std::env::var("WAI_JPEGAI_MCM_WEIGHTS_DIR") {
Ok(p) if std::path::Path::new(&p).exists() => p,
_ => { eprintln!("skip: set WAI_JPEGAI_MCM_WEIGHTS_DIR"); return; }
};
let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&fx).unwrap()).unwrap();
let f64v = |k: &str| v[k].as_array().unwrap().iter().map(|x| x.as_f64().unwrap()).collect::<Vec<f64>>();
let (c, h2, w2) = (
v["c"].as_u64().unwrap() as usize,
v["h2"].as_u64().unwrap() as usize,
v["w2"].as_u64().unwrap() as usize,
);
let resi = q16(&f64v("resi_dq_y"));
let psi = q16(&f64v("psi_y"));
let yhat_ref = f64v("yhat_y");
let load = |i: usize| -> Weights {
let raw = std::fs::read(format!("{wdir}/mcm_stage{i}_y.json")).unwrap();
Weights::from_json(&serde_json::from_slice(&raw).unwrap()).unwrap()
};
let (w0, w1, w2w, w3) = (load(0), load(1), load(2), load(3));
let got = reconstruct_yhat(&resi, &psi, c, h2, w2, [&w0, &w1, &w2w, &w3]);
assert_eq!(got.len(), yhat_ref.len(), "y_hat size mismatch");
let (mut maxd, mut se, mut sig) = (0f64, 0f64, 0f64);
for i in 0..got.len() {
let g = got[i] as f64 / 65536.0;
let r = yhat_ref[i];
let d = (g - r).abs();
maxd = maxd.max(d);
se += d * d;
sig += r * r;
}
let snr = 10.0 * (sig / se).log10();
eprintln!("reconstruct_yhat on real data: max|Δ| = {maxd:.5} SNR = {snr:.2} dB");
assert!(snr > 45.0, "SGMM reconstruction regressed (SNR {snr:.2} dB)");
}