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
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]>
439 lines
21 KiB
Rust
439 lines
21 KiB
Rust
// wai-conformance: int-kernels int-kernels-amd
|
||
//! `WIR1` (`wai.{image,video,audio,splat}.int_refine`, staged-delivery Appendix A)
|
||
//! through the integer operator set: the stage operators of
|
||
//! `extensions/integer-operators.md` §13.5, E1 `rans64_decode`, E11 `up2_predict`, E12
|
||
//! `rate_predict` and E9 `residual_step`, with no graph.
|
||
//!
|
||
//! A layer runs no network, so it has no lowering and no bounds certificate. What it has
|
||
//! is its **stage form** (`staged::wir1::ops::stages`): the operands its decode hands
|
||
//! each stage operator. The operators' own conformance vectors are
|
||
//! `ops-conformance/stage/`, which `wai-verify vectors verify` and the independent
|
||
//! checker (`tools/wai_ops_check.py`) reproduce byte for byte.
|
||
#![cfg(all(feature = "staged", feature = "legacy_int"))]
|
||
|
||
use std::collections::BTreeSet;
|
||
use std::path::{Path, PathBuf};
|
||
|
||
use serde_json::Value;
|
||
use wai::staged::wir1::{self, ops, Below, Predictor, RefineParams, UnitKind};
|
||
use wai_ops::stage::rans64::{self, End, Escape, TableRule};
|
||
|
||
fn wai() -> PathBuf {
|
||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
|
||
}
|
||
|
||
fn read(p: &Path) -> Vec<u8> {
|
||
std::fs::read(p).unwrap_or_else(|e| panic!("{}: {e}", p.display()))
|
||
}
|
||
|
||
/// A `WAI1` envelope's capability and payload.
|
||
fn envelope(env: &[u8]) -> Option<(String, Vec<u8>)> {
|
||
if env.get(..4)? != b"WAI1" {
|
||
return None;
|
||
}
|
||
let ml = u32::from_le_bytes(env.get(4..8)?.try_into().ok()?) as usize;
|
||
let man: Value = serde_json::from_slice(env.get(8..8 + ml)?).ok()?;
|
||
let at = 8 + ml;
|
||
let pl = u32::from_le_bytes(env.get(at..at + 4)?.try_into().ok()?) as usize;
|
||
let cap = man["model_requirement"]["capability"].as_str()?.to_string();
|
||
Some((cap, env.get(at + 4..at + 4 + pl)?.to_vec()))
|
||
}
|
||
|
||
/// Every committed `WIR1` layer of the staged corpus that its parser admits, with its
|
||
/// name and unit kind. (The corpus also commits layers each parse refuses, for the
|
||
/// codes they carry; those are the refusal fixtures of the later gates.)
|
||
fn committed() -> Vec<(String, UnitKind, Vec<u8>)> {
|
||
let cases = wai().join("staged-conformance/cases");
|
||
let mut dirs: Vec<_> = std::fs::read_dir(&cases).unwrap().map(|e| e.unwrap().path()).collect();
|
||
dirs.sort();
|
||
let mut out = Vec::new();
|
||
for d in dirs {
|
||
let mut files: Vec<_> = std::fs::read_dir(&d).unwrap().map(|e| e.unwrap().path()).filter(|p| p.extension().is_some_and(|x| x == "wai")).collect();
|
||
files.sort();
|
||
for f in files {
|
||
let Some((cap, p)) = envelope(&read(&f)) else { continue };
|
||
let Some(kind) = wai::staged::unit_kind(&cap) else { continue };
|
||
if p.starts_with(b"WIR1") && wir1::parse(&p, kind).is_ok() {
|
||
out.push((format!("{}/{}", d.file_name().unwrap().to_string_lossy(), f.file_name().unwrap().to_string_lossy()), kind, p));
|
||
}
|
||
}
|
||
}
|
||
out
|
||
}
|
||
|
||
/// E9's 32-bit form holds on `[lo, hi]` (§5E E9, *Width*): `hi − lo ≤ 65535`, and
|
||
/// `lo − 131070` and `hi + 131070` fit `i32`.
|
||
fn e9_width_holds((lo, hi): (i64, i64)) -> bool {
|
||
lo < hi && hi - lo <= 65535 && lo - 131070 >= i32::MIN as i64 && hi + 131070 <= i32::MAX as i64
|
||
}
|
||
|
||
/// Gate 1. Every committed layer has its stage form, and the form is the payload's:
|
||
/// E1's modes `t4097`, `lenient`, `canonical`, every table one E1 admits, and the
|
||
/// layer's offset; the prediction its predictor names (identity, E11 for up2, E12 for
|
||
/// rate at the layer's rates); E9's step is `q` on the unit kind's range, `[0, 255]` or
|
||
/// `[−32768, 32767]`, on both of which E9's 32-bit form holds. The committed layers
|
||
/// reach every unit kind and every predictor.
|
||
#[test]
|
||
fn every_committed_layer_has_its_stage_form() {
|
||
assert_eq!((ops::MODES.table, ops::MODES.escape, ops::MODES.end), (TableRule::T4097, Escape::Lenient, End::Canonical));
|
||
assert_eq!((ops::range(UnitKind::Rgb8), ops::range(UnitKind::Attr), ops::range(UnitKind::Pcm)), ((0, 255), (0, 255), (-32768, 32767)));
|
||
let all = committed();
|
||
let mut seen = BTreeSet::new();
|
||
for (name, kind, p) in &all {
|
||
let w = wir1::parse(p, *kind).unwrap();
|
||
let f = ops::stages(&w).unwrap_or_else(|e| panic!("{name}: {e}"));
|
||
for t in 0..w.n_tables() {
|
||
assert!(rans64::table_ok(w.table(t), TableRule::T4097), "{name}: table {t}");
|
||
}
|
||
assert_eq!(f.offset, w.offset as i64, "{name}: E1's offset");
|
||
assert_eq!(f.q, w.q as i64, "{name}: E9's step");
|
||
assert_eq!(f.range, ops::range(*kind), "{name}: E9's range");
|
||
assert!(e9_width_holds(f.range), "{name}: E9's 32-bit form holds on {:?}", f.range);
|
||
let want = match w.predictor {
|
||
Predictor::Identity => ops::Prediction::Identity,
|
||
Predictor::Up2 => ops::Prediction::Up2,
|
||
Predictor::Rate => ops::Prediction::Rate { num: w.rate_num, den: w.rate_den },
|
||
};
|
||
assert_eq!(f.prediction, want, "{name}: the prediction");
|
||
seen.insert(format!("{kind:?}/{}", w.predictor.token()));
|
||
}
|
||
let want: BTreeSet<String> = ["Attr/identity", "Pcm/identity", "Pcm/rate", "Rgb8/identity", "Rgb8/up2"].iter().map(|s| s.to_string()).collect();
|
||
assert_eq!(seen, want, "the committed layers reach every unit kind and predictor");
|
||
println!("{} committed WIR1 layers, each with its stage form", all.len());
|
||
}
|
||
|
||
/// Gate 1. E1's table rule `t4097` is `WIR1`'s: the parser admits a table exactly when
|
||
/// E1 does, on a coded layer's table and on each rule broken once; and the stage form
|
||
/// refuses a table E1 refuses.
|
||
#[test]
|
||
fn e1s_table_rule_is_the_payloads() {
|
||
let below: Vec<u8> = (0..4 * 4 * 3).map(|i| (i * 5) as u8).collect();
|
||
let target: Vec<u8> = (0..4 * 4 * 3).map(|i| (i * 7 % 251) as u8).collect();
|
||
let p = RefineParams { q: 3, predictor: Predictor::Identity, rate: (0, 0), table_per_unit: false, max_symbols: 4095 };
|
||
let (ok, _) = wir1::encode(UnitKind::Rgb8, &[Below::U8(&below)], (4, 4, 3), &[Below::U8(&target)], (4, 4, 3), &p).unwrap();
|
||
let w = wir1::parse(&ok, UnitKind::Rgb8).unwrap();
|
||
let n = w.cdf_len;
|
||
let t = |payload: &[u8], k: usize| i32::from_le_bytes(payload[44 + 4 * k..48 + 4 * k].try_into().unwrap());
|
||
let set = |payload: &mut Vec<u8>, k: usize, v: i32| payload[44 + 4 * k..48 + 4 * k].copy_from_slice(&v.to_le_bytes());
|
||
let mut cases: Vec<(&str, Vec<u8>)> = vec![("the coded table", ok.clone())];
|
||
let mut c = ok.clone();
|
||
set(&mut c, 0, 1);
|
||
cases.push(("a first entry of 1", c));
|
||
let mut c = ok.clone();
|
||
set(&mut c, n - 1, 65535);
|
||
cases.push(("a last entry of 65535", c));
|
||
let mut c = ok.clone();
|
||
set(&mut c, n - 1, 65537);
|
||
cases.push(("a last entry of 65537", c));
|
||
let mut c = ok.clone();
|
||
let v1 = t(&c, 1);
|
||
set(&mut c, 2, v1);
|
||
cases.push(("two equal entries", c));
|
||
let mut c = ok.clone();
|
||
let (v1, v2) = (t(&c, 1), t(&c, 2));
|
||
set(&mut c, 1, v2);
|
||
set(&mut c, 2, v1);
|
||
cases.push(("a decrease", c));
|
||
for (what, payload) in cases {
|
||
let table: Vec<i32> = (0..n).map(|k| t(&payload, k)).collect();
|
||
let e1 = rans64::table_ok(&table, TableRule::T4097);
|
||
let parsed = wir1::parse(&payload, UnitKind::Rgb8);
|
||
assert_eq!(parsed.is_ok(), e1, "{what}: the parser and E1 disagree");
|
||
match parsed {
|
||
Ok(w) => assert!(ops::stages(&w).is_ok(), "{what}"),
|
||
Err(e) => assert_eq!(e.code(), "cdf_malformed", "{what}"),
|
||
}
|
||
}
|
||
// Lengths: the header's cdf_len is 3..=4097 (field_range past it), E1's t4097 too.
|
||
for (len, admits) in [(2usize, false), (3, true), (4097, true), (4098, false)] {
|
||
let cdf: Vec<i32> = (0..len).map(|k| if k + 1 == len { 65536 } else { k as i32 }).collect();
|
||
assert_eq!(rans64::table_ok(&cdf, TableRule::T4097), admits, "{len} entries");
|
||
assert_eq!((wir1::CDF_LEN_MIN..=wir1::CDF_LEN_MAX).contains(&len), admits, "{len} entries: the header's bound");
|
||
}
|
||
}
|
||
|
||
/// Gate 1. The operators' conformance vectors cover what this stage form uses: E1 under
|
||
/// `t4097`, `lenient` and `canonical`; E11 and E12; E9 on both ranges, at `r = ±R` and
|
||
/// `±(R + 1)`.
|
||
#[test]
|
||
fn the_stage_vectors_cover_the_stage_form() {
|
||
let lines = |op: &str| -> Vec<Value> {
|
||
let t = String::from_utf8(read(&wai().join(format!("ops-conformance/stage/{op}.jsonl")))).unwrap();
|
||
t.lines().map(|l| serde_json::from_str(l).unwrap()).collect()
|
||
};
|
||
let e1 = lines("rans64_decode");
|
||
assert!(e1.iter().any(|v| v["modes"]["table"] == "t4097" && v["modes"]["escape"] == "lenient" && v["modes"]["end"] == "canonical"));
|
||
assert!(!lines("up2_predict").is_empty() && !lines("rate_predict").is_empty(), "E11 and E12");
|
||
let e9 = lines("residual_step");
|
||
for (lo, hi) in [(0i64, 255i64), (-32768, 32767)] {
|
||
let on: Vec<&Value> = e9.iter().filter(|v| v["in"]["lo"] == lo.to_string().as_str() && v["in"]["hi"] == hi.to_string().as_str()).collect();
|
||
let at = |k: i64| on.iter().any(|v| {
|
||
let q: i64 = v["in"]["q"].as_str().unwrap().parse().unwrap();
|
||
let r: i64 = v["in"]["r"].as_str().unwrap().parse().unwrap();
|
||
let big_r = (hi - lo) / q + 1;
|
||
r == k * big_r || r == k * (big_r + 1)
|
||
});
|
||
assert!(at(1) && at(-1), "E9 on [{lo}, {hi}] at ±R and ±(R + 1)");
|
||
}
|
||
}
|
||
|
||
/// A unit's current output for `w`'s predictor: the shape it reads (for rate, the
|
||
/// fewest source samples whose length `⌊n′·rate_num/rate_den⌋` is `d0`, if any), filled
|
||
/// with a fixed pattern that reaches both ends of the element range.
|
||
fn below_for(w: &wir1::Wir1, seed: u64) -> Option<((u32, u32, u32), Buf)> {
|
||
let shape = match w.predictor {
|
||
Predictor::Identity => (w.d0, w.d1, w.d2),
|
||
Predictor::Up2 => (w.d0.div_ceil(2), w.d1.div_ceil(2), w.d2),
|
||
Predictor::Rate => {
|
||
let (num, den) = (w.rate_num as u64, w.rate_den as u64);
|
||
let mut n = (w.d0 as u64 * den).div_ceil(num).max(1);
|
||
while n * num / den < w.d0 as u64 {
|
||
n += 1;
|
||
}
|
||
if n * num / den != w.d0 as u64 || n > u32::MAX as u64 {
|
||
return None;
|
||
}
|
||
(n as u32, 1, w.d2)
|
||
}
|
||
};
|
||
if !w.accepts_below(shape) {
|
||
return None;
|
||
}
|
||
let len = shape.0 as u64 * shape.1 as u64 * shape.2 as u64;
|
||
let at = |i: u64| -> u64 { (i.wrapping_add(seed)).wrapping_mul(0x9E37_79B9_7F4A_7C15) >> 17 };
|
||
Some((shape, match w.kind {
|
||
UnitKind::Pcm => Buf::I16((0..len).map(|i| match i % 23 { 0 => i16::MIN, 1 => i16::MAX, _ => at(i) as i16 }).collect()),
|
||
_ => Buf::U8((0..len).map(|i| match i % 23 { 0 => 0, 1 => 255, _ => at(i) as u8 }).collect()),
|
||
}))
|
||
}
|
||
|
||
/// Where two decodes of a unit first differ: the element index, or the refusals.
|
||
fn first_difference(a: &Result<wir1::Next, wir1::Wir1Error>, b: &Result<wir1::Next, wir1::Wir1Error>) -> String {
|
||
let wide = |n: &wir1::Next| -> Vec<i64> {
|
||
match n {
|
||
wir1::Next::U8(v) => v.iter().map(|&x| x as i64).collect(),
|
||
wir1::Next::I16(v) => v.iter().map(|&x| x as i64).collect(),
|
||
}
|
||
};
|
||
match (a, b) {
|
||
(Ok(x), Ok(y)) => {
|
||
let (x, y) = (wide(x), wide(y));
|
||
match x.iter().zip(&y).position(|(p, q)| p != q) {
|
||
Some(i) => format!("element {i}: {} through the operator set, {} directly", x[i], y[i]),
|
||
None => format!("lengths {} and {}", x.len(), y.len()),
|
||
}
|
||
}
|
||
_ => format!("{:?} and {:?}", a.as_ref().err(), b.as_ref().err()),
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||
enum Buf {
|
||
U8(Vec<u8>),
|
||
I16(Vec<i16>),
|
||
}
|
||
|
||
impl Buf {
|
||
fn below(&self) -> Below<'_> {
|
||
match self {
|
||
Buf::U8(v) => Below::U8(v),
|
||
Buf::I16(v) => Below::I16(v),
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Gate 2: golden equality. Every committed `WIR1` layer, every one of its units, decodes
|
||
/// through the stage operators (`wir1::ops`) to the elements the direct decode
|
||
/// (`wir1::legacy`) gives, over a current output of the shape its predictor reads that
|
||
/// reaches both ends of the element range; and every layer's streams are checked alike.
|
||
/// (The corpus's own stage digests through the operator set are byte-exact-conformance's
|
||
/// `staged_sets_through_the_stage_operators_are_byte_exact` on every leg of the matrix.)
|
||
#[test]
|
||
fn every_committed_layer_applies_through_the_stage_operators_as_directly() {
|
||
let (mut units, mut layers) = (0, 0);
|
||
for (name, kind, p) in committed() {
|
||
let w = wir1::parse(&p, kind).unwrap();
|
||
assert_eq!(ops::check_streams(&w, &p), wir1::legacy::check_streams(&w, &p), "{name}: the streams' check");
|
||
let Some((shape, below)) = below_for(&w, layers as u64) else { continue };
|
||
for u in 0..w.n_units {
|
||
let through = ops::apply_unit(&w, &p, u, below.below(), shape);
|
||
let direct = wir1::legacy::apply_unit(&w, &p, u, below.below(), shape);
|
||
if through != direct {
|
||
panic!("{name} unit {u}: the decode through the stage operators differs from the direct decode, first at {:?}", first_difference(&through, &direct));
|
||
}
|
||
units += 1;
|
||
}
|
||
layers += 1;
|
||
}
|
||
assert!(layers >= 100, "{layers} layers applied");
|
||
println!("{layers} committed layers, {units} units, through the stage operators as directly");
|
||
}
|
||
|
||
/// A one-unit layer coded by the reference encoder: `kind`, `predictor`, over a current
|
||
/// output of `below_shape` toward `dims`.
|
||
fn coded(kind: UnitKind, predictor: Predictor, rate: (u32, u32), below_shape: (u32, u32, u32), dims: (u32, u32, u32)) -> (Vec<u8>, Buf) {
|
||
let n_below = (below_shape.0 * below_shape.1 * below_shape.2) as usize;
|
||
let n = (dims.0 * dims.1 * dims.2) as usize;
|
||
let p = RefineParams { q: 3, predictor, rate, table_per_unit: false, max_symbols: 4095 };
|
||
match kind {
|
||
UnitKind::Pcm => {
|
||
let below: Vec<i16> = (0..n_below).map(|i| ((i * 2654) % 65536) as i16).collect();
|
||
let target: Vec<i16> = (0..n).map(|i| ((i * 7919) % 65536) as i16).collect();
|
||
let (out, _) = wir1::encode(kind, &[Below::I16(&below)], below_shape, &[Below::I16(&target)], dims, &p).unwrap();
|
||
(out, Buf::I16(below))
|
||
}
|
||
_ => {
|
||
let below: Vec<u8> = (0..n_below).map(|i| (i * 5) as u8).collect();
|
||
let target: Vec<u8> = (0..n).map(|i| (i * 7 % 251) as u8).collect();
|
||
let (out, _) = wir1::encode(kind, &[Below::U8(&below)], below_shape, &[Below::U8(&target)], dims, &p).unwrap();
|
||
(out, Buf::U8(below))
|
||
}
|
||
}
|
||
}
|
||
|
||
/// `p`, a one-unit layer of `kind`, with its stream replaced by `s` (its length field
|
||
/// rewritten).
|
||
fn with_stream(kind: UnitKind, p: &[u8], s: &[u8]) -> Vec<u8> {
|
||
let w = wir1::parse(p, kind).unwrap();
|
||
let at = 44 + 4 * w.cdf_len * w.n_tables();
|
||
let mut out = p[..at].to_vec();
|
||
out.extend((s.len() as u32).to_le_bytes());
|
||
out.extend(s);
|
||
out
|
||
}
|
||
|
||
/// Both decodes of unit 0 of `p` refuse alike or decode alike, and so do both checks of
|
||
/// its streams; returns the unit's refusal code, if any.
|
||
fn alike(what: &str, kind: UnitKind, p: &[u8], below: &Buf, shape: (u32, u32, u32)) -> Option<&'static str> {
|
||
let Ok(w) = wir1::parse(p, kind) else { return Some("parse") };
|
||
assert_eq!(ops::check_streams(&w, p), wir1::legacy::check_streams(&w, p), "{what}: the streams' check");
|
||
let through = ops::apply_unit(&w, p, 0, below.below(), shape);
|
||
let direct = wir1::legacy::apply_unit(&w, p, 0, below.below(), shape);
|
||
if through != direct {
|
||
panic!("{what}: through the stage operators and directly differ, {}", first_difference(&through, &direct));
|
||
}
|
||
through.err().map(|e| e.code())
|
||
}
|
||
|
||
/// Gate 3: refusal parity. (a) Every committed layer whose streams are refused (the
|
||
/// corpus's `stream_exhausted` and `stream_noncanonical` cases among them) is refused by
|
||
/// both checks alike, with the same unit and code. (b) A.4 step 1, each rule broken
|
||
/// once for each predictor: both decodes refuse `geometry_mismatch` before any symbol.
|
||
/// (c) A coded layer of each unit kind and predictor, its stream cut at every word, a
|
||
/// word appended, and bytes changed across it: both decode alike or refuse alike, the
|
||
/// streams' check too.
|
||
#[test]
|
||
fn every_refusal_is_the_direct_decodes() {
|
||
// (a)
|
||
let mut refused = std::collections::BTreeMap::new();
|
||
for (name, kind, p) in committed() {
|
||
let w = wir1::parse(&p, kind).unwrap();
|
||
let (through, direct) = (ops::check_streams(&w, &p), wir1::legacy::check_streams(&w, &p));
|
||
assert_eq!(through, direct, "{name}");
|
||
if let Err((_, e)) = through {
|
||
*refused.entry(e.code()).or_insert(0) += 1;
|
||
for case in ["stream_exhausted", "stream_noncanonical"] {
|
||
if name.starts_with(&format!("{case}/")) {
|
||
assert_eq!(e.code(), case, "{name}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
assert!(refused.contains_key("stream_exhausted") && refused.contains_key("stream_noncanonical"), "{refused:?}");
|
||
// (b)
|
||
let layers = [
|
||
(UnitKind::Rgb8, Predictor::Identity, (0, 0), (5, 4, 3), (5, 4, 3)),
|
||
(UnitKind::Rgb8, Predictor::Up2, (0, 0), (3, 2, 3), (5, 4, 3)),
|
||
(UnitKind::Attr, Predictor::Identity, (0, 0), (2, 3, 4), (2, 3, 4)),
|
||
(UnitKind::Pcm, Predictor::Identity, (0, 0), (40, 1, 2), (40, 1, 2)),
|
||
(UnitKind::Pcm, Predictor::Rate, (3, 2), (20, 1, 2), (30, 1, 2)),
|
||
];
|
||
let mut geometry = 0;
|
||
for &(kind, predictor, rate, shape, dims) in &layers {
|
||
let (p, below) = coded(kind, predictor, rate, shape, dims);
|
||
let what = format!("{kind:?} {}", predictor.token());
|
||
assert_eq!(alike(&what, kind, &p, &below, shape), None, "{what}: the coded layer");
|
||
let w = wir1::parse(&p, kind).unwrap();
|
||
let other = match &below {
|
||
Buf::U8(v) => Buf::I16(v.iter().map(|&x| x as i16).collect()),
|
||
Buf::I16(v) => Buf::U8(v.iter().map(|&x| x as u8).collect()),
|
||
};
|
||
let short = match &below {
|
||
Buf::U8(v) => Buf::U8(v[1..].to_vec()),
|
||
Buf::I16(v) => Buf::I16(v[1..].to_vec()),
|
||
};
|
||
let bad_shape = (shape.0 + 1, shape.1, shape.2);
|
||
for (rule, b, s, unit) in [
|
||
("the unit outside the payload", &below, shape, 1u32),
|
||
("the other element type", &other, shape, 0),
|
||
("an element short", &short, shape, 0),
|
||
("a shape the predictor does not read", &below, bad_shape, 0),
|
||
("a shape past u64", &below, (u32::MAX, u32::MAX, u32::MAX), 0),
|
||
] {
|
||
let through = ops::apply_unit(&w, &p, unit, b.below(), s);
|
||
assert_eq!(through, wir1::legacy::apply_unit(&w, &p, unit, b.below(), s), "{what}: {rule}");
|
||
assert_eq!(through.unwrap_err().code(), "geometry_mismatch", "{what}: {rule}");
|
||
geometry += 1;
|
||
}
|
||
}
|
||
// (c)
|
||
let mut n = 0;
|
||
for &(kind, predictor, rate, shape, dims) in &layers {
|
||
let (p, below) = coded(kind, predictor, rate, shape, dims);
|
||
let w = wir1::parse(&p, kind).unwrap();
|
||
let s = w.stream(&p, 0).to_vec();
|
||
let what = format!("{kind:?} {}", predictor.token());
|
||
for cut in (8..s.len()).step_by(4) {
|
||
let r = alike(&format!("{what}: the stream cut to {cut} bytes"), kind, &with_stream(kind, &p, &s[..cut]), &below, shape);
|
||
assert!(r.is_some(), "{what}: the stream cut to {cut} bytes decodes");
|
||
n += 1;
|
||
}
|
||
let mut long = s.clone();
|
||
long.extend([0, 0, 0, 0]);
|
||
assert_eq!(alike(&format!("{what}: a word appended"), kind, &with_stream(kind, &p, &long), &below, shape), Some("stream_noncanonical"));
|
||
for at in 0..s.len() {
|
||
let mut c = s.clone();
|
||
c[at] ^= 1 << (at % 8);
|
||
alike(&format!("{what}: byte {at} changed"), kind, &with_stream(kind, &p, &c), &below, shape);
|
||
n += 1;
|
||
}
|
||
}
|
||
println!("{refused:?} among the committed layers; {geometry} geometry fixtures and {n} changed streams refused alike");
|
||
}
|
||
|
||
/// Gate 5: the 32-bit form. Every committed layer's every unit, over gate 2's current
|
||
/// outputs that reach both ends of the range, and gate 3's coded layers with every byte
|
||
/// of their streams changed, apply with E9 in its 32-bit form (`ops::apply_unit_i32`, the
|
||
/// arithmetic a 32-bit fabric runs) as with the exact form.
|
||
#[cfg(feature = "i32_forms")]
|
||
#[test]
|
||
fn the_32bit_form_applies_every_committed_layer_alike() {
|
||
let mut n = 0;
|
||
for (name, kind, p) in committed() {
|
||
let w = wir1::parse(&p, kind).unwrap();
|
||
let Some((shape, below)) = below_for(&w, n as u64) else { continue };
|
||
for u in 0..w.n_units {
|
||
let (narrow, exact) = (ops::apply_unit_i32(&w, &p, u, below.below(), shape), ops::apply_unit(&w, &p, u, below.below(), shape));
|
||
if narrow != exact {
|
||
panic!("{name} unit {u}: the 32-bit form differs, {}", first_difference(&narrow, &exact));
|
||
}
|
||
n += 1;
|
||
}
|
||
}
|
||
for (kind, predictor, rate, shape, dims) in [
|
||
(UnitKind::Rgb8, Predictor::Up2, (0, 0), (3, 2, 3), (5, 4, 3)),
|
||
(UnitKind::Pcm, Predictor::Rate, (3, 2), (20, 1, 2), (30, 1, 2)),
|
||
] {
|
||
let (p, below) = coded(kind, predictor, rate, shape, dims);
|
||
let s = wir1::parse(&p, kind).unwrap().stream(&p, 0).to_vec();
|
||
for at in 0..s.len() {
|
||
let mut c = s.clone();
|
||
c[at] ^= 1 << (at % 8);
|
||
let q = with_stream(kind, &p, &c);
|
||
let w = wir1::parse(&q, kind).unwrap();
|
||
assert_eq!(ops::apply_unit_i32(&w, &q, 0, below.below(), shape), ops::apply_unit(&w, &q, 0, below.below(), shape), "{kind:?}: byte {at} changed");
|
||
n += 1;
|
||
}
|
||
}
|
||
println!("{n} units through the 32-bit form, each as through the exact form");
|
||
}
|