//! Calibration for the **dequant gain**, against the ISO reference on real //! `test256.bin` data, for both the luma and chroma planes. //! //! This closes the last underived decoder input. Before this, the per-position gain //! came from a dumped fixture; it is now built from normative assets only: //! //! ```text //! scale[i] = round_ties_even(base[i] · (grfs_flag ? 1.06 : 0.98)) base = [115,125,146,160] //! dequant[i] = round(2^7 · 2^16 / scale[i]) // RVS stage, Q16 //! additive[i] = round(ln(scale[i]/128) / (log_k / 2^7)) // == RVS_ADDITIVE //! scaler_vec[c] = round(exp((gain_vector_log[c] + beta) · log_k / 2^7) · 2^10) / 2^10 //! ``` //! //! `gain_vector_log` is the normative `gain_unit_mlog.csv`; `beta_displacement_log` //! comes from the picture header. //! //! Two rounding hazards are asserted here rather than left to chance: //! * the scale rounding is **half-to-even** — `125·1.06` is exactly `132.5` and //! `125·0.98` exactly `122.5`, and half-away-from-zero picks the wrong scale; //! * the reference's `dequantize_resi` has an integer `>>16` path and a float //! `/2^16` path chosen by a *device comparison*. They disagree for negative //! input (floor vs. exact). The float path is the one it executes. //! //! env: WAI_JPEGAI_DEQUANT_FIXTURE = dequant_fixture.json //! { y|uv: { channels, h, w, y_q, likely, grfs, gain_vector_log, //! beta_displacement_log, rvs_out_expected } } #![cfg(all(feature = "neural_int", feature = "legacy_int"))] use wai::jpegai_pipeline::{gain_unit_scaler_vec, rvs_dequant, rvs_likely, rvs_tables}; /// The tables the reference's `buildTables()` produces, read off its own dumps. #[test] fn derived_tables_match_reference() { // GRFS flag clear → base · 0.98; set → base · 1.06. let (scales, dq, add) = rvs_tables(false); assert_eq!(scales, [113, 122, 143, 157], "GRFS-clear scales"); assert_eq!(dq, [74235, 68759, 58662, 53431], "GRFS-clear dequant table (cwg2)"); assert_eq!(add, [-80, -31, 71, 130], "GRFS-clear additive == RVS_ADDITIVE[1]"); let (scales, dq, add) = rvs_tables(true); assert_eq!(scales, [122, 132, 155, 170], "GRFS-set scales"); assert_eq!(dq, [68759, 63550, 54120, 49345], "GRFS-set dequant table (cwg1)"); assert_eq!(add, [-31, 20, 122, 181], "GRFS-set additive == RVS_ADDITIVE[0]"); // Guard the half-to-even hazard explicitly: half-away-from-zero would give // 133 / 123 for the band-1 scale and silently mis-select its multiplier. assert_eq!((125.0f64 * 1.06).round_ties_even() as i64, 132); assert_eq!((125.0f64 * 0.98).round_ties_even() as i64, 122); } #[test] fn dequant_matches_reference() { let path = match std::env::var("WAI_JPEGAI_DEQUANT_FIXTURE") { Ok(p) if std::path::Path::new(&p).exists() => p, _ => { eprintln!("skip: set WAI_JPEGAI_DEQUANT_FIXTURE"); return; } }; let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap(); for plane in ["y", "uv"] { let o = &v[plane]; let channels = o["channels"].as_u64().unwrap() as usize; let i64v = |k: &str| o[k].as_array().unwrap().iter() .map(|x| x.as_i64().unwrap()).collect::>(); let (h, w) = (o["h"].as_u64().unwrap() as usize, o["w"].as_u64().unwrap() as usize); let y_q: Vec = i64v("y_q").iter().map(|&x| x as i16).collect(); let grfs: Vec = o["grfs"].as_array().unwrap().iter() .map(|x| x.as_bool().unwrap()).collect(); let gain_vector_log = i64v("gain_vector_log"); let beta = o["beta_displacement_log"].as_i64().unwrap(); let expected: Vec = o["rvs_out_expected"].as_array().unwrap().iter() .map(|x| x.as_f64().unwrap() as f32).collect(); // `likely` is DERIVED from the scale surface, not taken from the fixture: the // summed quantity is the gain-adjusted scale (i_s + gain_per_ch), and the // dequant is bit-exact only with the gain included. Summing |i_s| instead // happens to select the same RVS band on this image but is not the same // quantity — the fixture check below is what distinguishes them. let i_s = i64v("i_s"); let likely = rvs_likely(&i_s, &gain_vector_log, channels, h, w); let lk_expected = i64v("likely_expected"); let lk_exact = likely.iter().zip(&lk_expected).filter(|(a, b)| a == b).count(); assert_eq!( lk_exact, lk_expected.len(), "{plane}: derived likely mismatched ({lk_exact}/{})", lk_expected.len() ); // The RVS stage must be bit-exact against the reference — it is pure integer // table lookup plus an exact power-of-two divide. let got = rvs_dequant(&y_q, &likely, &grfs, channels); let exact = got.iter().zip(&expected).filter(|(a, b)| a == b).count(); assert_eq!( exact, expected.len(), "{plane}: RVS dequant not bit-exact ({exact}/{})", expected.len() ); // The gain unit is well-formed and strictly positive for every channel, so // the composed dequant never divides by ~0. let sv = gain_unit_scaler_vec(&gain_vector_log, beta); assert_eq!(sv.len(), channels, "{plane}: scaler_vec length"); assert!(sv.iter().all(|&s| s > 0.0 && s.is_finite()), "{plane}: scaler_vec sane"); eprintln!("{plane}: RVS dequant bit-exact {exact}/{}", expected.len()); } }