wai: state what each determinism tier guarantees, and make replicate mean it #103
35 changed files with 2654 additions and 369 deletions
66
.github/workflows/wai-neural-gates.yml
vendored
Normal file
66
.github/workflows/wai-neural-gates.yml
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
name: WAI neural sink gates
|
||||
|
||||
# The neural sink refuses some envelopes before it touches a model: a pinned
|
||||
# prior whose hash does not match the registered model
|
||||
# (ModelRegistry::resolve_checked), and a `replicate` that SPEC §7 does not back
|
||||
# — over a capability whose registry class cannot back it, or with a prior that
|
||||
# is float or absent (decode_envelope_strict). Those refusals live behind the
|
||||
# `neural` feature, which wai-conformance does not build, and the tests that
|
||||
# exercise them need no model, so wai-neural-e2e's reference filter never selects
|
||||
# them. This job runs exactly those tests and fails if any of them is not run:
|
||||
# a filter that matches nothing reports "0 passed" and exits 0.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'wai/wai-rs/src/neural/**'
|
||||
- 'wai/wai-rs/src/container.rs'
|
||||
- 'wai/wai-rs/src/codecs/mod.rs'
|
||||
- 'wai/wai-rs/tests/neural_native_decode.rs'
|
||||
- 'wai/wai-rs/Cargo.toml'
|
||||
- 'wai/wai-rs/Cargo.lock'
|
||||
- '.github/workflows/wai-neural-gates.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'wai/wai-rs/src/neural/**'
|
||||
- 'wai/wai-rs/src/container.rs'
|
||||
- 'wai/wai-rs/src/codecs/mod.rs'
|
||||
- 'wai/wai-rs/tests/neural_native_decode.rs'
|
||||
- 'wai/wai-rs/Cargo.toml'
|
||||
- 'wai/wai-rs/Cargo.lock'
|
||||
- '.github/workflows/wai-neural-gates.yml'
|
||||
|
||||
jobs:
|
||||
neural-gates:
|
||||
name: model-free refusals of the neural sink
|
||||
runs-on: linux
|
||||
# The ONNX Runtime binary the `ort` crate downloads needs glibc 2.38 and a
|
||||
# GCC 13 libstdc++ at link time (`__isoc23_strtol`, `_M_replace_cold`). The
|
||||
# `linux` label's default image is Ubuntu 22.04 (glibc 2.35, GCC 11), where
|
||||
# the `neural` test binary fails to link, so this job runs in the 24.04 image.
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
# Bootstrap rustup: the docker runner image ships no Rust.
|
||||
- name: Install Rust 1.98.0
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
command -v rustup >/dev/null 2>&1 || \
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
|
||||
rustup toolchain install 1.98.0 --profile minimal
|
||||
rustup default 1.98.0
|
||||
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||
- name: Prior-hash refusal and the strict replicate gate
|
||||
working-directory: wai/wai-rs
|
||||
shell: bash
|
||||
# --no-default-features: `neural` needs only `ort`, not the C codec chain.
|
||||
# --exact: each name selects one test. The count check turns a renamed or
|
||||
# removed test into a failure instead of a silent "0 passed".
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cargo test --no-default-features --features neural --test neural_native_decode -- \
|
||||
--exact resolve_checked_verifies_prior_hash strict_decode_gates_unsound_replicate \
|
||||
2>&1 | tee "$RUNNER_TEMP/neural-gates.log"
|
||||
grep -q "test result: ok. 2 passed; 0 failed" "$RUNNER_TEMP/neural-gates.log"
|
||||
189
wai/CHANGELOG.md
189
wai/CHANGELOG.md
|
|
@ -53,13 +53,188 @@ wire format may change and such changes are recorded here.
|
|||
- New [`extensions/determinism-tiers.md`]: names the two guarantees a neural
|
||||
capability can make, so a manifest can declare which it satisfies and a verifier
|
||||
knows what it may check. `entropy-consistency` — the entropy decode reproduces
|
||||
across devices (integer entropy arithmetic or explicit parameter transmission),
|
||||
the guarantee the base learned-codec standards make (JPEG AI's normative
|
||||
conformance point is the entropy-decoder output) and the mainstream cross-platform
|
||||
fix; the floor for a sound neural `replicate`. `decode-equivalence` — the whole
|
||||
decode to the final medium reproduces, so the rendered result has a portable hash,
|
||||
the tier WAI adds on top and the precondition for a hard reconstruction binding.
|
||||
Referenced from SPEC §7 (Replicate-soundness); framed self-referentially.
|
||||
across devices (integer entropy arithmetic or explicit parameter transmission);
|
||||
JPEG AI sets its bit-exact conformance point at this tier (the entropy-decoder
|
||||
output). `decode-equivalence` — the whole decode to the final medium reproduces
|
||||
on every conforming sink, so the rendered result has a portable hash; WAI's
|
||||
integer capabilities are registered at this tier, and it is the precondition for
|
||||
a hard reconstruction binding. Referenced from SPEC §7 (Replicate-soundness);
|
||||
framed self-referentially.
|
||||
- Normative: over a neural capability, `intent = replicate` promises
|
||||
`decode-equivalence` (SPEC §3, §7; standard codecs, below). The
|
||||
first version of the extension called `entropy-consistency` the floor for a
|
||||
sound neural `replicate`, and SPEC §7 said the same in its closing paragraph
|
||||
while requiring an integer decode path in its rule. Resolved: a neural
|
||||
capability backs `replicate` only if it is registered at `decode-equivalence`,
|
||||
which §7 admits only by the integer construction; `entropy-consistency` MUST NOT
|
||||
back it, and neither may a reconstruction that one implementation pins through
|
||||
fixed-order float stages. A tier is a property of the capability as registered,
|
||||
not of one implementation.
|
||||
- **Downgrade: `wai.image.jpegai` is registered at `entropy-consistency`, not
|
||||
`decode-equivalence`, and no longer backs `replicate`.** Its registry class
|
||||
moves from `StandardDefined` to the new `NeuralEntropyExact` (integer entropy
|
||||
decode, float later stages). Its decode has float stages and a float ONNX
|
||||
fallback, so decode-equivalence never held as a property of the capability, and
|
||||
`StandardDefined` ("the neural float hazard does not apply") did not describe it.
|
||||
What the exact decoder does is unchanged — one pinned reconstruction, reproducible
|
||||
across machines under the conditions in the extension's §5 — and is now stated as
|
||||
a property of that decoder. A reconstruction binding over `wai.image.jpegai` is
|
||||
checkable only with that decoder (reconstruction-binding §2). Earlier entries
|
||||
below that call the JPEG AI decode decode-equivalent, or byte-identical on every
|
||||
machine, are superseded by this one.
|
||||
- **`replicate` over a standard codec promises the named standard's decoder
|
||||
conformance, not byte identity across sinks.** The first form of this change
|
||||
stated in SPEC §3 that `replicate` promises the same bytes on every conforming
|
||||
sink, while every standard codec stayed `StandardDefined` and passed the rule —
|
||||
including codecs whose standard conforms decoders to a bound around a reference
|
||||
(RFC 6716 §6 holds an Opus decoder to `opus_compare` thresholds, not to
|
||||
identical output). SPEC §3 and §7 now state the promise per registry class, and
|
||||
two classes are added:
|
||||
- `StandardTolerance` — the named standard holds decoders to a criterion around
|
||||
a reference: `wai.audio.opus`, `wai.image.jpeg`, `wai.image.jxl`,
|
||||
`wai.image.jp2`, `wai.video.j2k`, `wai.video.av1`, `wai.video.av1.lossless`,
|
||||
`wai.image.avif` (AV1 §7.2: identical output unless film grain is signalled,
|
||||
and then no "perceptually significant differences", a criterion the AV1
|
||||
specification leaves undefined), `wai.audio.iamf`.
|
||||
- `StandardUnclassified` — the named standard's conformance clauses have not
|
||||
been checked: `wai.audio.ac4`, `wai.audio.ivas`, `wai.mesh.draco`,
|
||||
`wai.pc.gpcc`, `wai.pc.vpcc`, `wai.splat.sog`, `wai.haptic.mihs`,
|
||||
`wai.meta.hdr10plus`, `wai.meta.dovi`, and the pass-through asset formats
|
||||
`wai.mesh.glb` and `wai.splat.spz`.
|
||||
|
||||
`StandardDefined` keeps the capabilities whose reconstruction is specified
|
||||
exactly (PNG, FLAC, zstd, XZ and the WAI-native capabilities). `replicate` over
|
||||
the reclassified capabilities is still honoured; what it promises is narrower.
|
||||
SPEC §7 also states that a conversion a sink applies after the standard's decode
|
||||
(PNG depth reduction, YUV→RGB, JPEG colour space, rendering an IAMF mix) is not
|
||||
part of the promise, and that an extension composing other capabilities' output
|
||||
is only as exact as their classes (spatial-audio §4 now says so for sources
|
||||
decoded through Opus). The clauses read for each classification, and what was not
|
||||
read, are in `research/media-codec-registry.md`. API: new
|
||||
`ReplicateClass::{StandardTolerance, StandardUnclassified}` variants,
|
||||
`ReplicatePromise` and `ReplicateClass::replicate_promise`; `wai capabilities`
|
||||
prints `standard-tolerance` / `standard-unclassified` for them.
|
||||
- `wai.image.jpegai` stays `NeuralEntropyExact` as a conservative choice pending a
|
||||
reading of its conformance part, ISO/IEC 6048-4. An earlier form of this change
|
||||
said in SPEC §7 and the extension that its standard does not bound the
|
||||
reconstruction, so no weaker promise than `decode-equivalence` was available.
|
||||
Part 4 had not been read, and the overview of the standard that was read (arXiv
|
||||
2510.13867) says the conformance part "specifies the requirements for generating
|
||||
a JPEG AI-compliant reconstruction" and "considers the possibility that a decoder
|
||||
is conformant to the standard without having bit-exact reconstruction", with "a
|
||||
certain leeway" — which points to a criterion around a reference, though the
|
||||
overview does not state one. SPEC §7 (*`wai.image.jpegai` and the standard
|
||||
classes*) now states what was and was not read, that the capability is a
|
||||
candidate for `StandardTolerance` if Part 4 sets such a criterion, and that its
|
||||
treatment differs from the `StandardUnclassified` codecs' and film-grain AV1's
|
||||
by this revision's choice, not by anything found in the standards. No class or
|
||||
runtime behaviour changes.
|
||||
- `decode_envelope_strict` and `Wai::replicate_is_sound` now apply SPEC §7 in two
|
||||
steps (`codecs::replicate_refusal`): the capability's registry class first, then
|
||||
the pinned prior. Before, they read only the prior's *declared* contract string,
|
||||
so a `replicate` envelope over `wai.image.jpegai` or a float codec passed when its
|
||||
prior declared an integer contract; it is now refused. API: new
|
||||
`ReplicateClass::NeuralEntropyExact` variant (an exhaustive `match` must add it),
|
||||
`DeterminismTier`, `ReplicateClass::{neural_tier, label}`,
|
||||
`codecs::{replicate_refusal, ReplicateRefusal}` and `Wai::replicate_refusal`;
|
||||
`Wai::replicate_is_sound` now consults the registry (a floor capability with no
|
||||
prior now passes it; the free function `container::replicate_is_sound` is
|
||||
unchanged and checks only the prior).
|
||||
- Fix: `wai wrap` wrote `intent = replicate` over every capability, including
|
||||
`wai.image.jpegai` and the float neural codecs, which SPEC §7 says an encoder MUST
|
||||
NOT do, and it pins no prior, so its envelopes over an integer-exact neural codec
|
||||
were refused by the strict decode as well. It now takes `--intent <intent>`
|
||||
(default `replicate`) and writes `replicate` only where a sink accepts it with no
|
||||
prior — over the three standard classes; otherwise it refuses, says why, and
|
||||
writes nothing. The same holds for a `--fallback` capability, since a sink that
|
||||
lacks the primary decodes through it (SPEC §4 step 5): `wai wrap wai.image.jp2 …
|
||||
--fallback wai.image.jpegai` is refused unless given another intent. SPEC §7 now
|
||||
says the class a sink checks is that of the capability it decodes through. API:
|
||||
`codecs::unpinned_envelope_intent`. The library test checks every registered
|
||||
capability against the sink's own check; `tests/cli_wrap_intent.rs` runs the
|
||||
binary, which needs the `codecs` feature, which no CI job builds.
|
||||
- CI: new `wai-neural-gates.yml` runs the two model-free neural-sink tests,
|
||||
`strict_decode_gates_unsound_replicate` (the `decode_envelope_strict` gate) and
|
||||
`resolve_checked_verifies_prior_hash`, on the Linux runner, and fails unless both
|
||||
ran. No workflow ran them before: they need the `neural` feature, which
|
||||
`wai-conformance.yml` does not build, and `wai-neural-e2e.yml` selects only the
|
||||
reference-match tests. The job runs in an Ubuntu 24.04 image: the ONNX Runtime
|
||||
binary the `ort` crate downloads needs glibc 2.38 and a GCC 13 libstdc++, and
|
||||
in the runner's default 22.04 image the test binary fails to link.
|
||||
- Wording corrections, each checked against its source:
|
||||
- The claim that byte identity holds between sinks running the same decoder
|
||||
build (the `StandardTolerance` and `ReplicatePromise` docs, SPEC §7) had
|
||||
nothing behind it and is removed; `replicate` over those classes does not
|
||||
promise byte identity across sinks.
|
||||
- JPEG and JPEG 2000 were listed with Opus and JPEG XL as having a stated bound.
|
||||
The clauses that would state them were not read (T.81 leaves the IDCT's
|
||||
accuracy to its Part 2; only the table of contents and terms of ISO/IEC
|
||||
15444-4 were read), so SPEC §7, the extension and the registry docs now say so
|
||||
and give no bound.
|
||||
- The JPEG AI overview is quoted instead of paraphrased: it says Part 4
|
||||
"considers the possibility" of conformance without bit-exact reconstruction,
|
||||
and does not itself state a criterion on the reconstruction.
|
||||
- "Before v0.4.0" in the registry comments and "until v0.4.0" in the extension
|
||||
were wrong: the replicate classes and `wai.image.jpegai` were both added within
|
||||
v0.4.0. They now say "earlier in v0.4.0".
|
||||
- determinism-tiers §2 described ISO/IEC 23001-11's decoding-operation reduction
|
||||
as in-band metadata with which a decoder degrades its output after a conformant
|
||||
decode. The 4th-edition CD text (WG 3 N1864) says otherwise: a decoding
|
||||
operation reduction request goes from the receiving device to the remote
|
||||
encoder, which sends a less complex bitstream, and complexity metrics let a
|
||||
decoder vary its operating frequency; neither changes the output of a decode.
|
||||
§2 now sorts every metadata set that text's Introduction names by what it
|
||||
changes. Attenuation-map post-processing, display adaptation (the RGB
|
||||
components of reconstructed frames rescaled, saturated or, for contrast
|
||||
enhancement, set to zero or the peak signal before display) and cross-segment
|
||||
decoding (an enhanced picture used as a reference) change the decoded medium,
|
||||
and the post-decode rule applies to them. Decoding-operation-reduction and
|
||||
attenuated-video requests, and low-power encoding, change the payload before
|
||||
it arrives; the rule about "honouring a hint" is replaced by one about such a
|
||||
payload: a tier, hash or receipt over it covers that payload, not the one it
|
||||
stands in for. Media selection and complexity metrics change neither. §2 also
|
||||
says what the metadata is: power-saving metadata stated in advance, whose
|
||||
energy quantities are expected or potential savings (clauses 7.4 and 8), not
|
||||
energy that was spent. energy-binding §7.1–§7.2 and task-fidelity §4 follow;
|
||||
§7.2 now names the parties to `op_requested` and `op_committed` as the
|
||||
requesting and the acting party, where "sender" and "receiver" had them
|
||||
reversed for a DOR request. The transport landscape research note marks its
|
||||
earlier reading as superseded in a note under its provenance header that
|
||||
names every passage repeating it.
|
||||
- `int_entropy.rs` cited SPEC §6 for replicate-soundness; it is §7.
|
||||
- Correction to the JPEG AI entries (SPEC §5 row and the decoder entry below): the
|
||||
dequantisation, latent refinement, post-filters (including the eICCI network) and
|
||||
colour conversion run in IEEE-754 float with a fixed evaluation order, not in
|
||||
integer; and the end-to-end test bar is max|Δ| ≤ 2 (recorded max|Δ| = 1), not
|
||||
1 LSB.
|
||||
- Fix: `wai.image.jpegai` decoded codestreams it does not implement. The exact
|
||||
decoder checked only the picture size and latent channel counts, so a 256×256
|
||||
codestream with β ≠ 0, another `model_id`, another synthesis transform or another
|
||||
eICCI model selection passed that check and was decoded as if it had the
|
||||
implemented configuration; the float ONNX path was no better (it applied β to the
|
||||
entropy parameters but not to dequantisation). The earlier statement that every
|
||||
per-image quantity is derived from the bitstream did not hold while β is not
|
||||
implemented; β ≠ 0 is now refused. `jpegai_decode::check_codestream` now
|
||||
checks every header field either path hard-codes, and both paths refuse a
|
||||
codestream that fails it. The exact decoder also refuses to run in a non-default
|
||||
floating-point environment (`fp_env_is_default`). The committed reference
|
||||
codestream (`wai-rs/tests/vectors/jpegai/`) lets the library tests exercise the
|
||||
check without fixtures.
|
||||
- Fix: the JPEG AI picture-header parser mislabelled a flag. The bit after each
|
||||
component's GRFS channel flags is `synthesis_tile_enable`; the LSBS flags are the
|
||||
first two bits of the tool header (`parse_lsbs_flags`). It also read `c_ver` /
|
||||
`c_hor` when `s_ver` / `s_hor` is 2, where the reference codes neither; the float
|
||||
path's parser shared that defect and dropped the separate chroma β.
|
||||
- Float reproducibility stated precisely (SPEC §7, the extension, `DeterminismClass`):
|
||||
IEEE-754 basic operations are correctly rounded, and float decodes diverge across
|
||||
hardware through what a runtime chooses per device and through the floating-point
|
||||
environment. `replicate` still requires integer arithmetic, because those
|
||||
conditions belong to one build and one process.
|
||||
- The extension now also states what a receipt can hash under each tier, why
|
||||
transmitting entropy parameters stops at `entropy-consistency`, which capabilities
|
||||
are offered at `decode-equivalence` and at what cost, and the evidence behind each
|
||||
claim — which tests skip, which CI does not run, and which matrix legs actually
|
||||
ran (the Windows x86_64 leg has not run since 2026-08-27).
|
||||
|
||||
### Reproducible-reconstruction binding — a C2PA/JPEG-Trust hard binding over pixels
|
||||
|
||||
|
|
|
|||
316
wai/SPEC.md
316
wai/SPEC.md
|
|
@ -85,9 +85,23 @@ All WAI multi-byte integers are little-endian unless stated otherwise.
|
|||
reject. Unknown minor → accept by ignoring unknown fields.
|
||||
- `media` — media class; informational. The capability is authoritative.
|
||||
- `intent` — generative intent. `replicate` (reconstruct the source) is
|
||||
the only intent with normative reconstruction semantics in v1.0. For a
|
||||
**neural** capability, `replicate` is sound only under the integer-entropy
|
||||
contract (§7, *Replicate-soundness*) — a float neural decode MUST NOT claim it.
|
||||
the only intent with normative reconstruction semantics in v1.0. What it
|
||||
promises is set by the capability's registry class (§7, *Replicate-soundness*):
|
||||
a byte-exact reconstruction — every conforming sink that decodes the payload
|
||||
produces the same bytes (decode-equivalence) — where the capability's
|
||||
reconstruction is specified exactly; and, for a standard codec whose named
|
||||
standard holds decoders to a criterion around a reference rather than to
|
||||
identical output (Opus's thresholds, RFC 6716 §6, are one), no more than that
|
||||
standard's decoder conformance, so conforming sinks' reconstructions may differ
|
||||
as far as that criterion allows; for a standard codec §7 has not yet classified,
|
||||
what its standard's decoder conformance states, which the registry does not
|
||||
assert is byte identity.
|
||||
For a **neural** capability, `replicate` promises decode-equivalence and is sound
|
||||
only under the integer-entropy contract (§7): a capability whose decode runs
|
||||
float, or whose entropy decode alone is integer, MUST NOT claim it. That is
|
||||
WAI's rule, and this revision applies it to `wai.image.jpegai` as well; it is
|
||||
not a finding that JPEG AI's standard leaves the reconstruction unbounded (§7,
|
||||
`NeuralEntropyExact`).
|
||||
- `model_requirement.capability` — the capability string a sink MUST
|
||||
resolve. See §5 for the registered set.
|
||||
- `model_requirement.fallback` — a second capability the sink MAY use
|
||||
|
|
@ -194,7 +208,7 @@ decode route for each is implemented in the reference sink (see the
|
|||
| `wai.neural.mbt2018_mean` | mean-scale hyperprior (Gaussian-conditional entropy) | conditional-entropy family, stronger than factorized | `neural/hyperprior.rs` |
|
||||
| `wai.neural.int_synth` | integer fixed-point synthesis (all-i64 transposed-conv, no float/ONNX) | bit-identical on every machine — soundly backs `intent = replicate` | `neural/int_synth.rs` (QAT weights sink-supplied) |
|
||||
| `wai.neural.int_hyper` | integer fixed-point **conditional** codec — whole bitstream→image path integer (integer hyper-decoder σ → integer-σ entropy → integer synthesis) | the integer-entropy contract fully assembled; high quality (PTQ of mbt2018_mean) bit-identical on every machine | `int_hyper_synth.rs` (tables sink-supplied) |
|
||||
| `wai.image.jpegai` | ISO/IEC 6048 JPEG-AI codestream → RGB — integer entropy front end (mANS) + integer dequant/value path + fixed-order synthesis and post-filters; every per-image quantity is derived from the bitstream, only checkpoint constants are sink-supplied | **decode-equivalence**: one pinned reconstruction of a published-standard codestream to RGB, reproducible on every machine (a portable decoded-pixel hash); entropy and dequant are integer-exact, synthesis reconstructs to within 1 LSB of the reference | `jpegai_decode.rs` (+ `jpegai_{bitstream,mans,pipeline,synthesis,icci}.rs`) |
|
||||
| `wai.image.jpegai` | ISO/IEC 6048 JPEG-AI codestream → RGB — integer entropy front end (mANS, with an integer scale-index derivation) + 16-bit-PTQ integer hyper-decoder, context-model and synthesis networks + dequantisation, latent refinement, post-filters (the eICCI CNN among them) and colour conversion in IEEE-754 float with a fixed evaluation order. Scope: one configuration — 256×256 4:4:4, `model_id` 0 (tools_0), `beta_displacement_log` 0, the high-operation-point synthesis, the eICCI model pair the weight bundle carries, and the other header conditions in [determinism-tiers](extensions/determinism-tiers.md) §5; both decode paths refuse any other codestream. Within it, a sink without the integer weight bundle, or in a non-default floating-point environment, takes a float ONNX decode instead. Only checkpoint constants are sink-supplied | **entropy-consistency** (registry class `NeuralEntropyExact`): the entropy decode, including the scale-index derivation, is integer on both decode paths, so the decoded symbols reproduce on every machine. The exact decoder also pins one reconstruction to RGB, reproducible across machines under the build and floating-point conditions in [determinism-tiers](extensions/determinism-tiers.md) §5–§6 (it checks the floating-point environment before decoding) — a property of that decoder, not of the capability, so `wai.image.jpegai` does not back `replicate` (§7). On one reference codestream the exact decoder stays within max\|Δ\| ≤ 2 of the reference decoder (recorded max\|Δ\| = 1 on ~4.4% of samples); evidence in [determinism-tiers](extensions/determinism-tiers.md) §6. **Downgraded in v0.4.0:** this row previously claimed decode-equivalence, and the registry classed the capability `StandardDefined` | `jpegai_decode.rs` (+ `jpegai_{bitstream,mans,pipeline,synthesis,icci}.rs`) |
|
||||
| `wai.generate.spectral` | deterministic integer GENERATIVE synthesis (`intent=create`) — prompt+seed → integer-LUT spectral composition, no float/ONNX | byte-identical on every machine, pinned to (model, prompt, seed, steps); the create-side of "conformance is a hash" (generation-equivalence) | `generate.rs` (small pinned model bundle) |
|
||||
| `wai.neural.elic` | checkerboard context model (hyperprior + 2-pass spatial context) | the JPEG-AI / MLIC++ entropy class | `neural/context.rs` |
|
||||
| `wai.neural.mlicpp` | MLIC++ multi-reference entropy (channel-AR slices + checkerboard + global attention) | learned image, low-bitrate high-fidelity | research code, `neural/mlicpp.rs` |
|
||||
|
|
@ -256,14 +270,15 @@ private-channel sub-spec: MLS (RFC 9420) group keys + SFrame (RFC 9605)
|
|||
object encryption, the byte-level framing behind §6.
|
||||
See [`extensions/reconstruction-binding.md`](extensions/reconstruction-binding.md)
|
||||
for the reproducible-reconstruction binding: a C2PA / JPEG-Trust hard binding
|
||||
over the *deterministically decoded pixels* of a neural-coded asset (SHA-256 over
|
||||
the canonical RGB plus the descriptor that pins the reconstruction) — the
|
||||
reconstruct-side companion to `provenance`, applicable to the byte-exact
|
||||
`wai.neural.int_*` codecs and, over the exact decoder's pinned reconstruction
|
||||
only, to `wai.image.jpegai`.
|
||||
See [`extensions/energy-binding.md`](extensions/energy-binding.md) for the
|
||||
companion energy assertion: the joules a reconstruction cost, bound to that
|
||||
reconstruction, with the acquisition class and coverage C2PA 2.4's
|
||||
`c2pa.environmental-sustainability` has no field for.
|
||||
over the *deterministically decoded pixels* of a neural-coded asset (SHA-256 over
|
||||
the canonical RGB plus the descriptor that pins the reconstruction) — the
|
||||
reconstruct-side companion to `provenance`, applicable to `wai.image.jpegai` and
|
||||
the byte-exact `wai.neural.int_*` codecs.
|
||||
|
||||
### Interactive, temporal & computed content (extensions)
|
||||
|
||||
|
|
@ -332,7 +347,8 @@ property of the format, enforceable, not a policy on a slide.
|
|||
|
||||
See [`research/media-codec-registry.md`](research/media-codec-registry.md) for
|
||||
the per-capability standard / spec number / verified royalty status / reference
|
||||
library and the remaining spec follow-up (companion-component binding for the
|
||||
library, what each named standard's decoder conformance fixes (§7), and the
|
||||
remaining spec follow-up (companion-component binding for the
|
||||
HDR / audio metadata descriptors).
|
||||
|
||||
---
|
||||
|
|
@ -432,25 +448,82 @@ selects this path. Live: https://wai.transaction.science/private-channel
|
|||
conforming sink can read; the payload MUST be the canonical byte
|
||||
stream for the registered capability.
|
||||
- Conformance is verified by **bit-exact decode-equivalence with the
|
||||
reference library** named in §5 for each registered capability. The
|
||||
WAI Rust reference impl in `wai-rs/` is built on those very
|
||||
libraries and ships a test suite that exercises every registered
|
||||
reference library** named in §5 for each registered capability, except where
|
||||
this section states a weaker criterion through the capability's registry class
|
||||
(below): a `StandardTolerance` capability conforms by its named standard's own
|
||||
decoder-conformance criterion around a reference, not by bit-exact equality
|
||||
with one library's output; a `StandardUnclassified` capability conforms by its
|
||||
named standard's criterion, which this revision has not classified; a
|
||||
`NeuralEntropyExact` capability conforms, as WAI registers it,
|
||||
at the entropy-decoder output (for `wai.image.jpegai`, the criterion its named
|
||||
standard sets on the reconstruction is not read in this revision); and
|
||||
`NeuralFloat` and `Behavioral` capabilities make no claim that their
|
||||
reconstruction is bit-exact across sinks. The WAI Rust
|
||||
reference impl in `wai-rs/` is built on those
|
||||
very libraries and ships a test suite that exercises every registered
|
||||
capability through the full WAI envelope (`cargo test --lib`).
|
||||
|
||||
### Replicate-soundness — the integer-entropy contract (normative)
|
||||
|
||||
`intent = replicate` claims the sink reproduces the *exact* source bytes. For a
|
||||
**neural** capability that claim is only sound if the decode is byte-identical
|
||||
on every machine — and that is **not** automatic. A learned codec's entropy
|
||||
decode desyncs the instant the decoder's scale-bucket / σ computation drifts
|
||||
from the encoder's by one float ULP: the bucket assignment flips and the rest
|
||||
of the stream corrupts. So a neural decode that runs **float** inference is
|
||||
reproducible only on the *same build*, never guaranteed across hardware.
|
||||
`intent = replicate` promises the reconstruction the capability's registry class
|
||||
fixes (the classes are below). For every class that backs it except two, that is
|
||||
a **byte-exact reconstruction**: every conforming sink that decodes the payload
|
||||
produces the same bytes of the medium (*decode-equivalence*,
|
||||
[determinism-tiers](extensions/determinism-tiers.md) §2). The two exceptions are
|
||||
the standard codecs whose named standard fixes less than the bytes
|
||||
(`StandardTolerance`) or has not been checked (`StandardUnclassified`); over those,
|
||||
`replicate` promises that standard's decoder conformance and no more (*What
|
||||
`replicate` promises over a standard codec*, below).
|
||||
|
||||
For a **neural** capability `replicate` promises decode-equivalence, and this
|
||||
revision does not substitute a standard's decoder conformance for it. The one
|
||||
registered neural capability with a named external standard is
|
||||
`wai.image.jpegai` (ISO/IEC 6048). That standard's conformance part may set a
|
||||
criterion on the reconstruction — an overview of the standard says the part
|
||||
"considers the possibility that a decoder is conformant to the standard without
|
||||
having bit-exact reconstruction" — but this revision has not read it, so holding
|
||||
`wai.image.jpegai` to the neural rule is a conservative choice pending that
|
||||
reading, not a finding that its standard leaves the reconstruction unbounded
|
||||
(`NeuralEntropyExact`, below).
|
||||
Decode-equivalence is only sound if the decode is byte-identical on
|
||||
every machine — and that is **not** automatic. A learned
|
||||
codec's entropy decode desyncs the instant the decoder's scale-bucket / σ
|
||||
computation drifts from the encoder's by one float ULP: the bucket assignment
|
||||
flips and the rest of the stream corrupts. So a neural decode that runs **float**
|
||||
inference through a runtime — which chooses kernels, accumulation order, vector
|
||||
width and fused multiply-adds per device — is reproducible only on the *same
|
||||
build*, never guaranteed across hardware.
|
||||
|
||||
IEEE-754 basic operations are themselves correctly rounded. Float reproduces
|
||||
across machines only when one implementation fixes everything a runtime leaves
|
||||
free: the operations and their order, their precision, no contraction or
|
||||
reassociation, no library function whose last-place error can reach the output —
|
||||
and runs in the default floating-point environment (round-to-nearest-even, no
|
||||
flush-to-zero, no denormals-are-zero), which a host process can change. These are
|
||||
properties of one build and one process that neither the envelope nor the
|
||||
registry can state, which is why the rule below requires integer arithmetic.
|
||||
|
||||
Therefore a neural capability MAY back `intent = replicate` **only** if its
|
||||
entire decode path — entropy parameterization *and* synthesis — is
|
||||
integer / fixed-point, with no float operation anywhere (the **integer-entropy
|
||||
contract**). The reference impl factors the halves into ORT-free, pure-i64
|
||||
contract**). That is the only construction by which a neural capability is
|
||||
registered at `decode-equivalence`. Two weaker properties MUST NOT back
|
||||
`replicate`:
|
||||
|
||||
- **`entropy-consistency`** — the entropy decode (the decoded symbols, and the
|
||||
parameters they are decoded with) reproduces on every machine, but later stages
|
||||
run float, so the reconstruction may differ between conforming sinks. It is
|
||||
necessary for a sound neural `replicate` — without it the decode desyncs — and
|
||||
not sufficient, because `replicate` promises the reconstruction, not the
|
||||
symbols.
|
||||
- **A reconstruction pinned by one implementation** — float stages in a fixed
|
||||
evaluation order, reproducible across machines only under that
|
||||
implementation's build and the process's floating-point environment. Those
|
||||
conditions are the ones the envelope and the registry cannot state, so a
|
||||
`replicate` resting on them promises something no sink can check from what it
|
||||
received.
|
||||
|
||||
The reference impl factors the halves of the contract into ORT-free, pure-i64
|
||||
modules a codec composes: `int_entropy` (the deterministic scale→bucket step
|
||||
that removes the float-σ desync), `int_synth` (integer synthesis), and the
|
||||
integer rANS — assembled into a full conditional decode by `int_hyper_synth`
|
||||
|
|
@ -461,9 +534,22 @@ a property of the capability, classified in the
|
|||
registry as `codecs::capability_replicate_class(cap) -> ReplicateClass`:
|
||||
|
||||
- **`NeuralIntegerExact`** — integer by construction; byte-identical on every
|
||||
machine; the only neural class that soundly backs cross-hardware `replicate`.
|
||||
(`wai.neural.int_synth` is synthesis only; `wai.neural.int_hyper` is the full
|
||||
conditional codec — σ source, entropy, and synthesis all integer.)
|
||||
machine; registered at `decode-equivalence`, and the only neural class that
|
||||
backs `replicate`. (`wai.neural.int_synth` is synthesis only;
|
||||
`wai.neural.int_hyper` is the full conditional codec — σ source, entropy, and
|
||||
synthesis all integer; `wai.video.int_hyper`, `wai.audio.int_codec` and
|
||||
`wai.splat.int_codec` are integer throughout as well.)
|
||||
- **`NeuralEntropyExact`** — the entropy decode is integer by construction, so
|
||||
the decoded symbols are byte-identical on every machine; later stages run float.
|
||||
Registered at `entropy-consistency`. An encoder MUST NOT emit `intent =
|
||||
replicate` for one of these. (`wai.image.jpegai`: integer mANS entropy decode
|
||||
and integer scale-index derivation on both reference decode paths; float
|
||||
dequantisation, latent refinement, post-filters and colour conversion. What
|
||||
its exact decoder pins, and under which conditions, is stated in
|
||||
[determinism-tiers](extensions/determinism-tiers.md) §5. This class is the
|
||||
neural rule applied to it, not a statement about its standard's conformance on
|
||||
the reconstruction, which this revision has not read; see *`wai.image.jpegai`
|
||||
and the standard classes*, below.)
|
||||
- **`GenerativeDeterministic`** — the *create*-side of byte-exact conformance.
|
||||
A generator (`intent = create`) whose entire pipeline is integer/fixed-point
|
||||
and pinned to `(model, prompt, seed, steps)`, so the **generated** content is
|
||||
|
|
@ -474,40 +560,172 @@ registry as `codecs::capability_replicate_class(cap) -> ReplicateClass`:
|
|||
spectral synthesis — prompt+seed draw integer-LUT sinusoid components by a
|
||||
`splitmix64` PRNG; the float `sin()` that bakes the LUT runs once at
|
||||
model-build, never at generation.) Distinct from `Behavioral`, which conforms
|
||||
by similarity and never reproduces bytes.
|
||||
by similarity and never reproduces bytes. It generates rather than
|
||||
reconstructs, so it does not back `replicate`.
|
||||
- **`NeuralFloat`** — runs float inference; exact only on the same build. An
|
||||
encoder MUST NOT emit `intent = replicate` for one of these; `perceptual` /
|
||||
"exact on this build" is the honest claim.
|
||||
- **`StandardDefined`** — reconstruction is fixed by the named codec/standard
|
||||
(the floor + menu codecs) or by WAI's deterministic floor (§ extensions);
|
||||
the neural float hazard does not apply.
|
||||
"exact on this build" is the honest claim. The registry claims no determinism
|
||||
tier for these.
|
||||
- **`StandardDefined`** — the reconstruction is specified exactly: by the named
|
||||
standard, for the lossless formats whose decoded output it determines
|
||||
(`wai.image.png`, `wai.audio.flac`, `wai.text.zstd`, `wai.text.xz`), or by the
|
||||
WAI extension that defines the capability's `*-equivalence` over integer /
|
||||
fixed-point state (world, score, film, quantum, ternary, the haptic signal, the
|
||||
integer inter-frame codec and the other WAI-native capabilities). `replicate`
|
||||
promises the same bytes on every conforming sink. An extension's equivalence
|
||||
holds given its inputs: where it composes other capabilities' decoded output (a
|
||||
`wai.audio.scene` source decoded through `wai.audio.opus`, say), it is only as
|
||||
exact as those capabilities' classes. No neural capability is in this class.
|
||||
- **`StandardTolerance`** — a standard codec whose named standard, for at least
|
||||
some conforming payloads, holds decoders to a criterion around a reference
|
||||
rather than to identical output. For Opus and JPEG XL the clauses read state it
|
||||
as numeric thresholds. For JPEG and JPEG 2000 the text read points to a
|
||||
criterion without stating its bound (T.81 leaves the accuracy of dequantisation
|
||||
and IDCT to its Part 2, which was not read; only the table of contents and terms
|
||||
of ISO/IEC 15444-4 were read), so this revision states none. For AV1 and AVIF
|
||||
when film grain is signalled it is the absence of "perceptually significant
|
||||
differences" from the reference grain synthesis, which the AV1 specification
|
||||
leaves undefined (§7.2: its definition "is beyond the scope of this
|
||||
specification"). `replicate` promises what that conformance promises: every
|
||||
conforming sink reconstructs within the standard's criterion — for film-grain
|
||||
AV1, a criterion no document WAI cites quantifies. It does not promise byte
|
||||
identity across sinks.
|
||||
- **`StandardUnclassified`** — a standard codec whose named standard's
|
||||
decoder-conformance clauses this revision has not checked. `replicate` promises
|
||||
what that conformance promises; the registry does not say whether that is byte
|
||||
identity.
|
||||
- **`Behavioral`** — a sink-generator path that conforms by similarity, not
|
||||
bytes (`wai.semantic.*`).
|
||||
|
||||
A conforming sink that receives `intent = replicate` for a `NeuralFloat`
|
||||
capability MUST refuse the replicate claim (decode as perceptual or reject).
|
||||
The reference impl enforces this per-envelope in `decode_envelope_strict`, which
|
||||
rejects a `replicate` envelope whose pinned prior is not integer-exact
|
||||
(`DeterminismClass`) — and a `NeuralFloat` capability cannot honestly carry an
|
||||
integer-exact prior. The registry class is the *static* audit of the same
|
||||
property: `wai capabilities` prints it per row and reports the count of neural
|
||||
integer-exact capabilities, so a deployer can require "dispatch `replicate` only
|
||||
to a cross-hardware-sound decode" in code, exactly as it audits royalty status.
|
||||
#### What `replicate` promises over a standard codec
|
||||
|
||||
This is the standard fixing the one axis the learned-codec field leaves
|
||||
implicit: a neural codec that is *integer all the way down* is the only one that
|
||||
can put a reconstruction in a receipt and have it verify on someone else's
|
||||
machine.
|
||||
A standard codec's reconstruction is what its named standard's decoder
|
||||
conformance fixes, in that standard's own output domain; `replicate` promises that
|
||||
and no more. The registry classes each one by what the standard fixes (the clauses
|
||||
cited are the ones read; the evidence, and what was not read, is in
|
||||
[`research/media-codec-registry.md`](research/media-codec-registry.md)):
|
||||
|
||||
| class | capabilities | what the named standard fixes |
|
||||
|---|---|---|
|
||||
| `StandardDefined` | `wai.image.png`, `wai.audio.flac`, `wai.text.zstd`, `wai.text.xz` | the decoded output exactly: lossless formats (PNG, RFC 2083 — its filters are exact integer operations; FLAC, RFC 9639) and lossless byte formats |
|
||||
| `StandardTolerance` | `wai.audio.opus` | output within `opus_compare`'s thresholds of the reference decoder, with the same final range-decoder state (RFC 6716 §6) |
|
||||
| | `wai.image.jpeg` | decoding "with appropriate accuracy", the accuracy of dequantisation and IDCT specified in Part 2 (ITU-T T.81 §7, A.3.3); Part 2 (ITU-T T.83) was not read, so the bound is not stated here |
|
||||
| | `wai.image.jxl` | decoded samples within per-test peak-error and RMSE thresholds of reference images (ISO/IEC 18181-3 §4.1–§4.3) |
|
||||
| | `wai.image.jp2`, `wai.video.j2k` | decoded components compared with reference components by error metrics, and a reversible path its definitions describe as lossless (ISO/IEC 15444-4); only the table of contents and terms of its public preview were read, so the metrics and thresholds are not stated here |
|
||||
| | `wai.video.av1`, `wai.video.av1.lossless`, `wai.image.avif` | identical output frames, unless the payload signals film grain; then identical frames before grain synthesis, and output frames that "do not have perceptually significant differences" from the reference grain synthesis, a criterion whose definition the specification places outside its scope (AV1 §7.2) |
|
||||
| | `wai.audio.iamf` | its substreams include Opus (above), and renderers are out of its scope |
|
||||
| `StandardUnclassified` | `wai.audio.ac4`, `wai.audio.ivas`, `wai.mesh.draco`, `wai.pc.gpcc`, `wai.pc.vpcc`, `wai.splat.sog`, `wai.haptic.mihs`, `wai.meta.hdr10plus`, `wai.meta.dovi` | not checked in this revision (all sink-supplied; `wai.splat.sog` names no frozen standard yet) |
|
||||
| | `wai.mesh.glb`, `wai.splat.spz` | the payload bytes pass through intact; what a sink decodes from them is not classified here (glTF can embed JPEG images and compressed geometry; SPZ stores quantised attributes) |
|
||||
|
||||
A conversion a sink applies after the standard's decode is not part of the
|
||||
promise. A standard fixes its decoded samples at their own depth, layout and
|
||||
colour representation, and none of those above fixes a conversion to another: PNG
|
||||
sample-depth reduction (RFC 2083 §10.4 gives two methods), YUV→RGB for AV1 and
|
||||
AVIF, JPEG's colour space (outside T.81's scope, §4.1), rendering an IAMF mix to a
|
||||
loudspeaker layout. The reference sink returns `RGB8` images and f32 PCM, so its
|
||||
output buffers include such conversions; they are the reference implementation's,
|
||||
and this revision does not specify them.
|
||||
|
||||
#### `wai.image.jpegai` and the standard classes
|
||||
|
||||
`wai.image.jpegai` has a named standard, ISO/IEC 6048, but its registry class
|
||||
(`NeuralEntropyExact`) comes from the neural rule above, not from what that
|
||||
standard's decoder conformance fixes. What this revision has established, and what
|
||||
it has not:
|
||||
|
||||
- JPEG AI sets its bit-exact conformance point at the entropy-decoder output, and
|
||||
one codestream may be reconstructed through up to three synthesis transforms,
|
||||
which a profile or the encoder can restrict (an overview of the standard, arXiv
|
||||
2510.13867; [determinism-tiers](extensions/determinism-tiers.md) §1).
|
||||
- The same overview says the conformance part, ISO/IEC 6048-4, "specifies the
|
||||
requirements for generating a JPEG AI-compliant reconstruction" through a
|
||||
testing suite for each profile and level pair, and "considers the possibility
|
||||
that a decoder is conformant to the standard without having bit-exact
|
||||
reconstruction", which it also calls "the possibility of standard compliance
|
||||
with a certain leeway"; outputs of the processes after entropy decoding "may
|
||||
diverge slightly from the reference". Read together, these passages point to a
|
||||
criterion on the reconstruction around a reference, the kind
|
||||
`StandardTolerance` records. The overview does not state such a criterion.
|
||||
- ISO/IEC 6048-4 itself has not been read (the overview describes it as a draft
|
||||
when it was written), so this revision does not state whether it sets such a
|
||||
criterion, of what form, or how wide.
|
||||
|
||||
Classing `wai.image.jpegai` as `NeuralEntropyExact`, so that `replicate` over it
|
||||
is refused, is therefore a conservative choice pending a reading of Part 4. It is
|
||||
not a finding that the standard leaves the reconstruction unbounded. If Part 4
|
||||
states a criterion on the reconstruction, `wai.image.jpegai` is a candidate for
|
||||
`StandardTolerance`, over which `replicate` would promise that criterion; moving
|
||||
it there would also take an exception to the neural rule above, which admits a
|
||||
neural capability to `replicate` only by the integer construction.
|
||||
|
||||
This is not the choice made for the standard codecs. Over a `StandardUnclassified`
|
||||
codec, whose conformance clauses are unread, and over AV1 or AVIF with film grain,
|
||||
whose criterion the AV1 specification leaves undefined, `replicate` is honoured,
|
||||
with its promise narrowed to the standard's conformance. Those capabilities keep
|
||||
the behaviour they had before this revision. `wai.image.jpegai` had been
|
||||
registered at `decode-equivalence`, which its float stages do not meet, and it was
|
||||
moved to a class that does not back `replicate`. The two treatments differ because
|
||||
of those choices, not because of anything the standards' texts were found to say.
|
||||
|
||||
**Registry change in v0.4.0 — a downgrade.** `wai.image.jpegai` was classed
|
||||
`StandardDefined`, and §5 listed it at `decode-equivalence`. Its decode has float
|
||||
stages, and a sink without the integer weight bundle decodes it through a float
|
||||
ONNX Runtime path, so neither held as a property of the capability. It is now
|
||||
`NeuralEntropyExact`, registered at `entropy-consistency`, and it no longer backs
|
||||
`replicate`; before, the reference strict check passed a `replicate` envelope over
|
||||
it whenever the prior declared an integer contract.
|
||||
|
||||
**Registry change in v0.4.0 — the standard codecs.** Every standard codec was
|
||||
classed `StandardDefined`, and the first form of this revision's §3 promised the
|
||||
same bytes on every conforming sink over all of them. The capabilities in the `StandardTolerance` and
|
||||
`StandardUnclassified` rows above are now in those classes. `replicate` over them
|
||||
is still honoured; what it promises is narrower — the named standard's decoder
|
||||
conformance, not byte identity across sinks. No other registered capability
|
||||
changes class.
|
||||
|
||||
A conforming sink that receives `intent = replicate` for a capability whose class
|
||||
is `NeuralEntropyExact`, `NeuralFloat`, `GenerativeDeterministic` or
|
||||
`Behavioral` MUST refuse the replicate claim (decode as perceptual or reject). The
|
||||
capability is the one it decodes through: `model_requirement.capability`, or the
|
||||
fallback when it decodes via §4 step 5. The
|
||||
reference impl checks this per-envelope in `decode_envelope_strict`
|
||||
(`codecs::replicate_refusal`) in two steps. First the capability's registry
|
||||
class: only `NeuralIntegerExact` and the three standard classes pass, whatever the
|
||||
envelope declares (`ReplicateClass::replicate_promise` states what each
|
||||
promises). Then, for a `NeuralIntegerExact` capability, the pinned prior: it must
|
||||
declare an integer-exact contract (`DeterminismClass`). The prior check reads the
|
||||
sender's declaration; the class check is what ties it to the capability, so an
|
||||
envelope whose prior declares an integer contract over a float or entropy-only
|
||||
capability is refused. `decode_envelope_strict` decodes only through
|
||||
`model_requirement.capability`, so that is the one it checks. On the encoder
|
||||
side, `wai wrap`, which pins no prior, writes `intent = replicate` only where that
|
||||
check accepts it unpinned — over the three standard classes — for the capability
|
||||
and for any fallback it declares, and otherwise refuses unless given another
|
||||
intent (`codecs::unpinned_envelope_intent`). The registry class is also the *static*
|
||||
audit of the same property: `wai capabilities` prints it per row and reports the
|
||||
count of neural integer-exact capabilities, so a deployer can require "dispatch
|
||||
`replicate` only to a cross-hardware-sound decode", or only to a capability whose
|
||||
class promises the same bytes (`ReplicatePromise::ByteExact`), in code, exactly
|
||||
as it audits royalty status.
|
||||
|
||||
This makes the cross-hardware property explicit per capability: a neural
|
||||
capability whose decode is *integer all the way down* can put its reconstruction
|
||||
in a receipt that verifies on another machine, and the registry records which
|
||||
capabilities are.
|
||||
|
||||
Reproducibility is a **spectrum**, not a single point, and the `ReplicateClass`
|
||||
values above span it. See [`extensions/determinism-tiers.md`](extensions/determinism-tiers.md),
|
||||
which names the two tiers a neural capability can satisfy:
|
||||
**`entropy-consistency`** — the entropy decode reproduces across devices (integer
|
||||
entropy arithmetic or explicit parameter transmission), the guarantee the base
|
||||
learned-codec standards make and the floor for a sound neural `replicate`; and
|
||||
**`decode-equivalence`** — the whole decode to the final medium reproduces, so the
|
||||
rendered result has a portable hash, the tier WAI adds on top and the precondition
|
||||
for a hard [reconstruction binding](extensions/reconstruction-binding.md).
|
||||
values above span it. The neural classes map onto the two tiers
|
||||
[`extensions/determinism-tiers.md`](extensions/determinism-tiers.md) names.
|
||||
`NeuralIntegerExact` capabilities are registered at **`decode-equivalence`** —
|
||||
the whole decode to the final medium reproduces on every conforming sink, so the
|
||||
rendered result has a portable hash; this is the tier `replicate` over a neural
|
||||
capability promises, and the precondition for a hard
|
||||
[reconstruction binding](extensions/reconstruction-binding.md).
|
||||
`NeuralEntropyExact` capabilities are registered at **`entropy-consistency`** —
|
||||
the entropy decode reproduces across devices (integer entropy arithmetic or
|
||||
explicit parameter transmission), the tier at which JPEG AI sets its bit-exact
|
||||
conformance point; it does not back `replicate`. `NeuralFloat` capabilities claim
|
||||
neither tier.
|
||||
|
||||
### Machine-checked totality (informative)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,68 +2,148 @@
|
|||
|
||||
> Status: Draft. Names the **spectrum** of reproducibility guarantees a neural
|
||||
> capability can make, so a manifest can declare which one it satisfies and a
|
||||
> verifier knows what it may check. Positions WAI's byte-exact reconstruction
|
||||
> (`decode-equivalence`) as the strongest tier above the entropy-stage guarantee
|
||||
> the base learned-codec field provides. No new wire format; a vocabulary +
|
||||
> conformance framing over §7.
|
||||
> verifier knows what it may check. Defines two tiers — `entropy-consistency`
|
||||
> (the entropy decode reproduces) and `decode-equivalence` (the whole decode to
|
||||
> the final medium reproduces) — and states which one `intent = replicate` over a
|
||||
> neural capability promises, what a receipt can hash under each, which WAI
|
||||
> capabilities are registered at each and at what cost, and what the repository
|
||||
> demonstrates today.
|
||||
> No new wire format; a vocabulary + conformance framing over §7.
|
||||
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
||||
|
||||
## 1. Why tiers
|
||||
|
||||
Neural decode reproducibility is not binary. A float neural decode is *not*
|
||||
reproducible at all — round-off diverges across hardware, and one diverging bit
|
||||
corrupts a learned entropy decode. In response the field has converged on making
|
||||
the **entropy stage** reproducible while leaving reconstruction to pixels
|
||||
implementation-defined. Two facts make this concrete:
|
||||
Neural decode reproducibility is not binary. A neural decode evaluated in float
|
||||
through an inference runtime does not, in general, reproduce its reconstruction
|
||||
across hardware. Each IEEE-754 basic operation (add, subtract, multiply, divide,
|
||||
square root) is correctly rounded, so it gives the same result for the same
|
||||
operands everywhere; the differences come from what a runtime may choose per
|
||||
device — kernels and accumulation order, vector width, fused multiply-add, reduced
|
||||
precision, math-library functions — and from the process's floating-point
|
||||
environment. A decoder that also *derives* its entropy parameters in float can,
|
||||
from one diverging bit, select a different distribution from the encoder's and
|
||||
corrupt the entropy decode. A float stage whose operations, order, precision and
|
||||
environment are all fixed does reproduce, within the implementation that fixes
|
||||
them; §5 describes one, and §2–§3 say why that is not a tier and does not back
|
||||
`replicate`. Three published routes to reproducibility are below. Two make the
|
||||
**entropy stage** reproducible while leaving the reconstruction to pixels to the
|
||||
implementation, within whatever criterion a conformance specification sets on it:
|
||||
|
||||
- **The base standard.** JPEG AI (ISO/IEC 6048) defines its normative bit-exact
|
||||
- **The base standard.** JPEG AI (ISO/IEC 6048) defines its bit-exact
|
||||
conformance point at the **output of the entropy decoder**, not at
|
||||
reconstruction to pixels; its entropy pipeline is integer so that stage
|
||||
replicates across devices, while post-entropy processes MAY diverge. One
|
||||
codestream may legally reconstruct through up to three synthesis transforms.
|
||||
- **The learned-codec field.** The mainstream cross-platform fix is **explicit
|
||||
parameter transmission** — carrying the entropy/scale parameters in the
|
||||
codestream so the entropy decode is consistent across devices *without* requiring
|
||||
bit-exact arithmetic. Same target: a reproducible entropy stage, a
|
||||
reconstruction that may vary.
|
||||
replicates across devices, while the outputs of later processes "may diverge
|
||||
slightly from the reference". One codestream may legally reconstruct through up
|
||||
to three synthesis transforms, which a profile or the encoder can restrict.
|
||||
Bit-exact picture reconstruction was left out of the first version on purpose.
|
||||
An overview of the standard (arXiv 2510.13867) states all of this. It also says
|
||||
that the conformance part, ISO/IEC 6048-4, "specifies the requirements for
|
||||
generating a JPEG AI-compliant reconstruction", with a testing suite for each
|
||||
profile and level pair, and "considers the possibility that a decoder is
|
||||
conformant to the standard without having bit-exact reconstruction" — "the
|
||||
possibility of standard compliance with a certain leeway". These passages point
|
||||
to a criterion around a reference on the reconstruction; the overview does not
|
||||
state one. Part 4 was a draft when the overview was written; this document has
|
||||
not read it, so it does not say whether Part 4 sets such a criterion, of what
|
||||
form, or how wide.
|
||||
- **Explicit parameter transmission.** A published cross-platform learned video
|
||||
codec (arXiv 2606.28027) transmits its entropy model's **scale parameters**
|
||||
explicitly, through the hyperprior, so the decoder reads them instead of
|
||||
deriving them and the entropy decode is consistent across devices *without*
|
||||
bit-exact arithmetic. The side information costs bitrate. Same target: a
|
||||
reproducible entropy stage, a reconstruction that may vary.
|
||||
|
||||
WAI supports that guarantee **and a stronger one**. Naming both lets a capability
|
||||
be honest about which it makes, and lets a receipt or a provenance binding
|
||||
(§[reconstruction-binding](reconstruction-binding.md)) demand the tier it needs.
|
||||
The third makes the reconstruction itself reproducible:
|
||||
|
||||
- **A quantised decoder.** A published learned image codec (arXiv 2312.11209)
|
||||
quantises the weights and activations of all its decoder subnetworks, without
|
||||
accumulator overflow, so that the reconstructed image is deterministic across
|
||||
devices, and reports its output as bit-exact.
|
||||
|
||||
WAI names the two outcomes as tiers, so a capability states which one it makes, an
|
||||
envelope's `intent` can demand the one it needs (`replicate` over a neural
|
||||
capability demands `decode-equivalence`, §3), and a receipt or a provenance binding
|
||||
([reconstruction-binding](reconstruction-binding.md)) can do the same.
|
||||
|
||||
## 2. The tiers
|
||||
|
||||
### `entropy-consistency`
|
||||
|
||||
The **entropy decode** reproduces byte-for-byte across devices — the decoded
|
||||
symbols / quantized latent have a portable hash — but the reconstruction to the
|
||||
final medium (pixels, samples) MAY differ between conforming sinks. A sink
|
||||
symbols (the entropy-decoder output) have a portable hash — but the reconstruction
|
||||
to the final medium (pixels, samples) MAY differ between conforming sinks. A sink
|
||||
achieves this either by **integer entropy arithmetic** (deriving the coding
|
||||
parameters with fixed-point ops, as WAI's integer decoders and JPEG AI's entropy
|
||||
pipeline do) or by **explicit parameter transmission** (the codestream carries the
|
||||
parameters, so no bit-exact derivation is required).
|
||||
|
||||
- Conformance criterion: *entropy-equivalence* — a verifier decodes the entropy
|
||||
stage and compares the symbols / quantized latent, NOT the pixels.
|
||||
- This is the guarantee the base learned-codec standard and the mainstream
|
||||
cross-platform techniques provide. It is the **floor** for a sound neural
|
||||
`replicate` under §7: enough that the decode does not catastrophically desync,
|
||||
not enough to hash the rendered result.
|
||||
stage and compares the decoded symbols, NOT the pixels.
|
||||
- What a receipt can hash: the codestream and the decoded symbols. The latent
|
||||
formed from the symbols is hashable only where every step that forms it (adding
|
||||
a predicted mean, say) is itself integer or transmitted. The reconstruction has
|
||||
no portable hash, so an energy figure at this tier binds to the codestream and
|
||||
symbols, never to an output every conforming sink reproduces
|
||||
([energy-binding](energy-binding.md) §3); a reconstruction that one
|
||||
implementation pins is that implementation's (§3).
|
||||
- JPEG AI sets its bit-exact conformance point at this tier, and explicit
|
||||
parameter transmission reaches it (§1). The overview also says JPEG AI's
|
||||
conformance part "considers the possibility that a decoder is conformant to the
|
||||
standard without having bit-exact reconstruction" (§1); whether that part sets a
|
||||
criterion on the reconstruction is not read here, and any such criterion is not
|
||||
one of this document's tiers. WAI registers `wai.image.jpegai` here (§5). The
|
||||
tier is **necessary** for a sound neural `replicate` under SPEC §7 — without it
|
||||
the decode desyncs — but **not sufficient**, and it MUST NOT back `replicate`:
|
||||
`replicate` promises the reconstruction, and this tier leaves the
|
||||
reconstruction free.
|
||||
|
||||
**Why transmitting parameters stops at this tier.** A learned entropy decode
|
||||
desyncs when the decoder derives an entropy parameter (a scale, and from it the
|
||||
distribution the next symbol is decoded with) that selects a different distribution
|
||||
from the one the encoder used. Transmitting the parameter removes that derivation
|
||||
from the decoder: every decoder reads the same value and decodes the same symbols,
|
||||
whatever arithmetic its networks run in. Nothing after the entropy decoder is
|
||||
constrained. The steps that turn symbols into a latent and the synthesis transform
|
||||
still run in the arithmetic the device provides — float, reduced precision, fused
|
||||
or reordered accumulation — and, unless the implementation fixes that arithmetic,
|
||||
their results differ by device. A codestream can
|
||||
pin *values*; it cannot pin the arithmetic a network is evaluated in, and the
|
||||
reconstruction depends on that arithmetic. So a portable hash of the reconstruction
|
||||
needs every stage after the entropy decode fixed as well, which is the next tier.
|
||||
The two routes compose: a capability MAY transmit parameters *and* pin its
|
||||
arithmetic.
|
||||
|
||||
### `decode-equivalence`
|
||||
|
||||
The **whole decode to the final medium** reproduces byte-for-byte across devices —
|
||||
the reconstructed pixels (or samples, or attributes) have a portable hash. The
|
||||
sink pins **one** reconstruction and runs it in integer / fixed-order arithmetic
|
||||
end to end, entropy *and* synthesis. Where the base codec admits several
|
||||
conformant reconstructions, this tier fixes one.
|
||||
The **whole decode to the final medium** reproduces byte-for-byte on every
|
||||
conforming sink — the reconstructed pixels (or samples, or attributes) have a
|
||||
portable hash. The capability's registration pins **one** reconstruction and
|
||||
specifies it in integer / fixed-point arithmetic end to end, entropy *and*
|
||||
synthesis, so the output depends on nothing a build, a device or a process
|
||||
chooses. Where the base codec admits several conformant reconstructions, this
|
||||
tier fixes one. This is what `intent = replicate` over a neural capability
|
||||
promises (§3).
|
||||
|
||||
A tier is a property of the capability as registered, not of one implementation.
|
||||
An implementation that pins a reconstruction by evaluating float stages in a fixed
|
||||
order (§5 describes one) reproduces it only under conditions of its own build and
|
||||
process (§3). That is a property of the implementation, stated as such; it does
|
||||
not place the capability at this tier.
|
||||
|
||||
- Conformance criterion: the medium's `*-equivalence` (e.g. *decode-equivalence*
|
||||
for `wai.image.jpegai`, *sample-equivalence* for `wai.audio.int_codec`,
|
||||
for `wai.neural.int_hyper`, *sample-equivalence* for `wai.audio.int_codec`,
|
||||
*splat-equivalence* for `wai.splat.int_codec`).
|
||||
- This is WAI's contribution above the field's baseline: it is a determinism
|
||||
guarantee **beyond what the base standard requires**, and it is the precondition
|
||||
for a hard provenance binding over the *rendered* content — a decoded-pixel hash
|
||||
- What a receipt can hash: everything the lower tier can, plus the reconstructed
|
||||
medium itself as the capability's canonical buffer (canonical `RGB8` for images,
|
||||
per [reconstruction-binding](reconstruction-binding.md); int16 PCM; the attribute
|
||||
tensor; a per-frame hash for video), under the descriptor that pins the
|
||||
reconstruction. This is the tier at which an energy figure binds to an output a
|
||||
verifier can reproduce ([energy-binding](energy-binding.md) §3).
|
||||
- Where a base standard sets its conformance point at the entropy decoder (JPEG
|
||||
AI, §1), a capability over it reaches this tier only by registering one
|
||||
reconstruction in integer arithmetic; `wai.image.jpegai` has not (§5). For any
|
||||
capability this tier is the precondition for a hard provenance binding over the
|
||||
*rendered* content that every conforming sink can check — a decoded-pixel hash
|
||||
is only portable when the reconstruction is pinned.
|
||||
|
||||
A capability satisfying `decode-equivalence` satisfies `entropy-consistency` by
|
||||
|
|
@ -76,26 +156,91 @@ hashed, bound, or presented** — not of the decode stage in isolation. A sink t
|
|||
decodes conformantly and then alters the result has not satisfied the tier,
|
||||
however faithful the decode itself was.
|
||||
|
||||
This is not hypothetical. Two mechanisms in force today change the medium *after*
|
||||
a conformant decode, and both arrive through the same pipe as the codestream:
|
||||
This is not hypothetical. Published and draft standards define mechanisms that
|
||||
change the medium after, or alongside, a conformant decode, and they arrive
|
||||
through the same pipe as the codestream:
|
||||
|
||||
- **Post-decode neural filters.** ITU-T H.274 (V4, 01/2026) `nnpfc` / `nnpfa` SEI
|
||||
messages activate a neural post-filter after decoding, changing output pixels.
|
||||
The filter may be named by URI or carried in-band.
|
||||
- **Operation-reduction hints.** ISO/IEC 23001-11 (green metadata) carries
|
||||
decoding-operation-reduction metadata whose express purpose is to let a decoder
|
||||
spend fewer joules by doing less work — deliberate degradation, signalled
|
||||
in-band and invisible to a conformance check that stops at the decoder.
|
||||
- **Energy-saving presentation and quality-recovery metadata.** ISO/IEC 23001-11
|
||||
(green metadata) defines metadata with which a receiver changes the decoded
|
||||
pictures, before display or inside the decode:
|
||||
- *Attenuation-map information*, carried in an SEI message with the attenuation
|
||||
map as an auxiliary picture, describes post-processing to apply to the decoded
|
||||
pictures so the display emits less light. A receiver can also ask the
|
||||
transmitter for such maps with a display attenuation map power reduction
|
||||
request (DAMPR-Req); the maps it receives are applied to the decoded content
|
||||
in the same way.
|
||||
- *RGB-component statistics and quality levels* drive display adaptation. The
|
||||
receiver chooses a quality level, scales the RGB components of the
|
||||
reconstructed frames by the peak signal over that level's
|
||||
`max_rgb_component`, and lowers the backlight or voltage in proportion
|
||||
(Annex B.2). At any level other than the no-quality-loss operating point,
|
||||
components above that level's `max_rgb_component` are saturated; for contrast
|
||||
enhancement, components at or below `lower_bound` are set to zero and those at
|
||||
or above `upper_bound` to the peak signal (clause 7.4).
|
||||
- *Quality metrics for cross-segment decoding*: a decoder uses them to decide
|
||||
whether to enhance the first picture of a low-quality segment from the last
|
||||
picture of the previous segment, and the enhanced picture becomes the
|
||||
reference for the pictures that follow.
|
||||
|
||||
The standard notes that its metadata can also be used "to get larger energy
|
||||
savings, but at the expense of some QoE degradation".
|
||||
|
||||
Other 23001-11 mechanisms leave the decode as it is. Three of them change the
|
||||
payload before it arrives:
|
||||
|
||||
- A decoding operation reduction request (DOR-Req) goes from the receiving device
|
||||
to the **remote encoder** in a point-to-point session. The encoder produces a
|
||||
less complex bitstream and can answer with a response (DOR-Resp) saying how it
|
||||
decided to answer.
|
||||
- A display power reduction attenuated video request (DPRAV-Req) asks the remote
|
||||
encoder to apply an attenuation map to the video before encoding it. The
|
||||
receiver then gets an attenuated video, and the response (DPRAV-Resp) states the
|
||||
energy reduction rate and quality it can expect.
|
||||
- Low-power encoding, which produces the low-quality segments that cross-segment
|
||||
decoding repairs, alternates high-quality and low-quality segments to reduce the
|
||||
encoder's power.
|
||||
|
||||
In each case the sink decodes what it receives like any other bitstream, but the
|
||||
payload is not the one that would have been sent otherwise. The remaining two
|
||||
alter neither a payload nor a decode's output. Media-selection metadata lets an
|
||||
adaptive-streaming client choose among the available representations by their
|
||||
decoder- and display-power characteristics; what it receives is one of those
|
||||
representations as published. Complexity metrics let a decoder vary its operating
|
||||
frequency, which changes what a decode costs, not what it outputs.
|
||||
|
||||
All of this is metadata for saving power, stated in advance; none of it reports
|
||||
energy that was spent. Its energy quantities are expectations: an attenuation
|
||||
map's expected energy saving rate, and the rates a receiver asks for and a
|
||||
transmitter says the receiver can expect, each a percentage (clause 7.4); a
|
||||
representation's decoder-operation reduction ratios and its maximum potential
|
||||
display power saving (clause 8). Complexity metrics are proportions of decoding
|
||||
operations over a period (clause 6.2), and a DOR-Resp acknowledges what the
|
||||
encoder changed. So a sink that acts on this metadata has a prescription, not a
|
||||
measurement, and a tier claim or receipt over its output is bound by the rules
|
||||
below like any other.
|
||||
|
||||
This section accounts for every metadata set that the Introduction of the
|
||||
4th-edition CD text (WG 3 N1864, dated 2026-08-28) names. Read in that text: the
|
||||
Introduction, and in part clauses 6, 7, 8 and 9 and Annex B.2, B.4, B.5 and B.6.
|
||||
The published edition was not read.
|
||||
|
||||
The rules:
|
||||
|
||||
- A sink claiming a tier MUST evaluate it over the medium it **emits**. If it
|
||||
applies post-decode processing that alters that medium, it MUST either not
|
||||
apply the processing, or MUST NOT claim the tier for the emitted result.
|
||||
- An object that honours a decoding-operation-reduction hint MUST NOT claim
|
||||
`decode-equivalence`, and a receipt over its output MUST NOT carry a
|
||||
reproducible decoded-medium hash. Spending fewer joules by computing less is a
|
||||
fidelity choice; a receipt that reports the joules while concealing the
|
||||
applies processing to the decoded medium that alters it — after decode, as
|
||||
attenuation maps and display adaptation do, or fed back into the decode as
|
||||
cross-segment decoding does — it MUST either not apply the processing, or MUST
|
||||
NOT claim the tier for the emitted result.
|
||||
- A tier claim, a decoded-medium hash or an energy figure over a payload that an
|
||||
encoder altered to save energy — at a receiver's request, such as a
|
||||
decoding-operation-reduction or attenuated-video request, or on its own
|
||||
account, as low-power encoding does — covers that payload, not the one it
|
||||
stands in for, and a receipt over it MUST NOT be presented as covering the
|
||||
payload it stands in for. Spending fewer joules by computing or emitting less is
|
||||
a fidelity choice; a receipt that reports the joules while concealing the
|
||||
degradation states a cost without its consideration.
|
||||
- A capability's registration SHOULD state whether its payload can carry
|
||||
post-decode processing directives at all. A capability whose payload cannot is
|
||||
|
|
@ -108,23 +253,75 @@ thing.
|
|||
|
||||
## 3. Declaring and using a tier
|
||||
|
||||
- A capability's registration (§5) states its tier via its `*-equivalence`
|
||||
criterion; the WAI capabilities that decode a learned image/audio/3D latent to
|
||||
bytes (`wai.image.jpegai`, `wai.neural.int_*`, `wai.audio.int_codec`,
|
||||
`wai.splat.int_codec`) are `decode-equivalence`. A capability MAY instead
|
||||
declare `entropy-consistency` when it only guarantees the entropy stage.
|
||||
- **`replicate`-soundness (§7).** An envelope with `intent = replicate` MUST pin a
|
||||
prior that meets at least `entropy-consistency`; a float neural decode meets
|
||||
neither tier and MUST NOT claim `replicate`. A receipt that carries a
|
||||
reproducible decoded-medium hash MUST come from a `decode-equivalence`
|
||||
capability.
|
||||
- **Declaring.** A capability's registration (SPEC §5) states its tier via its
|
||||
`*-equivalence` criterion, and its registry class carries it (SPEC §7):
|
||||
`NeuralIntegerExact` capabilities are registered at `decode-equivalence`,
|
||||
`NeuralEntropyExact` capabilities at `entropy-consistency`, and `NeuralFloat`
|
||||
capabilities claim neither. §5 lists WAI's capabilities at each tier. A
|
||||
capability MAY declare `entropy-consistency` when it only guarantees the entropy
|
||||
stage.
|
||||
- **Over a neural capability, `replicate` promises `decode-equivalence` (SPEC
|
||||
§7).** An envelope with `intent = replicate` over a neural capability MUST be
|
||||
over a capability registered at `decode-equivalence`, which SPEC §7 admits only
|
||||
by the integer construction: an integer / fixed-point decode path with no float
|
||||
operation.
|
||||
`entropy-consistency` MUST NOT back `replicate`. A neural decode that derives
|
||||
its entropy parameters in float meets neither tier; one that reads them from the
|
||||
codestream, or derives them in integer arithmetic, and runs its later stages in
|
||||
float meets `entropy-consistency` only. A reconstruction that one
|
||||
implementation pins through fixed-order float stages does not back `replicate`
|
||||
either: what makes such a stage reproducible — a build that emits no fused or
|
||||
reassociated operations, the default floating-point environment in the running
|
||||
process, library functions whose last-place error cannot reach the output —
|
||||
belongs to one implementation and one process, and neither the envelope nor the
|
||||
registry can state it. That is why `wai.image.jpegai` is registered at
|
||||
`entropy-consistency` and does not back `replicate` (§5).
|
||||
- **Over a standard codec, `replicate` promises the named standard's decoder
|
||||
conformance (SPEC §7, *What `replicate` promises over a standard codec*).** For
|
||||
some standards that is the same bytes on every sink; others hold decoders to a
|
||||
criterion around a reference — numeric thresholds in the clauses read for Opus
|
||||
and JPEG XL; for JPEG and JPEG 2000 a criterion whose bound the text read does
|
||||
not state (SPEC §7); and, for AV1 when film grain is signalled, a perceptual
|
||||
criterion the AV1 specification leaves undefined — and over those `replicate`
|
||||
promises that criterion, not byte identity. The tiers in this document describe
|
||||
neural capabilities. `wai.image.jpegai` has a named standard too, and the
|
||||
overview's account of its conformance part (§1) points to a criterion around a
|
||||
reference on the reconstruction; if Part 4 states one, that would put it among
|
||||
the standards whose conformance `replicate` could promise. That part has not
|
||||
been read here. Holding `wai.image.jpegai` to
|
||||
`decode-equivalence`, and so refusing `replicate` over it, is a conservative
|
||||
choice pending that reading, not a finding about the standard; SPEC §7
|
||||
(*`wai.image.jpegai` and the standard classes*) states the choice and how it
|
||||
differs from the choice made for the standard codecs.
|
||||
- **What the reference impl checks.** `decode_envelope_strict` applies SPEC §7 in
|
||||
two steps (`codecs::replicate_refusal`). First the capability's registry class:
|
||||
only `NeuralIntegerExact` passes among the neural classes (the three standard
|
||||
classes, which are not neural, are not refused by this rule). The class does
|
||||
not depend on anything the sender declares, so a `replicate` envelope over `wai.image.jpegai` or a float
|
||||
codec is refused even when its prior declares an integer contract. Then, for an
|
||||
integer-exact capability, the pinned prior: `Prior::determinism_class` must
|
||||
classify its sender-declared contract string as integer-exact. That
|
||||
classification is a substring match (a contract containing `int`, `fixed` or
|
||||
`integer` and none of `f32`, `f64`, `float`), so on its own it verifies the
|
||||
declaration, not the arithmetic. Neither step inspects the decode path a sink
|
||||
actually runs; for `wai.neural.int_synth`, the one `NeuralIntegerExact`
|
||||
capability the reference neural dispatch decodes, there is only the integer
|
||||
path.
|
||||
- **Receipts.** A receipt that carries a decoded-medium hash as reproducible by
|
||||
any conforming sink MUST come from a `decode-equivalence` capability. A hash
|
||||
over a reconstruction that one implementation pins (§5) is that
|
||||
implementation's, and a receipt MUST NOT present it as the capability's.
|
||||
- **Post-decode processing.** A tier claim is void if the sink alters the medium
|
||||
after decode (§2, *What a tier covers*). This applies to the emitted result,
|
||||
not to the decoder's internal conformance.
|
||||
- **Provenance.** The [reproducible-reconstruction binding](reconstruction-binding.md)
|
||||
— a C2PA / JPEG-Trust hard binding over decoded pixels — requires
|
||||
`decode-equivalence`; over an `entropy-consistency` capability only the
|
||||
entropy-stage output is bindable, not the rendered result.
|
||||
— a C2PA / JPEG-Trust hard binding over decoded pixels — is checkable by every
|
||||
conforming sink only over a `decode-equivalence` capability; over an
|
||||
`entropy-consistency` capability only the entropy-stage output is bindable that
|
||||
way. [reconstruction-binding](reconstruction-binding.md) §1–§2 also define a
|
||||
binding over `wai.image.jpegai` as a binding over its exact decoder's pinned
|
||||
reconstruction; that binding is checkable only by that decoder under the
|
||||
conditions in §5–§6.
|
||||
|
||||
## 4. Framing
|
||||
|
||||
|
|
@ -134,9 +331,183 @@ downstream model's behaviour rather than a byte comparison — see
|
|||
[task-fidelity](task-fidelity.md), which is a sibling rather than a third tier
|
||||
precisely because such a claim is *not* sink-checkable from the bytes.
|
||||
|
||||
WAI spans the spectrum rather than competing on one point of it. The
|
||||
`entropy-consistency` tier is the base learned-codec floor — the guarantee the
|
||||
field and the underlying standards already make — and WAI supports it directly.
|
||||
`decode-equivalence` is the tier WAI adds on top: pinning one full reconstruction
|
||||
so the rendered result, not only the entropy stream, is reproducible and
|
||||
hashable. Both are stated as capabilities of the standard, not as comparisons.
|
||||
The two tiers are named so that each capability states which one it makes.
|
||||
`entropy-consistency` is the tier at which JPEG AI sets its bit-exact conformance
|
||||
point, and the tier WAI registers `wai.image.jpegai` at. `decode-equivalence`
|
||||
pins one full reconstruction, so the rendered result, not only the entropy
|
||||
stream, is reproducible and hashable; it is what `replicate` over a neural
|
||||
capability promises. §5 lists the WAI capabilities at each tier, with what the
|
||||
tier costs them.
|
||||
|
||||
## 5. Where WAI offers each tier, and what it costs
|
||||
|
||||
### `decode-equivalence`
|
||||
|
||||
| capability | hashable medium | how the reconstruction is pinned |
|
||||
|---|---|---|
|
||||
| `wai.neural.int_synth` | RGB | integer synthesis (QAT weights) |
|
||||
| `wai.neural.int_hyper` | RGB | integer hyper-decoder, integer scale → distribution step, integer synthesis (post-training quantisation of a float model) |
|
||||
| `wai.video.int_hyper` | per-frame | an `int_hyper` keyframe, then integer motion-compensated P-frames |
|
||||
| `wai.audio.int_codec` | int16 PCM | integer synthesis over a factorized rANS latent |
|
||||
| `wai.splat.int_codec` | attribute tensor | integer synthesis over a factorized rANS latent |
|
||||
|
||||
These five are integer throughout, are the capabilities the registry classifies as
|
||||
`NeuralIntegerExact`, and are the neural capabilities that back `replicate`.
|
||||
|
||||
### `entropy-consistency`: `wai.image.jpegai`, and its exact decoder's pinned reconstruction
|
||||
|
||||
The registry classifies `wai.image.jpegai` as `NeuralEntropyExact` and registers
|
||||
it at `entropy-consistency`. **This is a downgrade:** earlier in v0.4.0 the
|
||||
capability was listed in the table above and classified `StandardDefined`, and the reference
|
||||
strict check passed a `replicate` envelope over it whenever the prior declared an
|
||||
integer contract. It moved because its reconstruction runs float stages and the
|
||||
reference sink can decode it through a float ONNX Runtime path, so
|
||||
decode-equivalence never held as a property of the capability (SPEC §7).
|
||||
|
||||
| stage | arithmetic |
|
||||
|---|---|
|
||||
| entropy decode (mANS) and the scale-index derivation (an integer hyper-scale network) | integer on both reference decode paths — what the capability guarantees |
|
||||
| hyper-decoder, context-model and synthesis networks | 16-bit-PTQ integer in the exact decoder; float through ONNX Runtime in the fallback |
|
||||
| dequantisation, latent refinement, the post-filter chain (the eICCI post-filter is a float CNN), colour conversion | IEEE-754 float in a fixed evaluation order in the exact decoder; float in the fallback |
|
||||
|
||||
**The exact decoder's pinned reconstruction.** WAI's exact decoder
|
||||
(`jpegai_decode::decode`) pins one reconstruction to canonical `RGB8`: the
|
||||
high-operation-point synthesis, then the post-filters, in the arithmetic above. It
|
||||
reproduces across machines when the conditions in §6 hold: the build, the default
|
||||
floating-point environment (which the decoder probes before decoding,
|
||||
`jpegai_decode::check_scope`), and the margin of its one library call. Those
|
||||
conditions belong to this implementation. That is why the pinned reconstruction is
|
||||
not a tier, does not back `replicate`, and is bindable only as
|
||||
[reconstruction-binding](reconstruction-binding.md) defines.
|
||||
|
||||
The exact decoder implements one configuration, which its tests exercise.
|
||||
`jpegai_decode::check_codestream` accepts a codestream only when its headers select
|
||||
exactly that configuration:
|
||||
|
||||
- a 256×256, 8-bit, 4:4:4 picture with no display cropping and the built-in
|
||||
YUV→RGB colour transform;
|
||||
- the high-operation-point synthesis (`synthesis_transform_id` 2);
|
||||
- `model_id` 0, whose gain, LSBS and LEF tables and residual-scaling constants are
|
||||
tools_0's;
|
||||
- `beta_displacement_log` 0 for luma and chroma. The exact decoder does not
|
||||
implement the quantiser's β displacement, so a codestream with any other β is
|
||||
refused, not decoded;
|
||||
- 160 luma and 96 chroma latent channels, one entropy substream per plane, and no
|
||||
region partitioning, cube flags, 3-D gain or synthesis tiling; LSBS, residual
|
||||
variance scaling and GRFS enabled;
|
||||
- post-filters only in the forms implemented: one single-tap linear enhancement
|
||||
filter per chroma plane; eICCI untiled on all three planes with the model pair the
|
||||
weight bundle carries (short-list indices 0 and 1 — the bundle format does not
|
||||
record its pair, and the exporter emits only that one); the nonlinear enhancement
|
||||
filter untiled and unmasked, with eight weights; LEF on a luma channel;
|
||||
- both headers parse to the end of their segments, and the SOZ, SORP and SORS
|
||||
substreams are present with no SOQ segment.
|
||||
|
||||
That is narrow. Of the reference encoder's five default rate points
|
||||
(`cfg/BRM/default.json`), only the first selects `model_id` 0 with β = 0; the
|
||||
others select `model_id` 1–3 or a non-zero β and are refused, as is any codestream
|
||||
to which the encoder's bitrate matcher assigns a non-zero β.
|
||||
|
||||
The float ONNX path hard-codes the same models, tables and filter selection, and
|
||||
refuses the same codestreams, so the reference sink refuses a codestream outside
|
||||
this configuration rather than decoding it to the wrong image. Within it, the exact
|
||||
decoder runs when the sink supplies its integer weight bundle and the thread's
|
||||
floating-point environment is the IEEE-754 default. Otherwise the reference sink
|
||||
decodes the same capability ID through the float ONNX Runtime path, whose
|
||||
reconstruction is not pinned. Both paths return the same result type, and the
|
||||
reference dispatch does not report which one ran. A decoded-pixel hash or a
|
||||
[reconstruction binding](reconstruction-binding.md) over `wai.image.jpegai` holds
|
||||
only for output of the exact decoder.
|
||||
|
||||
### What `decode-equivalence` costs
|
||||
|
||||
The tier adds nothing to the wire: nothing is transmitted beyond the capability's
|
||||
own codestream. The costs fall elsewhere, and the JPEG AI exact decoder pays the
|
||||
same ones for its integer networks:
|
||||
|
||||
- **Fidelity to the float model.** The quantised networks do not reproduce the
|
||||
float model's output, so the pinned reconstruction differs from it. For
|
||||
`wai.neural.int_hyper`, `wai-rs/src/int_hyper_synth.rs` records 42.6 dB PSNR for
|
||||
one pretrained model (`mbt2018_mean`), within ~0.6 dB of the float model; the
|
||||
test image, quality level and machine are not recorded there. For the JPEG AI
|
||||
exact decoder, `wai-rs/tests/jpegai_e2e_full.rs` compares against the reference
|
||||
decoder's output on one 256×256 reference codestream and asserts max|Δ| ≤ 2 with
|
||||
at most 5% of samples differing; the recorded result is max|Δ| = 1 on 4.446% of
|
||||
samples (macOS arm64, release build, 2026-09-27). Neither figure is re-derived in
|
||||
CI (§6).
|
||||
- **Compute.** The reference decoders are single-threaded CPU code with no
|
||||
explicit SIMD, in integer arithmetic (i64, with i128 intermediates in places;
|
||||
plus fixed-order float for the JPEG AI exact decoder's float stages). They
|
||||
cannot use the float GPU / NPU paths a float learned decoder runs on. This
|
||||
document states no throughput figure for them.
|
||||
- **Model preparation.** A model is offered at this tier only once exported into
|
||||
the decoder's pinned form, sink-supplied: quantised weights and requantisation
|
||||
constants for the integer networks (and, for the JPEG AI exact decoder's eICCI
|
||||
post-filter, float weights with BatchNorm folded in). A float-only model is not
|
||||
offered at this tier as it stands.
|
||||
|
||||
Parameter transmission pays in bitrate and leaves the decoder's arithmetic free;
|
||||
the integer decode pays in quantisation, compute and model preparation and adds no
|
||||
bits. A capability's tier states which trade it made.
|
||||
|
||||
## 6. Evidence status
|
||||
|
||||
What the repository demonstrates, claim by claim, as of 2026-09-27 (main at
|
||||
`afc7ece`). A test that skips reports as passing, and a matrix leg whose runner did
|
||||
not run reports nothing; neither is evidence.
|
||||
|
||||
The CI rows below come from the forge's commit statuses
|
||||
(`/api/v1/repos/Transaction-Science/open-standards/commits/<sha>/statuses`), read
|
||||
for every commit on main since 2026-08-10 and for the pre-merge commits named, not
|
||||
from the workflow definitions. Two workflows run the same golden-byte suite
|
||||
(`wai/byte-exact-conformance`, `cargo test --release`): the *cross-arch
|
||||
byte-equality* job of `wai-conformance.yml`, and `wai-byte-equality.yml`. Both
|
||||
declare Linux x86_64, Linux arm64, macOS arm64 and Windows x86_64 legs; there is no
|
||||
macOS x86_64 or Windows arm64 leg. No Windows x86_64 job has run for this
|
||||
repository since 2026-08-27: every later Windows status on main is "Waiting to run"
|
||||
or "Has been cancelled", and the forge's task list has no Windows task after that
|
||||
day.
|
||||
|
||||
| claim | evidence | where |
|
||||
|---|---|---|
|
||||
| Cross-architecture identity of the rANS coder, `int_synth`, and the JPEG AI symbol decode (a reference-encoder codestream, given its distribution indices) | golden-byte assertions passed on Linux x86_64, Linux arm64 and macOS arm64 on main at `afc7ece` (2026-09-27, `wai-conformance.yml`; `wai-byte-equality.yml` last ran on main at `3f50097`, 2026-08-29, all three legs passing), and on Windows x86_64 last on main at `3e7811f` (2026-08-27). Between `3e7811f` and `afc7ece` the suite only gained the video and keyframe goldens; these goldens, the sources they decode and the suite's lockfile are unchanged | `byte-exact-conformance/`; `.github/workflows/wai-conformance.yml`, `wai-byte-equality.yml` |
|
||||
| Cross-architecture identity of integer inter-frame video, and of `int_hyper` on a small learned keyframe | the same suite, passing on Linux x86_64, Linux arm64 and macOS arm64 on main at `afc7ece` (2026-09-27). Windows x86_64 never decoded the keyframe clip: it was added in `d4c922b` (2026-08-28), whose Windows legs were cancelled. Windows decoded the integer video goldens only on the pre-merge commits `c9be2ad`, `256e5dd`, `7dfca26` and `3d34860` (2026-08-25/26), whose video sources, vectors and golden file match main but whose `byte-exact-conformance/Cargo.lock` differs; the change reached main at `3f50097`, after the last Windows run on main | as above |
|
||||
| `wai.image.jpegai` exact decoder: the integer derivation of the distribution indices matches the reference decoder exactly; the whole decode stays within a stated bound of it (max\|Δ\| ≤ 2, ≤ 5% of samples) | tests on one machine that skip unless their fixtures (sink-supplied weights, normative tables, codestream) are provided; CI does not provide them. The whole-decode test last ran on macOS arm64 on 2026-09-27 with a local bundle | `wai-rs/tests/jpegai_hyperscale_calibration.rs`, `jpegai_e2e_full.rs` |
|
||||
| `wai.image.jpegai` scope: the reference codestream is accepted; copies with β, `model_id`, the colour transform or an LSBS flag changed are refused; a flush-to-zero or round-toward-zero environment is detected. The float ONNX path calls the same check | library unit tests over a committed copy of the reference codestream, which never skip and fall under the library-test step of the conformance workflow (`neural_int`); the environment test runs on arm64 only. Run so far on macOS arm64 only. The float path's refusal (β and `model_id` edits) is tested only with its ONNX bundle supplied (`jpegai_scope_ort.rs`, skips otherwise) | `wai-rs/src/jpegai_decode.rs` tests, `wai-rs/tests/vectors/jpegai/` |
|
||||
| SPEC §7's replicate rule: the registry class decides first, so an integer-declared prior over `wai.image.jpegai` or a float codec is refused; `wai.image.jpegai` is the only `NeuralEntropyExact` capability; the standard codecs sit in the classes SPEC §7 lists, and the tolerance and unclassified ones are not refused; an encoder that pins no prior (`wai wrap`) writes `replicate` only over the standard classes, for the capability and for any declared fallback | library unit tests (`codecs`, `container`) that never skip and fall under the same library-test step. The strict-decode test in `tests/neural_native_decode.rs` needs the `neural` feature; `wai-neural-gates.yml` runs it on the Linux runner, in an Ubuntu 24.04 image because the `neural` test binary does not link in that runner's default 22.04 image. The workflow has not run through the forge; its job passed under `forgejo-runner exec` on the Linux runner's host (Linux x86_64, 2026-09-27). The test that runs the `wai wrap` binary needs the `codecs` feature, which no CI job builds. Otherwise run so far on macOS arm64 only | `wai-rs/src/codecs/mod.rs`, `container.rs` tests; `wai-rs/tests/neural_native_decode.rs`, `cli_wrap_intent.rs` |
|
||||
| `wai.neural.int_hyper` and `wai.video.int_hyper` at full model scale | tests that skip when the exported model is absent; not run in CI | `wai-rs/tests/int_hyper_synth.rs`, `int_video_sota_keyframe.rs` |
|
||||
| `wai.audio.int_codec`, `wai.splat.int_codec` | committed vectors that never skip, matched against an independent Python integer reference; their cargo features (`audio_int`, `splat_int`) are enabled by no CI job | `wai-rs/tests/int_audio.rs`, `int_splat.rs` |
|
||||
|
||||
So at `entropy-consistency`, WAI's JPEG AI symbol decode is demonstrated across
|
||||
architectures (x86_64 against arm64) once the distribution indices are given; the
|
||||
integer derivation of those indices is demonstrated against the reference on one
|
||||
machine, by a test CI does not run. At `decode-equivalence`, cross-architecture
|
||||
identity (x86_64 against arm64) is demonstrated for `int_synth`, integer video and
|
||||
`int_hyper` on committed small-scale vectors; of these, only `int_synth` has also
|
||||
been decoded on Windows on main. `wai.audio.int_codec` and `wai.splat.int_codec`
|
||||
reproduce a separate implementation's output, but no CI job runs them and no
|
||||
cross-architecture comparison exists. For full-scale models, identity rests on
|
||||
construction, not on a cross-machine comparison of decoded output.
|
||||
|
||||
For the JPEG AI exact decoder's pinned reconstruction (§5), identity across
|
||||
machines also rests on construction, not on comparison. The construction is
|
||||
integer arithmetic for the integer stages and, for the float stages, only IEEE-754
|
||||
basic operations, which are correctly rounded:
|
||||
|
||||
- evaluated single-threaded in the fixed order of the source, each at its own
|
||||
precision (true of x86_64, AArch64 and wasm32 targets; not of x87);
|
||||
- with no fused or reassociated operations, which Rust does not emit unless the
|
||||
source asks for them;
|
||||
- in the default floating-point environment, which the exact decoder probes before
|
||||
decoding (§5).
|
||||
|
||||
One float stage calls the platform `exp` (the per-channel gain scaler, rounded to
|
||||
2⁻¹⁰), which math libraries are not required to round correctly. Its inputs are
|
||||
exactly the normative gain tables, because the decoder refuses β ≠ 0. Every result
|
||||
lies more than 10¹⁰ f64 ULPs from a rounding boundary — checked with 60-digit
|
||||
decimal arithmetic by `tools/wai_jpegai_gain_exp_margin.py` over the tables exported
|
||||
from the reference software — so a last-place difference between math libraries
|
||||
cannot change it. Its `--beta-sweep` option checks every β the 12-bit header field
|
||||
can carry: the smallest margin over those inputs is 3.7 × 10⁸ ULPs. A decoder that
|
||||
implemented β would therefore not reopen this argument; this one does not implement
|
||||
it.
|
||||
|
|
|
|||
|
|
@ -51,8 +51,12 @@ a manifest whose two digests disagree is self-refuting.
|
|||
|
||||
## 3. What this makes checkable, and what it does not
|
||||
|
||||
Because a WAI reconstruction is byte-exact and reproducible on every
|
||||
architecture, a verifier holding the codestream can:
|
||||
Where the reconstruction is at `decode-equivalence` — reproducible byte for byte
|
||||
on every conforming sink ([determinism-tiers](determinism-tiers.md) §2) — a
|
||||
verifier holding the codestream can do the following with any conforming decoder,
|
||||
and over `wai.image.jpegai`'s exact-decoder reconstruction only with that decoder
|
||||
under the conditions in [determinism-tiers](determinism-tiers.md) §5
|
||||
([reconstruction-binding](reconstruction-binding.md) §2):
|
||||
|
||||
- re-decode under the pinned descriptor,
|
||||
- hash the pixels and confirm the energy figure is about **those** bytes,
|
||||
|
|
@ -176,9 +180,13 @@ by decoding worse, and a figure that cannot distinguish *efficient* from
|
|||
*degraded* rewards the wrong behaviour precisely where the number is meant to
|
||||
carry weight.
|
||||
|
||||
This is not hypothetical. ISO/IEC 23001-11 carries decoding-operation-reduction
|
||||
metadata whose purpose is to make a decoder do less; the sender requests a
|
||||
reduction, and the receipt as specified today records only what was spent.
|
||||
This is not hypothetical. ISO/IEC 23001-11 defines a decoding operation reduction
|
||||
request (DOR-Req) with which a receiving device asks the remote encoder for a less
|
||||
complex bitstream, so that its own decoder does less, and notes that its metadata
|
||||
can save more energy "at the expense of some QoE degradation". Its energy
|
||||
quantities are expected or potential savings stated in advance, not energy that
|
||||
was spent (determinism-tiers §2), and a WAI receipt without §7.2's fields records
|
||||
only what was spent, with nothing about the operating point it was spent at.
|
||||
`energy-measurement.md` §5's recomputable-work-unit rule blocks the substitution
|
||||
at the byte-exact tier, but not at `entropy-consistency`, and not for the
|
||||
conventional codecs WAI already carries.
|
||||
|
|
@ -188,15 +196,19 @@ is scored against something rather than merely reported.
|
|||
|
||||
### 7.2 Request, commitment, delivery
|
||||
|
||||
Where a sender requests an operating point and a receiver acts on it, the receipt
|
||||
Where one party requests an operating point and another acts on it, the receipt
|
||||
**MUST** seal all three of:
|
||||
|
||||
| field | meaning |
|
||||
|---|---|
|
||||
| `op_requested` | the operating point the sender asked for |
|
||||
| `op_committed` | the operating point the receiver said it would use |
|
||||
| `op_requested` | the operating point the requesting party asked for |
|
||||
| `op_committed` | the operating point the acting party said it would use |
|
||||
| `op_delivered` | the operating point actually used |
|
||||
|
||||
In the 23001-11 case in §7.1 the receiver requests and the sender acts: a
|
||||
receiving device sends a DOR-Req, and the remote encoder answers with a DOR-Resp
|
||||
saying how it decided to answer.
|
||||
|
||||
An operating point is a class-scoped descriptor — frame rate, spatial resolution,
|
||||
a complexity target — and this extension does not define its vocabulary. What it
|
||||
fixes is that the three are **distinct fields**, because the interesting cases are
|
||||
|
|
@ -204,14 +216,16 @@ exactly the ones where they differ.
|
|||
|
||||
- A receipt **MUST NOT** carry `op_delivered` alone. A delivered figure with
|
||||
nothing to score it against is the degradation-blind case §7.1 describes.
|
||||
- `op_committed` **MUST** be recorded as what the receiver stated, even where it
|
||||
differs from the request. A commitment that silently becomes the request is not
|
||||
- `op_committed` **MUST** be recorded as what the acting party stated, even where
|
||||
it differs from the request. A commitment that silently becomes the request is not
|
||||
a commitment.
|
||||
- Where `op_delivered` differs from `op_committed`, the receipt **MUST** record
|
||||
both and **MUST NOT** claim the commitment was met.
|
||||
- A sink that honoured an operation-reduction request **MUST NOT** claim
|
||||
`decode-equivalence` for the result — see [determinism-tiers](determinism-tiers.md)
|
||||
§2, *What a tier covers*.
|
||||
- A receipt over a payload that an encoder altered to save energy, whether at a
|
||||
receiver's request (such as a decoding-operation-reduction or attenuated-video
|
||||
request) or on its own account, covers that payload, and **MUST NOT** be
|
||||
presented as covering the payload it stands in for — see
|
||||
[determinism-tiers](determinism-tiers.md) §2, *What a tier covers*.
|
||||
|
||||
This converts a recorded number into a number measured against a promise. Neither
|
||||
the prescriptive standards nor the measurement standards provide that pair: one
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@
|
|||
|
||||
A provenance manifest binds itself to an asset with a **hard binding**: a
|
||||
cryptographic hash over the asset's bytes. For neural-coded media that hash
|
||||
covers the *compressed* codestream, and it has been the only hard option
|
||||
available — because a neural decode is normally not reproducible. Two conformant
|
||||
decoders may produce different pixels, so a hash of the *decoded image* is not
|
||||
portable across implementations, and provenance over the rendered result has had
|
||||
to fall back to fuzzy **soft** bindings (perceptual hashes, watermarks), which
|
||||
are approximate and spoofable.
|
||||
covers the *compressed* codestream. A hard binding over the *decoded image* is
|
||||
possible only when the decode is reproducible: where two conformant decoders may
|
||||
produce different pixels, a hash of the decoded image is not portable across
|
||||
implementations, and provenance over the rendered result falls back to fuzzy
|
||||
**soft** bindings (perceptual hashes, watermarks), which are approximate and
|
||||
spoofable.
|
||||
|
||||
This is not incidental to the codec. The JPEG AI standard (ISO/IEC 6048 /
|
||||
ITU-T T.840) defines its normative bit-exact conformance point at the **output
|
||||
|
|
@ -27,12 +27,33 @@ to pixels is therefore, by design, **not** required to be bit-exact, and one
|
|||
codestream may legally decode to different images. A hash of the decoded pixels is
|
||||
not portable under the base standard.
|
||||
|
||||
WAI decodes to RGB **deterministically** — one pinned reconstruction, byte-identical
|
||||
on every machine (integer entropy and dequant; fixed-order, reproducible synthesis).
|
||||
Pinning one reconstruction is a determinism guarantee **beyond what the base standard
|
||||
requires**, and it restores exactly the precondition a hard binding needs: a stable,
|
||||
portable hash of the decoded pixels. This extension expresses that hash as a
|
||||
provenance assertion.
|
||||
Over a capability registered at `decode-equivalence` — WAI's integer-exact
|
||||
decoders, `wai.neural.int_hyper` and the other `NeuralIntegerExact` capabilities
|
||||
([determinism-tiers](determinism-tiers.md) §5) — every conforming sink
|
||||
reconstructs the same pixels, so the decoded-pixel hash is portable by
|
||||
construction.
|
||||
|
||||
`wai.image.jpegai` is registered at `entropy-consistency`, the tier of the base
|
||||
standard's conformance point. WAI's exact JPEG AI decoder nevertheless reconstructs
|
||||
to RGB **deterministically** — one pinned reconstruction, reproducible across
|
||||
machines under stated conditions. Its entropy decode and its hyper-decoder,
|
||||
context-model and synthesis networks are integer; dequantisation, latent
|
||||
refinement, the post-filter chain (including the eICCI post-filter, a float CNN)
|
||||
and colour conversion run in IEEE-754 float with a fixed evaluation order, in the
|
||||
default floating-point environment, which the decoder checks before decoding. It
|
||||
implements one configuration: 256×256 4:4:4, `model_id` 0 (tools_0),
|
||||
`beta_displacement_log` 0, the high-operation-point synthesis (so a binding over its
|
||||
output carries `decoderId` 2), and the other header conditions in
|
||||
[determinism-tiers](determinism-tiers.md) §5. The reference sink refuses codestreams
|
||||
outside that configuration. Within it, a sink without the integer weight bundle, or
|
||||
in a non-default floating-point environment, falls back to a float decode whose
|
||||
pixels are not pinned, and no binding applies to its output. The pinned
|
||||
reconstruction is a property of the exact decoder, not of the capability: its
|
||||
reproducibility rests on that decoder's build and on the process's floating-point
|
||||
environment ([determinism-tiers](determinism-tiers.md) §5–§6). Within those
|
||||
conditions it restores the precondition a hard binding needs — a stable hash of the
|
||||
decoded pixels — for a verifier that runs the same decoder (§2). This extension
|
||||
expresses that hash as a provenance assertion.
|
||||
|
||||
A `reconstruction-binding` is **not a content capability**. The asset declares an
|
||||
ordinary capability (`wai.image.jpegai`, `wai.neural.int_hyper`, …) and is carried
|
||||
|
|
@ -48,7 +69,8 @@ A binding is a hash plus the descriptor that makes the decode reproducible:
|
|||
"alg": "sha256",
|
||||
"hash": "<lowercase hex SHA-256 over the canonical decoded pixels>",
|
||||
"reconstruction": {
|
||||
"decoderId": 0, // the pinned synthesis branch (multi-branch codecs)
|
||||
"decoderId": 2, // the pinned synthesis branch (multi-branch codecs;
|
||||
// 2 for wai.image.jpegai's exact decoder)
|
||||
"profile": "<id>", // codec profile
|
||||
"level": "<id>", // codec level
|
||||
"width": 256,
|
||||
|
|
@ -69,9 +91,21 @@ A binding is a hash plus the descriptor that makes the decode reproducible:
|
|||
`decoderId`, `profile`, and `level` before hashing, or the comparison is
|
||||
meaningless. The descriptor pins the one reconstruction the hash is over.
|
||||
|
||||
Conformance criterion: **decode-equivalence** (see [determinism-tiers](determinism-tiers.md)) — a verifier that decodes the
|
||||
codestream with a WAI decoder under the binding's descriptor, hashes the canonical
|
||||
`RGB8` buffer, and compares MUST obtain the recorded `hash`.
|
||||
Conformance criterion:
|
||||
|
||||
- Over a capability registered at **decode-equivalence** (see
|
||||
[determinism-tiers](determinism-tiers.md)), a verifier that decodes the
|
||||
codestream with any conforming decoder under the binding's descriptor, hashes the
|
||||
canonical `RGB8` buffer, and compares MUST obtain the recorded `hash`.
|
||||
- Over `wai.image.jpegai` (registered at `entropy-consistency`), the hash is over
|
||||
the reconstruction of WAI's exact decoder (§1). A verifier MUST decode with that
|
||||
decoder — not the float fallback — in the default floating-point environment,
|
||||
and then MUST obtain the recorded `hash`. A verifier that decodes any other way
|
||||
has not checked the binding: a mismatch it finds is not evidence that the asset
|
||||
changed, and it MUST NOT report the binding as failed on that basis. The
|
||||
reference dispatch (`decode_envelope`) does not report which path ran, so a
|
||||
verifier calls the exact decoder directly (`jpegai_decode::decode`), which
|
||||
refuses rather than falls back.
|
||||
|
||||
## 3. C2PA / JPEG Trust carriage
|
||||
|
||||
|
|
@ -93,7 +127,8 @@ assertions:
|
|||
claim's `created_assertions`, so it is valid in any C2PA validator; the
|
||||
reconstruction binding sits **beside** it. The byte-binding proves *these
|
||||
compressed bytes*; the reconstruction binding upgrades that to *and anyone who
|
||||
decodes them per this descriptor obtains this exact image*.
|
||||
decodes them per this descriptor obtains this exact image* (for
|
||||
`wai.image.jpegai`, anyone who decodes them with the exact decoder, §2).
|
||||
- **Signature:** the assertion is covered by the C2PA claim signature like any
|
||||
other, so it is tamper-evident.
|
||||
|
||||
|
|
@ -106,7 +141,8 @@ WAI receipt.
|
|||
The binding MAY be carried in a WAI receipt alongside an [asset
|
||||
provenance](provenance.md) receipt: provenance binds the opaque asset bytes
|
||||
(content-hash-equivalence, BLAKE3 over the envelope); this binds the reconstructed
|
||||
pixels (decode-equivalence, SHA-256 over the canonical RGB). Together they cover
|
||||
pixels (SHA-256 over the canonical RGB — decode-equivalence, or for
|
||||
`wai.image.jpegai` the exact decoder's pinned reconstruction). Together they cover
|
||||
both halves of the thesis — the bytes that are carried and the pixels that are
|
||||
reconstructed. The reference impl emits the §2 JSON via
|
||||
`ReconstructionBinding::to_json`.
|
||||
|
|
|
|||
|
|
@ -113,6 +113,13 @@ out[c][t] = Σ_objects src_o[t] · gain_o · dist_atten(|p_o(t)|) · pan_gain(p
|
|||
mixdown_hash = BLAKE3("wai:audio-mixdown\x01" || layout_id || pcm_i16le)
|
||||
```
|
||||
|
||||
The mixdown is a function of the sources' decoded PCM, so the hash is portable
|
||||
only as far as that PCM is. A source whose capability promises the same bytes on
|
||||
every sink (`wai.audio.flac`, an integer codec) keeps it portable; a source decoded
|
||||
through a codec whose standard conforms decoders to a tolerance (`wai.audio.opus`,
|
||||
SPEC §7, `StandardTolerance`) may decode differently on two conforming sinks, and
|
||||
then so does the mixdown.
|
||||
|
||||
The `stereo` floor is mandatory and bit-exact. `binaural@<hrtf>` is
|
||||
perceptual (conformance is similarity, not bytes — a sink advertising
|
||||
it states the metric, like the `wai.semantic.*` path). The conformance
|
||||
|
|
|
|||
|
|
@ -98,8 +98,9 @@ formatted δ says nothing about whether anyone ran the test.
|
|||
task, not perceptual fidelity, and the two **MUST NOT** be reported in the same
|
||||
field.
|
||||
- It does **not** license degradation elsewhere. A task-fidelity claim says
|
||||
nothing about energy, and an object honouring a decoding-operation-reduction
|
||||
hint is still bound by `determinism-tiers.md` §2.
|
||||
nothing about energy, and a payload an encoder altered to save energy, such as
|
||||
one produced in answer to a decoding-operation-reduction request, is still bound
|
||||
by `determinism-tiers.md` §2.
|
||||
|
||||
## 5. The split-computation case — named, not solved
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,23 @@
|
|||
> specified something, WAI names it, registers a capability string for it, or
|
||||
> profiles it — and does not restate it. Where WAI's own text has a hole, the
|
||||
> hole is stated plainly.
|
||||
>
|
||||
> **Later revision: ISO/IEC 23001-11.** This survey read 23001-11's
|
||||
> decoding-operation reduction as a hint on which a decoder decodes worse. That
|
||||
> reading is superseded wherever it appears: §1.2 (degradation under a power-saving
|
||||
> hint), §2 (a hint that degrades decode), §3.2 Instance two, §5.3(d) and (e) (an
|
||||
> operation reduction the sender requested, as a departure from byte-exact
|
||||
> reconstruction), §8 row 1 and §9 item 2. In the 4th-edition CD text (WG 3
|
||||
> N1864), a decoding operation reduction request goes from the receiving device
|
||||
> to the remote encoder, which sends a less complex bitstream. Where that text
|
||||
> allows "larger energy savings, but at the expense of some QoE degradation", the
|
||||
> loss comes from what is sent (a payload altered before it is sent, or a
|
||||
> lower-quality representation chosen) or from processing of the decoded
|
||||
> pictures, not from a decoder decoding its payload worse. Its energy
|
||||
> quantities are expected or potential savings, not energy that was spent.
|
||||
> `determinism-tiers.md` §2 sorts that text's metadata sets by what they change
|
||||
> and states the rules over them; the passages above are left as first written.
|
||||
> The 2015 edition was not read, so §1.2's "since 2015" is unchecked.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -204,6 +221,10 @@ WAI's job.
|
|||
This is the highest-value finding in the document, and it is a defect in WAI's
|
||||
own text that exists whether or not anything external is ingested.
|
||||
|
||||
> **Later revision.** This section quotes `determinism-tiers.md` §3 as it stood
|
||||
> when the survey was written. §3 and SPEC §7 have since been revised: `replicate`
|
||||
> promises `decode-equivalence`, and `entropy-consistency` does not back it.
|
||||
|
||||
**Instance one — post-decode neural filters.** ITU-T H.274's `nnpfc` /
|
||||
`nnpfa` SEI messages activate a neural post-filter *after* a conformant decode,
|
||||
changing output pixels. `determinism-tiers.md` §3 says a capability's
|
||||
|
|
@ -222,6 +243,15 @@ reconstruction. The extension must say so. This is the same hole from the other
|
|||
side: a deliberate departure from the pinned reconstruction, with no tier
|
||||
consequence written down.
|
||||
|
||||
> **Later revision.** Instance two misdescribes ISO/IEC 23001-11. In its
|
||||
> 4th-edition CD text (WG 3 N1864), a decoding operation reduction request goes to
|
||||
> the remote encoder, which sends a less complex bitstream; the request does not
|
||||
> ask the decoder to decode worse. Of the metadata sets that text's Introduction
|
||||
> names, those that change the decoded medium are attenuation-map
|
||||
> post-processing, display adaptation and cross-segment decoding.
|
||||
> `determinism-tiers.md` §2 now describes each mechanism and states its rules over
|
||||
> them.
|
||||
|
||||
Both instances share a root cause: the tiers are defined over *the decode*, as if
|
||||
the decode were the whole pipeline between bytes and output. It is not.
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ decoded attribute tensor is byte-identical on every machine, a portable cloud
|
|||
hash. The float rasterizer stays sink-supplied presentation; the *attributes* are
|
||||
the contract.
|
||||
|
||||
That is the 3D instance of the same thesis WAI applies to `wai.image.jpegai`: the
|
||||
learned decode to the medium's canonical representation is pinned and integer, so
|
||||
the reconstruction has a portable hash. `wai.splat.int_codec` already sits at the
|
||||
That is the 3D instance of the same thesis WAI applies to its integer image
|
||||
codecs (`wai.neural.int_hyper`): the learned decode to the medium's canonical
|
||||
representation is pinned and integer, so the reconstruction has a portable hash. `wai.splat.int_codec` already sits at the
|
||||
**`decode-equivalence`** tier (see [`extensions/determinism-tiers.md`]) — the
|
||||
attribute tensor is the "final medium" whose bytes reproduce.
|
||||
|
||||
|
|
@ -57,18 +57,20 @@ attribute tensor is the "final medium" whose bytes reproduce.
|
|||
the MPEG splat-coding stream. The shared thing is the *problem and the approach*
|
||||
(a learned 3D decode that needs to be reproducible), not the wire format. A
|
||||
future `wai.pointcloud.*` that byte-exactly decodes a published 3D standard's
|
||||
codestream would be the 3D analogue of what `wai.image.jpegai` is for JPEG AI —
|
||||
and, because JPEG-Pleno PCC reuses JPEG AI for its colour attributes, the
|
||||
byte-exact JPEG-AI decode WAI already has is a component that path could build
|
||||
on. Not built; recorded as the natural next capability if the 3D neural-coding
|
||||
standards land in scope.
|
||||
codestream would be the 3D analogue of what WAI's exact JPEG AI decoder is for
|
||||
JPEG AI — and, because JPEG-Pleno PCC reuses JPEG AI for its colour attributes,
|
||||
that decoder (integer entropy decode and synthesis networks;
|
||||
`wai.image.jpegai` itself is registered at `entropy-consistency`, because its
|
||||
later stages are float) is a component that path could build on. Not built;
|
||||
recorded as the natural next capability if the 3D neural-coding standards land
|
||||
in scope.
|
||||
|
||||
## Takeaway
|
||||
|
||||
The determinism contract is not image-specific. WAI's byte-exact family already
|
||||
spans image (`jpegai`, `int_hyper`), audio (`int_codec`), and 3D
|
||||
(`splat.int_codec`); the reconstruction binding and the tier vocabulary apply to
|
||||
all of them. The emerging 3D neural-coding standards face the same
|
||||
spans image (`int_synth`, `int_hyper`), audio (`int_codec`), and 3D
|
||||
(`splat.int_codec`), with `jpegai` at `entropy-consistency` beside them; the
|
||||
reconstruction binding and the tier vocabulary apply to all of them. The emerging 3D neural-coding standards face the same
|
||||
non-determinism WAI addresses for 2D, and the JPEG-AI decode WAI has is a
|
||||
component of the point-cloud path — so the ingest is: keep the determinism
|
||||
contract media-general, and treat a byte-exact decode of a published 3D standard
|
||||
|
|
|
|||
|
|
@ -130,6 +130,68 @@ characteristics already in-band in the video bitstream and need only a manifest
|
|||
color-descriptor field, not a separate capability. **This is the one place to
|
||||
resolve in SPEC before an integration partner's engineers ask.**
|
||||
|
||||
## Decoder conformance — what each named standard fixes
|
||||
|
||||
SPEC §7 classes every standard codec — the floor and modern menu as well as the
|
||||
capabilities below — by what its named standard's decoder conformance fixes,
|
||||
because that is what `intent = replicate` over it promises: the same bytes on
|
||||
every conforming sink (`StandardDefined`), a criterion around a reference
|
||||
(`StandardTolerance`), or not yet classified (`StandardUnclassified`). Checked
|
||||
2026-09-27. The last column says what was read; a row is only as strong as that.
|
||||
|
||||
| capability | class | what the standard fixes | read |
|
||||
|---|---|---|---|
|
||||
| `wai.image.png` | `StandardDefined` | lossless: "All PNG filters are strictly lossless", and the Paeth predictor's calculations "must be performed exactly". Reducing to a lesser sample depth is the decoder's choice: §10.4 gives a rounding formula and a right shift | RFC 2083, full text |
|
||||
| `wai.audio.flac` | `StandardDefined` | lossless: decompressing "returns exactly the original data" (§3); STREAMINFO carries an MD5 of the unencoded audio | RFC 9639, definitions and STREAMINFO table |
|
||||
| `wai.text.zstd`, `wai.text.xz` | `StandardDefined` | lossless byte formats | not re-read |
|
||||
| `wai.audio.opus` | `StandardTolerance` | §6: conformance is "defined through the reference implementation"; a decoder's output "MUST also be within the thresholds specified by the opus_compare.c tool" against the reference on the test vectors, with "the same final range decoder state". §6.1: quality 0 is the passing threshold, calibrated to additive white noise at 48 dB SNR; 100 means identical to the reference. §1.1: "Various operations in the codec require bit-exact fixed-point behavior"; §4.2.7.9: the rest of SILK frame reconstruction "does not need to be bit-exact" | RFC 6716 §1.1, §4.2.7.9, §6–§6.1 |
|
||||
| `wai.image.jpeg` | `StandardTolerance` | §7: a decoder shall "with appropriate accuracy, convert to reconstructed image data"; A.3.3 NOTE: the IDCT equations "contain terms which cannot be represented with perfect accuracy by any real implementation", and the accuracy of dequantisation + IDCT is specified in Part 2; §4.1: colour space "is outside the scope of this Specification". The lossless process (Annex H) is exact, but the capability's role is the DCT processes | ITU-T T.81 (1992), full text. Part 2 (ITU-T T.83 \| ISO/IEC 10918-2) not read: the download failed |
|
||||
| `wai.image.jxl` | `StandardTolerance` | §4.1.1 NOTE: JPEG XL specifies infinite-precision arithmetic, and "this document therefore specifies tolerances for the decoded samples"; §4.2: a decoded image is similar to the reference iff every sample is within a peak-error threshold and each channel's RMSE within an RMSE threshold; §4.3: thresholds per test (`peak_error`, `rms_error`) | ISO/IEC 18181-3:2022, public preview (clauses 1–4.3) |
|
||||
| `wai.image.jp2`, `wai.video.j2k` | `StandardTolerance` | decoder compliance compares decoded components with reference components and their error metrics with specified values (Annex B.2.4, B.2.5; "Tolerances", G.4.3; MSE among the abbreviations; a "9-7I precision guarantee", A.1.7); the reversible 5-3 path is lossless (definitions 3.41, 3.58) | ISO/IEC 15444-4:2024 \| ITU-T T.803, public preview: table of contents, terms and abbreviations only. The clauses that state the metrics and thresholds were not in the preview |
|
||||
| `wai.video.av1`, `wai.video.av1.lossless`, `wai.image.avif` | `StandardTolerance` | §7.2: without film grain, decoders "shall produce output frames that are identical in all respects" to the decoding process's; with film grain, a decoder may instead produce identical frames before grain synthesis and output frames that "do not have perceptually significant differences" from the reference grain synthesis; "The definition of “perceptually significant differences” is beyond the scope of this specification and may be specified, for example, by a service provider as part of their accreditation program", so this criterion is not a stated bound. The film-grain syntax does not depend on lossless coding, so `av1.lossless` is in the same class. A text search of AVIF v1.2.0 found no film-grain restriction | AV1 Bitstream & Decoding Process Specification v1.0.0 with Errata 1, §7.2 and §5.9.30; AVIF v1.2.0, text search |
|
||||
| `wai.audio.iamf` | `StandardTolerance` | substreams are Opus, AAC-LC, FLAC or LPCM (`codec_id`); "specific renderers are out of scope" (with reference to §2.2) | IAMF working draft of 21 April 2025, text search |
|
||||
| `wai.audio.ac4`, `wai.audio.ivas`, `wai.mesh.draco`, `wai.pc.gpcc`, `wai.pc.vpcc`, `wai.splat.sog`, `wai.haptic.mihs`, `wai.meta.hdr10plus`, `wai.meta.dovi` | `StandardUnclassified` | not checked | nothing read for this purpose. (`wai.haptic.mihs`'s registry comment says ISO/IEC 23090-33 defines bit-exact decoder verification; that was not checked here) |
|
||||
| `wai.mesh.glb`, `wai.splat.spz` | `StandardUnclassified` | the payload bytes pass through intact; a sink's decode of them is not classified (glTF can embed JPEG images and compressed geometry; SPZ stores quantised attributes) | not read |
|
||||
|
||||
Two limits apply to every row. The standard fixes its decoded output in its own
|
||||
domain (sample depth, planes, colour representation); a conversion a sink applies
|
||||
afterwards — PNG depth reduction, YUV→RGB, a JPEG colour-space choice, rendering an
|
||||
IAMF mix — is not part of it, and the reference sink's `RGB8` / f32 buffers include
|
||||
such conversions. And the class describes the standard, not the reference sink's
|
||||
libraries: nothing here tests those libraries against their standard's conformance
|
||||
suite.
|
||||
|
||||
JPEG AI (`wai.image.jpegai`) is not in a standard class: its registry class is
|
||||
`NeuralEntropyExact` ([determinism-tiers](../extensions/determinism-tiers.md) §5),
|
||||
from SPEC §7's neural rule, not from what its standard's conformance fixes. What
|
||||
was read is an overview of the standard (arXiv 2510.13867, read 2026-09-27):
|
||||
|
||||
- the bit-exact conformance point is "only at the end of the entropy decoding
|
||||
pipeline"; "Outputs from subsequent processes may diverge slightly from the
|
||||
reference";
|
||||
- one codestream may be decoded through "up to three different synthesis
|
||||
transforms", restricted by the profile (Part 2) and possibly by the encoder;
|
||||
bit-exact picture reconstruction was "deliberately excluded from the first
|
||||
version";
|
||||
- Part 4 (ISO/IEC 6048-4, conformance) "specifies the requirements for generating
|
||||
a JPEG AI-compliant reconstruction" and "defines a testing suite for each
|
||||
profile and level pair"; it "considers the possibility that a decoder is
|
||||
conformant to the standard without having bit-exact reconstruction", which the
|
||||
overview goes on to call "standard compliance with a certain leeway". It says
|
||||
Part 4 was a draft at the time of writing.
|
||||
|
||||
Read together, these passages point to a criterion around a reference on the
|
||||
reconstruction — the kind `StandardTolerance` records — but the overview does not
|
||||
state one, nor its form or width.
|
||||
Part 4 itself was not read. A web search on 2026-09-27 returned the ISO catalogue
|
||||
entry for ISO/IEC 6048-4 as under publication (stage 60.00); the catalogue page
|
||||
refused a direct fetch (HTTP 403), so that status is the search result's, not
|
||||
confirmed here. Keeping `wai.image.jpegai` at `NeuralEntropyExact`, where
|
||||
`replicate` is refused, is therefore a conservative choice pending Part 4, not a
|
||||
reading of the standard; if Part 4 states a criterion on the reconstruction, the
|
||||
capability is a candidate for `StandardTolerance` (SPEC §7, *`wai.image.jpegai`
|
||||
and the standard classes*).
|
||||
|
||||
## Implementation & demonstration status
|
||||
|
||||
WAI's job is **carriage + dispatch**; decoders are sink-supplied (even the
|
||||
|
|
@ -137,7 +199,8 @@ floor codecs are *wrapped* reference libraries, not re-implemented). So
|
|||
"implemented and demonstrated" means, per capability:
|
||||
|
||||
- **Carriage proven for every registered class** — `wai wrap <cap> <payload>`
|
||||
builds an envelope around the canonical bytes; `wai unwrap` returns them
|
||||
builds an envelope around the canonical bytes (over a class that does not back
|
||||
an unpinned `replicate`, only with `--intent`, SPEC §7); `wai unwrap` returns them
|
||||
**byte-identically**; the registry reports the tier + license. The
|
||||
`tests/carriage.rs` conformance asserts this for the *entire* registry (0 B …
|
||||
64 KiB payloads) and runs in the no-system-deps CI matrix.
|
||||
|
|
|
|||
104
wai/tools/wai_jpegai_gain_exp_margin.py
Normal file
104
wai/tools/wai_jpegai_gain_exp_margin.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Check that the one math-library call in the `wai.image.jpegai` decode path cannot
|
||||
change the decoded output on a different machine.
|
||||
|
||||
The per-channel gain scaler (`jpegai_pipeline::gain_unit_scaler_vec`) is
|
||||
|
||||
scaler[c] = round( exp( (g[c] + beta) * GAIN_LOG_K / 128 ) * 2^10 ) / 2^10
|
||||
|
||||
in f64. The exact decoder calls it with `beta = 0`: it refuses any codestream whose
|
||||
`beta_displacement_log` is not 0 (`jpegai_decode::check_codestream`), because it does
|
||||
not implement the beta displacement. So its inputs are only the normative
|
||||
per-channel gain table `g`. The multiply and divide are IEEE-754 basic operations,
|
||||
correctly rounded on every conforming target; `exp` comes from the platform math
|
||||
library, which is not required to be correctly rounded. A last-place difference in
|
||||
`exp` can change the scaler only if the exact value sits within a few ULPs of a
|
||||
rounding boundary (k + 0.5). This script computes, for every table entry, the
|
||||
distance from that boundary in ULPs of the f64 value, using 60-digit decimal
|
||||
arithmetic for `exp`, and fails if any entry is closer than MIN_MARGIN_ULPS.
|
||||
|
||||
python wai_jpegai_gain_exp_margin.py <assets_dir> [--beta-sweep]
|
||||
|
||||
<assets_dir> is the jpegai-vm-assets root (the decoder assets exported from the
|
||||
reference software; see wai_jpegai_build_e2e_inputs.py). Every
|
||||
model/CCS_SGMM/tools_*/model_{y,uv} gain table present is checked; the decoder's
|
||||
scope is tools_0. GAIN_LOG_K is read from the Rust source so the check follows the
|
||||
code. Standard library only.
|
||||
|
||||
--beta-sweep also reports, without gating, the smallest margin over g + beta for
|
||||
every beta the 12-bit header field can carry (-2048..2047): what a decoder that
|
||||
implements the beta displacement would face.
|
||||
"""
|
||||
import glob
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from decimal import Decimal, getcontext
|
||||
|
||||
getcontext().prec = 60
|
||||
MIN_MARGIN_ULPS = 1e6 # far beyond any libm's error bound
|
||||
SCALER_PRECISION = 10
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
PIPELINE_RS = os.path.join(HERE, "..", "wai-rs", "src", "jpegai_pipeline.rs")
|
||||
|
||||
|
||||
def gain_log_k():
|
||||
src = open(PIPELINE_RS).read()
|
||||
m = re.search(r"const GAIN_LOG_K: f64 = ([0-9_.]+);", src)
|
||||
if not m:
|
||||
sys.exit(f"GAIN_LOG_K not found in {PIPELINE_RS}")
|
||||
return float(m.group(1).replace("_", ""))
|
||||
|
||||
|
||||
def margin_ulps(g, k):
|
||||
# Same f64 operations, same order, as the Rust: (((g + beta) as f64) * K) / 128.0,
|
||||
# where `g` here is already the integer sum g + beta.
|
||||
x = (float(g) * k) / 128.0
|
||||
v = Decimal(x).exp() * (1 << SCALER_PRECISION) # exact to 60 digits
|
||||
dist = abs((v - int(v)) - Decimal("0.5"))
|
||||
return float(dist) / math.ulp(float(v))
|
||||
|
||||
|
||||
BETA_RANGE = range(-2048, 2048) # 12-bit beta_displacement_log, de-biased by 2048
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
sweep = "--beta-sweep" in args
|
||||
args = [a for a in args if a != "--beta-sweep"]
|
||||
if len(args) != 1:
|
||||
sys.exit(__doc__)
|
||||
k = gain_log_k()
|
||||
pattern = os.path.join(args[0], "model", "CCS_SGMM", "tools_*", "model_*",
|
||||
"common_modules", "quantizer", "gain_unit_mlog.csv")
|
||||
tables = sorted(glob.glob(pattern))
|
||||
if not tables:
|
||||
sys.exit(f"no gain tables under {pattern}")
|
||||
worst_all = math.inf
|
||||
swept = {}
|
||||
for path in tables:
|
||||
gains = [int(s) for s in open(path).read().split()]
|
||||
worst = min(margin_ulps(g, k) for g in gains)
|
||||
worst_all = min(worst_all, worst)
|
||||
rel = os.path.relpath(path, args[0])
|
||||
print(f"{rel}: {len(gains)} entries, min margin {worst:.3e} ULPs")
|
||||
if sweep:
|
||||
xs = {g + b for g in gains for b in BETA_RANGE}
|
||||
for x in xs:
|
||||
if x not in swept:
|
||||
swept[x] = margin_ulps(x, k)
|
||||
w = min(swept[x] for x in xs)
|
||||
print(f" with beta in [{BETA_RANGE.start}, {BETA_RANGE.stop - 1}]: "
|
||||
f"{len(xs)} distinct exp inputs, min margin {w:.3e} ULPs (not gated)")
|
||||
print(f"GAIN_LOG_K = {k!r}; overall min margin {worst_all:.3e} ULPs "
|
||||
f"(threshold {MIN_MARGIN_ULPS:.0e})")
|
||||
if worst_all < MIN_MARGIN_ULPS:
|
||||
sys.exit("FAIL: an entry is close enough to a rounding boundary that a libm "
|
||||
"difference could change the decoded scaler")
|
||||
print("OK: no libm last-place difference can change the scaler for these tables")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -20,7 +20,7 @@ fn usage() {
|
|||
eprintln!("wai encode <codec> <input> [-o out.wai] [-q quality]");
|
||||
eprintln!("wai decode <in.wai> -o <output>");
|
||||
eprintln!("wai inspect <in.wai>");
|
||||
eprintln!("wai wrap <capability> <payload> [-o out.wai] [--fallback <cap>]");
|
||||
eprintln!("wai wrap <capability> <payload> [-o out.wai] [--fallback <cap>] [--intent <intent>]");
|
||||
eprintln!("wai unwrap <in.wai> [-o payload] carry/extract ANY registered codec's bytes");
|
||||
eprintln!("wai capabilities list registered capabilities + tier + license");
|
||||
eprintln!();
|
||||
|
|
@ -333,16 +333,37 @@ fn license_str(cap: &str) -> &'static str {
|
|||
/// (a real JPEG 2000 codestream, an IAMF stream, a Draco buffer, a proprietary
|
||||
/// AC-4 frame — WAI carries it, the sink decodes it). The bytes survive
|
||||
/// byte-identically (§2): `wrap` then `unwrap` returns the exact input.
|
||||
fn wrap(cap: &str, input: &str, out: &str, fallback: Option<&str>) -> Result<(), String> {
|
||||
///
|
||||
/// The envelope pins no prior. Its intent is `--intent` when given, else
|
||||
/// `replicate`, and `replicate` is written only where a sink accepts it unpinned
|
||||
/// (SPEC §7, `codecs::unpinned_envelope_intent`): over the standard classes. Over
|
||||
/// any other capability (`wai.image.jpegai`, a float or integer-exact neural codec,
|
||||
/// a generator, a behavioral path) `wrap` refuses and writes nothing unless another
|
||||
/// intent is given.
|
||||
fn wrap(cap: &str, input: &str, out: &str, fallback: Option<&str>,
|
||||
intent: Option<&str>) -> Result<(), String> {
|
||||
if !wai::codecs::is_known_capability(cap) {
|
||||
return Err(format!("'{cap}' is not a registered capability (see `wai capabilities`)"));
|
||||
}
|
||||
let intent = wai::codecs::unpinned_envelope_intent(cap, intent).map_err(|why| format!(
|
||||
"not writing intent=replicate over {cap}: {why} (SPEC \u{a7}7). `wai wrap` pins no \
|
||||
prior; pass --intent <intent> to carry the payload without a reconstruction claim \
|
||||
(`create` for a generator, `improve` otherwise)"))?;
|
||||
// A sink that lacks `cap` decodes through the fallback (SPEC §4 step 5), so the
|
||||
// intent has to hold over the fallback's class as well.
|
||||
if let Some(fb) = fallback {
|
||||
wai::codecs::unpinned_envelope_intent(fb, Some(intent)).map_err(|why| format!(
|
||||
"not writing intent=replicate over {cap} with fallback {fb}: a sink without \
|
||||
{cap} decodes through {fb} (SPEC \u{a7}4), and over {fb}: {why} (SPEC \u{a7}7). \
|
||||
Drop --fallback, or pass --intent <intent> to carry the payload without a \
|
||||
reconstruction claim"))?;
|
||||
}
|
||||
let payload = std::fs::read(input).map_err(|e| format!("read {input}: {e}"))?;
|
||||
let n_in = payload.len();
|
||||
let manifest = Manifest {
|
||||
wai: "1.0".into(),
|
||||
media: media_for(cap).into(),
|
||||
intent: "replicate".into(),
|
||||
intent: intent.into(),
|
||||
model_requirement: ModelRequirement {
|
||||
capability: cap.into(),
|
||||
fallback: fallback.map(String::from),
|
||||
|
|
@ -355,7 +376,8 @@ fn wrap(cap: &str, input: &str, out: &str, fallback: Option<&str>) -> Result<(),
|
|||
let n = Wai::new(manifest, payload).write(out).map_err(|e| e.to_string())?;
|
||||
let tier = wai::codecs::capability_tier(cap).map(|t| format!("{t:?}")).unwrap_or_else(|| "?".into());
|
||||
println!("wrapped → {out} ({n} B envelope, {n_in} B payload)");
|
||||
println!(" capability {cap} · media {} · {tier} · {}", media_for(cap), license_str(cap));
|
||||
println!(" capability {cap} · media {} · {tier} · {} · intent {intent}",
|
||||
media_for(cap), license_str(cap));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -408,14 +430,9 @@ fn capabilities() -> Result<(), String> {
|
|||
Some(wai::codecs::LicenseClass::NonCommercial) => "non-commercial",
|
||||
None => "?",
|
||||
};
|
||||
let replicate = match wai::codecs::capability_replicate_class(c) {
|
||||
Some(wai::codecs::ReplicateClass::StandardDefined) => "standard-defined",
|
||||
Some(wai::codecs::ReplicateClass::NeuralIntegerExact) => "neural-int-exact",
|
||||
Some(wai::codecs::ReplicateClass::GenerativeDeterministic) => "generative-exact",
|
||||
Some(wai::codecs::ReplicateClass::NeuralFloat) => "neural-float",
|
||||
Some(wai::codecs::ReplicateClass::Behavioral) => "behavioral",
|
||||
None => "?",
|
||||
};
|
||||
let replicate = wai::codecs::capability_replicate_class(c)
|
||||
.map(wai::codecs::ReplicateClass::label)
|
||||
.unwrap_or("?");
|
||||
println!(" {c:<26} {tier:<11} {decode:<13} {license:<14} {replicate}");
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -436,7 +453,8 @@ fn main() -> ExitCode {
|
|||
"decode" if args.len() >= 4 => decode(&args[1], &args[3]),
|
||||
"wrap" if args.len() >= 3 => {
|
||||
let out = opt(&args[3..], "-o").map(String::from).unwrap_or("out.wai".into());
|
||||
wrap(&args[1], &args[2], &out, opt(&args[3..], "--fallback"))
|
||||
wrap(&args[1], &args[2], &out, opt(&args[3..], "--fallback"),
|
||||
opt(&args[3..], "--intent"))
|
||||
}
|
||||
"unwrap" if args.len() >= 2 => unwrap(&args[1], opt(&args[2..], "-o")),
|
||||
"inspect" if args.len() >= 2 => inspect(&args[1]),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub const CAP_IMAGE_PNG: &str = "wai.image.png"; // universal floor
|
|||
pub const CAP_IMAGE_JPEG: &str = "wai.image.jpeg"; // most-supported lossy
|
||||
pub const CAP_IMAGE_AVIF: &str = "wai.image.avif"; // modern lossy (AV1-based)
|
||||
pub const CAP_IMAGE_JXL: &str = "wai.image.jxl"; // JPEG-XL (lossless + lossy)
|
||||
pub const CAP_IMAGE_JPEGAI: &str = "wai.image.jpegai"; // JPEG AI (ITU-T T.840.1 / ISO/IEC 6048-1:2025) standardized neural image codec. Byte-exact decoder in-crate: codestream→RGB via jpegai_decode::decode (integer entropy/dequant, deterministic synthesis, ±1 LSB of the reference). Model weights sink-supplied.
|
||||
pub const CAP_IMAGE_JPEGAI: &str = "wai.image.jpegai"; // JPEG AI (ITU-T T.840.1 / ISO/IEC 6048-1:2025) standardized neural image codec. Deterministic decoder in-crate for one configuration (256×256 4:4:4, model_id 0 / tools_0, β = 0, high-operation-point synthesis; jpegai_decode::check_codestream lists the rest): codestream→RGB via jpegai_decode::decode (integer entropy and PTQ networks; dequant, post-filters and colour conversion in fixed-order IEEE-754 float; max|Δ| ≤ 2 vs the reference in its test). Without the integer weight bundle, or in a non-default floating-point environment, the float ORT decode runs; codestreams outside the configuration are refused. Model weights sink-supplied.
|
||||
// Audio
|
||||
pub const CAP_AUDIO_OPUS: &str = "wai.audio.opus"; // modern lossy
|
||||
pub const CAP_AUDIO_FLAC: &str = "wai.audio.flac"; // lossless
|
||||
|
|
@ -385,8 +385,9 @@ pub fn is_known_capability(cap: &str) -> bool {
|
|||
/// carried in the bitstream, so this is the ceiling, not a per-file guarantee.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum FidelityTier {
|
||||
/// Reproduces the exact original bytes/samples/pixels. The only tier that
|
||||
/// can honestly back `intent=replicate` of an arbitrary source.
|
||||
/// Reproduces the exact original bytes/samples/pixels: the reconstruction is
|
||||
/// the source. What `intent=replicate` promises across sinks is a separate
|
||||
/// axis, the capability's [`ReplicateClass`].
|
||||
Lossless,
|
||||
/// Deterministic approximation — fixed given the bitstream, but not the
|
||||
/// original. Conventional lossy + lossy neural codecs (incl. WavTokenizer,
|
||||
|
|
@ -513,33 +514,110 @@ pub fn is_royalty_free(cap: &str) -> bool {
|
|||
}
|
||||
|
||||
/// How a capability's reconstruction relates to cross-hardware reproducibility —
|
||||
/// the **integer-entropy contract**, a property of the capability looked up in
|
||||
/// the registry (like [`capability_license`], not a per-file claim). It answers
|
||||
/// the one question `intent=replicate` actually turns on: *will two machines
|
||||
/// running this capability produce the identical bytes?*
|
||||
/// the **integer-entropy contract** for neural decodes, and the named standard's
|
||||
/// decoder conformance for standard codecs — a property of the capability looked
|
||||
/// up in the registry (like [`capability_license`], not a per-file claim). It
|
||||
/// answers the question `intent=replicate` turns on: *what does every conforming
|
||||
/// sink running this capability reconstruct?* [`ReplicateClass::replicate_promise`]
|
||||
/// states it per class — the same bytes on every conforming sink
|
||||
/// (*decode-equivalence*) for the integer-exact neural decodes and the capabilities
|
||||
/// whose reconstruction is specified exactly; what the named standard's decoder
|
||||
/// conformance admits for the other standard codecs; and nothing, so `replicate` is
|
||||
/// refused, for the rest (SPEC §3, §7; `extensions/determinism-tiers.md`).
|
||||
/// [`replicate_refusal`] applies the rule.
|
||||
///
|
||||
/// The hazard this isolates is specific to **neural** regenerate paths. A
|
||||
/// learned codec's entropy decode desyncs the instant the decoder's
|
||||
/// scale-bucket / σ computation drifts from the encoder's by one float ULP —
|
||||
/// the bucket assignment flips and the whole stream corrupts. So a float neural
|
||||
/// decode is reproducible only on the *same build*; only an integer/fixed-point
|
||||
/// neural decode is byte-identical on *every* machine. Standard-defined codecs
|
||||
/// are a separate axis: their reconstruction is fixed by the codec/standard
|
||||
/// itself (audited via [`capability_tier`] + the codec spec), not by a model
|
||||
/// WAI runs, so they are not classified for the neural hazard here.
|
||||
/// The hazard this isolates for **neural** regenerate paths: a learned codec's
|
||||
/// entropy decode desyncs the instant the decoder's scale-bucket / σ computation
|
||||
/// drifts from the encoder's by one float ULP — the bucket assignment flips and the
|
||||
/// whole stream corrupts. So a float neural decode is reproducible only on the
|
||||
/// *same build*. An integer entropy stage fixes the decoded symbols on every
|
||||
/// machine but leaves the reconstruction to whatever arithmetic the later stages
|
||||
/// run in; only a decode that is integer/fixed-point end to end is byte-identical
|
||||
/// on *every* machine. Standard codecs are classified on a separate axis: by what
|
||||
/// their named standard's decoder conformance fixes — the output exactly
|
||||
/// ([`StandardDefined`](Self::StandardDefined)), a criterion around a reference
|
||||
/// ([`StandardTolerance`](Self::StandardTolerance)), or not yet classified
|
||||
/// ([`StandardUnclassified`](Self::StandardUnclassified)).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ReplicateClass {
|
||||
/// Reconstruction is fixed by the named codec/standard (the floor + menu
|
||||
/// codecs) or by WAI's own deterministic floor (`world`/`score`/`film`/
|
||||
/// `splat`/`scene` — integer fixed-point, BLAKE3 state-equivalence). No
|
||||
/// learned model or float inference WAI introduces; cross-hardware
|
||||
/// reproducibility is the codec's / the floor's own property.
|
||||
/// The reconstruction is specified exactly, so `replicate` promises the same
|
||||
/// bytes on every conforming sink: by the named standard, for the lossless
|
||||
/// formats whose decoded output it determines (PNG, FLAC, the zstd and XZ byte
|
||||
/// formats), or by the WAI extension that defines the capability's
|
||||
/// `*-equivalence` over integer / fixed-point state (`world`, `score`, `film`,
|
||||
/// `quantum`, `ternary`, the haptic signal, the integer inter-frame codec, …).
|
||||
/// The promise covers the output the standard or extension specifies, at its
|
||||
/// own sample depth and layout; a conversion a sink applies afterwards (PNG
|
||||
/// sample-depth rescaling, for which RFC 2083 §10.4 gives two methods) is not
|
||||
/// part of it. An extension's equivalence holds given its inputs: where it
|
||||
/// composes other capabilities' decoded output (a `wai.audio.scene` source
|
||||
/// decoded through `wai.audio.opus`, say), it is only as exact as their
|
||||
/// classes. No neural capability is in this class.
|
||||
StandardDefined,
|
||||
/// A standard codec whose named standard holds decoders to a criterion around
|
||||
/// a reference instead of to identical output, for at least some conforming
|
||||
/// payloads, so two conforming sinks may reconstruct different bytes. For Opus
|
||||
/// and JPEG XL the clauses read state the criterion as numeric thresholds. For
|
||||
/// JPEG and JPEG 2000 the text read points to a criterion without stating its
|
||||
/// bound — T.81 leaves the accuracy of dequantisation and IDCT to its Part 2,
|
||||
/// which was not read, and only the table of contents and terms of ISO/IEC
|
||||
/// 15444-4 were read — so no bound is given here. For AV1 and AVIF with film
|
||||
/// grain it is the absence of "perceptually significant differences", whose
|
||||
/// definition AV1 §7.2 places outside the specification. `replicate` over it
|
||||
/// promises what that conformance promises — every conforming sink within the
|
||||
/// standard's criterion — and not byte identity across sinks.
|
||||
/// `wai.audio.opus` (RFC 6716 §6: within `opus_compare`'s thresholds of the
|
||||
/// reference decoder, with the same final range-decoder state);
|
||||
/// `wai.image.jpeg` (ITU-T T.81 §7 and A.3.3: decoding "with appropriate
|
||||
/// accuracy", the accuracy of dequantisation and IDCT specified in Part 2);
|
||||
/// `wai.image.jxl` (ISO/IEC 18181-3 §4.2–§4.3, read in its public preview:
|
||||
/// peak-error and RMSE thresholds per test); `wai.image.jp2` / `wai.video.j2k`
|
||||
/// (ISO/IEC 15444-4, per the table of contents and terms of its public preview:
|
||||
/// decoded components compared with reference components by error metrics, and
|
||||
/// a reversible path its definitions describe as lossless);
|
||||
/// `wai.video.av1`, `wai.video.av1.lossless` and
|
||||
/// `wai.image.avif` (AV1 §7.2: identical output unless the payload signals film
|
||||
/// grain, and then identical frames before grain synthesis, and output frames
|
||||
/// that "do not have perceptually significant differences" from the reference
|
||||
/// grain synthesis); `wai.audio.iamf` (its substreams
|
||||
/// include Opus, and its renderers are out of its scope).
|
||||
StandardTolerance,
|
||||
/// A standard codec this registry has not yet classified between
|
||||
/// [`StandardDefined`](Self::StandardDefined) and
|
||||
/// [`StandardTolerance`](Self::StandardTolerance): its named standard's
|
||||
/// decoder-conformance clauses have not been checked. `replicate` over it
|
||||
/// promises what that conformance promises, and the registry does not say
|
||||
/// whether that is byte identity. `wai.audio.ac4`, `wai.audio.ivas`,
|
||||
/// `wai.mesh.draco`, `wai.pc.gpcc`, `wai.pc.vpcc`, `wai.splat.sog` (no frozen
|
||||
/// standard yet), `wai.haptic.mihs`, and the HDR metadata descriptors
|
||||
/// `wai.meta.hdr10plus` / `wai.meta.dovi`; and the asset capabilities
|
||||
/// `wai.mesh.glb` and `wai.splat.spz`, whose payload bytes pass through intact
|
||||
/// but whose decode is unclassified (glTF can embed JPEG images and compressed
|
||||
/// geometry; SPZ stores quantised attributes). All are sink-supplied.
|
||||
StandardUnclassified,
|
||||
/// A neural regenerate path that is integer/fixed-point **by construction**
|
||||
/// — no float inference anywhere on the decode — so it is byte-identical on
|
||||
/// every machine. The only neural class that soundly backs cross-hardware
|
||||
/// `intent=replicate`.
|
||||
/// — no float inference anywhere on the decode, entropy and synthesis — so it
|
||||
/// is byte-identical on every machine: registered at *decode-equivalence*. The
|
||||
/// only neural class that soundly backs cross-hardware `intent=replicate`.
|
||||
NeuralIntegerExact,
|
||||
/// A neural regenerate path whose **entropy decode** is integer by
|
||||
/// construction — the decoded symbols, and the entropy parameters they are
|
||||
/// decoded with, are byte-identical on every machine — but whose later stages
|
||||
/// run float, so the reconstruction is not guaranteed across conforming sinks:
|
||||
/// registered at *entropy-consistency*, the lower tier. **Not** sound for
|
||||
/// `replicate`, which promises the reconstruction, not the symbols. A
|
||||
/// particular implementation may still pin one reconstruction (WAI's exact
|
||||
/// JPEG AI decoder does, under the conditions in `determinism-tiers` §5); that
|
||||
/// is a property of the implementation, not of the capability.
|
||||
/// `wai.image.jpegai`. It is here by the neural rule (SPEC §7), not because
|
||||
/// its standard was found to leave the reconstruction unbounded: an overview of
|
||||
/// the standard says its conformance part (ISO/IEC 6048-4) specifies the
|
||||
/// requirements for a compliant reconstruction and "considers the possibility
|
||||
/// that a decoder is conformant to the standard without having bit-exact
|
||||
/// reconstruction", and that part has not been read. Refusing `replicate` over
|
||||
/// it is a conservative choice pending that reading (SPEC §7,
|
||||
/// *`wai.image.jpegai` and the standard classes*).
|
||||
NeuralEntropyExact,
|
||||
/// A **generative** path (`intent=create`) that is integer/fixed-point by
|
||||
/// construction and pinned to `(model, prompt, seed, steps)` — so the
|
||||
/// *generated* content is byte-identical on every machine. There is no
|
||||
|
|
@ -550,13 +628,90 @@ pub enum ReplicateClass {
|
|||
GenerativeDeterministic,
|
||||
/// A neural regenerate path that runs float inference (ONNX synthesis, and
|
||||
/// for the conditional-entropy family a float σ/scale computation). Exact
|
||||
/// only on the same build; **not** sound for cross-hardware `replicate`.
|
||||
/// only on the same build; **not** sound for cross-hardware `replicate`. The
|
||||
/// registry claims no determinism tier for these.
|
||||
NeuralFloat,
|
||||
/// Regenerated by a sink generator; conforms by similarity, not bytes — no
|
||||
/// byte reproduction at all (the `wai.semantic.*` path).
|
||||
Behavioral,
|
||||
}
|
||||
|
||||
/// The two reproducibility tiers a neural capability can be registered at
|
||||
/// (`extensions/determinism-tiers.md` §2). Each is a property of the capability as
|
||||
/// registered — it holds on every conforming sink — not of one implementation.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DeterminismTier {
|
||||
/// The entropy decode reproduces byte-for-byte on every conforming sink; the
|
||||
/// reconstruction may differ. Does not back `replicate`.
|
||||
EntropyConsistency,
|
||||
/// The whole decode to the final medium reproduces byte-for-byte on every
|
||||
/// conforming sink. What `replicate` over a neural capability promises.
|
||||
DecodeEquivalence,
|
||||
}
|
||||
|
||||
/// What `intent = replicate` promises over a capability, by its registry class
|
||||
/// (SPEC §3, §7). See [`ReplicateClass::replicate_promise`].
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ReplicatePromise {
|
||||
/// Every conforming sink reconstructs the same bytes: *decode-equivalence*, or
|
||||
/// the `*-equivalence` the capability's extension defines. For a
|
||||
/// [`ReplicateClass::NeuralIntegerExact`] capability the envelope must also pin
|
||||
/// an integer-exact prior ([`replicate_refusal`]).
|
||||
ByteExact,
|
||||
/// Every conforming sink reconstructs what the named standard's decoder
|
||||
/// conformance admits — within its criterion around a reference
|
||||
/// ([`ReplicateClass::StandardTolerance`]; for film-grain AV1 that criterion
|
||||
/// is perceptual and not quantified by the standard), or a criterion this
|
||||
/// registry has not classified ([`ReplicateClass::StandardUnclassified`]).
|
||||
/// Byte identity across sinks is not promised.
|
||||
NamedStandardConformance,
|
||||
}
|
||||
|
||||
impl ReplicateClass {
|
||||
/// The determinism tier a neural capability of this class is registered at.
|
||||
/// `None` for [`NeuralFloat`](Self::NeuralFloat), which claims no tier, and for
|
||||
/// the classes the neural tiers do not describe (the standard classes,
|
||||
/// generative, behavioral).
|
||||
pub fn neural_tier(self) -> Option<DeterminismTier> {
|
||||
match self {
|
||||
Self::NeuralIntegerExact => Some(DeterminismTier::DecodeEquivalence),
|
||||
Self::NeuralEntropyExact => Some(DeterminismTier::EntropyConsistency),
|
||||
Self::StandardDefined | Self::StandardTolerance | Self::StandardUnclassified
|
||||
| Self::GenerativeDeterministic | Self::NeuralFloat | Self::Behavioral => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// What `intent = replicate` promises over a capability of this class, or
|
||||
/// `None` when the class cannot back `replicate` at all (SPEC §7): entropy-only
|
||||
/// and float neural decodes, whose reconstruction nothing the registry states
|
||||
/// bounds, and the generative and behavioral paths, which do not reconstruct a
|
||||
/// source.
|
||||
pub fn replicate_promise(self) -> Option<ReplicatePromise> {
|
||||
match self {
|
||||
Self::NeuralIntegerExact | Self::StandardDefined => Some(ReplicatePromise::ByteExact),
|
||||
Self::StandardTolerance | Self::StandardUnclassified => {
|
||||
Some(ReplicatePromise::NamedStandardConformance)
|
||||
}
|
||||
Self::NeuralEntropyExact | Self::NeuralFloat
|
||||
| Self::GenerativeDeterministic | Self::Behavioral => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The short label `wai capabilities` prints in its `replicate` column.
|
||||
pub fn label(self) -> &'static str {
|
||||
match self {
|
||||
Self::StandardDefined => "standard-defined",
|
||||
Self::StandardTolerance => "standard-tolerance",
|
||||
Self::StandardUnclassified => "standard-unclassified",
|
||||
Self::NeuralIntegerExact => "neural-int-exact",
|
||||
Self::NeuralEntropyExact => "neural-entropy-exact",
|
||||
Self::GenerativeDeterministic => "generative-exact",
|
||||
Self::NeuralFloat => "neural-float",
|
||||
Self::Behavioral => "behavioral",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`ReplicateClass`] of a registered capability, or `None` if unknown.
|
||||
pub fn capability_replicate_class(cap: &str) -> Option<ReplicateClass> {
|
||||
use ReplicateClass::*;
|
||||
|
|
@ -577,6 +732,18 @@ pub fn capability_replicate_class(cap: &str) -> Option<ReplicateClass> {
|
|||
// transform, integer synthesis → byte-exact attribute tensor.
|
||||
CAP_NEURAL_INT_SYNTH | CAP_NEURAL_INT_HYPER | CAP_VIDEO_INT_HYPER
|
||||
| CAP_AUDIO_INT_CODEC | CAP_SPLAT_INT_CODEC => NeuralIntegerExact,
|
||||
// JPEG AI: the entropy decode, including the scale-index derivation (an
|
||||
// integer hyper-scale network), is integer on both reference decode paths,
|
||||
// so the decoded symbols reproduce everywhere. Dequantisation, latent
|
||||
// refinement, the post-filters and colour conversion are float (fixed-order
|
||||
// in the exact decoder, ONNX Runtime in the fallback), so the reconstruction
|
||||
// is not guaranteed across conforming sinks. Earlier in v0.4.0 this capability
|
||||
// fell through to StandardDefined, which let a `replicate` envelope over it
|
||||
// pass the strict check; it no longer backs `replicate` (SPEC §7). Its
|
||||
// standard's conformance part (ISO/IEC 6048-4) may hold the reconstruction
|
||||
// to a criterion around a reference; it has not been read, so this class is
|
||||
// a conservative choice pending it, not a reading of the standard.
|
||||
CAP_IMAGE_JPEGAI => NeuralEntropyExact,
|
||||
// Every other neural regenerate path runs float inference, so the decode
|
||||
// is exact only on the same build, never guaranteed cross-hardware.
|
||||
CAP_NEURAL_ENCODEC32 | CAP_NEURAL_DAC | CAP_NEURAL_MIMI | CAP_NEURAL_WAVTOKENIZER
|
||||
|
|
@ -589,8 +756,25 @@ pub fn capability_replicate_class(cap: &str) -> Option<ReplicateClass> {
|
|||
CAP_GENERATE_SPECTRAL => GenerativeDeterministic,
|
||||
// Sink-generator regeneration; conforms by similarity, not bytes.
|
||||
CAP_SEMANTIC_CLIP | CAP_SEMANTIC_PERCO2 => Behavioral,
|
||||
// Everything else: reconstruction fixed by the codec/standard or by
|
||||
// WAI's deterministic floor.
|
||||
// Standard codecs whose named standard holds decoders to a criterion around
|
||||
// a reference, not to identical output (clauses in the variant's doc and in
|
||||
// research/media-codec-registry.md): Opus (RFC 6716 §6), JPEG (T.81 §7,
|
||||
// A.3.3), JPEG XL (18181-3 §4.2), JPEG 2000 (15444-4), AV1 and AVIF (AV1
|
||||
// §7.2, when film grain is signalled), IAMF (Opus substreams; renderers out
|
||||
// of scope). Earlier in v0.4.0 these were StandardDefined.
|
||||
CAP_AUDIO_OPUS | CAP_IMAGE_JPEG | CAP_IMAGE_JXL | CAP_IMAGE_JP2 | CAP_VIDEO_J2K
|
||||
| CAP_VIDEO_AV1 | CAP_VIDEO_AV1_LOSSLESS | CAP_IMAGE_AVIF | CAP_AUDIO_IAMF => {
|
||||
StandardTolerance
|
||||
}
|
||||
// Sink-supplied standards whose decoder-conformance clauses the registry has
|
||||
// not checked, and the two pass-through asset formats whose decode it has not
|
||||
// classified. Earlier in v0.4.0 these were StandardDefined.
|
||||
CAP_AUDIO_AC4 | CAP_AUDIO_IVAS | CAP_MESH_DRACO | CAP_PC_GPCC | CAP_PC_VPCC
|
||||
| CAP_SPLAT_SOG | CAP_HAPTIC_MIHS | CAP_META_HDR10PLUS | CAP_META_DOVI
|
||||
| CAP_MESH_GLB | CAP_SPLAT_SPZ => StandardUnclassified,
|
||||
// Everything else: the reconstruction is specified exactly — PNG, FLAC, zstd
|
||||
// and XZ by their standards, the WAI-native capabilities by the extension
|
||||
// that defines their `*-equivalence`.
|
||||
_ => StandardDefined,
|
||||
})
|
||||
}
|
||||
|
|
@ -599,12 +783,111 @@ pub fn capability_replicate_class(cap: &str) -> Option<ReplicateClass> {
|
|||
/// the integer-entropy contract. Isolates exactly the neural codecs WAI itself
|
||||
/// guarantees byte-identical on every machine, so a deployer can require
|
||||
/// `intent=replicate` to dispatch only to a cross-hardware-sound neural decode.
|
||||
/// Standard-defined codecs reproduce per their own spec and are audited via
|
||||
/// [`capability_tier`], not this predicate.
|
||||
/// Standard codecs are not neural; what `replicate` promises over them is their
|
||||
/// class's [`ReplicateClass::replicate_promise`].
|
||||
pub fn is_neural_integer_exact(cap: &str) -> bool {
|
||||
capability_replicate_class(cap) == Some(ReplicateClass::NeuralIntegerExact)
|
||||
}
|
||||
|
||||
/// Why SPEC §7 refuses an `intent = replicate` envelope. See [`replicate_refusal`].
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ReplicateRefusal {
|
||||
/// The capability is not registered, so nothing states what it reproduces.
|
||||
Unregistered,
|
||||
/// The capability's registry class cannot back `replicate`
|
||||
/// ([`ReplicateClass::replicate_promise`] is `None`), whatever the envelope's
|
||||
/// prior declares.
|
||||
Class(ReplicateClass),
|
||||
/// The class is [`ReplicateClass::NeuralIntegerExact`], but the envelope pins no
|
||||
/// prior (`None`), or its prior's declared contract is not integer-exact.
|
||||
Prior(Option<crate::container::DeterminismClass>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ReplicateRefusal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use ReplicateClass::*;
|
||||
match self {
|
||||
Self::Unregistered => write!(f, "the capability is not registered"),
|
||||
Self::Class(NeuralEntropyExact) => write!(f,
|
||||
"registry class NeuralEntropyExact: only the entropy decode is integer \
|
||||
(entropy-consistency); later stages run float, so the reconstruction is not \
|
||||
byte-identical on every conforming sink"),
|
||||
Self::Class(NeuralFloat) => write!(f,
|
||||
"registry class NeuralFloat: float inference is not byte-identical across hardware"),
|
||||
Self::Class(Behavioral) => write!(f,
|
||||
"registry class Behavioral: conforms by similarity, not bytes"),
|
||||
Self::Class(GenerativeDeterministic) => write!(f,
|
||||
"registry class GenerativeDeterministic: a generator (intent = create) has no \
|
||||
source to replicate"),
|
||||
Self::Class(c) => write!(f, "registry class {c:?} does not back replicate"),
|
||||
Self::Prior(None) => write!(f, "no pinned prior"),
|
||||
Self::Prior(Some(d)) => write!(f,
|
||||
"the pinned prior declares a {d:?} contract, not an integer-exact one"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SPEC §7 *replicate-soundness* for one envelope: `None` when `(cap, intent, prior)`
|
||||
/// may be honoured as `replicate`, otherwise why not.
|
||||
///
|
||||
/// The registry class decides first, and does not depend on anything the sender
|
||||
/// declares: a class whose [`ReplicateClass::replicate_promise`] is `None` is refused.
|
||||
/// For a neural capability `replicate` promises decode-equivalence — the same
|
||||
/// reconstruction bytes on every conforming sink — which only
|
||||
/// [`ReplicateClass::NeuralIntegerExact`] can keep, and then only against a pinned
|
||||
/// prior that declares an integer-exact contract
|
||||
/// ([`crate::container::Prior::is_cross_hardware_exact`]); a prior that *declares* an
|
||||
/// integer contract does not rescue a capability whose decode is float or only
|
||||
/// entropy-consistent. The three standard classes pass with no prior: over them
|
||||
/// `replicate` promises what their class states — the same bytes for
|
||||
/// [`ReplicateClass::StandardDefined`], the named standard's decoder conformance for
|
||||
/// [`ReplicateClass::StandardTolerance`] and [`ReplicateClass::StandardUnclassified`].
|
||||
/// Nothing here checks a sink's decoder against its standard. Intents other than
|
||||
/// `replicate` are unconstrained.
|
||||
pub fn replicate_refusal(
|
||||
cap: &str,
|
||||
intent: &str,
|
||||
prior: Option<&crate::container::Prior>,
|
||||
) -> Option<ReplicateRefusal> {
|
||||
if intent != "replicate" {
|
||||
return None;
|
||||
}
|
||||
match capability_replicate_class(cap) {
|
||||
None => Some(ReplicateRefusal::Unregistered),
|
||||
Some(ReplicateClass::NeuralIntegerExact) => match prior {
|
||||
Some(p) if p.is_cross_hardware_exact() => None,
|
||||
Some(p) => Some(ReplicateRefusal::Prior(Some(p.determinism_class()))),
|
||||
None => Some(ReplicateRefusal::Prior(None)),
|
||||
},
|
||||
Some(c) if c.replicate_promise().is_some() => None,
|
||||
Some(c) => Some(ReplicateRefusal::Class(c)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The intent an encoder that pins **no prior** may write over `cap`: `requested`,
|
||||
/// or `replicate` when nothing is requested — unless [`replicate_refusal`] refuses
|
||||
/// that intent over `cap` with no prior, in which case the refusal comes back and
|
||||
/// the encoder writes nothing.
|
||||
///
|
||||
/// This is the encoder side of SPEC §7. An encoder MUST NOT emit `intent =
|
||||
/// replicate` over a `NeuralEntropyExact` or `NeuralFloat` capability, and a sink
|
||||
/// refuses `replicate` over any class whose [`ReplicateClass::replicate_promise`] is
|
||||
/// `None`, and over a `NeuralIntegerExact` capability whose envelope pins no
|
||||
/// integer-exact prior — which an unpinned envelope cannot. So an unpinned
|
||||
/// `replicate` is accepted exactly over the three standard classes. `wai wrap` uses
|
||||
/// this, so the reference tool does not write an envelope the reference strict
|
||||
/// decode refuses. An intent other than `replicate` is returned unchanged.
|
||||
pub fn unpinned_envelope_intent<'a>(
|
||||
cap: &str,
|
||||
requested: Option<&'a str>,
|
||||
) -> Result<&'a str, ReplicateRefusal> {
|
||||
let intent = requested.unwrap_or("replicate");
|
||||
match replicate_refusal(cap, intent, None) {
|
||||
None => Ok(intent),
|
||||
Some(why) => Err(why),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -719,14 +1002,29 @@ mod tests {
|
|||
assert_eq!(capability_replicate_class(c), Some(NeuralFloat), "{c}");
|
||||
assert!(!is_neural_integer_exact(c), "{c} must not claim integer-exact");
|
||||
}
|
||||
// Standard / floor codecs and the deterministic-floor WAI-native classes
|
||||
// are standard-defined (reconstruction fixed by the codec/spec, not a
|
||||
// model WAI runs).
|
||||
for &c in &[CAP_IMAGE_PNG, CAP_VIDEO_AV1, CAP_AUDIO_FLAC, CAP_IMAGE_JPEGAI,
|
||||
// JPEG AI: integer entropy decode, float later stages → entropy-consistency
|
||||
// only. It is the only capability in that class, and it is NOT
|
||||
// standard-defined: its reconstruction runs float stages WAI introduces.
|
||||
assert_eq!(capability_replicate_class(CAP_IMAGE_JPEGAI), Some(NeuralEntropyExact));
|
||||
assert!(!is_neural_integer_exact(CAP_IMAGE_JPEGAI));
|
||||
let entropy_only: Vec<_> = known_capabilities().iter().copied()
|
||||
.filter(|c| capability_replicate_class(c) == Some(NeuralEntropyExact)).collect();
|
||||
assert_eq!(entropy_only, vec![CAP_IMAGE_JPEGAI]);
|
||||
// The lossless floor formats and the deterministic-floor WAI-native classes
|
||||
// are standard-defined (reconstruction specified exactly, not by a model
|
||||
// WAI runs).
|
||||
for &c in &[CAP_IMAGE_PNG, CAP_AUDIO_FLAC, CAP_TEXT_ZSTD,
|
||||
CAP_WORLD_REPLAY, CAP_AUDIO_SCORE, CAP_FILM_REEL, CAP_QUANTUM_CIRCUIT] {
|
||||
assert_eq!(capability_replicate_class(c), Some(StandardDefined), "{c}");
|
||||
assert!(!is_neural_integer_exact(c), "{c} is not a neural decode");
|
||||
}
|
||||
// No `wai.neural.*` capability is in a standard class.
|
||||
for &c in known_capabilities().iter().filter(|c| c.starts_with("wai.neural.")) {
|
||||
let class = capability_replicate_class(c);
|
||||
for std_class in [StandardDefined, StandardTolerance, StandardUnclassified] {
|
||||
assert_ne!(class, Some(std_class), "{c}");
|
||||
}
|
||||
}
|
||||
// The semantic path reproduces nothing byte-wise (similarity only).
|
||||
assert_eq!(capability_replicate_class(CAP_SEMANTIC_CLIP), Some(Behavioral));
|
||||
// The create-side quadrant: a DETERMINISTIC generator is byte-exact
|
||||
|
|
@ -739,4 +1037,196 @@ mod tests {
|
|||
assert_eq!(capability_replicate_class("wai.image.nope"), None);
|
||||
assert!(!is_neural_integer_exact("wai.image.nope"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn neural_classes_map_onto_the_determinism_tiers() {
|
||||
use DeterminismTier::*;
|
||||
use ReplicateClass::*;
|
||||
assert_eq!(NeuralIntegerExact.neural_tier(), Some(DecodeEquivalence));
|
||||
assert_eq!(NeuralEntropyExact.neural_tier(), Some(EntropyConsistency));
|
||||
for c in [NeuralFloat, StandardDefined, StandardTolerance, StandardUnclassified,
|
||||
GenerativeDeterministic, Behavioral] {
|
||||
assert_eq!(c.neural_tier(), None, "{c:?}");
|
||||
}
|
||||
assert_eq!(capability_replicate_class(CAP_IMAGE_JPEGAI).and_then(ReplicateClass::neural_tier),
|
||||
Some(EntropyConsistency));
|
||||
assert_eq!(capability_replicate_class(CAP_NEURAL_INT_HYPER).and_then(ReplicateClass::neural_tier),
|
||||
Some(DecodeEquivalence));
|
||||
// Labels are distinct (the CLI column must tell the classes apart).
|
||||
let labels: std::collections::HashSet<_> = [StandardDefined, StandardTolerance,
|
||||
StandardUnclassified, NeuralIntegerExact, NeuralEntropyExact,
|
||||
GenerativeDeterministic, NeuralFloat, Behavioral]
|
||||
.iter().map(|c| c.label()).collect();
|
||||
assert_eq!(labels.len(), 8);
|
||||
}
|
||||
|
||||
/// SPEC §7: a standard codec is classed by what its named standard's decoder
|
||||
/// conformance fixes, and `replicate` over it promises that and no more. A codec
|
||||
/// whose standard conforms decoders to anything but identical output must not
|
||||
/// sit in the class that promises the same bytes on every sink.
|
||||
#[test]
|
||||
fn standard_classes_follow_the_named_standards_decoder_conformance() {
|
||||
use ReplicateClass::*;
|
||||
let of = |class: ReplicateClass| {
|
||||
let mut v: Vec<_> = known_capabilities().iter().copied()
|
||||
.filter(|c| capability_replicate_class(c) == Some(class)).collect();
|
||||
v.sort_unstable();
|
||||
v
|
||||
};
|
||||
let sorted = |mut v: Vec<&'static str>| { v.sort_unstable(); v };
|
||||
// Opus (RFC 6716 §6), JPEG (T.81 §7, A.3.3), JPEG XL (18181-3 §4.2),
|
||||
// JPEG 2000 (15444-4), AV1/AVIF (AV1 §7.2 with film grain), IAMF.
|
||||
assert_eq!(of(StandardTolerance), sorted(vec![
|
||||
CAP_AUDIO_OPUS, CAP_IMAGE_JPEG, CAP_IMAGE_JXL, CAP_IMAGE_JP2, CAP_VIDEO_J2K,
|
||||
CAP_VIDEO_AV1, CAP_VIDEO_AV1_LOSSLESS, CAP_IMAGE_AVIF, CAP_AUDIO_IAMF]));
|
||||
// The sink-supplied standards and asset formats not yet classified.
|
||||
assert_eq!(of(StandardUnclassified), sorted(vec![
|
||||
CAP_AUDIO_AC4, CAP_AUDIO_IVAS, CAP_MESH_DRACO, CAP_PC_GPCC, CAP_PC_VPCC,
|
||||
CAP_SPLAT_SOG, CAP_HAPTIC_MIHS, CAP_META_HDR10PLUS, CAP_META_DOVI,
|
||||
CAP_MESH_GLB, CAP_SPLAT_SPZ]));
|
||||
// Every natively decoded standard codec is classified: none is unclassified.
|
||||
for &c in sink_capabilities() {
|
||||
assert_ne!(capability_replicate_class(c), Some(StandardUnclassified), "{c}");
|
||||
}
|
||||
// The promise per class: byte-exact only where the reconstruction is
|
||||
// specified exactly; the named standard's conformance for the other two.
|
||||
assert_eq!(StandardDefined.replicate_promise(), Some(ReplicatePromise::ByteExact));
|
||||
assert_eq!(NeuralIntegerExact.replicate_promise(), Some(ReplicatePromise::ByteExact));
|
||||
for c in [StandardTolerance, StandardUnclassified] {
|
||||
assert_eq!(c.replicate_promise(), Some(ReplicatePromise::NamedStandardConformance), "{c:?}");
|
||||
}
|
||||
for c in [NeuralEntropyExact, NeuralFloat, GenerativeDeterministic, Behavioral] {
|
||||
assert_eq!(c.replicate_promise(), None, "{c:?}");
|
||||
}
|
||||
// A tolerance codec is not refused by the replicate rule: it carries no prior,
|
||||
// and what it promises is its standard's conformance, not the same bytes.
|
||||
for &c in &[CAP_AUDIO_OPUS, CAP_IMAGE_JPEG, CAP_VIDEO_AV1, CAP_AUDIO_AC4] {
|
||||
assert_eq!(replicate_refusal(c, "replicate", None), None, "{c}");
|
||||
}
|
||||
}
|
||||
|
||||
/// SPEC §7: `replicate` promises decode-equivalence, so the registry class
|
||||
/// decides, and a prior that merely *declares* an integer contract cannot
|
||||
/// rescue a float or entropy-only capability.
|
||||
#[test]
|
||||
fn replicate_follows_the_registry_class_not_the_declared_prior() {
|
||||
use crate::container::{DeterminismClass, Prior};
|
||||
let p = |det: &str| Prior { id: "m".into(), sha256: "ab".repeat(32), determinism: det.into() };
|
||||
let integer = p("int-rans/p16+int-synth/i64");
|
||||
let floaty = p("int-rans/p16+onnx-cpu-f32/1thread");
|
||||
|
||||
// Every registered capability, replicate with an integer-declared prior:
|
||||
// allowed exactly for the classes that promise something — the integer-exact
|
||||
// neural decodes and the three standard classes.
|
||||
for &c in known_capabilities() {
|
||||
let class = capability_replicate_class(c).unwrap();
|
||||
let allowed = class.replicate_promise().is_some();
|
||||
assert_eq!(allowed, matches!(class,
|
||||
ReplicateClass::NeuralIntegerExact | ReplicateClass::StandardDefined
|
||||
| ReplicateClass::StandardTolerance | ReplicateClass::StandardUnclassified),
|
||||
"{c} ({class:?})");
|
||||
assert_eq!(replicate_refusal(c, "replicate", Some(&integer)).is_none(), allowed, "{c} ({class:?})");
|
||||
// Intents other than replicate are never constrained.
|
||||
for intent in ["improve", "create"] {
|
||||
assert_eq!(replicate_refusal(c, intent, Some(&floaty)), None, "{c} {intent}");
|
||||
assert_eq!(replicate_refusal(c, intent, None), None, "{c} {intent}");
|
||||
}
|
||||
}
|
||||
|
||||
// The mis-declared prior: an integer contract over JPEG AI or a float codec
|
||||
// is refused on the class, before the prior is read.
|
||||
assert_eq!(replicate_refusal(CAP_IMAGE_JPEGAI, "replicate", Some(&integer)),
|
||||
Some(ReplicateRefusal::Class(ReplicateClass::NeuralEntropyExact)));
|
||||
assert_eq!(replicate_refusal(CAP_NEURAL_BMSHJ2018, "replicate", Some(&integer)),
|
||||
Some(ReplicateRefusal::Class(ReplicateClass::NeuralFloat)));
|
||||
assert_eq!(replicate_refusal(CAP_SEMANTIC_CLIP, "replicate", Some(&integer)),
|
||||
Some(ReplicateRefusal::Class(ReplicateClass::Behavioral)));
|
||||
assert_eq!(replicate_refusal(CAP_GENERATE_SPECTRAL, "replicate", Some(&integer)),
|
||||
Some(ReplicateRefusal::Class(ReplicateClass::GenerativeDeterministic)));
|
||||
|
||||
// An integer-exact capability still needs its integer-exact prior.
|
||||
assert_eq!(replicate_refusal(CAP_NEURAL_INT_SYNTH, "replicate", Some(&integer)), None);
|
||||
assert_eq!(replicate_refusal(CAP_NEURAL_INT_SYNTH, "replicate", Some(&floaty)),
|
||||
Some(ReplicateRefusal::Prior(Some(DeterminismClass::FloatReproducible))));
|
||||
assert_eq!(replicate_refusal(CAP_NEURAL_INT_SYNTH, "replicate", None),
|
||||
Some(ReplicateRefusal::Prior(None)));
|
||||
|
||||
// A standard-defined floor codec carries no prior and is not refused here.
|
||||
assert_eq!(replicate_refusal(CAP_IMAGE_PNG, "replicate", None), None);
|
||||
// An unregistered capability cannot back replicate.
|
||||
assert_eq!(replicate_refusal("wai.image.nope", "replicate", Some(&integer)),
|
||||
Some(ReplicateRefusal::Unregistered));
|
||||
// The refusal says why, naming the tier.
|
||||
let why = replicate_refusal(CAP_IMAGE_JPEGAI, "replicate", Some(&integer)).unwrap().to_string();
|
||||
assert!(why.contains("entropy-consistency"), "{why}");
|
||||
}
|
||||
|
||||
/// `wai wrap` pins no prior, and used to write `intent = replicate` over every
|
||||
/// capability, `wai.image.jpegai` included, against SPEC §7's MUST NOT. The
|
||||
/// intent it writes now comes from `unpinned_envelope_intent`, which must agree
|
||||
/// with the sink's check on the envelope it produces.
|
||||
#[test]
|
||||
fn an_unpinned_envelope_claims_replicate_only_where_a_sink_accepts_it() {
|
||||
use crate::container::{Conditioning, Manifest, ModelRequirement, Wai};
|
||||
let envelope = |cap: &str, intent: &str| Wai::new(
|
||||
Manifest {
|
||||
wai: "1.0".into(),
|
||||
media: "binary".into(),
|
||||
intent: intent.into(),
|
||||
model_requirement: ModelRequirement {
|
||||
capability: cap.into(),
|
||||
fallback: None,
|
||||
min_sim: None,
|
||||
sim_metric: None,
|
||||
},
|
||||
conditioning: Conditioning { kind: "bytes".into(), prior: None },
|
||||
target: serde_json::Value::Null,
|
||||
},
|
||||
vec![],
|
||||
);
|
||||
|
||||
for &c in known_capabilities() {
|
||||
let class = capability_replicate_class(c).unwrap();
|
||||
let default = unpinned_envelope_intent(c, None);
|
||||
// Unpinned, `replicate` is written exactly over the standard classes.
|
||||
assert_eq!(default.is_ok(), matches!(class,
|
||||
ReplicateClass::StandardDefined | ReplicateClass::StandardTolerance
|
||||
| ReplicateClass::StandardUnclassified), "{c} ({class:?})");
|
||||
match default {
|
||||
// What the encoder writes, the sink's check accepts …
|
||||
Ok(intent) => {
|
||||
assert_eq!(intent, "replicate", "{c}");
|
||||
assert_eq!(envelope(c, intent).replicate_refusal(), None, "{c}");
|
||||
}
|
||||
// … and what it refuses is what the sink would refuse, for the same reason.
|
||||
Err(why) => assert_eq!(envelope(c, "replicate").replicate_refusal(), Some(why), "{c}"),
|
||||
}
|
||||
// An explicit `replicate` is held to the same rule; any other intent passes.
|
||||
assert_eq!(unpinned_envelope_intent(c, Some("replicate")), default, "{c}");
|
||||
assert_eq!(unpinned_envelope_intent(c, Some("improve")), Ok("improve"), "{c}");
|
||||
}
|
||||
|
||||
// The case that was wrong: JPEG AI is refused, and the refusal names its tier.
|
||||
let why = unpinned_envelope_intent(CAP_IMAGE_JPEGAI, None).unwrap_err();
|
||||
assert_eq!(why, ReplicateRefusal::Class(ReplicateClass::NeuralEntropyExact));
|
||||
assert!(why.to_string().contains("entropy-consistency"), "{why}");
|
||||
// A float neural codec and a generator are refused on their class.
|
||||
assert_eq!(unpinned_envelope_intent(CAP_NEURAL_BMSHJ2018, None),
|
||||
Err(ReplicateRefusal::Class(ReplicateClass::NeuralFloat)));
|
||||
assert_eq!(unpinned_envelope_intent(CAP_GENERATE_SPECTRAL, None),
|
||||
Err(ReplicateRefusal::Class(ReplicateClass::GenerativeDeterministic)));
|
||||
assert_eq!(unpinned_envelope_intent(CAP_GENERATE_SPECTRAL, Some("create")), Ok("create"));
|
||||
// An integer-exact neural codec backs replicate only with a pinned prior,
|
||||
// which an unpinned envelope does not carry.
|
||||
assert_eq!(unpinned_envelope_intent(CAP_NEURAL_INT_HYPER, None),
|
||||
Err(ReplicateRefusal::Prior(None)));
|
||||
|
||||
// Every capability `wai encode` writes (all with `replicate`, no prior) is
|
||||
// one of the standard classes, so its envelopes stay acceptable.
|
||||
for c in [CAP_IMAGE_PNG, CAP_IMAGE_JPEG, CAP_IMAGE_AVIF, CAP_IMAGE_JXL,
|
||||
CAP_AUDIO_OPUS, CAP_AUDIO_FLAC, CAP_VIDEO_AV1, CAP_VIDEO_AV1_LOSSLESS,
|
||||
CAP_TEXT_ZSTD, CAP_TEXT_XZ] {
|
||||
assert_eq!(unpinned_envelope_intent(c, None), Ok("replicate"), "{c}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,20 +79,26 @@ pub struct Prior {
|
|||
|
||||
/// How reproducible a [`Prior`]'s decode actually is, parsed from its
|
||||
/// `determinism` contract. This distinction is load-bearing for any normative
|
||||
/// `replicate` claim: the published result is that **floating-point round-off
|
||||
/// is platform-dependent**, so a single-threaded-float pin is reproducible on
|
||||
/// the *same build* but can still diverge across hardware — and in a learned
|
||||
/// entropy coder a single diverging bit corrupts the whole decode. Only
|
||||
/// integer-only inference is byte-identical *everywhere* (the route shipping
|
||||
/// codecs like DCVC-RT take via model integerization). See `SOTA-GAP-2026.md`.
|
||||
/// `replicate` claim. Float inference through a runtime is not reproducible
|
||||
/// across hardware: the runtime chooses kernels, accumulation order, vector
|
||||
/// width and fused multiply-adds per device, so a single-threaded fixed-graph
|
||||
/// pin reproduces on the *same build* but can still diverge elsewhere — and in
|
||||
/// a learned entropy coder a single diverging bit corrupts the whole decode.
|
||||
/// IEEE-754 basic operations are correctly rounded, so float does reproduce
|
||||
/// when one implementation fixes all of those choices and runs in the default
|
||||
/// floating-point environment; but that is a property of a build and a
|
||||
/// process, which a contract string cannot state. Only integer-only inference
|
||||
/// is byte-identical *everywhere* by construction. See SPEC §7 and
|
||||
/// `extensions/determinism-tiers.md`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DeterminismClass {
|
||||
/// Integer-only inference (PTQ / integer network): byte-identical across
|
||||
/// arbitrary hardware. The ONLY class that may back a normative `replicate`.
|
||||
IntegerExact,
|
||||
/// Float inference pinned (single thread + fixed graph): reproducible on
|
||||
/// the same build/runtime, but NOT guaranteed across different hardware.
|
||||
/// Honest tier — "exact here", not "exact everywhere".
|
||||
/// the same build/runtime, but NOT guaranteed across different hardware,
|
||||
/// where the runtime may pick other kernels, accumulation order or fused
|
||||
/// operations. Honest tier — "exact here", not "exact everywhere".
|
||||
FloatReproducible,
|
||||
/// Unrecognized contract — treat as not reproducible.
|
||||
Unknown,
|
||||
|
|
@ -124,12 +130,17 @@ impl Prior {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether a `(intent, prior)` pair makes a sound normative-`replicate` claim:
|
||||
/// `replicate` requires a pinned prior whose decode is integer-exact across
|
||||
/// hardware. A `replicate` intent backed by a float-reproducible (or absent)
|
||||
/// prior is only "exact on this build" and should be tagged a perceptual /
|
||||
/// `improve` tier instead — this is the WAI honesty rule the determinism work
|
||||
/// exists to enforce.
|
||||
/// The **prior half** of SPEC §7's replicate rule: whether a `(intent, prior)` pair
|
||||
/// declares what a normative `replicate` over a neural capability needs — a pinned
|
||||
/// prior whose declared contract is integer-exact. A `replicate` intent backed by a
|
||||
/// float-reproducible (or absent) prior is only "exact on this build" and should be
|
||||
/// tagged a perceptual / `improve` tier instead.
|
||||
///
|
||||
/// This reads only the sender's declaration. The other half is the capability's
|
||||
/// registry class: a prior that declares an integer contract over a capability
|
||||
/// whose decode is float or only entropy-consistent still does not back
|
||||
/// `replicate`. [`Wai::replicate_is_sound`] and [`crate::codecs::replicate_refusal`]
|
||||
/// apply both.
|
||||
pub fn replicate_is_sound(intent: &str, prior: Option<&Prior>) -> bool {
|
||||
intent != "replicate" || prior.is_some_and(Prior::is_cross_hardware_exact)
|
||||
}
|
||||
|
|
@ -253,13 +264,26 @@ impl Wai {
|
|||
self.manifest.model_requirement.sim_metric.as_deref().unwrap_or("clip")
|
||||
}
|
||||
|
||||
/// Whether this envelope makes a *sound* normative-`replicate` claim:
|
||||
/// either it doesn't claim `replicate`, or it does and pins an
|
||||
/// integer-exact prior. A `replicate` envelope with a float-reproducible
|
||||
/// or absent prior is "exact on this build" only — see
|
||||
/// [`replicate_is_sound`] and [`DeterminismClass`].
|
||||
/// Whether this envelope makes a *sound* normative-`replicate` claim (SPEC §7):
|
||||
/// either it doesn't claim `replicate`, or its capability's registry class backs
|
||||
/// `replicate` ([`crate::codecs::ReplicateClass::replicate_promise`]) and — for a
|
||||
/// neural capability — it pins an integer-exact prior. A `replicate` envelope over a float or entropy-only
|
||||
/// capability is unsound whatever its prior declares; one with a
|
||||
/// float-reproducible or absent prior is "exact on this build" only. See
|
||||
/// [`crate::codecs::replicate_refusal`] for the rule and [`DeterminismClass`]
|
||||
/// for the prior half.
|
||||
pub fn replicate_is_sound(&self) -> bool {
|
||||
replicate_is_sound(&self.manifest.intent, self.prior())
|
||||
self.replicate_refusal().is_none()
|
||||
}
|
||||
|
||||
/// Why this envelope's `replicate` claim is unsound, or `None` if it is sound
|
||||
/// (or does not claim `replicate`). See [`crate::codecs::replicate_refusal`].
|
||||
pub fn replicate_refusal(&self) -> Option<crate::codecs::ReplicateRefusal> {
|
||||
crate::codecs::replicate_refusal(
|
||||
&self.manifest.model_requirement.capability,
|
||||
&self.manifest.intent,
|
||||
self.prior(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -635,6 +659,49 @@ mod tests {
|
|||
assert!(replicate_is_sound("create", None));
|
||||
}
|
||||
|
||||
/// The envelope-level check applies both halves of SPEC §7: the capability's
|
||||
/// registry class first, then the prior. An integer-declared prior over JPEG AI
|
||||
/// (entropy-consistency only) or over a float codec does not make `replicate`
|
||||
/// sound; the same prior over an integer-exact capability does.
|
||||
#[test]
|
||||
fn envelope_replicate_soundness_consults_the_registry() {
|
||||
use crate::codecs::{ReplicateClass, ReplicateRefusal};
|
||||
let env = |cap: &str, intent: &str, det: Option<&str>| {
|
||||
Wai::new(Manifest {
|
||||
wai: "1.0".into(),
|
||||
media: "image".into(),
|
||||
intent: intent.into(),
|
||||
model_requirement: ModelRequirement {
|
||||
capability: cap.into(), fallback: None, min_sim: None, sim_metric: None,
|
||||
},
|
||||
conditioning: Conditioning {
|
||||
kind: "k".into(),
|
||||
prior: det.map(|d| Prior { id: "m".into(), sha256: "ab".repeat(32), determinism: d.into() }),
|
||||
},
|
||||
target: serde_json::json!({}),
|
||||
}, vec![])
|
||||
};
|
||||
let int = Some("int-rans/p16+int-synth/i64");
|
||||
|
||||
let jpegai = env("wai.image.jpegai", "replicate", int);
|
||||
assert!(!jpegai.replicate_is_sound());
|
||||
assert_eq!(jpegai.replicate_refusal(),
|
||||
Some(ReplicateRefusal::Class(ReplicateClass::NeuralEntropyExact)));
|
||||
assert!(!env("wai.neural.bmshj2018", "replicate", int).replicate_is_sound());
|
||||
|
||||
assert!(env("wai.neural.int_synth", "replicate", int).replicate_is_sound());
|
||||
assert!(!env("wai.neural.int_synth", "replicate", Some("int-rans+onnx-f32")).replicate_is_sound());
|
||||
assert!(!env("wai.neural.int_synth", "replicate", None).replicate_is_sound());
|
||||
|
||||
// A floor codec carries no prior and is not refused by the neural rule.
|
||||
assert!(env("wai.image.png", "replicate", None).replicate_is_sound());
|
||||
// Nor is a codec whose standard conforms decoders to a tolerance: over it
|
||||
// `replicate` promises the standard's conformance, not the same bytes.
|
||||
assert!(env("wai.audio.opus", "replicate", None).replicate_is_sound());
|
||||
// Non-replicate intents are unconstrained.
|
||||
assert!(env("wai.image.jpegai", "improve", None).replicate_is_sound());
|
||||
}
|
||||
|
||||
// ---- v1.1: multi-rendition WAI2 ----
|
||||
|
||||
fn sample_multi() -> WaiMulti {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//! Integer Gaussian-conditional entropy — the integer-entropy contract's
|
||||
//! reusable core (SPEC §6, *Replicate-soundness*).
|
||||
//! reusable core (SPEC §7, *Replicate-soundness*).
|
||||
//!
|
||||
//! A learned conditional codec entropy-decodes each latent against a CDF chosen
|
||||
//! by that element's scale `σ`. In the float path ([`crate::neural`]'s
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
//!
|
||||
//! This is the deterministic member of the neural family. The integer rANS
|
||||
//! recovers latents exactly; the divergence in float decoders like
|
||||
//! `bmshj2018` / `mbt2018_mean` is the **float ONNX synthesis** — and float
|
||||
//! round-off is platform-dependent. Here the synthesis is a stack of integer
|
||||
//! `bmshj2018` / `mbt2018_mean` is the **float ONNX synthesis**, whose round-off
|
||||
//! depends on the kernels, accumulation order and fused operations the runtime
|
||||
//! picks for each platform. Here the synthesis is a stack of integer
|
||||
//! transposed convolutions with integer activations: every operation is `i64`
|
||||
//! arithmetic + an arithmetic shift, so two sinks honoring the spec produce the
|
||||
//! same bytes everywhere. No ONNX, no float, nothing implementation-defined.
|
||||
|
|
|
|||
|
|
@ -159,11 +159,14 @@ pub struct ComponentHeader {
|
|||
pub num_threads_r: u32,
|
||||
pub num_chs: u32,
|
||||
pub use_cube_flags: bool,
|
||||
pub lsbs_enable: bool,
|
||||
pub rvs_enable: bool,
|
||||
pub grfs_enable: bool,
|
||||
/// GRFS channel-selection flags, `num_chs` of them (empty if `grfs_enable` is false).
|
||||
pub grfs_channel_flags: Vec<bool>,
|
||||
/// `synthesis_tile_enable[c]` — the synthesis tile manager's flag, coded in the
|
||||
/// picture header right after this component's GRFS channel flags. (The
|
||||
/// component's LSBS flag is not here: LSBS codes it into the tool header; see
|
||||
/// [`parse_lsbs_flags`].)
|
||||
pub synthesis_tile_enable: bool,
|
||||
}
|
||||
|
||||
|
|
@ -205,13 +208,23 @@ pub struct PictureHeader {
|
|||
/// (`Segment::start_bit`). A faithful port of the reference decode order:
|
||||
/// prefix → `CCS_SGMM::decode_header` (`multi_threading_z`, quantizer β F-header,
|
||||
/// `region_partitioning`, quantizer β O-header) → the per-component tool groups
|
||||
/// (`multi_threading_r`, `num_chs`, then the tools in sub-tool order:
|
||||
/// `use_cube_flags`, `rvs_enable`, `grfs_enable` + channel flags, then `lsbs_enable`) →
|
||||
/// `gain_3D_enable` → `synthesis_tile_enable` per component.
|
||||
/// (`multi_threading_r`, `num_chs`, `use_cube_flags`, `rvs_enable`, `grfs_enable` +
|
||||
/// channel flags, `synthesis_tile_enable`) → `gain_3D_enable`.
|
||||
///
|
||||
/// Header-part placement follows the reference: the synthesis tile manager and
|
||||
/// `gain_3D` are declared with `stream_header_part='pic_header'`, while LSBS keeps
|
||||
/// the default `'tool_header'`, so `lsbs_enable_flag[0..1]` are the first two bits of
|
||||
/// TON, not PIH fields ([`parse_lsbs_flags`]). The reference header trace records the
|
||||
/// same order (`synthesis_tile_enable[0]` before `multi_threading_r[1]`,
|
||||
/// `gain_3D_enable_flag` last) and `lsbs_enable_flag = 1` for both components.
|
||||
///
|
||||
/// `c_ver`/`c_hor` are coded only when the matching `s_ver`/`s_hor` is 1; otherwise
|
||||
/// they are 2 and take no bits (reference `CodingEngine` header decode).
|
||||
///
|
||||
/// Branches not exercised by the 4:4:4 single-tile reference stream (region
|
||||
/// sub-splits, `independent_beta_uv`'s second β, the signalled colour matrix,
|
||||
/// multi-threading counts) follow the reference syntax and are decoded but untested.
|
||||
/// multi-threading counts, `s_ver`/`s_hor` = 2) follow the reference syntax and are
|
||||
/// decoded but untested against a real codestream.
|
||||
// ---- tools header (TON) ----
|
||||
|
||||
/// One `decode_filters` group of the EFE **linear** filter header.
|
||||
|
|
@ -411,6 +424,15 @@ pub fn parse_tools_header(data: &[u8], start_bit: usize, scale_2x2: bool, models
|
|||
t
|
||||
}
|
||||
|
||||
/// `lsbs_enable_flag[0..1]` (luma, chroma): the first two bits of the tool header
|
||||
/// (TON), ahead of the post-filter chain that [`parse_tools_header`] reads from
|
||||
/// `ton_start_bit + 2`. LSBS codes its enable flag into the tool header (the
|
||||
/// reference's default header part), one flag per component.
|
||||
pub fn parse_lsbs_flags(data: &[u8], ton_start_bit: usize) -> [bool; 2] {
|
||||
let mut br = BitReader::at(data, ton_start_bit);
|
||||
[br.read(1) == 1, br.read(1) == 1]
|
||||
}
|
||||
|
||||
pub fn parse_picture_header(data: &[u8], start_bit: usize) -> PictureHeader {
|
||||
let mut br = BitReader::at(data, start_bit);
|
||||
let mut h = PictureHeader::default();
|
||||
|
|
@ -427,8 +449,8 @@ pub fn parse_picture_header(data: &[u8], start_bit: usize) -> PictureHeader {
|
|||
h.bit_depth_idc = br.read(3) as u32;
|
||||
h.s_ver = br.read(1) as u32 + 1;
|
||||
h.s_hor = br.read(1) as u32 + 1;
|
||||
h.c_ver = br.read(1) as u32 + 1;
|
||||
h.c_hor = br.read(1) as u32 + 1;
|
||||
h.c_ver = if h.s_ver == 1 { br.read(1) as u32 + 1 } else { 2 };
|
||||
h.c_hor = if h.s_hor == 1 { br.read(1) as u32 + 1 } else { 2 };
|
||||
h.colour_transform_idx = br.read(2) as u32;
|
||||
if h.colour_transform_idx == 2 {
|
||||
let mut m = [0u32; 9];
|
||||
|
|
@ -464,25 +486,21 @@ pub fn parse_picture_header(data: &[u8], start_bit: usize) -> PictureHeader {
|
|||
let comp = &mut h.components[c];
|
||||
comp.num_threads_r = if br.read(1) == 1 { 1 << (br.read(2) + 1) } else { 1 };
|
||||
comp.num_chs = br.read(8) as u32;
|
||||
// Only THREE flags precede the channel flags; the fourth TRAILS them. The
|
||||
// tools own different parts of the walk, so `res_var_scale`'s pair
|
||||
// (rvs_enable, grfs_enable) sits immediately before the channel flags it
|
||||
// gates, and the remaining tool's flag is emitted after that group.
|
||||
// Reading four up-front shifts `grfs_channel_flags` one bit late and
|
||||
// corrupts them (while still landing on the right end_bit, since the extra
|
||||
// leading bit is cancelled by one fewer channel flag).
|
||||
// Only THREE flags precede the channel flags; the fourth PIH flag TRAILS
|
||||
// them. `res_var_scale`'s pair (rvs_enable, grfs_enable) sits immediately
|
||||
// before the channel flags it gates, and the synthesis tile manager's flag
|
||||
// follows the group. Reading four up-front shifts `grfs_channel_flags` one
|
||||
// bit late and corrupts them (while still landing on the right end_bit,
|
||||
// since the extra leading bit is cancelled by one fewer channel flag).
|
||||
comp.use_cube_flags = br.read(1) == 1;
|
||||
comp.rvs_enable = br.read(1) == 1;
|
||||
comp.grfs_enable = br.read(1) == 1;
|
||||
if comp.grfs_enable {
|
||||
comp.grfs_channel_flags = (0..comp.num_chs).map(|_| br.read(1) == 1).collect();
|
||||
}
|
||||
comp.lsbs_enable = br.read(1) == 1;
|
||||
comp.synthesis_tile_enable = br.read(1) == 1;
|
||||
}
|
||||
h.gain_3d_enable = br.read(1) == 1;
|
||||
for c in 0..2 {
|
||||
h.components[c].synthesis_tile_enable = br.read(1) == 1;
|
||||
}
|
||||
h.end_bit = br.bit_pos();
|
||||
h
|
||||
}
|
||||
|
|
@ -537,6 +555,42 @@ mod tests {
|
|||
assert_eq!(br.bit_pos(), 16);
|
||||
}
|
||||
|
||||
/// MSB-first bit writer for synthetic headers.
|
||||
fn pack(fields: &[(u64, u32)]) -> Vec<u8> {
|
||||
let mut out = Vec::new();
|
||||
let mut n = 0usize;
|
||||
for &(v, w) in fields {
|
||||
for i in (0..w).rev() {
|
||||
if n % 8 == 0 { out.push(0); }
|
||||
let bit = ((v >> i) & 1) as u8;
|
||||
*out.last_mut().unwrap() |= bit << (7 - n % 8);
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
out.extend([0u8; 8]);
|
||||
out
|
||||
}
|
||||
|
||||
/// `c_ver`/`c_hor` take no bits when `s_ver`/`s_hor` is 2 (reference
|
||||
/// `CodingEngine` header decode): the fields after them must not shift.
|
||||
#[test]
|
||||
fn chroma_factors_are_implicit_when_secondary_is_subsampled() {
|
||||
let prefix = [(0, 4), (2, 4), (0, 4), (2, 4), (52, 8), (192, 16), (192, 16), (0, 6), (0, 6), (0, 3)];
|
||||
// s_ver = 2, s_hor = 2 ⇒ no c_ver / c_hor bits; then colour_transform_idx = 1, model_id = 5
|
||||
let mut f: Vec<(u64, u32)> = prefix.to_vec();
|
||||
f.extend([(1, 1), (1, 1), (1, 2), (5, 4)]);
|
||||
let h = parse_picture_header(&pack(&f), 0);
|
||||
assert_eq!((h.s_ver, h.s_hor, h.c_ver, h.c_hor), (2, 2, 2, 2));
|
||||
assert_eq!((h.colour_transform_idx, h.model_id), (1, 5), "fields after s/c stay aligned");
|
||||
|
||||
// s_ver = s_hor = 1 ⇒ c_ver / c_hor are coded (here 2 and 1)
|
||||
let mut f: Vec<(u64, u32)> = prefix.to_vec();
|
||||
f.extend([(0, 1), (0, 1), (1, 1), (0, 1), (1, 2), (5, 4)]);
|
||||
let h = parse_picture_header(&pack(&f), 0);
|
||||
assert_eq!((h.s_ver, h.s_hor, h.c_ver, h.c_hor), (1, 1, 2, 1));
|
||||
assert_eq!((h.colour_transform_idx, h.model_id), (1, 5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_container_walks_markers_and_lengths() {
|
||||
// SOC | PIH(len 2, payload "ab") | EOC
|
||||
|
|
|
|||
|
|
@ -9,16 +9,39 @@
|
|||
//!
|
||||
//! Determinism, not float-exactness. ψ, the four MCM stages and synthesis are 16-bit
|
||||
//! PTQ, so the decoded pixels differ from the float reference by ~1 LSB on a few percent
|
||||
//! of samples. Everything is deterministic — integer arithmetic, or IEEE-754 float with
|
||||
//! a fixed accumulation order — so the output is byte-identical on every machine, which
|
||||
//! is the contract. See `tests/jpegai_e2e_full.rs`, which drives this and compares the
|
||||
//! reference decode of `test256.bin` (max|Δ| = 1, ~4.4% of samples).
|
||||
//! of samples. The entropy decode, the scale-index derivation and the PTQ networks are
|
||||
//! integer. Dequantisation, LSBS refinement, the post-filter chain (the eICCI network is
|
||||
//! a float CNN) and colour conversion are float, and are reproducible across machines
|
||||
//! only under conditions this code relies on:
|
||||
//!
|
||||
//! Scope: the 256×256, 4:4:4, tools_0 profile the reference ships — luma 160 channels
|
||||
//! (4 MCM stages), chroma 96 (no MCM). Other geometries are rejected up front.
|
||||
//! - every float operation is an IEEE-754 basic operation (add, subtract, multiply,
|
||||
//! divide, square root, conversion), which is correctly rounded and so gives the
|
||||
//! same result for the same operands on every conforming target — except one
|
||||
//! `exp` in the gain scaler, whose results `tools/wai_jpegai_gain_exp_margin.py`
|
||||
//! shows lie far from any rounding boundary for the tables this decoder accepts;
|
||||
//! - the operations run single-threaded in the fixed order of this source, at their
|
||||
//! own precision (true of x86_64 SSE2, AArch64 and wasm32; not of x87), and Rust
|
||||
//! neither fuses `a * b + c` into a fused multiply-add nor reassociates;
|
||||
//! - the thread runs in the IEEE-754 default floating-point environment
|
||||
//! (round-to-nearest-even, no flush-to-zero, no denormals-are-zero). A host process
|
||||
//! can change this through the FFI; [`check_scope`] probes it and refuses to decode
|
||||
//! otherwise ([`fp_env_is_default`]).
|
||||
//!
|
||||
//! `tests/jpegai_e2e_full.rs` drives this and compares the reference decode of
|
||||
//! `test256.bin` (max|Δ| = 1, ~4.4% of samples; asserted bound max|Δ| ≤ 2).
|
||||
//!
|
||||
//! Scope: one configuration, the one the reference encoder's `test256.bin` exercises
|
||||
//! and the stage tests verified. [`check_codestream`] checks every header condition,
|
||||
//! [`check_scope`] adds the floating-point environment, and [`decode`] returns `None`
|
||||
//! for a codestream that fails either — notably
|
||||
//! `beta_displacement_log ≠ 0` (β is not implemented), `model_id ≠ 0` (the tables and
|
||||
//! constants are tools_0's), a synthesis transform other than the high-operation-point
|
||||
//! one, chroma subsampling, and an eICCI model selection other than the one the weight
|
||||
//! bundle carries.
|
||||
|
||||
use crate::jpegai_bitstream::{find_segment, parse_container, parse_picture_header,
|
||||
parse_tools_header, Marker};
|
||||
use crate::jpegai_bitstream::{find_segment, parse_container, parse_lsbs_flags,
|
||||
parse_picture_header, parse_tools_header, Marker, PictureHeader,
|
||||
ToolsHeader};
|
||||
use crate::jpegai_icci::IcciNet;
|
||||
use crate::jpegai_mans::{build_decode_transitions, cdf_from_pmf, MansDecoder};
|
||||
use crate::jpegai_pipeline::{dequantize_resi, efl_chroma, efn_filter, gain_unit_scaler_vec,
|
||||
|
|
@ -39,7 +62,9 @@ pub struct PlaneWeights {
|
|||
}
|
||||
|
||||
/// Every model weight the decode needs. Luma carries the four MCM stages; chroma has no
|
||||
/// MCM (its hyper params are used directly as the means). `icci` is the whole eICCI net.
|
||||
/// MCM (its hyper params are used directly as the means). `icci` is the whole eICCI net
|
||||
/// for the model pair [`ICCI_SELECTION`] names; the decoder refuses a picture that
|
||||
/// signals another pair.
|
||||
pub struct DecoderWeights {
|
||||
pub luma: PlaneWeights,
|
||||
pub chroma: PlaneWeights,
|
||||
|
|
@ -49,8 +74,8 @@ pub struct DecoderWeights {
|
|||
|
||||
/// The normative, image-independent tables. All are shipped decoder assets, not derived
|
||||
/// per image: the me-tANS PMF/bounds, the factorized-`z` CDFs, the per-channel gain
|
||||
/// vectors (`gain_unit_mlog`), the LSBS refinement tables, and the LEF op-point tables
|
||||
/// selected at the picture's `model_id`.
|
||||
/// vectors (`gain_unit_mlog`), the LSBS refinement tables, and the LEF op-point tables.
|
||||
/// All are tools_0's (`model_id` 0), the only model the decoder accepts.
|
||||
pub struct NormTables {
|
||||
pub pmf: Vec<Vec<i64>>,
|
||||
pub bounds: Vec<u8>,
|
||||
|
|
@ -150,17 +175,152 @@ fn grfs_flags(data: &[u8], channels: usize, marker: Marker) -> Vec<bool> {
|
|||
f
|
||||
}
|
||||
|
||||
/// Decode a JPEG-AI codestream to RGB. Returns `None` if the picture is not the
|
||||
/// supported 256×256 4:4:4 tools_0 geometry.
|
||||
pub fn decode(data: &[u8], w: &DecoderWeights, n: &NormTables) -> Option<Rgb> {
|
||||
/// The eICCI model selection the weight bundle's `icci` net implements, as the picture
|
||||
/// signals it: the short list, luma index 0 and chroma index 1 (models 6 and 3 under
|
||||
/// the high-operation-point synthesis at `model_id` 0). It is the only pair
|
||||
/// `tools/wai_jpegai_build_e2e_inputs.py` exports; the bundle format does not record
|
||||
/// its selection, so a picture that signals any other pair is refused.
|
||||
pub const ICCI_SELECTION: (bool, u32, u32) = (true, 0, 1);
|
||||
|
||||
/// The eICCI model-list size at `model_id` 0 under the high-operation-point synthesis.
|
||||
/// It sets the width of the signalled model indices in the tool header.
|
||||
const ICCI_MODELS_COUNT: u32 = 3;
|
||||
|
||||
/// `synthesis_transform_id` of the high-operation-point synthesis — the transform the
|
||||
/// bundle's synthesis weights and the eICCI base model belong to.
|
||||
const HOP_SYNTHESIS: u32 = 2;
|
||||
|
||||
fn need(ok: bool, why: &'static str) -> Result<(), &'static str> {
|
||||
if ok { Ok(()) } else { Err(why) }
|
||||
}
|
||||
|
||||
/// True when this thread runs in the IEEE-754 default floating-point environment the
|
||||
/// float stages assume: round-to-nearest-ties-to-even, subnormal results kept (no
|
||||
/// flush-to-zero) and subnormal operands honoured (no denormals-are-zero), for both
|
||||
/// binary32 and binary64. Rust code never changes these, but a host process can
|
||||
/// (the x86 MXCSR, the AArch64 FPCR), and a library loaded into the host can set them
|
||||
/// as a side effect. Every operand passes through `black_box`, so each probe runs at
|
||||
/// run time in the current environment instead of being folded at compile time.
|
||||
#[inline(never)]
|
||||
pub fn fp_env_is_default() -> bool {
|
||||
use std::hint::black_box as bb;
|
||||
let e32 = f32::EPSILON;
|
||||
let f32_ok = (bb(f32::MIN_POSITIVE) * bb(0.5f32)).to_bits() == 0x0040_0000 // subnormal result kept
|
||||
&& (bb(f32::from_bits(1)) * bb(2.0f32)).to_bits() == 2 // subnormal operand honoured
|
||||
&& (bb(1.0f32) + bb(0.75 * e32)).to_bits() == 0x3F80_0001 // not toward zero / down
|
||||
&& (bb(-1.0f32) - bb(0.75 * e32)).to_bits() == 0xBF80_0001 // not toward zero / up
|
||||
&& (bb(1.0f32) + bb(0.5 * e32)).to_bits() == 0x3F80_0000; // ties to even
|
||||
let e64 = f64::EPSILON;
|
||||
let f64_ok = (bb(f64::MIN_POSITIVE) * bb(0.5f64)).to_bits() == 0x0008_0000_0000_0000
|
||||
&& (bb(f64::from_bits(1)) * bb(2.0f64)).to_bits() == 2
|
||||
&& (bb(1.0f64) + bb(0.75 * e64)).to_bits() == 0x3FF0_0000_0000_0001
|
||||
&& (bb(-1.0f64) - bb(0.75 * e64)).to_bits() == 0xBFF0_0000_0000_0001
|
||||
&& (bb(1.0f64) + bb(0.5 * e64)).to_bits() == 0x3FF0_0000_0000_0000;
|
||||
f32_ok && f64_ok
|
||||
}
|
||||
|
||||
/// Parse the headers and check that the codestream asks for exactly what this decoder
|
||||
/// implements. Every condition is a hard-coded assumption somewhere in the decode, so a
|
||||
/// codestream that fails one would still decode deterministically — to the wrong image.
|
||||
fn codestream_scope(data: &[u8]) -> Result<(PictureHeader, ToolsHeader), &'static str> {
|
||||
let segs = parse_container(data);
|
||||
let ph = parse_picture_header(data, find_segment(&segs, Marker::Pih)?.start_bit());
|
||||
let (img_h, img_w) = (ph.img_height as usize, ph.img_width as usize);
|
||||
if (img_h, img_w) != (256, 256) || ph.components.len() != 2
|
||||
|| ph.components[0].num_chs != 160 || ph.components[1].num_chs != 96 {
|
||||
let seg = |m| find_segment(&segs, m);
|
||||
let (Some(pih), Some(ton)) = (seg(Marker::Pih), seg(Marker::Ton)) else {
|
||||
return Err("missing picture header (PIH) or tool header (TON)");
|
||||
};
|
||||
need(seg(Marker::Soz).is_some() && seg(Marker::Sorp).is_some() && seg(Marker::Sors).is_some(),
|
||||
"missing SOZ, SORP or SORS substream")?;
|
||||
need(seg(Marker::Soq).is_none(), "SOQ segment present; not implemented")?;
|
||||
|
||||
// ---- picture header ----
|
||||
let ph = parse_picture_header(data, pih.start_bit());
|
||||
let pih_end = (pih.start + pih.len) * 8;
|
||||
need(ph.end_bit <= pih_end && pih_end - ph.end_bit < 8,
|
||||
"picture header does not end in its segment's final byte (unparsed syntax)")?;
|
||||
need((ph.img_width, ph.img_height) == (256, 256), "picture is not 256×256")?;
|
||||
need((ph.diff_display_width, ph.diff_display_height) == (0, 0), "display cropping is not implemented")?;
|
||||
need(ph.bit_depth_idc == 0, "bit depth other than 8 is not implemented")?;
|
||||
need((ph.s_ver, ph.s_hor, ph.c_ver, ph.c_hor) == (1, 1, 1, 1), "chroma subsampling; only 4:4:4 is implemented")?;
|
||||
need(ph.colour_transform_idx == 1, "colour transform other than the built-in YUV→RGB")?;
|
||||
need(ph.synthesis_transform_ids.first() == Some(&HOP_SYNTHESIS),
|
||||
"synthesis transform other than the high-operation-point one")?;
|
||||
need(ph.model_id == 0, "model_id ≠ 0; the tables and constants are tools_0's")?;
|
||||
need(ph.beta_displacement_log == [0, 0],
|
||||
"beta_displacement_log ≠ 0; the quantiser β displacement is not implemented")?;
|
||||
need(ph.num_threads_z == 1, "multi-threaded z substream")?;
|
||||
need(!ph.region_partitioning, "region partitioning")?;
|
||||
need(!ph.gain_3d_enable, "3-D gain is not implemented")?;
|
||||
for (c, want) in ph.components.iter().zip([160u32, 96]) {
|
||||
need(c.num_chs == want, "latent channel count other than 160 luma / 96 chroma")?;
|
||||
need(c.num_threads_r == 1, "multi-threaded residual substream")?;
|
||||
need(!c.use_cube_flags, "cube flags are not implemented")?;
|
||||
need(c.rvs_enable && c.grfs_enable, "residual variance scaling or GRFS disabled")?;
|
||||
need(c.grfs_channel_flags.len() == want as usize, "GRFS channel flags missing")?;
|
||||
need(!c.synthesis_tile_enable, "synthesis tiling is not implemented")?;
|
||||
}
|
||||
|
||||
// ---- tool header ----
|
||||
need(parse_lsbs_flags(data, ton.start_bit()) == [true, true], "LSBS disabled")?;
|
||||
let th = parse_tools_header(data, ton.start_bit() + 2, true, ICCI_MODELS_COUNT, 1);
|
||||
let ton_end = (ton.start + ton.len) * 8;
|
||||
need(th.end_bit <= ton_end && ton_end - th.end_bit < 8,
|
||||
"tool header does not end in its segment's final byte (unparsed syntax)")?;
|
||||
if let Some(efl) = th.efl.as_ref() {
|
||||
let f = &efl.filters_best2;
|
||||
need((f.cand_u, f.cand_v, f.fl_u, f.fl_v) == (0, 0, 1, 1)
|
||||
&& [&f.weights_u, &f.weights_u2, &f.weights_v, &f.weights_v2].iter().all(|w| w.len() == 1),
|
||||
"linear enhancement filter other than one single-tap filter per plane")?;
|
||||
}
|
||||
if th.icci_enabled {
|
||||
need(!th.icci_tile_manager_enabled && th.icci_tiles.len() == 1, "eICCI tiling")?;
|
||||
let t = &th.icci_tiles[0];
|
||||
need(t.use_yuv == [true, true, true], "eICCI on a subset of planes")?;
|
||||
need((t.use_short_list, t.model_idx_y, t.model_idx_uv) == ICCI_SELECTION,
|
||||
"eICCI model selection other than the one the weight bundle carries")?;
|
||||
}
|
||||
if let Some(efn) = th.efn.as_ref() {
|
||||
need(!efn.mask1_enabled && !efn.mask2_enabled, "nonlinear enhancement filter masks")?;
|
||||
need(efn.luma_min.len() == 1 && efn.luma_max.len() == 1, "nonlinear enhancement filter tiling")?;
|
||||
need((!efn.nonlinear_u_enabled || efn.weights_u.len() == 8)
|
||||
&& (!efn.nonlinear_v_enabled || efn.weights_v.len() == 8),
|
||||
"nonlinear enhancement filter with other than 8 weights")?;
|
||||
}
|
||||
need(!th.lef_enabled || th.lef_ch_idx < 160, "LEF channel index out of range")?;
|
||||
Ok((ph, th))
|
||||
}
|
||||
|
||||
fn scope(data: &[u8]) -> Result<(PictureHeader, ToolsHeader), &'static str> {
|
||||
need(fp_env_is_default(),
|
||||
"floating-point environment is not the IEEE-754 default (flush-to-zero, \
|
||||
denormals-are-zero or a directed rounding mode is set)")?;
|
||||
codestream_scope(data)
|
||||
}
|
||||
|
||||
/// Check whether the codestream's headers ask for exactly the configuration this
|
||||
/// decoder implements, and if not, which condition fails first. The same models,
|
||||
/// tables and filter selection are hard-coded in the float ONNX path
|
||||
/// (`neural::jpegai`), which uses this check to refuse the same codestreams. This
|
||||
/// does not validate the entropy-coded substreams.
|
||||
pub fn check_codestream(data: &[u8]) -> Result<(), &'static str> {
|
||||
codestream_scope(data).map(|_| ())
|
||||
}
|
||||
|
||||
/// Check whether [`decode`] will decode `data`, and if not, why: the floating-point
|
||||
/// environment must be the default ([`fp_env_is_default`]) and the codestream must
|
||||
/// pass [`check_codestream`].
|
||||
pub fn check_scope(data: &[u8]) -> Result<(), &'static str> {
|
||||
scope(data).map(|_| ())
|
||||
}
|
||||
|
||||
/// Decode a JPEG-AI codestream to RGB. Returns `None` if [`check_scope`] refuses the
|
||||
/// codestream, or if the tables in `n` do not have the tools_0 shapes (160 luma and
|
||||
/// 96 chroma gain entries).
|
||||
pub fn decode(data: &[u8], w: &DecoderWeights, n: &NormTables) -> Option<Rgb> {
|
||||
let (ph, th) = scope(data).ok()?;
|
||||
if n.gain_y.len() != 160 || n.gain_uv.len() != 96 || n.per_channel == 0 {
|
||||
return None;
|
||||
}
|
||||
let (h, w_) = (img_h, img_w);
|
||||
let (h, w_) = (ph.img_height as usize, ph.img_width as usize);
|
||||
|
||||
// ---- luma + chroma latents → pixel planes (float, pre-round) ----
|
||||
let mcm = [&w.mcm_y[0], &w.mcm_y[1], &w.mcm_y[2], &w.mcm_y[3]];
|
||||
|
|
@ -176,9 +336,6 @@ pub fn decode(data: &[u8], w: &DecoderWeights, n: &NormTables) -> Option<Rgb> {
|
|||
let (mut up, mut vp) = (uv[..h * w_].to_vec(), uv[h * w_..].to_vec());
|
||||
|
||||
// ---- post-filters, parameters from the tools header ----
|
||||
let ton = find_segment(&segs, Marker::Ton)?;
|
||||
let th = parse_tools_header(data, ton.start_bit() + 2, (ph.c_ver, ph.c_hor) == (1, 1), 3, 1);
|
||||
|
||||
// EFElinear — `filters_best2` is the applied group (the naming is inverted).
|
||||
if let Some(efl) = th.efl.as_ref() {
|
||||
let f = &efl.filters_best2;
|
||||
|
|
@ -228,3 +385,113 @@ pub fn decode(data: &[u8], w: &DecoderWeights, n: &NormTables) -> Option<Rgb> {
|
|||
}
|
||||
Some(Rgb { w: w_, h, data: out })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// The reference encoder's codestream at its default operating point — the one
|
||||
/// configuration the exact decoder implements (`tests/vectors/jpegai/README.md`).
|
||||
const TEST256: &[u8] = include_bytes!("../tests/vectors/jpegai/test256.bin");
|
||||
|
||||
/// Overwrite `n` bits (MSB-first) at absolute bit `pos` with `value`.
|
||||
fn set_bits(data: &mut [u8], pos: usize, n: usize, value: u64) {
|
||||
for i in 0..n {
|
||||
let bit = (value >> (n - 1 - i)) & 1;
|
||||
let (byte, sh) = ((pos + i) / 8, 7 - (pos + i) % 8);
|
||||
data[byte] = (data[byte] & !(1 << sh)) | ((bit as u8) << sh);
|
||||
}
|
||||
}
|
||||
|
||||
fn pih_start_bit(data: &[u8]) -> usize {
|
||||
find_segment(&parse_container(data), Marker::Pih).unwrap().start_bit()
|
||||
}
|
||||
|
||||
// Offsets inside the PIH payload, from the field widths in `parse_picture_header`
|
||||
// (the header calibration test pins the cursor after `model_id` at 89 bits in).
|
||||
const MODEL_ID_AT: usize = 85; // 4 bits
|
||||
const COLOUR_IDX_AT: usize = 83; // 2 bits
|
||||
const BETA_Y_AT: usize = 90; // 12 bits, after the 1-bit multi_threading_z flag
|
||||
|
||||
#[test]
|
||||
fn reference_codestream_is_in_scope() {
|
||||
assert_eq!(check_scope(TEST256), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nonzero_beta_is_refused() {
|
||||
let mut d = TEST256.to_vec();
|
||||
let p = pih_start_bit(&d);
|
||||
set_bits(&mut d, p + BETA_Y_AT, 12, 2048 + 7); // β = +7
|
||||
let ph = parse_picture_header(&d, p);
|
||||
assert_eq!(ph.beta_displacement_log, [7, 7], "the edit hit β (shared Y/UV)");
|
||||
let err = check_scope(&d).unwrap_err();
|
||||
assert!(err.contains("beta_displacement_log"), "{err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn other_model_id_is_refused() {
|
||||
let mut d = TEST256.to_vec();
|
||||
let p = pih_start_bit(&d);
|
||||
set_bits(&mut d, p + MODEL_ID_AT, 4, 1);
|
||||
assert_eq!(parse_picture_header(&d, p).model_id, 1, "the edit hit model_id");
|
||||
let err = check_scope(&d).unwrap_err();
|
||||
assert!(err.contains("model_id"), "{err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn other_colour_transform_is_refused() {
|
||||
let mut d = TEST256.to_vec();
|
||||
let p = pih_start_bit(&d);
|
||||
set_bits(&mut d, p + COLOUR_IDX_AT, 2, 0);
|
||||
assert_eq!(parse_picture_header(&d, p).colour_transform_idx, 0, "the edit hit the index");
|
||||
let err = check_scope(&d).unwrap_err();
|
||||
assert!(err.contains("colour transform"), "{err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsbs_off_is_refused() {
|
||||
let mut d = TEST256.to_vec();
|
||||
let ton = find_segment(&parse_container(&d), Marker::Ton).unwrap().start_bit();
|
||||
assert_eq!(parse_lsbs_flags(&d, ton), [true, true]);
|
||||
set_bits(&mut d, ton, 1, 0);
|
||||
let err = check_scope(&d).unwrap_err();
|
||||
assert!(err.contains("LSBS"), "{err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truncated_or_empty_input_is_refused_without_panicking() {
|
||||
assert!(check_scope(&[]).is_err());
|
||||
for cut in [4, 40, 60, 120, 200, 300] {
|
||||
assert!(check_scope(&TEST256[..cut]).is_err(), "prefix of {cut} bytes");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_fp_environment_is_recognised() {
|
||||
assert!(fp_env_is_default());
|
||||
}
|
||||
|
||||
/// Set the AArch64 FPCR's flush-to-zero bit, then a directed rounding mode, and
|
||||
/// check the probe notices each. FPCR is per thread, and it is restored before any
|
||||
/// assertion runs.
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[test]
|
||||
fn non_default_fp_environment_is_detected() {
|
||||
use core::arch::asm;
|
||||
let orig: u64;
|
||||
let (ftz, rz);
|
||||
unsafe {
|
||||
asm!("mrs {}, fpcr", out(reg) orig);
|
||||
asm!("msr fpcr, {}", in(reg) orig | (1 << 24)); // FZ
|
||||
ftz = fp_env_is_default();
|
||||
asm!("msr fpcr, {}", in(reg) orig | (3 << 22)); // RMode = toward zero
|
||||
rz = fp_env_is_default();
|
||||
asm!("msr fpcr, {}", in(reg) orig);
|
||||
}
|
||||
assert!(!ftz, "flush-to-zero not detected");
|
||||
assert!(!rz, "round-toward-zero not detected");
|
||||
assert!(fp_env_is_default());
|
||||
assert!(check_scope(TEST256).is_ok());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,9 +114,11 @@ pub fn icci_dwt_planes(y: &[f32], u: &[f32], v: &[f32], h: usize, w: usize)
|
|||
|
||||
// ---- network body ----
|
||||
//
|
||||
// The eICCI CNN is float in the reference, so we run it in f32 rather than quantising:
|
||||
// IEEE-754 add/mul with a fixed accumulation order is deterministic across machines, so
|
||||
// a faithful float port is byte-identical *and* avoids any PTQ error. BatchNorm is
|
||||
// The eICCI CNN is float in the reference, so we run it in f32 rather than quantising.
|
||||
// IEEE-754 add and multiply are correctly rounded, so with the fixed accumulation order
|
||||
// below — single-threaded, no fused multiply-add (Rust emits none unless asked), in the
|
||||
// default floating-point environment `jpegai_decode` checks for — the port gives the
|
||||
// same bytes on every conforming target, and it avoids any PTQ error. BatchNorm is
|
||||
// folded into the preceding convolution, which is exact at inference:
|
||||
//
|
||||
// BN(conv(x)) = γ·(w·x + b − μ)/√(σ²+ε) + β
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//! of the ISO reference `cpp_exts/mans/decompressor.cpp`. Two interleaved ANS states,
|
||||
//! MSB-first reads from a rolling 64-bit window (`read`/`flush`), sentinel-bit init,
|
||||
//! and a group-of-4 inbound→flush→outbound schedule. Pure integer ⇒ byte-identical
|
||||
//! on every machine. Backs the entropy stage of `wai.neural.jpeg_ai`.
|
||||
//! on every machine. Backs the entropy stage of `wai.image.jpegai`.
|
||||
//!
|
||||
//! `decode_sgm` (main y-latent): per position a distribution `sigma_idx` selects one
|
||||
//! of the 32 precomputed transition tables; `mask=false` ⇒ the position is skipped
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
//! — threads the real Restormer topology (traced from the ISO reference ONNX)
|
||||
//! through the integer ops in [`crate::int_transformer`] + [`crate::int_hyper_synth`],
|
||||
//! loading 16-bit-PTQ'd weights the sink supplies. Pure i64 ⇒ byte-identical on
|
||||
//! every machine; backs `wai.neural.jpeg_ai` / `intent = replicate`.
|
||||
//! every machine. This is the integer synthesis stage of `wai.image.jpegai`'s exact
|
||||
//! decoder; the decode around it also runs float stages (dequantisation, post-filters,
|
||||
//! colour conversion), so the capability does not back `intent = replicate`
|
||||
//! (SPEC §7).
|
||||
//!
|
||||
//! [`decode_y`] reconstructs the luma plane [1×256×256] from the 160-channel latent;
|
||||
//! [`decode_uv`] reconstructs the chroma planes [2×256×256] from the 256-channel
|
||||
|
|
|
|||
|
|
@ -8,13 +8,21 @@
|
|||
//!
|
||||
//! The entropy + integer σ path is native Rust; the learned transforms
|
||||
//! (hyper-decoder, MCM value nets, synthesis, eICCI post-filters) are
|
||||
//! sink-supplied ONNX run via `ort`. This is the live `wai.image.jpegai`
|
||||
//! decoder; the e2e test in `tests/jpegai_e2e.rs` drives it against the
|
||||
//! sink-supplied ONNX run via `ort`. The reference dispatch uses this path for
|
||||
//! `wai.image.jpegai` when the sink has no integer weight bundle for the exact
|
||||
//! decoder (`jpegai_decode`); the e2e test in `tests/jpegai_e2e.rs` drives it against the
|
||||
//! reference decoder's PNG.
|
||||
//!
|
||||
//! Sizing note: the bundled ONNX nets are traced for 256×256 (`synthesis16`,
|
||||
//! the 4×4 hyper input). This decoder targets that traced model; other sizes
|
||||
//! need nets traced for them. `img_width/height` from the header are asserted.
|
||||
//!
|
||||
//! Scope: the bundle is one configuration — tools_0 (`model_id` 0), the
|
||||
//! high-operation-point synthesis, one eICCI model pair, and a dequant scaler
|
||||
//! precomputed for `beta_displacement_log` = 0. `decode` refuses any codestream
|
||||
//! that [`crate::jpegai_decode::check_codestream`] refuses (the exact decoder's
|
||||
//! header conditions), so both `wai.image.jpegai` paths accept the same codestreams.
|
||||
//! This path runs in float through ONNX Runtime and is not decode-equivalent.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
|
@ -223,6 +231,13 @@ pub fn decode(codestream: &[u8], model: &JpegAiModel) -> R<DecodedImage> {
|
|||
.ok_or_else(|| JpegAiError::Bitstream(format!("missing marker {mk:#06x}")))
|
||||
};
|
||||
|
||||
// This path hard-codes the same configuration as the exact decoder: the tools_0
|
||||
// tables and nets (traced at 256×256), the β = 0 dequant scaler
|
||||
// (`jpegai_scaler_vec.json`), the eICCI model pair below, the high-operation-point
|
||||
// synthesis. A codestream that asks for anything else is refused here rather than
|
||||
// decoded to the wrong image.
|
||||
crate::jpegai_decode::check_codestream(codestream)
|
||||
.map_err(|why| JpegAiError::Unsupported(why.into()))?;
|
||||
let hdr = parse_headers(payload(0xFF82)?, payload(0xFF83)?)
|
||||
.map_err(|e| JpegAiError::Bitstream(format!("headers: {e:?}")))?;
|
||||
let (h, w) = (hdr.img_width as usize, hdr.img_height as usize);
|
||||
|
|
@ -265,8 +280,11 @@ pub fn decode(codestream: &[u8], model: &JpegAiModel) -> R<DecodedImage> {
|
|||
let z_net: Vec<i64> = z_dec[pi].iter().enumerate().map(|(i, &v)| v as i64 - off[i / per]).collect();
|
||||
let net = make_net(&model.sigma_weights, plane);
|
||||
let i_s = net.forward(&z_net, 4, 4);
|
||||
// β is 0 here: `check_codestream` refuses β ≠ 0, because the dequant scaler
|
||||
// below is the precomputed β = 0 table.
|
||||
let beta = [hdr.beta_displacement_log, hdr.beta_displacement_log_uv][pi];
|
||||
let gain: Vec<i64> = i64s(&model.consts["tools_0"][format!("gain_mlog_{plane}")])
|
||||
.iter().map(|&g| g + hdr.beta_displacement_log).collect();
|
||||
.iter().map(|&g| g + beta).collect();
|
||||
let hw = i_s.len() / gain.len();
|
||||
let skip: Vec<i64> = i_s.iter().enumerate().map(|(i, &v)| v + gain[i / hw]).collect();
|
||||
let t_f1 = i64s(&model.consts["rvs_sigma_t_flag1"]);
|
||||
|
|
|
|||
|
|
@ -93,7 +93,11 @@ pub struct JpegAiHeader {
|
|||
pub c_hor: u64,
|
||||
pub colour_transform_idx: u64,
|
||||
pub model_id: u64,
|
||||
/// Luma `beta_displacement_log` (de-biased by 2048).
|
||||
pub beta_displacement_log: i64,
|
||||
/// Chroma `beta_displacement_log`: its own 12-bit field when
|
||||
/// `independent_beta_uv` is set, otherwise the luma value.
|
||||
pub beta_displacement_log_uv: i64,
|
||||
pub models: Vec<ModelBlock>,
|
||||
pub efe_linear_enabled: bool,
|
||||
pub efe_linear: EfeLinearHeader,
|
||||
|
|
@ -172,8 +176,9 @@ pub fn parse_headers(pih: &[u8], ton: &[u8]) -> Result<JpegAiHeader, HeaderError
|
|||
h.bit_depth_idc = t(r.ue_max(4))?;
|
||||
h.s_ver = t(r.ue_max(1))? + 1;
|
||||
h.s_hor = t(r.ue_max(1))? + 1;
|
||||
h.c_ver = t(r.ue_max(1))? + 1;
|
||||
h.c_hor = t(r.ue_max(1))? + 1;
|
||||
// c_ver / c_hor are coded only when s_ver / s_hor is 1; otherwise they are 2.
|
||||
h.c_ver = if h.s_ver == 1 { t(r.ue_max(1))? + 1 } else { 2 };
|
||||
h.c_hor = if h.s_hor == 1 { t(r.ue_max(1))? + 1 } else { 2 };
|
||||
h.colour_transform_idx = t(r.ue_max(2))?;
|
||||
if h.colour_transform_idx == 2 {
|
||||
return Err(HeaderError::Unsupported("signalled colour matrix"));
|
||||
|
|
@ -188,7 +193,12 @@ pub fn parse_headers(pih: &[u8], ton: &[u8]) -> Result<JpegAiHeader, HeaderError
|
|||
if region_partitioning != 0 {
|
||||
return Err(HeaderError::Unsupported("region partitioning"));
|
||||
}
|
||||
let _independent_beta_uv = t(r.ue_max(1))?;
|
||||
// quantizer β O-header: a separate chroma β follows when signalled.
|
||||
h.beta_displacement_log_uv = if t(r.ue_max(1))? == 1 {
|
||||
t(r.bits(12))? as i64 - 2048
|
||||
} else {
|
||||
h.beta_displacement_log
|
||||
};
|
||||
|
||||
for _ in 0..2 {
|
||||
let mt = t(r.bits(1))?;
|
||||
|
|
|
|||
|
|
@ -138,9 +138,11 @@ pub enum DecodeError {
|
|||
/// The registered model does not hash to the prior the manifest pins —
|
||||
/// decoding would reconstruct against the wrong model. Refused loudly.
|
||||
PriorMismatch(String),
|
||||
/// The envelope claims `intent = replicate` but its prior is not
|
||||
/// integer-exact, so the decode is not byte-identical across hardware —
|
||||
/// the `replicate` claim is unfounded. Raised by [`decode_envelope_strict`].
|
||||
/// The envelope claims `intent = replicate`, but its capability's registry
|
||||
/// class does not guarantee decode-equivalence (a float or entropy-only neural
|
||||
/// decode), or its prior is absent or not integer-exact — so the reconstruction
|
||||
/// is not byte-identical on every conforming sink and the `replicate` claim is
|
||||
/// unfounded. Raised by [`decode_envelope_strict`].
|
||||
UnsoundReplicate(String),
|
||||
Ort(String),
|
||||
InvalidPayload(String),
|
||||
|
|
@ -203,11 +205,20 @@ pub fn decode_envelope(env: &Wai, registry: &ModelRegistry) -> Result<Decoded, D
|
|||
// `path` is the model directory, not a single ONNX. The learned transforms
|
||||
// (hyper-decoder, MCM value nets, synthesis, eICCI) are sink ONNX via ort.
|
||||
"wai.image.jpegai" => {
|
||||
// Prefer the byte-exact deterministic decoder when the sink ships the
|
||||
// integer weight bundle (`<dir>/weights/*.json` + `<dir>/norm.json`) — that
|
||||
// path reconstructs the codestream to RGB with a portable decoded-pixel hash
|
||||
// (`wai.image.jpegai` decode-equivalence). Otherwise fall back to the ORT
|
||||
// float decode, so existing ONNX bundles keep working unchanged.
|
||||
// Both decode paths implement one configuration (tools_0, β = 0, the
|
||||
// high-operation-point synthesis, one eICCI model pair, 256×256 4:4:4);
|
||||
// a codestream that asks for anything else is refused, not mis-decoded.
|
||||
crate::jpegai_decode::check_codestream(&env.payload).map_err(|why| {
|
||||
DecodeError::InvalidPayload(format!("wai.image.jpegai: unsupported codestream: {why}"))
|
||||
})?;
|
||||
// Prefer the exact decoder when the sink ships the integer weight bundle
|
||||
// (`<dir>/weights/*.json` + `<dir>/norm.json`) — that path pins one
|
||||
// reconstruction, reproducible across machines under the conditions in
|
||||
// `extensions/determinism-tiers.md` §5. Otherwise (no bundle, or a
|
||||
// non-default floating-point environment) fall back to the ORT float
|
||||
// decode. Both paths share the integer entropy decode, which is all the
|
||||
// capability guarantees (entropy-consistency, `NeuralEntropyExact`). The
|
||||
// result does not say which path ran.
|
||||
if let Some(img) = try_jpegai_exact(&env.payload, path) {
|
||||
Ok(Decoded::Image(img))
|
||||
} else {
|
||||
|
|
@ -224,8 +235,11 @@ pub fn decode_envelope(env: &Wai, registry: &ModelRegistry) -> Result<Decoded, D
|
|||
|
||||
/// Load the byte-exact JPEG-AI integer weight bundle from a model directory and run the
|
||||
/// deterministic [`crate::jpegai_decode::decode`]. Returns `None` — so the caller falls
|
||||
/// back to the ORT decode — if the integer bundle is absent, malformed, or the geometry
|
||||
/// is unsupported. The bundle is what `tools/wai_jpegai_build_e2e_inputs.py` produces:
|
||||
/// back to the ORT decode — if the bundle's directory or `norm.json` is absent, a file
|
||||
/// does not parse as JSON, or `decode` refuses (codestream out of scope, a non-default
|
||||
/// floating-point environment, table shapes). A JSON file with missing or mistyped
|
||||
/// fields panics in the loaders rather than returning `None`. The bundle is what
|
||||
/// `tools/wai_jpegai_build_e2e_inputs.py` produces:
|
||||
/// a `weights/` dir of per-plane / MCM / synthesis / eICCI JSON plus a `norm.json` of
|
||||
/// the normative tables. Keeps `jpegai_decode` itself I/O-free; the file reads live here.
|
||||
fn try_jpegai_exact(payload: &[u8], dir: &Path) -> Option<image::DecodedImage> {
|
||||
|
|
@ -271,24 +285,42 @@ fn try_jpegai_exact(payload: &[u8], dir: &Path) -> Option<image::DecodedImage> {
|
|||
Some(image::DecodedImage { rgb: rgb.data, width: rgb.w as u32, height: rgb.h as u32 })
|
||||
}
|
||||
|
||||
/// Decode like [`decode_envelope`], but first enforce WAI's replicate-soundness
|
||||
/// rule: an envelope whose `intent` is `replicate` MUST pin an **integer-exact**
|
||||
/// prior, because single-threaded float is not byte-identical across hardware
|
||||
/// (float round-off is platform-dependent, and one diverging bit corrupts a
|
||||
/// learned entropy decode). Returns [`DecodeError::UnsoundReplicate`] *before*
|
||||
/// touching the model otherwise. Use this when you need the `replicate` claim
|
||||
/// to actually hold cross-hardware; `decode_envelope` stays lenient (it decodes
|
||||
/// regardless, honest about being "exact on this build").
|
||||
/// Decode like [`decode_envelope`], but first apply WAI's replicate-soundness rule
|
||||
/// (SPEC §7, [`crate::codecs::replicate_refusal`]). Over a neural capability
|
||||
/// `replicate` promises decode-equivalence — the same reconstruction bytes on every
|
||||
/// conforming sink — so an envelope whose `intent` is `replicate` is decoded only when
|
||||
///
|
||||
/// 1. its capability's registry class is `NeuralIntegerExact` (integer end to end,
|
||||
/// entropy and synthesis), and
|
||||
/// 2. it pins a prior that declares an integer-exact contract.
|
||||
///
|
||||
/// The class is checked first and does not depend on anything the sender declares:
|
||||
/// a `replicate` envelope over `wai.image.jpegai` (`NeuralEntropyExact`: integer
|
||||
/// entropy decode, float later stages) or over a float codec (`NeuralFloat`) is
|
||||
/// refused even when its prior declares an integer contract. Float inference through
|
||||
/// a runtime is not byte-identical across hardware (the runtime picks kernels,
|
||||
/// accumulation order and fused multiply-adds per device, and one diverging bit
|
||||
/// corrupts a learned entropy decode); even a fixed-order float stage depends on the
|
||||
/// build and on the process's floating-point environment, which neither the
|
||||
/// envelope nor the registry can state.
|
||||
///
|
||||
/// Returns [`DecodeError::UnsoundReplicate`] *before* touching the model otherwise,
|
||||
/// and [`DecodeError::UnknownCapability`] for an unregistered capability.
|
||||
/// `decode_envelope` stays lenient (it decodes regardless, honest about being
|
||||
/// "exact on this build").
|
||||
pub fn decode_envelope_strict(env: &Wai, registry: &ModelRegistry) -> Result<Decoded, DecodeError> {
|
||||
if !env.replicate_is_sound() {
|
||||
let class = env.prior().map(|p| p.determinism_class());
|
||||
return Err(DecodeError::UnsoundReplicate(format!(
|
||||
"intent=replicate but the prior is not integer-exact (determinism {class:?}); \
|
||||
float decode is not byte-identical across hardware — tag this perceptual/improve, \
|
||||
or pin an integer-only prior"
|
||||
)));
|
||||
use crate::codecs::ReplicateRefusal;
|
||||
let cap = &env.manifest.model_requirement.capability;
|
||||
match env.replicate_refusal() {
|
||||
None => decode_envelope(env, registry),
|
||||
Some(ReplicateRefusal::Unregistered) => Err(DecodeError::UnknownCapability(cap.clone())),
|
||||
Some(why) => Err(DecodeError::UnsoundReplicate(format!(
|
||||
"intent=replicate over {cap}: {why}. Over this capability `replicate` would \
|
||||
promise the same reconstruction bytes on every conforming sink, which its \
|
||||
registry class does not provide; tag this improve/perceptual, or use an \
|
||||
integer-exact capability with an integer-only prior"
|
||||
))),
|
||||
}
|
||||
decode_envelope(env, registry)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -11,9 +11,12 @@
|
|||
//! transforms. So provenance over the *rendered* result has had to fall back to fuzzy
|
||||
//! **soft** bindings (perceptual hashes, watermarks).
|
||||
//!
|
||||
//! WAI decodes to RGB deterministically (one pinned reconstruction, byte-identical on
|
||||
//! every machine), which restores the precondition a hard binding needs: a stable,
|
||||
//! portable hash of the decoded pixels. This module produces that binding — a SHA-256
|
||||
//! WAI's integer-exact decoders (decode-equivalence) reconstruct byte-identically on
|
||||
//! every conforming sink, and its exact JPEG AI decoder pins one reconstruction that
|
||||
//! reproduces across machines under the conditions in `extensions/determinism-tiers.md`
|
||||
//! §5 (a property of that decoder; `wai.image.jpegai` itself is registered at
|
||||
//! entropy-consistency). Either restores the precondition a hard binding needs: a
|
||||
//! stable hash of the decoded pixels. This module produces that binding — a SHA-256
|
||||
//! (the C2PA default hash) over the canonical decoded RGB, plus the descriptor that
|
||||
//! makes the decode reproducible (which synthesis branch, profile/level, pixel layout,
|
||||
//! colour space). A verifier with a WAI decoder re-decodes per the descriptor, re-hashes,
|
||||
|
|
|
|||
117
wai/wai-rs/tests/cli_wrap_intent.rs
Normal file
117
wai/wai-rs/tests/cli_wrap_intent.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
//! `wai wrap` writes an envelope that pins no prior, so SPEC §7 limits the intent
|
||||
//! it may claim: `replicate` only over the standard classes, where a sink accepts
|
||||
//! it unpinned. It used to write `intent = replicate` over every capability,
|
||||
//! `wai.image.jpegai` included. These tests run the binary itself; the rule it
|
||||
//! applies is `codecs::unpinned_envelope_intent`, which the library tests check
|
||||
//! for every registered capability.
|
||||
//!
|
||||
//! The `wai` binary needs the `codecs` feature (the C codec chain), so this file
|
||||
//! does too.
|
||||
#![cfg(feature = "codecs")]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Output};
|
||||
|
||||
use wai::container::Wai;
|
||||
|
||||
/// The committed JPEG AI reference codestream; `wrap` treats any payload as opaque.
|
||||
fn payload() -> PathBuf {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/vectors/jpegai/test256.bin")
|
||||
}
|
||||
|
||||
fn scratch(name: &str) -> PathBuf {
|
||||
let dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cli_wrap_intent");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let p = dir.join(name);
|
||||
let _ = std::fs::remove_file(&p);
|
||||
p
|
||||
}
|
||||
|
||||
fn wrap(cap: &str, out: &Path, extra: &[&str]) -> Output {
|
||||
Command::new(env!("CARGO_BIN_EXE_wai"))
|
||||
.arg("wrap").arg(cap).arg(payload()).arg("-o").arg(out).args(extra)
|
||||
.output()
|
||||
.expect("run wai")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_refuses_replicate_over_jpegai_and_writes_nothing() {
|
||||
for extra in [&[][..], &["--intent", "replicate"][..]] {
|
||||
let out = scratch("jpegai.wai");
|
||||
let run = wrap("wai.image.jpegai", &out, extra);
|
||||
let stderr = String::from_utf8_lossy(&run.stderr);
|
||||
assert!(!run.status.success(), "{extra:?}: wrap must refuse; stderr: {stderr}");
|
||||
assert!(stderr.contains("not writing intent=replicate over wai.image.jpegai"), "{stderr}");
|
||||
assert!(stderr.contains("entropy-consistency"), "the refusal names the tier: {stderr}");
|
||||
assert!(stderr.contains("--intent"), "the refusal says how to proceed: {stderr}");
|
||||
assert!(!out.exists(), "{extra:?}: a refused wrap must not write an envelope");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_writes_another_intent_over_jpegai_when_asked() {
|
||||
let out = scratch("jpegai-improve.wai");
|
||||
let run = wrap("wai.image.jpegai", &out, &["--intent", "improve"]);
|
||||
assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr));
|
||||
let env = Wai::read(&out).unwrap();
|
||||
assert_eq!(env.intent(), "improve");
|
||||
assert_eq!(env.replicate_refusal(), None);
|
||||
assert_eq!(env.payload, std::fs::read(payload()).unwrap(), "the payload is carried byte-identically");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_refuses_replicate_when_the_fallback_is_jpegai() {
|
||||
// The primary backs an unpinned replicate, but a sink without it decodes
|
||||
// through the fallback (SPEC §4 step 5), where replicate is refused.
|
||||
for extra in [&["--fallback", "wai.image.jpegai"][..],
|
||||
&["--fallback", "wai.image.jpegai", "--intent", "replicate"][..]] {
|
||||
let out = scratch("jp2-fb-jpegai.wai");
|
||||
let run = wrap("wai.image.jp2", &out, extra);
|
||||
let stderr = String::from_utf8_lossy(&run.stderr);
|
||||
assert!(!run.status.success(), "{extra:?}: wrap must refuse; stderr: {stderr}");
|
||||
assert!(stderr.contains("with fallback wai.image.jpegai"), "{stderr}");
|
||||
assert!(stderr.contains("entropy-consistency"), "the refusal names the tier: {stderr}");
|
||||
assert!(!out.exists(), "{extra:?}: a refused wrap must not write an envelope");
|
||||
}
|
||||
// Another intent is carried, fallback and all.
|
||||
let out = scratch("jp2-fb-jpegai-improve.wai");
|
||||
let run = wrap("wai.image.jp2", &out, &["--fallback", "wai.image.jpegai", "--intent", "improve"]);
|
||||
assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr));
|
||||
let env = Wai::read(&out).unwrap();
|
||||
assert_eq!(env.intent(), "improve");
|
||||
assert_eq!(env.fallback(), Some("wai.image.jpegai"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_still_writes_replicate_with_a_standard_fallback() {
|
||||
let out = scratch("jp2-fb-png.wai");
|
||||
let run = wrap("wai.image.jp2", &out, &["--fallback", "wai.image.png"]);
|
||||
assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr));
|
||||
let env = Wai::read(&out).unwrap();
|
||||
assert_eq!(env.intent(), "replicate");
|
||||
assert_eq!(env.fallback(), Some("wai.image.png"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_refuses_an_unpinned_replicate_over_an_integer_exact_neural_codec() {
|
||||
// Integer-exact, but `replicate` over it needs a pinned integer-exact prior,
|
||||
// which `wrap` does not write.
|
||||
let out = scratch("int_hyper.wai");
|
||||
let run = wrap("wai.neural.int_hyper", &out, &[]);
|
||||
assert!(!run.status.success());
|
||||
assert!(String::from_utf8_lossy(&run.stderr).contains("no pinned prior"));
|
||||
assert!(!out.exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_still_writes_replicate_over_a_standard_codec() {
|
||||
// `wai.image.jp2` is StandardTolerance: replicate is honoured, promising the
|
||||
// standard's decoder conformance, and needs no prior.
|
||||
let out = scratch("jp2.wai");
|
||||
let run = wrap("wai.image.jp2", &out, &[]);
|
||||
assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr));
|
||||
let env = Wai::read(&out).unwrap();
|
||||
assert_eq!(env.intent(), "replicate");
|
||||
assert_eq!(env.replicate_refusal(), None, "a sink accepts what wrap wrote");
|
||||
assert_eq!(env.payload, std::fs::read(payload()).unwrap());
|
||||
}
|
||||
|
|
@ -6,15 +6,19 @@
|
|||
//! recovered by the container parse must equal the `mem` lengths in the entropy fixture
|
||||
//! that the byte-exact mANS decoder consumes — two independent routes to the same bytes.
|
||||
//!
|
||||
//! env: WAI_JPEGAI_CODESTREAM = path to test256.bin
|
||||
//! env: WAI_JPEGAI_CODESTREAM = path to test256.bin (optional; defaults to the committed
|
||||
//! copy in tests/vectors/jpegai/)
|
||||
#![cfg(feature = "neural_int")]
|
||||
|
||||
use wai::jpegai_bitstream::{find_segment, parse_container, parse_picture_header, parse_tools_header, BitReader, Marker};
|
||||
use wai::jpegai_bitstream::{find_segment, parse_container, parse_lsbs_flags, parse_picture_header,
|
||||
parse_tools_header, BitReader, Marker};
|
||||
|
||||
/// `WAI_JPEGAI_CODESTREAM` if set, else the committed copy of the same reference
|
||||
/// codestream (`tests/vectors/jpegai/test256.bin`), so these tests do not skip.
|
||||
fn codestream() -> Option<Vec<u8>> {
|
||||
match std::env::var("WAI_JPEGAI_CODESTREAM") {
|
||||
Ok(p) if std::path::Path::new(&p).exists() => Some(std::fs::read(p).unwrap()),
|
||||
_ => { eprintln!("skip: set WAI_JPEGAI_CODESTREAM to test256.bin"); None }
|
||||
Ok(p) => Some(std::fs::read(p).expect("WAI_JPEGAI_CODESTREAM is set but unreadable")),
|
||||
Err(_) => Some(include_bytes!("vectors/jpegai/test256.bin").to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -108,25 +112,31 @@ fn full_picture_header_matches_reference() {
|
|||
assert!(!h.region_partitioning);
|
||||
assert!(!h.gain_3d_enable);
|
||||
|
||||
// per-component (luma 160ch, chroma 96ch); all four tool flags as decoded
|
||||
// per-component (luma 160ch, chroma 96ch); the four PIH tool flags as decoded
|
||||
assert_eq!(h.components[0].num_chs, 160);
|
||||
assert_eq!(h.components[1].num_chs, 96);
|
||||
for c in 0..2 {
|
||||
let comp = &h.components[c];
|
||||
assert!(!comp.use_cube_flags, "c{c} use_cube");
|
||||
assert!(comp.rvs_enable && comp.grfs_enable, "c{c} rvs/grfs precede the channel flags");
|
||||
assert!(!comp.lsbs_enable, "c{c} lsbs trails the channel flags");
|
||||
assert_eq!(comp.grfs_channel_flags.len(), comp.num_chs as usize, "c{c} grfs flag count == num_chs");
|
||||
assert!(!comp.synthesis_tile_enable, "c{c} tile");
|
||||
assert!(!comp.synthesis_tile_enable, "c{c} synthesis tile flag trails the channel flags");
|
||||
}
|
||||
// LSBS codes its flags into the tool header, not here: the first two TON bits,
|
||||
// both 1 (reference trace: lsbs_enable_flag[0] = lsbs_enable_flag[1] = 1).
|
||||
let ton = find_segment(&segs, Marker::Ton).expect("TON present");
|
||||
assert_eq!(parse_lsbs_flags(&data, ton.start_bit()), [true, true], "LSBS on for Y and UV");
|
||||
// GRFS channel-selection counts — independently confirmed by deriving the same
|
||||
// per-channel cwg assignment from the reference RVS output (both planes byte-exact)
|
||||
assert_eq!(h.components[0].grfs_channel_flags.iter().filter(|&&b| b).count(), 5);
|
||||
assert_eq!(h.components[1].grfs_channel_flags.iter().filter(|&&b| b).count(), 10);
|
||||
|
||||
// the whole header consumed exactly to the padding boundary of the 49-byte PIH
|
||||
assert_eq!(h.end_bit, 437, "all PIH fields consumed");
|
||||
assert!(h.end_bit <= (pih.start + pih.len) * 8, "within the PIH payload");
|
||||
// the whole header consumed, leaving only the zero padding of the 49-byte PIH
|
||||
let pih_end = (pih.start + pih.len) * 8;
|
||||
assert_eq!(h.end_bit, 435, "all PIH fields consumed");
|
||||
assert!(pih_end - h.end_bit < 8, "only byte-alignment padding remains");
|
||||
let mut br = BitReader::at(&data, h.end_bit);
|
||||
assert_eq!(br.read((pih_end - h.end_bit) as u32), 0, "the padding bits are zero");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@
|
|||
//! mismatch — the class of bug no per-stage test can see.
|
||||
//!
|
||||
//! The result is ~1 LSB off the float reference on a few percent of samples: ψ, the MCM
|
||||
//! stages and synthesis are 16-bit PTQ. The point is determinism (byte-identical output
|
||||
//! everywhere), not bit-equality with the reference PNG — so the bar is max|Δ| ≤ 1 with
|
||||
//! the differing fraction near the measured PTQ floor.
|
||||
//! stages and synthesis are 16-bit PTQ. The point is a pinned reconstruction, not
|
||||
//! bit-equality with the reference PNG — so the asserted bar is max|Δ| ≤ 2 and at most
|
||||
//! 5% of samples differing (recorded: max|Δ| = 1 on ~4.4%). This test runs on one
|
||||
//! machine; it does not compare decoded output across machines.
|
||||
//!
|
||||
//! env: WAI_JPEGAI_CODESTREAM = test256.bin
|
||||
//! WAI_JPEGAI_WEIGHTS_DIR = dir of {hs,hyp}_{y,uv}.json, mcm{0..3}_y.json,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
//! the binding on synthetic RGB; this closes the loop on real content — the byte-exact
|
||||
//! decoder produces the pixels, and the C2PA/JPEG-Trust hard binding is taken over them.
|
||||
//!
|
||||
//! It exercises the property the whole capability rests on: the decode is deterministic
|
||||
//! (`decode-equivalence`), so the binding taken over one decode verifies any faithful
|
||||
//! reproduction, and a single flipped pixel breaks it. That is exactly what a hard
|
||||
//! binding over neural-coded media could not do before a byte-exact decode existed.
|
||||
//! It exercises the property the binding rests on: the exact decoder is deterministic,
|
||||
//! so the binding taken over one decode verifies a second decode, and a single flipped
|
||||
//! pixel breaks it. Both decodes run in this process; that the same pixels come out on
|
||||
//! another machine rests on the conditions in `extensions/determinism-tiers.md` §5–§6,
|
||||
//! not on this test. (`wai.image.jpegai` is registered at entropy-consistency; the
|
||||
//! pinned reconstruction is a property of the exact decoder.)
|
||||
//!
|
||||
//! env: WAI_JPEGAI_CODESTREAM, WAI_JPEGAI_WEIGHTS_DIR, WAI_JPEGAI_NORM
|
||||
//! (the bundle from `tools/wai_jpegai_build_e2e_inputs.py`; see jpegai_e2e_full).
|
||||
|
|
@ -62,8 +64,15 @@ fn real_decode_to_reconstruction_binding() {
|
|||
assert_eq!((img.h, img.w), (256, 256));
|
||||
assert_eq!(img.data.len(), 256 * 256 * 3);
|
||||
|
||||
// The descriptor names the synthesis branch the decode actually ran. The exact
|
||||
// decoder implements only the high-operation-point synthesis
|
||||
// (`synthesis_transform_id` 2) and refuses codestreams that select another.
|
||||
let segs = wai::jpegai_bitstream::parse_container(&data);
|
||||
let pih = wai::jpegai_bitstream::find_segment(&segs, wai::jpegai_bitstream::Marker::Pih).unwrap();
|
||||
let ph = wai::jpegai_bitstream::parse_picture_header(&data, pih.start_bit());
|
||||
assert_eq!(ph.synthesis_transform_ids[0], 2, "test256 selects the high-operation-point synthesis");
|
||||
let desc = ReconstructionDescriptor {
|
||||
decoder_id: 0, // WAI pins one synthesis branch
|
||||
decoder_id: ph.synthesis_transform_ids[0] as u8,
|
||||
profile: "tools_0".into(),
|
||||
level: "L1".into(),
|
||||
width: img.w as u32,
|
||||
|
|
@ -78,10 +87,10 @@ fn real_decode_to_reconstruction_binding() {
|
|||
// The binding verifies its own decoded pixels.
|
||||
assert!(binding.verify(&img.data), "the binding must verify the pixels it was taken over");
|
||||
|
||||
// decode-equivalence: a second decode is byte-identical, and the binding — taken
|
||||
// over the first — verifies the second. That is the portable-hard-binding property.
|
||||
// A second decode in this process is byte-identical, and the binding — taken over
|
||||
// the first — verifies the second.
|
||||
let img2 = decode(&data, &weights, &norm).expect("supported geometry");
|
||||
assert_eq!(img2.data, img.data, "the decode is deterministic (decode-equivalence)");
|
||||
assert_eq!(img2.data, img.data, "the exact decoder is deterministic within a process");
|
||||
assert!(binding.verify(&img2.data), "the binding verifies any faithful reproduction");
|
||||
|
||||
// A single flipped pixel breaks the hard binding.
|
||||
|
|
|
|||
49
wai/wai-rs/tests/jpegai_scope_ort.rs
Normal file
49
wai/wai-rs/tests/jpegai_scope_ort.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
//! The float ONNX path (`wai::neural::jpegai`) accepts exactly the codestreams the
|
||||
//! exact decoder accepts: both hard-code one configuration (tools_0, β = 0, the
|
||||
//! high-operation-point synthesis, one eICCI model pair, 256×256 4:4:4), and a
|
||||
//! codestream outside it is refused with `Unsupported` rather than decoded to the
|
||||
//! wrong image.
|
||||
//!
|
||||
//! env: WAI_JPEGAI_ASSETS = the jpegai-vm-assets root (the ONNX model bundle).
|
||||
//! Skips without it; no CI job provides it.
|
||||
#![cfg(feature = "neural")]
|
||||
|
||||
use wai::neural::jpegai::{decode, JpegAiError, JpegAiModel};
|
||||
|
||||
const TEST256: &[u8] = include_bytes!("vectors/jpegai/test256.bin");
|
||||
|
||||
/// Overwrite `n` bits (MSB-first) at absolute bit `pos` with `value`.
|
||||
fn set_bits(data: &mut [u8], pos: usize, n: usize, value: u64) {
|
||||
for i in 0..n {
|
||||
let bit = (value >> (n - 1 - i)) & 1;
|
||||
let (byte, sh) = ((pos + i) / 8, 7 - (pos + i) % 8);
|
||||
data[byte] = (data[byte] & !(1 << sh)) | ((bit as u8) << sh);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ort_path_refuses_what_the_exact_decoder_refuses() {
|
||||
let Ok(dir) = std::env::var("WAI_JPEGAI_ASSETS") else {
|
||||
eprintln!("skip: set WAI_JPEGAI_ASSETS to the jpegai-vm-assets root");
|
||||
return;
|
||||
};
|
||||
let model = JpegAiModel::load(&dir).expect("load the ONNX model bundle");
|
||||
|
||||
use wai::jpegai_bitstream::{find_segment, parse_container, parse_picture_header, Marker};
|
||||
let pih = find_segment(&parse_container(TEST256), Marker::Pih).unwrap().start_bit();
|
||||
// (field offset inside the PIH payload, width, new value, word the refusal names)
|
||||
for (at, width, value, word) in [(90, 12, 2048 + 7, "beta"), (85, 4, 1, "model_id")] {
|
||||
let mut d = TEST256.to_vec();
|
||||
set_bits(&mut d, pih + at, width, value);
|
||||
let ph = parse_picture_header(&d, pih);
|
||||
assert!(ph.beta_displacement_log != [0, 0] || ph.model_id != 0, "the edit hit a field");
|
||||
match decode(&d, &model) {
|
||||
Err(JpegAiError::Unsupported(why)) => assert!(why.contains(word), "{why}"),
|
||||
Err(e) => panic!("expected Unsupported naming {word}, got {e}"),
|
||||
Ok(_) => panic!("an out-of-scope codestream ({word}) was decoded"),
|
||||
}
|
||||
}
|
||||
|
||||
let img = decode(TEST256, &model).expect("the in-scope codestream decodes");
|
||||
assert_eq!((img.width, img.height), (256, 256));
|
||||
}
|
||||
|
|
@ -251,23 +251,26 @@ fn video_bmshj2018_decodes_natively() {
|
|||
}
|
||||
|
||||
/// The replicate-soundness gate runs BEFORE any model is touched, so this is
|
||||
/// model-independent. A `replicate` envelope is decodable strictly only if it
|
||||
/// pins an integer-exact prior; float-reproducible or absent priors are
|
||||
/// rejected, and non-`replicate` intents are unconstrained.
|
||||
/// model-independent. `replicate` promises decode-equivalence (SPEC §7), so the
|
||||
/// capability's registry class decides first: only an integer-exact capability
|
||||
/// can back it, and then only with a pinned integer-exact prior. A prior that
|
||||
/// *declares* an integer contract over a float codec or over JPEG AI (integer
|
||||
/// entropy decode, float later stages) is refused. Non-`replicate` intents are
|
||||
/// unconstrained.
|
||||
#[test]
|
||||
fn strict_decode_gates_unsound_replicate() {
|
||||
fn env(prior: Option<Prior>, intent: &str) -> Wai {
|
||||
fn env(cap: &str, prior: Option<Prior>, intent: &str) -> Wai {
|
||||
let manifest = Manifest {
|
||||
wai: "1.0".into(),
|
||||
media: "image".into(),
|
||||
intent: intent.into(),
|
||||
model_requirement: ModelRequirement {
|
||||
capability: "wai.neural.bmshj2018".into(),
|
||||
capability: cap.into(),
|
||||
fallback: None,
|
||||
min_sim: None,
|
||||
sim_metric: None,
|
||||
},
|
||||
conditioning: Conditioning { kind: "bmshj2018".into(), prior },
|
||||
conditioning: Conditioning { kind: "k".into(), prior },
|
||||
target: serde_json::json!({"w": 256, "h": 256}),
|
||||
};
|
||||
Wai::new(manifest, vec![])
|
||||
|
|
@ -275,31 +278,51 @@ fn strict_decode_gates_unsound_replicate() {
|
|||
let p = |det: &str| Prior { id: "m".into(), sha256: "ab".repeat(32), determinism: det.into() };
|
||||
let integer = p("int-rans/p16+onnx-int8-integerized");
|
||||
let floaty = p("int-rans/p16+onnx-cpu-f32/1thread");
|
||||
const FLOAT_CODEC: &str = "wai.neural.bmshj2018";
|
||||
const INT_CODEC: &str = "wai.neural.int_synth";
|
||||
const JPEGAI: &str = "wai.image.jpegai";
|
||||
|
||||
let reg = ModelRegistry::new(); // empty: the gate fires before model resolution
|
||||
|
||||
// replicate + float prior → rejected, before any model touch.
|
||||
// replicate over a float codec → rejected, whatever the prior declares.
|
||||
for prior in [Some(floaty.clone()), Some(integer.clone()), None] {
|
||||
assert!(matches!(
|
||||
decode_envelope_strict(&env(FLOAT_CODEC, prior, "replicate"), ®),
|
||||
Err(DecodeError::UnsoundReplicate(_))
|
||||
));
|
||||
}
|
||||
// replicate over JPEG AI → rejected even with an integer-declared prior: its
|
||||
// registry class is entropy-consistency only.
|
||||
match decode_envelope_strict(&env(JPEGAI, Some(integer.clone()), "replicate"), ®) {
|
||||
Err(DecodeError::UnsoundReplicate(why)) => assert!(why.contains("entropy-consistency"), "{why}"),
|
||||
other => panic!("jpegai replicate must be refused, got {:?}", other.map(|_| ())),
|
||||
}
|
||||
// replicate over the integer-exact codec: float or absent prior → rejected …
|
||||
for prior in [Some(floaty.clone()), None] {
|
||||
assert!(matches!(
|
||||
decode_envelope_strict(&env(INT_CODEC, prior, "replicate"), ®),
|
||||
Err(DecodeError::UnsoundReplicate(_))
|
||||
));
|
||||
}
|
||||
// … integer-exact prior → gate PASSES, falls through to model resolution
|
||||
// (ModelNotRegistered proves the gate let it past).
|
||||
assert!(matches!(
|
||||
decode_envelope_strict(&env(Some(floaty.clone()), "replicate"), ®),
|
||||
Err(DecodeError::UnsoundReplicate(_))
|
||||
));
|
||||
// replicate + NO prior → rejected.
|
||||
assert!(matches!(
|
||||
decode_envelope_strict(&env(None, "replicate"), ®),
|
||||
Err(DecodeError::UnsoundReplicate(_))
|
||||
));
|
||||
// replicate + integer-exact prior → gate PASSES, falls through to model
|
||||
// resolution (ModelNotRegistered proves the gate let it past).
|
||||
assert!(matches!(
|
||||
decode_envelope_strict(&env(Some(integer), "replicate"), ®),
|
||||
decode_envelope_strict(&env(INT_CODEC, Some(integer.clone()), "replicate"), ®),
|
||||
Err(DecodeError::ModelNotRegistered(_))
|
||||
));
|
||||
// A non-replicate intent isn't constrained by the gate.
|
||||
// Non-replicate intents aren't constrained by the gate.
|
||||
for cap in [FLOAT_CODEC, JPEGAI] {
|
||||
assert!(matches!(
|
||||
decode_envelope_strict(&env(cap, Some(floaty.clone()), "improve"), ®),
|
||||
Err(DecodeError::ModelNotRegistered(_))
|
||||
));
|
||||
}
|
||||
// An unregistered capability is reported as such.
|
||||
assert!(matches!(
|
||||
decode_envelope_strict(&env(Some(floaty), "improve"), ®),
|
||||
Err(DecodeError::ModelNotRegistered(_))
|
||||
decode_envelope_strict(&env("wai.image.nope", Some(integer), "replicate"), ®),
|
||||
Err(DecodeError::UnknownCapability(_))
|
||||
));
|
||||
println!(" strict gate: float/absent rejected, integer-exact + non-replicate pass");
|
||||
println!(" strict gate: class first (float, entropy-only refused), then prior; non-replicate passes");
|
||||
}
|
||||
|
||||
/// END-TO-END validation against the real CompressAI mbt2018-mean model:
|
||||
|
|
|
|||
14
wai/wai-rs/tests/vectors/jpegai/README.md
Normal file
14
wai/wai-rs/tests/vectors/jpegai/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# JPEG AI reference codestream
|
||||
|
||||
`test256.bin` (367 bytes, SHA-256
|
||||
`99840e5f472423f5a1261c9ec219d12dc910e9623d752672555dfea69ea4a097`) is the output
|
||||
of the ISO/IEC 6048-1 reference software's encoder (BSD-3) at its default operating
|
||||
point, for a 256×256 synthetic RGB test image (gradients and blocks). Segment layout:
|
||||
PIH 49 bytes, TON 63, RDI 1, SORP 97, SORS 47, SOZ 83.
|
||||
|
||||
It is the one configuration `wai::jpegai_decode` implements, so the unit tests in
|
||||
`src/jpegai_decode.rs` use it to check the decoder's scope guard: the unmodified
|
||||
codestream is accepted, and copies with a single header field changed
|
||||
(`beta_displacement_log`, `model_id`, the colour transform, an LSBS flag) are refused.
|
||||
Decoding it to pixels needs the sink-supplied weight bundle, which is not committed;
|
||||
see `tests/jpegai_e2e_full.rs`.
|
||||
BIN
wai/wai-rs/tests/vectors/jpegai/test256.bin
Normal file
BIN
wai/wai-rs/tests/vectors/jpegai/test256.bin
Normal file
Binary file not shown.
|
|
@ -176,11 +176,16 @@ pub fn decode_jpegai_mans(
|
|||
// ---- JPEG-AI full decode → RGB, in the browser (PTQ value/synthesis path) ----
|
||||
|
||||
/// Decode a full ISO/IEC 6048 JPEG-AI codestream to RGB in the browser
|
||||
/// (`wai.image.jpegai`, decode-equivalence). The same decoder a native sink runs
|
||||
/// (`wai::jpegai_decode::decode`), compiled to wasm32: integer entropy front end +
|
||||
/// deterministic value/synthesis/post-filter path. One pinned reconstruction,
|
||||
/// byte-identical on every machine — so the decoded RGB has a portable hash. The 13
|
||||
/// byte inputs are the model weight bundle (`tools/wai_jpegai_build_e2e_inputs.py`):
|
||||
/// (`wai.image.jpegai`). The same exact decoder a native sink runs
|
||||
/// (`wai::jpegai_decode::decode`), compiled to wasm32: an integer entropy decode and
|
||||
/// integer PTQ networks, then dequantisation, post-filters and colour conversion in
|
||||
/// IEEE-754 float with a fixed evaluation order. It pins one reconstruction, which
|
||||
/// reproduces across machines under the conditions in
|
||||
/// `extensions/determinism-tiers.md` §5; that is a property of this decoder, not of
|
||||
/// the capability, which is registered at entropy-consistency and does not back
|
||||
/// `intent = replicate`. It decodes one configuration and refuses any other
|
||||
/// codestream with the reason (`wai::jpegai_decode::check_scope`). The 13 byte
|
||||
/// inputs are the model weight bundle (`tools/wai_jpegai_build_e2e_inputs.py`):
|
||||
/// per-plane hyper-scale / hyper-decoder / synthesis, the four luma MCM stages, the
|
||||
/// eICCI net, and the normative tables (`norm`).
|
||||
#[wasm_bindgen(js_name = decodeJpegAiFull)]
|
||||
|
|
@ -223,6 +228,11 @@ pub fn decode_jpegai_full(
|
|||
lsbs_t0: i32v("lsbs_t0"), lsbs_t1: i32v("lsbs_t1"), lef_thr: i3("lef_thr0"), lef_mag: f3("lef_mag0"),
|
||||
};
|
||||
|
||||
let img = decode(codestream, &weights, &norm_t).ok_or_else(|| JsError::new("unsupported geometry"))?;
|
||||
if let Err(why) = wai::jpegai_decode::check_scope(codestream) {
|
||||
return Err(JsError::new(&format!("wai.image.jpegai: codestream refused: {why}")));
|
||||
}
|
||||
let img = decode(codestream, &weights, &norm_t).ok_or_else(|| {
|
||||
JsError::new("wai.image.jpegai: decode refused (the weight bundle or tables do not fit the codestream)")
|
||||
})?;
|
||||
Ok(DecodedImage { rgb: img.data, width: img.w as u32, height: img.h as u32 })
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue