open-standards/wai/wai-rs/tests/int_audio_ops.rs
Transaction Science 946f3beda9
All checks were successful
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 6s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 7s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 6s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 6s
wai-audit collector and player integration / does this change touch it (pull_request) Successful in 6s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 6s
WAI operation catalogue / does this change touch it (pull_request) Successful in 6s
WAI conformance / does this change touch it (pull_request) Successful in 6s
WAI energy receipts / does this change touch it (pull_request) Successful in 5s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 6s
wai-fleet service / does this change touch it (pull_request) Successful in 6s
WAI JPEG-AI whole decode (pinned inputs, required) / does this change touch it (pull_request) Successful in 7s
wai-ledger service / does this change touch it (pull_request) Successful in 6s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 1m25s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 6s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 6s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 6s
wai-sink-android native sink library / does this change touch it (pull_request) Successful in 6s
wai-sink-swift native sink package / does this change touch it (pull_request) Successful in 6s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m57s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 2m7s
WAI Studio / does this change touch it (pull_request) Successful in 6s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 6s
wai-web wasm32 / does this change touch it (pull_request) Successful in 6s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 29s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 2m1s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 2m59s
wai-audit collector and player integration / collector · linux (pull_request) Successful in 1m1s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 26s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m19s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 16s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m4s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Successful in 1m15s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 5m15s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 6m19s
wai-fleet service / service · macos (pull_request) Successful in 1m2s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (pull_request) Successful in 2m46s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 1m43s
wai-ledger service / service · macos (pull_request) Successful in 1m24s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 1m2s
WAI operation catalogue / the catalogue and every door · linux (pull_request) Successful in 4m18s
wai-quantum studio and desktop / desktop app · windows (pull_request) Successful in 9m19s
wai-pack / wai-pack · macos (pull_request) Successful in 3m8s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 30s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 7m49s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 3m23s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 1m39s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m9s
wai-fleet service / service · linux (pull_request) Successful in 2m5s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 3m28s
wai-ledger service / service · linux (pull_request) Successful in 1m43s
wai-pack / wai-pack · linux (pull_request) Successful in 1m55s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 3m0s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 1m10s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 16m12s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 11m32s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 4m51s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 13m12s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 15m2s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 4m3s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 16m34s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m40s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 17m22s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m44s
wai-quantum studio and desktop / desktop app · linux (pull_request) Successful in 5m46s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 34s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 17s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 9m28s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 5m7s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 14m49s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m34s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 2m16s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 11m4s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 13m6s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 5m58s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 10m55s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 9m51s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 10m15s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 9m21s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 30m14s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h4m7s
Changelog entries and the conformance workflow's lists move into files a change adds
Every change to WAI added an entry at the head of wai/CHANGELOG.md, and every new module
appended to the hand-kept lists of .github/workflows/wai-conformance.yml. So any two
branches conflicted on those lines and had to merge one after another. This moves both into
files a change adds.

- Changelog entries: a change adds wai/changes/<yyyy-mm-dd>-<slug>.md holding the entry
  text. scripts/changelog-assemble.py renders the entries into CHANGELOG.md's Unreleased
  section for a release, in a stable order. scripts/check-changelog-fragment.py, run by
  repo-checks on every pull request, fails a pull request that changes wai/ and adds or
  edits no entry file directly in wai/changes/ (a release passes, and so does a commit
  with the trailer line "Changelog: none"). A pull request opened before the check reached
  main passes as it is; one opened after it that adds its entry to the head of Unreleased
  fails and is told where the entry goes. wai breaking reads breaking changes from entry
  files too.
- The conformance workflow: each per-module verifier step is a file in
  .github/wai-conformance/verifiers/, each corpus a file in corpora/, and the
  integer-kernel tests carry a tag line. scripts/wai-conformance-lists.py derives every
  list the workflow kept by hand (WAI_FEATURES, the union --bin and --test lists, the
  features-alone lists, the kernel and corpus steps) from those files when the workflow
  runs. Its `selftest --exact` holds the derived lists to the hand lists of the commit
  before this one, and its dry-run prints every command each job runs: the dry-runs before
  and after this change differ only in the gate's path list, which gains the two paths this
  change adds.
- What stays shared, and how to insert there, is written in wai/CONTRIBUTING.md and
  wai/changes/README.md: wai-rs Cargo.toml features and [[test]] entries, lib.rs, registry
  rows, wai/.gitattributes and the live corpus table take an insert beside the related
  entry, never at the end.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 01:41:29 -05:00

500 lines
27 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.

// wai-conformance: int-kernels int-kernels-amd
//! `wai.audio.int_codec` through the integer operator set: its lowering `wam1/1`
//! (`extensions/integer-operators.md` §13.3, with the PCM step) and the certificate of
//! every committed set (§8.5), as this crate loads them (`int_ops`).
//!
//! The lowered graphs and certificates are committed under `ops-conformance/certificates/`,
//! where `wai-verify` and the independent checker (`tools/wai_ops_check.py`) each
//! reproduce them byte for byte (`wai-ops.yml`). Here the lowering this crate runs, from
//! the model it parses (`int_audio::ops::wam1_net`), must write those same bytes, and the
//! load a sink makes must give the verdict the certificate records.
//!
//! The decode through the lowering (`int_audio::ops`) must give, on every committed
//! vector, the samples of the direct decode (`int_audio::legacy`) and the vector's
//! committed digests.
use std::path::PathBuf;
use serde_json::Value;
use wai::int_audio::{self, AudioJson, AudioModel, AudioStream};
use wai_ops::Profile;
const CAP: &str = "wai.audio.int_codec";
fn wai() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
}
fn read(rel: &str) -> Vec<u8> {
std::fs::read(wai().join(rel)).unwrap_or_else(|e| panic!("{rel}: {e}"))
}
fn json(rel: &str) -> Value {
serde_json::from_slice(&read(rel)).unwrap_or_else(|e| panic!("{rel}: {e}"))
}
fn sha256(b: &[u8]) -> String {
wai_ops::sha256::sha256(b).iter().map(|x| format!("{x:02x}")).collect()
}
/// The `wai.audio.int_codec` sets `ops-conformance/certificates/index.json` lists:
/// `(name, synthetic, set file, set digest, lowered graph file)`, each relative to `wai/`.
fn indexed() -> Vec<(String, bool, String, String, String)> {
json("ops-conformance/certificates/index.json")["sets"]
.as_array()
.unwrap()
.iter()
.filter(|s| s["capability"] == CAP)
.map(|s| {
assert_eq!(s["lowering"], "wam1/1");
let roles = s["roles"].as_array().unwrap();
assert_eq!(roles.len(), 1, "wam1/1 lowers an audio set to one graph, g_s");
(
s["name"].as_str().unwrap().to_string(),
s["synthetic"].as_bool().unwrap(),
s["members"]["model.wam"].as_str().unwrap().to_string(),
s["set_sha256"].as_str().unwrap().to_string(),
roles[0].as_str().unwrap().to_string(),
)
})
.collect()
}
/// The graph this crate lowers from the model it parses: `int_audio::ops::wam1_net`,
/// then `wam1/1` with the PCM step.
fn lowered_from_the_parsed_model(set: &[u8]) -> wai_ops::Graph {
let m = AudioModel::from_bytes(set).expect("the WAM1 set parses");
let net = wai::int_audio::ops::wam1_net(&m).expect("a model parsed from bytes converts");
assert!(net == wai_ops::lower::parse_wam1(set).unwrap(), "the converted model is the one wai-ops parses from the bytes");
wai_ops::lower::wam1_net(&net).expect("the set lowers")
}
/// Gate 1 of the migration: every committed `wai.audio.int_codec` set (the conformance
/// vector's and the synthetic one of `ops-conformance/sets/`) lowers to its committed
/// graph, from its bytes (`lower::wam1`) and from the model this crate parses; the
/// certificate beside it is that graph's; and loading the graph under the capability's
/// profile gives the certificate's verdict. Each set carries `check` ranges (§13.2,
/// §13.3), so it meets `acc64` by construction and not `acc32`, first failing at `g_s`'s
/// input range (the vector's at 47 bits, as Appendix C predicts); and the PCM step's
/// `crop`, whose length is a scalar, keeps it out of the accelerator subset.
#[test]
fn every_committed_set_lowers_to_its_committed_graph_and_verdict() {
let sets = indexed();
let mut names: Vec<(&str, bool)> = sets.iter().map(|s| (s.0.as_str(), s.1)).collect();
names.sort();
assert_eq!(names, [("audio", false), ("audio", true)], "the committed audio sets");
for (name, synthetic, set, digest, role) in &sets {
let name = if *synthetic { format!("{name} (synthetic)") } else { name.clone() };
let bytes = read(set);
let g = wai_ops::lower::wam1(&bytes).unwrap_or_else(|r| panic!("{name}: does not lower: {r:?}"));
// The verdict first: the load a sink makes.
let loaded = wai::int_ops::load(&g).unwrap_or_else(|r| panic!("{name}: refused under acc64: {r:?}"));
assert!(!loaded.meets(Profile::Acc32), "{name}: a set with check ranges inside its graph does not meet acc32");
// Then the committed bytes: the set, its lowered graph (both ways) and its certificate.
assert_eq!(&sha256(&bytes), digest, "{name}: the set's digest");
let graph = g.to_bytes();
assert!(graph == read(role), "{name}: the lowering of the bytes differs from the committed {role}");
assert!(lowered_from_the_parsed_model(&bytes).to_bytes() == graph, "{name}: the lowering of the parsed model differs from the committed {role}");
let cert = json(&format!("ops-conformance/certificates/{CAP}/{digest}.json"));
assert_eq!(cert["set_sha256"].as_str(), Some(digest.as_str()), "{name}");
assert_eq!(cert["lowering"], "wam1/1", "{name}");
assert_eq!(cert["graphs"][0]["name"], "g_s", "{name}");
assert_eq!(cert["graphs"][0]["graph_sha256"].as_str(), Some(sha256(&graph).as_str()), "{name}: the certificate is the graph's");
let v = &cert["verdict"];
assert_eq!((v["acc64"].as_bool(), v["acc32"].as_bool()), (Some(true), Some(false)), "{name}: the certificate's verdict");
let first = &v["acc32_first_failure"];
assert_eq!(
(first["graph"].as_str(), first["where"].as_str(), first["index"].as_str(), first["key"].as_str()),
(Some("g_s"), Some("input"), Some("0"), Some("range")),
"{name}: the first acc32 failure is g_s's input range"
);
assert!(v["npu_reasons"].as_array().unwrap().iter().any(|r| r == "crop_scalar"), "{name}: the PCM step's crop");
let x0 = &cert["graphs"][0]["inputs"][0];
assert_eq!(x0["policy"].as_str(), Some("check"), "{name}");
assert_eq!(x0["hi"].as_str(), Some(g.tensors[0].hi.to_string().as_str()), "{name}: the input's range is X_0");
if !synthetic {
assert_eq!(first["bits"].as_str(), Some("47"), "{name}: Appendix C's 47 bits");
assert_eq!(g.tensors[0].hi, 56322496561155, "{name}");
}
// The scalar is t_out, `[1, 2^26]` (§13.0's driver contract).
assert_eq!((g.scalars.len(), g.scalars[0].lo, g.scalars[0].hi), (1, 1, 1 << 26), "{name}: scalar 0 is t_out");
}
}
/// The typed form of a parsed `WIA1` payload.
fn stream<'a>(a: &'a wai::int_wire::Wia1<'a>) -> AudioStream<'a> {
AudioStream {
afrac: a.afrac as u32, n_ch: a.n_ch as usize, lat_len: a.lat_len as usize, t_out: a.t_out as usize,
offset: a.offset, median_q: &a.median_q, cdfs: &a.cdfs, rans: a.rans,
}
}
/// The `wai.audio.int_codec` vectors `int-payload-conformance/vectors.json` indexes:
/// `(name, payload, set member model.wam, JSON form, sidecar)`, each relative to `wai/`.
fn vectors() -> Vec<(String, String, String, String, String)> {
json("int-payload-conformance/vectors.json")["vectors"]
.as_array()
.unwrap()
.iter()
.filter(|v| v["capability"] == CAP)
.map(|v| {
let s = |k: &Value| k.as_str().unwrap().to_string();
(s(&v["name"]), s(&v["payload"]), s(&v["set"]["model.wam"]), s(&v["converted_from"]["json"]), s(&v["sidecar"]))
})
.collect()
}
fn le_bytes(pcm: &[i16]) -> Vec<u8> {
pcm.iter().flat_map(|v| v.to_le_bytes()).collect()
}
/// Gate 2 of the migration: golden equality. Every committed `wai.audio.int_codec`
/// vector decodes through the lowering (`int_audio::ops`) to the samples the direct
/// decode gives (`int_audio::legacy`), and to every digest the corpus commits for it:
/// the SHA-256 sidecar of the PCM and the export's FNV-1a. The payload (`WIA1`) and the
/// JSON form it is converted from both decode, and alike. The staged audio base carries
/// the same payload, so it is covered too.
#[test]
fn every_committed_vector_decodes_through_the_lowering_to_its_golden() {
let vs = vectors();
assert_eq!(vs.len(), 1, "the committed audio vectors");
for (name, payload, set, from, sidecar) in &vs {
let m = AudioModel::from_bytes(&read(set)).unwrap();
let p = read(payload);
let a = wai::int_wire::parse_wia1(&p).unwrap_or_else(|e| panic!("{name}: {e:?}"));
let j = AudioJson::from_value(&json(from)).unwrap();
let want = json(sidecar)[name]["sha256"].as_str().unwrap().to_string();
let fnv = json("wai-rs/tests/vectors/int_audio/audio.json")["pcm_fnv1a"].as_str().unwrap().to_string();
for (form, st) in [("WIA1", stream(&a)), ("JSON", j.stream())] {
let ops = int_audio::ops::decode_typed(&m, &st).unwrap_or_else(|r| panic!("{name} {form}: {r}"));
let direct = int_audio::legacy::decode_typed(&m, &st).unwrap_or_else(|r| panic!("{name} {form}: {r}"));
assert!(ops == direct, "{name} {form}: the decode through the lowering differs from the direct decode");
assert_eq!(ops.len(), st.t_out, "{name} {form}: t_out samples");
assert_eq!(sha256(&le_bytes(&ops)), want, "{name} {form}: the SHA-256 sidecar");
assert_eq!(format!("{:016x}", int_audio::pcm_fnv1a(&ops)), fnv, "{name} {form}: the export's FNV-1a");
}
let base = read("staged-conformance/cases/audio_int_codec_1l/base.wai");
assert!(base.windows(p.len()).any(|w| w == p.as_slice()), "{name}: the staged audio base carries this payload");
}
}
/// The committed vector's set and payload (`int-payload-conformance`'s `audio`).
const SET: &str = "wai-rs/tests/vectors/int_audio/audio_model.bin";
const PAYLOAD: &str = "wai-rs/tests/vectors/int_audio/audio_bitstream.wia1";
/// A typed clip that owns its tables, so a fixture can change any field.
#[derive(Clone)]
struct Owned {
afrac: u32,
n_ch: usize,
lat_len: usize,
t_out: usize,
offset: i32,
median_q: Vec<i64>,
cdfs: Vec<Vec<i32>>,
rans: Vec<u8>,
}
impl Owned {
fn committed() -> Owned {
let p = read(PAYLOAD);
let a = wai::int_wire::parse_wia1(&p).unwrap();
Owned {
afrac: a.afrac as u32, n_ch: a.n_ch as usize, lat_len: a.lat_len as usize, t_out: a.t_out as usize,
offset: a.offset, median_q: a.median_q.clone(), cdfs: a.cdfs.clone(), rans: a.rans.to_vec(),
}
}
/// `n_ch` channels of `lat_len` latents at `afrac` 12, every latent of channel `k`
/// equal to `values[k]` (one table symbol each, its median placing it), presenting
/// `t_out` samples.
fn constant(values: &[i64], lat_len: usize, t_out: usize) -> Owned {
let (t, offset) = (vec![0, 1 << 15, 1 << 16], 3);
let mut enc = wai::rans::RansEncoder::new();
for _ in 0..values.len() * lat_len {
assert!(enc.encode(offset, &t, 3, offset));
}
Owned {
afrac: 12, n_ch: values.len(), lat_len, t_out, offset,
median_q: values.iter().map(|v| v - ((offset as i64) << 12)).collect(), cdfs: vec![t; values.len()], rans: enc.flush(),
}
}
fn st(&self) -> AudioStream<'_> {
AudioStream {
afrac: self.afrac, n_ch: self.n_ch, lat_len: self.lat_len, t_out: self.t_out, offset: self.offset,
median_q: &self.median_q, cdfs: &self.cdfs, rans: &self.rans,
}
}
}
/// The committed set, parsed, changed by `f`.
fn model(f: impl FnOnce(&mut AudioModel)) -> AudioModel {
let mut m = AudioModel::from_bytes(&read(SET)).unwrap();
f(&mut m);
m
}
/// The committed clip, changed by `f`.
fn clip(f: impl FnOnce(&mut Owned)) -> Owned {
let mut o = Owned::committed();
f(&mut o);
o
}
/// The code integer-payloads §8 gives a refusal of the audio decode.
fn code_of(r: wai::int_hyper_synth::Refused) -> &'static str {
wai::int_payload::IntPayloadError::from(r).code()
}
/// Both decodes of a clip against a model: through the lowering, then directly.
fn both(m: &AudioModel, o: &Owned) -> (Result<Vec<i16>, &'static str>, Result<Vec<i16>, &'static str>) {
(int_audio::ops::decode_typed(m, &o.st()).map_err(code_of), int_audio::legacy::decode_typed(m, &o.st()).map_err(code_of))
}
/// Gate 3 of the migration: refusal parity, on the committed fixtures. Each
/// `wai.audio.int_codec` fixture of `int-payload-conformance` is refused by a sink with
/// its code; one that parses (`decode`) is refused by the decode through the lowering and
/// by the direct decode alike, with that code.
#[test]
fn every_committed_refusal_fixture_keeps_its_code() {
let mut n = 0;
for f in json("int-payload-conformance/vectors.json")["refusals"].as_array().unwrap().iter().filter(|f| f["capability"] == CAP) {
let (name, want) = (f["name"].as_str().unwrap(), f["code"].as_str().unwrap());
let (p, set) = (read(f["payload"].as_str().unwrap()), read(f["set"]["model.wam"].as_str().unwrap()));
let params = wai::int_payload::resolve(CAP, None, &[wai::pin::HeldBytes::File(&set)], None).expect("an unpinned set resolves");
let sink = wai::int_payload::decode_int(CAP, &p, &params).map(|_| ()).map_err(|e| e.code());
assert_eq!(sink, Err(want), "{name}: the sink's code");
if f["layer"] == "decode" {
let m = AudioModel::from_bytes(&set).unwrap();
let a = wai::int_wire::parse_wia1(&p).unwrap_or_else(|e| panic!("{name}: a decode fixture parses: {e:?}"));
let ops = int_audio::ops::decode_typed(&m, &stream(&a)).err().map(code_of);
let direct = int_audio::legacy::decode_typed(&m, &stream(&a)).err().map(code_of);
assert_eq!((ops, direct), (Some(want), Some(want)), "{name}: through the lowering, then directly");
}
n += 1;
}
assert!(n >= 14, "the committed audio fixtures: {n}");
}
/// Gate 3, beside the committed fixtures: a fixture for each refusal the direct decode
/// makes (integer-payloads §5 and §7, in their order), each made from the committed set
/// and clip by one change. Each is refused by both decodes with the same code; the code
/// it states is integer-payloads §8's for that rule. The committed set and clip decode.
#[test]
fn every_refusal_of_the_direct_decode_is_refused_alike_through_the_lowering() {
use int_audio::ALayer;
let (m, base) = (model(|_| {}), Owned::committed());
assert!(int_audio::ops::decode_typed(&m, &base.st()).is_ok(), "the fixtures' base decodes");
let same = || model(|_| {});
let last = |m: &mut AudioModel| m.layers.len() - 1;
let fixtures: Vec<(&str, &str, AudioModel, Owned)> = vec![
("the set's afrac of 0", "model_mismatch", model(|m| m.afrac = 0), clip(|_| {})),
("the set's afrac of 31", "model_mismatch", model(|m| m.afrac = 31), clip(|_| {})),
("a clip afrac not the set's", "model_mismatch", same(), clip(|o| o.afrac = 11)),
("no latent channels", "field_range", same(), clip(|o| o.n_ch = 0)),
("a latent length of 0", "field_range", same(), clip(|o| o.lat_len = 0)),
("a t_out of 0", "field_range", same(), clip(|o| o.t_out = 0)),
("a median short", "field_range", same(), clip(|o| { o.median_q.pop(); })),
("a table short", "field_range", same(), clip(|o| { o.cdfs.pop(); })),
("a median past 2^47", "field_range", same(), clip(|o| o.median_q[3] = -(1 << 47) - 1)),
("a table that does not end at 2^16", "cdf_malformed", same(), clip(|o| *o.cdfs[2].last_mut().unwrap() = 65535)),
("a table of another length", "cdf_malformed", same(), clip(|o| { o.cdfs[5].pop(); *o.cdfs[5].last_mut().unwrap() = 1 << 16; })),
("a latent past 2^26", "too_large", same(), clip(|o| o.lat_len = 1 << 23)),
("a t_out past 2^26", "too_large", same(), clip(|o| o.t_out = (1 << 26) + 1)),
("an uncropped buffer past 2^26", "too_large", same(), clip(|o| (o.lat_len, o.t_out) = (1 << 22, 1 << 25))),
("a layer's bias short", "model_mismatch", model(|m| {
if let ALayer::ConvT1d { bias, .. } = &mut m.layers[0] { bias.pop(); }
}), clip(|_| {})),
("a stride of 0", "model_mismatch", model(|m| {
if let ALayer::ConvT1d { stride, .. } = &mut m.layers[2] { *stride = 0; }
}), clip(|_| {})),
("an inverse GDN short of a beta", "model_mismatch", model(|m| {
if let ALayer::Igdn { beta, .. } = &mut m.layers[1] { beta.pop(); }
}), clip(|_| {})),
("padding that leaves no output", "model_mismatch", model(|m| {
let l = last(m);
if let ALayer::ConvT1d { pad, .. } = &mut m.layers[l] { *pad = 1 << 20; }
}), clip(|_| {})),
("a synthesis of 16 channels", "model_mismatch", model(|m| { m.layers.pop(); }), clip(|_| {})),
("a t_out past the synthesis", "geometry_mismatch", same(), clip(|o| o.t_out += 1)),
("a latent longer than t_out needs", "geometry_mismatch", same(), clip(|o| o.t_out -= 512)),
("a stream too short to be one", "field_range", same(), clip(|o| o.rans.truncate(4))),
("a stream that runs out", "stream_exhausted", same(), clip(|o| { let n = o.rans.len() / 2; o.rans.truncate(n - n % 4); })),
("a word left unread", "stream_noncanonical", same(), clip(|o| o.rans.extend([0, 0, 0, 0]))),
("every latent past layer 0's range", "field_range", same(), clip(|o| o.median_q.iter_mut().for_each(|m| *m = 1 << 47))),
("every latent below it", "field_range", same(), clip(|o| o.median_q.iter_mut().for_each(|m| *m = -(1 << 47)))),
];
for (what, want, m, o) in &fixtures {
let (ops, direct) = both(m, o);
assert_eq!((ops.err(), direct.err()), (Some(*want), Some(*want)), "{what}: through the lowering, then directly");
}
}
/// Gate 3, at the edge of every `check` range of the committed set: for each of its
/// layers, a network of that layer alone (with the set's header), followed by a
/// transposed convolution to one channel whose weights and bias are 0 (whose own range
/// is all of `i64`), decodes a clip whose latents all lie in `[−X_ℓ, X_ℓ]`, with one
/// channel at `X_ℓ` (or `−X_ℓ`), to the same samples both ways, and refuses one at
/// `X_ℓ + 1` (or `−X_ℓ − 1`) both ways (`field_range`), where `X_ℓ` is tensor `ℓ`'s
/// range in the committed graph. And the PCM step's range: a network adding a bias to
/// its one channel decodes a sample at the top of the range in which
/// `v·32767 + 2^(afrac−1)` fits `i64`, and the bottom, and refuses one past each, both
/// ways.
#[test]
fn every_check_range_refuses_exactly_what_the_direct_decode_refuses() {
use int_audio::ALayer;
let full = wai_ops::lower::wam1(&read(SET)).unwrap();
let n = AudioModel::from_bytes(&read(SET)).unwrap().layers.len();
for l in 0..n {
let one = model(|m| {
let layer = m.layers.swap_remove(l);
let c = match &layer {
ALayer::ConvT1d { out_ch, .. } => *out_ch,
ALayer::Igdn { c, .. } => *c,
};
m.layers = vec![layer, ALayer::ConvT1d { out_ch: 1, k: 1, stride: 1, pad: 0, opad: 0, weight: vec![0; c], mult: vec![1], bias: vec![0] }];
});
let g = wai_ops::lower::wam1_net(&int_audio::ops::wam1_net(&one).unwrap()).unwrap();
let (c, x) = (g.tensors[0].channels as usize, g.tensors[0].hi);
assert_eq!((g.tensors[0].lo, x), (full.tensors[l].lo, full.tensors[l].hi), "layer {l}: the range of tensor {l}");
// The clip's length: the layer's output length on 4 latents.
let t = match &one.layers[0] {
ALayer::ConvT1d { k, stride, pad, opad, .. } => 3 * stride + k + opad - 2 * pad,
ALayer::Igdn { .. } => 4,
};
let at = |v: i64| {
let mut vals = vec![0i64; c];
vals[c / 2] = v;
Owned::constant(&vals, 4, t)
};
for v in [x, -x] {
let (ops, direct) = both(&one, &at(v));
assert!(ops.is_ok() && ops == direct, "layer {l}: at {v}: {ops:?} through the lowering, {direct:?} directly");
}
for v in [x + 1, -x - 1] {
assert_eq!(both(&one, &at(v)), (Err("field_range"), Err("field_range")), "layer {l}: one past the range, {v}");
}
}
// The PCM step: one channel plus a bias.
let lo = -((1i128 << 63) / 32767) as i64;
let hi = ((i64::MAX as i128 - (1 << 11)) / 32767) as i64;
let add = |b: i64| AudioModel {
afrac: 12, gf: 16, shift: 0,
layers: vec![ALayer::ConvT1d { out_ch: 1, k: 1, stride: 1, pad: 0, opad: 0, weight: vec![1], mult: vec![1], bias: vec![b] }],
};
let one = Owned::constant(&[5 << 12], 4, 4);
for (b, ok) in [(hi - (5 << 12), Ok(vec![32767; 4])), (lo - (5 << 12), Ok(vec![-32768; 4])), (hi - (5 << 12) + 1, Err("field_range")), (lo - (5 << 12) - 1, Err("field_range"))] {
let (ops, direct) = both(&add(b), &one);
assert_eq!((&ops, &direct), (&ok, &ok), "a sample at {}", 5 * 4096 + b);
}
}
/// Gate 5 of the migration, the whole-decoder half: the decode through the lowering
/// under the reference kernels (the interpreter computes every operator) and under each
/// fast policy (the transposed convolutions on this crate's fast kernels, serial and
/// threaded) gives the same samples, and the same refusals, on every committed vector,
/// as `WIA1` and as its JSON form, and on clips with a channel moved to the input's
/// check range and one past it, at each end. The per-operator half is `int_ops`'
/// equivalence tests, one of which counts the fast kernel's runs on this set.
#[test]
fn every_kernel_policy_decodes_through_the_lowering_alike() {
use wai::int_kernels::{with_policy, Policy};
static POLICIES: std::sync::LazyLock<Vec<Policy>> = std::sync::LazyLock::new(wai::int_kernels::equivalence_policies);
let m = model(|_| {});
let x0 = wai_ops::lower::wam1(&read(SET)).unwrap().tensors[0].hi;
let at = |t: i64| clip(move |o| o.median_q[1] = t - ((o.offset as i64) << o.afrac));
let j = AudioJson::from_value(&json("wai-rs/tests/vectors/int_audio/audio_bitstream.json")).unwrap();
let mut clips: Vec<(String, Owned)> = vec![
("WIA1".into(), Owned::committed()),
("JSON".into(), Owned {
afrac: j.afrac, n_ch: j.n_ch, lat_len: j.lat_len, t_out: j.t_out, offset: j.offset,
median_q: j.median_q.clone(), cdfs: j.cdfs.clone(), rans: j.rans.clone(),
}),
];
for (what, t) in [("channel 1's median at X_0", x0), ("at X_0 + 1", x0 + 1), ("at -X_0", -x0), ("at -X_0 - 1", -x0 - 1)] {
clips.push((what.into(), at(t)));
}
for (k, (what, o)) in clips.iter().enumerate() {
let want = with_policy(POLICIES[0], || int_audio::ops::decode_typed(&m, &o.st())).map_err(code_of);
assert!(k >= 2 || want.is_ok(), "{what}: the committed form decodes");
for pol in &POLICIES[1..] {
let got = with_policy(*pol, || int_audio::ops::decode_typed(&m, &o.st())).map_err(code_of);
assert!(got == want, "{what}: {pol:?} differs from the interpreter alone");
}
}
}
/// The committed `wai.audio.int_codec` sets and payloads, relative to `wai/`: every set
/// and payload `int-payload-conformance/vectors.json` names for the capability (its
/// vectors and its refusal fixtures), and every base of a staged case decoded through
/// the capability, with the set its case names and the payload its envelope carries.
/// Returns `(set, (where, payload))` pairs.
fn committed_sets_and_payloads() -> Vec<(String, (String, Vec<u8>))> {
let mut v = Vec::new();
let index = json("int-payload-conformance/vectors.json");
for e in index["vectors"].as_array().unwrap().iter().chain(index["refusals"].as_array().unwrap()) {
if e["capability"] == CAP {
let (set, p) = (e["set"]["model.wam"].as_str().unwrap(), e["payload"].as_str().unwrap());
v.push((set.to_string(), (p.to_string(), read(p))));
}
}
let cases = wai().join("staged-conformance/cases");
let mut dirs: Vec<_> = std::fs::read_dir(&cases).unwrap().filter_map(|e| e.ok()).map(|e| e.path()).collect();
dirs.sort();
for d in dirs {
let Ok(b) = std::fs::read(d.join("case.json")) else { continue };
let case: Value = serde_json::from_slice(&b).unwrap();
for base in case["bases"].as_array().into_iter().flatten().filter(|b| b["decoded_via"] == CAP) {
let f = d.join(base["file"].as_str().unwrap());
let env = wai::container::Wai::from_bytes(&std::fs::read(&f).unwrap()).unwrap();
assert_eq!(env.manifest.model_requirement.capability, CAP, "{}", f.display());
v.push((base["decode"]["set"]["model.wam"].as_str().unwrap().to_string(), (f.display().to_string(), env.payload)));
}
}
v
}
/// The scan for the load rules the switch brings (integer-operators §15.3 item 3): no
/// committed set or payload is affected. Every committed audio set (the one the
/// payloads decode against, and the synthetic one of `ops-conformance/sets/`) has
/// layers, header shifts under 128, no bias of magnitude `2^63 − 1` or more, and lowers
/// and loads under `acc64`, its PCM step's range included; every committed payload that
/// the direct decode decodes decodes through the lowering to the same samples, and every
/// one it refuses is refused with the same code. (These are the files that carry a `WIA1`
/// payload or name the capability's set; `WIA1` appears in no other committed payload or
/// envelope.)
#[test]
fn the_new_load_rules_affect_no_committed_set_or_payload() {
use wai_ops::lower::NetLayer as N;
let all = committed_sets_and_payloads();
let mut sets: Vec<String> = all.iter().map(|(s, _)| s.clone()).collect();
sets.extend(indexed().into_iter().map(|s| s.2));
sets.sort_unstable();
sets.dedup();
for set in &sets {
let bytes = read(set);
let net = wai_ops::lower::parse_wam1(&bytes).unwrap_or_else(|r| panic!("{set}: {r:?}"));
assert!(!net.layers.is_empty(), "{set}: no layers");
assert!(net.shift < 128 && net.gf < 128, "{set}: a header shift of 128 or more");
for l in &net.layers {
if let N::ConvT { bias, .. } = l {
assert!(bias.iter().all(|b| b.unsigned_abs() < i64::MAX as u64), "{set}: a bias of magnitude 2^63 - 1 or more");
}
}
let g = wai_ops::lower::wam1(&bytes).unwrap_or_else(|r| panic!("{set}: does not lower: {r:?}"));
assert!(wai::int_ops::load(&g).is_ok(), "{set}: does not load under acc64");
}
let (mut decoded, mut refused) = (0, 0);
for (set, (at, p)) in &all {
let m = AudioModel::from_bytes(&read(set)).unwrap();
let Ok(a) = wai::int_wire::parse_wia1(p) else {
refused += 1;
continue;
};
let ops = int_audio::ops::decode_typed(&m, &stream(&a)).map_err(code_of);
let direct = int_audio::legacy::decode_typed(&m, &stream(&a)).map_err(code_of);
assert!(ops == direct, "{at}: the decode through the lowering differs from the direct decode");
if ops.is_ok() { decoded += 1 } else { refused += 1 }
}
assert_eq!(sets.len(), 2, "the committed audio sets: {sets:?}");
assert!(decoded >= 2 && refused >= 14, "the committed audio payloads, at least those of this revision: {decoded} decoded, {refused} refused");
}