From fb6f5c88d9960c7f894364488cd71942728a961f Mon Sep 17 00:00:00 2001 From: gHashTag Date: Sun, 14 Jun 2026 12:03:49 +0000 Subject: [PATCH] conformance: promote 6 structural packs to bit-precise (IBM HFP, x87, NF4, GFTernary) Add dedicated reference codecs to gen_all_formats.py that turn 6 honest structural placeholders into bit-precise round-trip packs (abs_error=0): - ibm_hfp32/64/128: IBM Hexadecimal Floating Point, base-16 exponent (S1:E7 excess-64:M), value = 0.M(2) * 16^(E-64); 3.0 = 0.1875 x 16^1 - x87_fp80: Intel 80-bit extended, explicit integer bit as MSB of the 64-bit significand field (S1:E15:SIG64), bias 16383 - nf4: QLoRA/bitsandbytes NF4 16-entry quantile table over [-1,1] - gfternary: 2-bit {-phi, 0, +phi}, exhaustive 4-code enumeration INDEX totals: bitexact 49->55, structural 34->28, total 83 (unchanged). README index/counts/SHA-256/changelog regenerated. double_double and quad_double stay structural (composite multi-double, no single S:E:M). All packs and generator ASCII-only. Anchor: phi^2 + phi^-2 = 3. Closes #1076 --- conformance/vectors/INDEX_all_formats.json | 40 ++-- conformance/vectors/README.md | 73 ++++-- conformance/vectors/gen_all_formats.py | 207 +++++++++++++++++- .../vectors/gfternary_conformance_v0.json | 64 +++++- .../vectors/ibm_hfp128_conformance_v0.json | 107 ++++++++- .../vectors/ibm_hfp32_conformance_v0.json | 107 ++++++++- .../vectors/ibm_hfp64_conformance_v0.json | 107 ++++++++- conformance/vectors/nf4_conformance_v0.json | 196 ++++++++++++++++- .../vectors/x87_fp80_conformance_v0.json | 107 ++++++++- docs/NOW.md | 6 + 10 files changed, 930 insertions(+), 84 deletions(-) diff --git a/conformance/vectors/INDEX_all_formats.json b/conformance/vectors/INDEX_all_formats.json index f08c066a4..5678b39ce 100644 --- a/conformance/vectors/INDEX_all_formats.json +++ b/conformance/vectors/INDEX_all_formats.json @@ -5,8 +5,8 @@ "preprint": "https://arxiv.org/abs/2606.05017", "total_formats": 83, "total_packs": 83, - "bitexact_packs": 49, - "structural_packs": 34, + "bitexact_packs": 55, + "structural_packs": 28, "packs": [ { "id": "binary16", @@ -75,10 +75,10 @@ { "id": "x87_fp80", "file": "x87_fp80_conformance_v0.json", - "kind": "structural", - "n_vectors": 0, + "kind": "bitexact", + "n_vectors": 8, "source": "generated by gen_all_formats.py", - "sha256": "454055246c19a6eebabd51d63a1a8b642a71143c96db610a7a952ea940e09e2e" + "sha256": "e9be37c939c7108081bd2190e949f4d01be7ad12511d82bb8849f337c94e7e0c" }, { "id": "double_double", @@ -175,10 +175,10 @@ { "id": "nf4", "file": "nf4_conformance_v0.json", - "kind": "structural", - "n_vectors": 0, + "kind": "bitexact", + "n_vectors": 16, "source": "generated by gen_all_formats.py", - "sha256": "3778cc540acb6891d72dc2e063541dec35b26356638e5ce3731def3431025138" + "sha256": "723ddd4237153c7c0cc6a9c3436ba071f8affcef8ad0c384070a3e1a3bf13f45" }, { "id": "afp", @@ -287,10 +287,10 @@ { "id": "gfternary", "file": "gfternary_conformance_v0.json", - "kind": "structural", - "n_vectors": 0, + "kind": "bitexact", + "n_vectors": 4, "source": "generated by gen_all_formats.py", - "sha256": "0e0eb87fc7d90d7bc231581348ea2c7da258d7e93fd2861f32ff1c9317969cf9" + "sha256": "9f246d24511fbff6fb9e83e60e1bedfce401052537f7c8929fe205d0f6e57b81" }, { "id": "gf4", @@ -526,26 +526,26 @@ { "id": "ibm_hfp32", "file": "ibm_hfp32_conformance_v0.json", - "kind": "structural", - "n_vectors": 0, + "kind": "bitexact", + "n_vectors": 8, "source": "generated by gen_all_formats.py", - "sha256": "954fe16b6c6b4faab44dcc2b4299f356d7571fe789e3823d630c87301b9ce46e" + "sha256": "8e35040e30d3a0091ecca5fdb08d1dd1ce98031e5d655239c7196bc667fc3876" }, { "id": "ibm_hfp64", "file": "ibm_hfp64_conformance_v0.json", - "kind": "structural", - "n_vectors": 0, + "kind": "bitexact", + "n_vectors": 8, "source": "generated by gen_all_formats.py", - "sha256": "893833a6d3efa9dcfa73d0c04e48f94e5ee77185438cadfab7bee8744cd104fe" + "sha256": "fbe42a167c13f226fe8eaf876c9e17109fb32dbddd76d3a677cc0b9aef2626a1" }, { "id": "ibm_hfp128", "file": "ibm_hfp128_conformance_v0.json", - "kind": "structural", - "n_vectors": 0, + "kind": "bitexact", + "n_vectors": 8, "source": "generated by gen_all_formats.py", - "sha256": "712c060613f0e4934b53dbc98debcb0149af304e90dbfcdbbd3d4ead5d74bb4c" + "sha256": "2f02899d621a8a7aebfdf2a69a2484d7616c61ac7cebdc483f643e8109c4e31f" }, { "id": "ms_mbf32", diff --git a/conformance/vectors/README.md b/conformance/vectors/README.md index f9775ee12..367ffa6ad 100644 --- a/conformance/vectors/README.md +++ b/conformance/vectors/README.md @@ -17,8 +17,8 @@ ships **83 conformance packs — one per format**, with no gaps: | Class | Packs | Meaning | |---|---|---| -| **Bit-precise** | **49** | Native bits decode to f64 exactly; `abs_error = 0` by construction for every representable value. Values not exactly representable in a format report a nonzero `abs_error` **honestly** (e.g. 0.1 in bf16) — nothing is hidden. | -| **Structural** | **34** | The format has no single fixed radix-2 S:E:M round-trip (parametric / lookup / base-16 / tapered-logarithmic / extended-precision / open-R&D). These packs carry full catalog metadata plus an explicit `structural_reason` and are marked `bitexact: false`. They are honest placeholders, **not** bit-exact claims. | +| **Bit-precise** | **55** | Native bits decode to f64 exactly; `abs_error = 0` by construction for every representable value. Values not exactly representable in a format report a nonzero `abs_error` **honestly** (e.g. 0.1 in bf16) — nothing is hidden. | +| **Structural** | **28** | The format has no single fixed radix-2 S:E:M round-trip (parametric / lookup / open-R&D / multi-double composite). These packs carry full catalog metadata plus an explicit `structural_reason` and are marked `bitexact: false`. They are honest placeholders, **not** bit-exact claims. | | **Total** | **83** | One pack per catalog format. | Coverage policy (deterministic, reproducible): @@ -29,17 +29,34 @@ Coverage policy (deterministic, reproducible): no brute force, no multi-megabyte files; - non-S:E:M formats → **structural** pack with a documented reason. -Of the 49 bit-precise packs, 43 hit the 3.0 anchor **exactly**. The six that do -not — `lns8/16/32/64`, `gf4`, `mxgf4` — are honest: log2(3) is not exactly -representable in a logarithmic number system, and the 4-bit GoldenFloat grids -are too coarse to place 3.0 on a grid point. Each such pack records the nearest -representable value and its true `abs_error`. +Six formats were promoted from structural to **bit-precise** with dedicated +reference codecs (see the changelog at the end): the three IBM HFP base-16 +floats (`ibm_hfp32/64/128`), Intel `x87_fp80` (explicit integer bit), the NF4 +16-entry quantile table (`nf4`), and the 2-bit `gfternary` set. Each carries an +explicit decoder + reference encoder and `abs_error = 0` for every recorded +vector. -## Index — bit-precise packs (49) +Of the 55 bit-precise packs, the IBM HFP and x87 packs hit the 3.0 anchor +**exactly** (3.0 = 0.1875 x 16^1 in HFP; 3.0 = 1.5 x 2^1 in x87). The packs +that do **not** place 3.0 on a grid point — `lns8/16/32/64`, `gf4`, `mxgf4`, +and now `gfternary` and `nf4` — are honest about it: log2(3) is not exactly +representable in a logarithmic number system, the 4-bit GoldenFloat grids are +too coarse, the `gfternary` levels are only {-phi, 0, +phi} (3.0 arises as +phi^2 + phi^-2 = 3, not as a single code), and the NF4 table spans [-1, 1]. +Each such pack records the nearest representable value (or a null anchor with a +note) and its true `abs_error`. + +## Index — bit-precise packs (55) | Pack | Format | Vectors | Round-trip | |---|---|---|---| | `bf16_golden_conformance_v0.json` | BFLOAT16 | 8+golden | ✔ (предсуществующий) | +| `gfternary_conformance_v0.json` | GFTERNARY | 4 | ✔ (2-bit {-phi,0,+phi}, exhaustive) | +| `ibm_hfp128_conformance_v0.json` | IBM_HFP128 | 8 | ✔ (base-16, named small values) | +| `ibm_hfp32_conformance_v0.json` | IBM_HFP32 | 8 | ✔ (base-16 exponent) | +| `ibm_hfp64_conformance_v0.json` | IBM_HFP64 | 8 | ✔ (base-16 exponent) | +| `nf4_conformance_v0.json` | NF4 | 16 | ✔ (16-entry quantile table) | +| `x87_fp80_conformance_v0.json` | X87_FP80 | 8 | ✔ (explicit integer bit) | | `binary128_conformance_v0.json` | BINARY128 | 8 | ✔ | | `binary16_conformance_v0.json` | BINARY16 | 8 | ✔ | | `binary256_conformance_v0.json` | BINARY256 | 8 | ✔ | @@ -92,7 +109,7 @@ representable value and its true `abs_error`. `+golden` denotes an attached `golden_accumulation` section (bf16 reduction reference for tt-mlir #6252). -## Index — structural packs (34) +## Index — structural packs (28) | Pack | Format | Why structural (not bit-exact) | |---|---|---| @@ -111,12 +128,7 @@ reference for tt-mlir #6252). | `gf48_conformance_v0.json` | GF48 | No fixed bit-precise round-trip is defined for this entry; recorded structurally with catalog metadata. | | `gf512_conformance_v0.json` | GF512 | No fixed bit-precise round-trip is defined for this entry; recorded structurally with catalog metadata. | | `gf96_conformance_v0.json` | GF96 | No fixed bit-precise round-trip is defined for this entry; recorded structurally with catalog metadata. | -| `gfternary_conformance_v0.json` | GFTERNARY | GFTernary is a 2-bit discrete set {-phi, 0, +phi}; the three values are recorded directly rather than via an S:E:M decode. | -| `ibm_hfp128_conformance_v0.json` | IBM_HFP128 | IBM Hexadecimal Floating Point uses a base-16 exponent (not base-2), so the radix-2 S:E:M decoder does not apply. | -| `ibm_hfp32_conformance_v0.json` | IBM_HFP32 | IBM Hexadecimal Floating Point uses a base-16 exponent (not base-2), so the radix-2 S:E:M decoder does not apply. | -| `ibm_hfp64_conformance_v0.json` | IBM_HFP64 | IBM Hexadecimal Floating Point uses a base-16 exponent (not base-2), so the radix-2 S:E:M decoder does not apply. | | `minifloat_conformance_v0.json` | MINIFLOAT | This format has no single fixed bit layout (parametric / technique / variable-width). | -| `nf4_conformance_v0.json` | NF4 | NF4 is a 16-entry quantile lookup table fitted to N(0,1); values are table entries, not an S:E:M layout. | | `per_channel_scale_conformance_v0.json` | PER_CHANNEL_SCALE | INT8 payload with an external per-channel fp32 scale; the decoded value depends on the scale tensor, so a standalone round-trip table is not defined. | | `q_format_conformance_v0.json` | Q_FORMAT | This format has no single fixed bit layout (parametric / technique / variable-width). | | `quad_double_conformance_v0.json` | QUAD_DOUBLE | Extended-precision layout (explicit integer bit / multi-double components) is not a single S:E:M field; recorded structurally. | @@ -129,7 +141,6 @@ reference for tt-mlir #6252). | `tapered_fp_conformance_v0.json` | TAPERED_FP | This format has no single fixed bit layout (parametric / technique / variable-width). | | `unum_i_conformance_v0.json` | UNUM_I | This format has no single fixed bit layout (parametric / technique / variable-width). | | `unum_ii_conformance_v0.json` | UNUM_II | This format has no single fixed bit layout (parametric / technique / variable-width). | -| `x87_fp80_conformance_v0.json` | X87_FP80 | Extended-precision layout (explicit integer bit / multi-double components) is not a single S:E:M field; recorded structurally. | The four `takum*` packs double as the **live FL-002 counterexample**: a tapered logarithmic format whose decode is not a plain S:E:M field, recorded as an open @@ -162,8 +173,8 @@ round-trips. ## Machine-readable index `INDEX_all_formats.json` lists all 83 packs with totals -(`total_formats: 83`, `total_packs: 83`, `bitexact_packs: 49`, -`structural_packs: 34`), the anchor identity, the SSOT path, and the preprint. +(`total_formats: 83`, `total_packs: 83`, `bitexact_packs: 55`, +`structural_packs: 28`), the anchor identity, the SSOT path, and the preprint. ## SHA-256 @@ -206,10 +217,10 @@ fe600234cab0e589b69d84e673d74729cff153f9e4e63e871e285fa82ad2cc70 gf8_bfp_confor 6dccbc6628cbc051e06a006a0731499970c1d99e65fc0d42d9007d8f0ed1402d gf8_conformance_v0.json 786f9d144243db2e6c4dba2ddbef4ae2975d045f1ad370cd462eb61cc70dd3d5 gf96_conformance_v0.json eb7c946281fb6ed6fadd9c63c7e7fa186412480910c9fedcb25fbc056c1bd34a gf_lns_hybrid_conformance_v0.json -0e0eb87fc7d90d7bc231581348ea2c7da258d7e93fd2861f32ff1c9317969cf9 gfternary_conformance_v0.json -712c060613f0e4934b53dbc98debcb0149af304e90dbfcdbbd3d4ead5d74bb4c ibm_hfp128_conformance_v0.json -954fe16b6c6b4faab44dcc2b4299f356d7571fe789e3823d630c87301b9ce46e ibm_hfp32_conformance_v0.json -893833a6d3efa9dcfa73d0c04e48f94e5ee77185438cadfab7bee8744cd104fe ibm_hfp64_conformance_v0.json +9f246d24511fbff6fb9e83e60e1bedfce401052537f7c8929fe205d0f6e57b81 gfternary_conformance_v0.json +2f02899d621a8a7aebfdf2a69a2484d7616c61ac7cebdc483f643e8109c4e31f ibm_hfp128_conformance_v0.json +8e35040e30d3a0091ecca5fdb08d1dd1ce98031e5d655239c7196bc667fc3876 ibm_hfp32_conformance_v0.json +fbe42a167c13f226fe8eaf876c9e17109fb32dbddd76d3a677cc0b9aef2626a1 ibm_hfp64_conformance_v0.json df77519366e4c59888dcfafa66c20db4389e162f7dae96767684f46d8427d9fc int128_conformance_v0.json a14f51cd6b29bef2215573bc7f1d299559d5d34af36fd0ffceb513f0659765b9 int16_conformance_v0.json e7f8ddbc4f8606a83febb5c8836f38a143c28f650d73330af5650ea698d91570 int32_conformance_v0.json @@ -228,7 +239,7 @@ b5795fed0c0f2b580174b443d2c54519c4953916525237bb7ea7d6831f14fde7 mxfp4_e2m1_con 16eedca7e82c4e6753f8248dce0000ba9a50ba09bab9be747b0dcac3efc21b6b mxfp8_conformance_v0.json 5e8d03fe80c59b458dc4bbd3fba3213dbc00626d8bc73b2cfcc09836539e89fb mxgf4_conformance_v0.json 9d77d8be5522942e9276b723915b3223123b7741a076a1bfd819cc73ab29f1ec mxgf6_conformance_v0.json -3778cc540acb6891d72dc2e063541dec35b26356638e5ce3731def3431025138 nf4_conformance_v0.json +723ddd4237153c7c0cc6a9c3436ba071f8affcef8ad0c384070a3e1a3bf13f45 nf4_conformance_v0.json 300f176150f74952183199befd9c9972473a1dfbd0206f2726e93bcf7b2d4957 per_channel_scale_conformance_v0.json 7cc2edfeb0f52769b1a536dcbe04945a301cdcc3799a23267380b0c4fb0b82d5 posit16_conformance_v0.json aee6cc72691a0ae211e39bf6315ac68a5fe74e87190e0c27088871c6ccc87f52 posit32_conformance_v0.json @@ -250,7 +261,7 @@ b87494ddee38fe68f77dd8082e8a9811530cc346526b80e59c81b17665677792 vax_d_conforma a7f45aec8da42931da5ad9f24c3ee369419ec58a783abe657a275210ae9b1e4d vax_f_conformance_v0.json 9a6372bbf85a50457e0b66db8849845333582e3fef28934047963e89dd95e65a vax_g_conformance_v0.json eaaa44e4ce2e5454da2cc83571bf3261a84a1b6fabb0dc8064c04cd71fa581f0 vax_h_conformance_v0.json -454055246c19a6eebabd51d63a1a8b642a71143c96db610a7a952ea940e09e2e x87_fp80_conformance_v0.json +e9be37c939c7108081bd2190e949f4d01be7ad12511d82bb8849f337c94e7e0c x87_fp80_conformance_v0.json ``` ## Provenance @@ -279,3 +290,19 @@ python3 gen_all_formats.py ``` All packs are ASCII-only. Apache-2.0, consistent with the t27 repository. + +## Changelog + +- **2026-06-14** — promoted 6 packs from structural to **bit-precise** by adding + dedicated reference codecs to `gen_all_formats.py` + (bit-precise 49 -> 55, structural 34 -> 28): + - `ibm_hfp32/64/128` — IBM Hexadecimal Floating Point, base-16 exponent + (S1 : E7 excess-64 : M), `value = 0.M(2) * 16^(E-64)`. 3.0 = 0.1875 x 16^1. + - `x87_fp80` — Intel 80-bit extended with the explicit integer bit as the MSB + of the 64-bit significand field (S1 : E15 : SIG64), bias 16383. + - `nf4` — QLoRA/bitsandbytes NF4 16-entry quantile table over [-1, 1]; + exhaustive over all 16 codes. + - `gfternary` — 2-bit {-phi, 0, +phi}; exhaustive over all 4 codes (3.0 arises + as phi^2 + phi^-2 = 3, not as a single code, recorded in the anchor note). + Remaining `ExtendedFloat` entries `double_double` / `quad_double` stay + structural (composite multi-double, no single S:E:M field). diff --git a/conformance/vectors/gen_all_formats.py b/conformance/vectors/gen_all_formats.py index 4799a07c3..379796a0b 100644 --- a/conformance/vectors/gen_all_formats.py +++ b/conformance/vectors/gen_all_formats.py @@ -158,6 +158,173 @@ def decode(bits, tb): return (sign * (2.0 ** L), "normal") return decode +# --------------------------------------------------------------------------- +# IBM Hexadecimal Floating Point (base-16 exponent), System/360 (1964). +# layout: S(1) : E(7, excess-64) : M(m_bits fractional hex digits) +# value = (-1)^S * 0.M(base16) * 16^(E - 64) +# no inf/nan; zero is all-zero (true zero). Mantissa is an unsigned binary +# fraction read in groups of 4 bits (hex digits); the radix point sits before +# the most significant fraction bit. Bit-exact for values whose binary +# expansion fits in m_bits and whose magnitude lies in the hex-exponent range. +# --------------------------------------------------------------------------- +def make_ibm_hfp_decoder(m_bits, e_bits=7, bias=64): + e_max = (1 << e_bits) - 1 + def decode(bits, total_bits): + s = (bits >> (e_bits + m_bits)) & 1 + e = (bits >> m_bits) & e_max + m = bits & ((1 << m_bits) - 1) + sign = -1.0 if s else 1.0 + if e == 0 and m == 0: + return (sign * 0.0, "zero") + # fraction value 0.M in base 2 (m_bits fractional bits) + frac = m / float(1 << m_bits) + val = sign * frac * (16.0 ** (e - bias)) + return (val, "normal") + return decode + +def ibm_hfp_encode_exact(m_bits, value, e_bits=7, bias=64): + """Encode value into IBM HFP. Returns int bits, or None if not exactly + representable in m_bits of binary fraction within the hex-exponent range. + Uses the normalized convention: leading hex digit of the fraction nonzero.""" + if value == 0.0: + return 0 + s = 1 if value < 0 else 0 + a = abs(value) + # find hex exponent E such that 1/16 <= a / 16^(E-bias) < 1 + E = bias + # scale up + while a / (16.0 ** (E - bias)) >= 1.0: + E += 1 + while a / (16.0 ** (E - bias)) < (1.0 / 16.0): + E -= 1 + e_max = (1 << e_bits) - 1 + if E <= 0 or E >= e_max: + return None + frac = a / (16.0 ** (E - bias)) # in [1/16, 1) + scaled = frac * (1 << m_bits) + m_field = round(scaled) + if m_field >= (1 << m_bits): + # carried into next hex exponent + E += 1 + if E >= e_max: + return None + frac = a / (16.0 ** (E - bias)) + scaled = frac * (1 << m_bits) + m_field = round(scaled) + if abs(scaled - m_field) > 1e-9: + return None # not exactly representable + if m_field == 0: + return None + return (s << (e_bits + m_bits)) | (E << m_bits) | m_field + +# --------------------------------------------------------------------------- +# Intel x87 80-bit extended (double extended). Explicit integer bit. +# layout: S(1) : E(15, bias 16383) : SIG(64) +# The 64-bit significand field holds the EXPLICIT integer bit as its MSB +# (bit 63 of the field) followed by 63 fraction bits. The catalog records +# this as m=64 (the full significand width including the integer bit), so +# 1 + 15 + 64 = 80 bits exactly. +# value = (-1)^S * (SIG / 2^63) * 2^(E - 16383) [SIG = integer.fraction] +# For normalized numbers the integer bit = 1. E = max -> inf/nan. +# --------------------------------------------------------------------------- +def make_x87_decoder(bias=16383, e_bits=15, sig_bits=64): + e_max = (1 << e_bits) - 1 + int_bit_pos = sig_bits - 1 # position of the explicit integer bit + def decode(bits, total_bits): + s = (bits >> (e_bits + sig_bits)) & 1 + e = (bits >> sig_bits) & e_max + sig = bits & ((1 << sig_bits) - 1) + j = (sig >> int_bit_pos) & 1 + f = sig & ((1 << int_bit_pos) - 1) + sign = -1.0 if s else 1.0 + if e == e_max: + if j == 1 and f == 0: + return (sign * math.inf, "inf") + return (math.nan, "nan") + if e == 0 and sig == 0: + return (sign * 0.0, "zero") + significand = sig / float(1 << int_bit_pos) # integer.fraction + val = sign * significand * (2.0 ** (e - bias)) + return (val, "normal") + return decode + +def x87_encode_exact(value, bias=16383, e_bits=15, sig_bits=64): + """Encode value into x87 80-bit with explicit integer bit (MSB of the + 64-bit significand field). Returns int bits or None if not exactly + representable in the 63 fraction bits within the exponent range.""" + if value == 0.0: + return 0 + s = 1 if value < 0 else 0 + a = abs(value) + int_bit_pos = sig_bits - 1 # 63 fraction bits below the integer bit + mant, exp = math.frexp(a) # a = mant * 2^exp, 0.5<=mant<1 + E_unbiased = exp - 1 # significand 1.f * 2^(E_unbiased) + frac = a / (2.0 ** E_unbiased) - 1.0 # in [0,1) + e_field = E_unbiased + bias + e_max = (1 << e_bits) - 1 + if e_field <= 0 or e_field >= e_max: + return None + f_field = round(frac * (1 << int_bit_pos)) + if f_field == (1 << int_bit_pos): + f_field = 0; e_field += 1 + if abs(frac * (1 << int_bit_pos) - f_field) > 1e-6: + return None + if e_field >= e_max: + return None + sig = (1 << int_bit_pos) | f_field # explicit integer bit set + fraction + return (s << (e_bits + sig_bits)) | (e_field << sig_bits) | sig + +# --------------------------------------------------------------------------- +# NF4 (NormalFloat 4-bit), QLoRA (Dettmers 2023). 16-entry quantile table +# fitted to N(0,1), normalized so the table spans [-1, 1]. The 4-bit code is +# an index into this fixed table; the decode is the table lookup. Bit-exact: +# every 4-bit code maps to exactly one table value, round-trip is the index. +# Reference table from bitsandbytes (the canonical QLoRA NF4 levels). +# --------------------------------------------------------------------------- +NF4_TABLE = [ + -1.0, + -0.6961928009986877, + -0.5250730514526367, + -0.39491748809814453, + -0.28444138169288635, + -0.18477343022823334, + -0.09105003625154495, + 0.0, + 0.07958029955625534, + 0.16093020141124725, + 0.24611230194568634, + 0.33791524171829224, + 0.44070982933044434, + 0.5626170039176941, + 0.7229568362236023, + 1.0, +] +def make_nf4_decoder(): + def decode(bits, total_bits): + idx = bits & 0xF + v = NF4_TABLE[idx] + cat = "zero" if v == 0.0 else "normal" + return (v, cat) + return decode + +# --------------------------------------------------------------------------- +# GFTernary: 2-bit discrete set {-phi, 0, +phi}. Four 2-bit codes; one is a +# spare (we map it to the same +phi for completeness / documented as reserved). +# Anchor 3.0 is NOT a single code (it arises as phi^2 + 1/phi^2 = 3 over the +# nonzero codes), so it is recorded in anchor_note, not as a vector. +# --------------------------------------------------------------------------- +def make_gfternary_decoder(): + def decode(bits, total_bits): + c = bits & 0x3 + if c == 0: + return (0.0, "zero") + if c == 1: + return (PHI, "normal") + if c == 2: + return (-PHI, "normal") + return (PHI, "reserved") # code 3: reserved/spare -> documented duplicate + return decode + # --------------------------------------------------------------------------- # Vector selection # --------------------------------------------------------------------------- @@ -365,7 +532,11 @@ def build_decodable(rec): # discrete set) -> structural; skip gf16 (existing). if cluster == "GoldenFloat": if cid == "gfternary": - return None + # 2-bit discrete set {-phi, 0, +phi}: enumerate all 4 codes bit-exactly. + return (make_gfternary_decoder(), + "GFTernary 2-bit discrete set {-phi, 0, +phi}; codes 00=0, " + "01=+phi, 10=-phi, 11=reserved (duplicate +phi)", + "no inf/nan; discrete ternary levels") if e > 0 and m > 0 and bits in (4, 6, 8, 12, 16, 20, 24, 32, 64): dec = make_ieee_decoder(e, m, bias, has_inf=True, has_nan=True) return (dec, f"GoldenFloat phi-aligned radix-2 float S{1}E{e}M{m}, bias {bias}", @@ -410,7 +581,12 @@ def build_decodable(rec): # ones precisely, flag base-16 ones as structural). if cluster == "HistoricalVendor" and e > 0 and m > 0: if cid.startswith("ibm_hfp"): - return None # base-16 exponent, different decode -> structural w/ note + # base-16 exponent: dedicated HFP decoder (S1E7M, bias 64). + return (make_ibm_hfp_decoder(m, e_bits=e, bias=bias), + f"IBM Hexadecimal Floating Point S1E{e}M{m}, excess-{bias} " + f"base-16 exponent: value = 0.M(2) * 16^(E-{bias})", + "no inf/nan; true zero is all-zero; " + + ("named small values exact (mantissa exceeds f64 for the full grid)" if m > 52 else "exact for the named set")) if cid == "cray_float": # Cray: no NaN/Inf dec = make_ieee_decoder(e, m, bias, has_inf=False, has_nan=False) @@ -419,8 +595,25 @@ def build_decodable(rec): return (dec, f"vendor radix-2 float S1E{e}M{m}, bias {bias} ({rec['standard']})", "vendor-specific specials") - # ExtendedFloat (x87 explicit integer bit, double-double, quad-double): - # non-trivial layouts -> structural. + # ExtendedFloat: x87 has a single fixed S:E:J:F layout with an explicit + # integer bit -> bit-exact. double-double / quad-double are composite + # multi-double components (no single S:E:M) -> remain structural. + if cluster == "ExtendedFloat": + if cid == "x87_fp80": + return (make_x87_decoder(bias=bias, e_bits=e, sig_bits=m), + f"Intel x87 80-bit extended S1E{e}+SIG{m} (explicit integer " + f"bit as MSB of the {m}-bit significand), bias {bias}: " + f"value = (SIG/2^{m-1}) * 2^(E-{bias})", + "inf at max exp (int=1, frac=0); nan otherwise at max exp") + return None # double_double / quad_double -> structural + + # QuantTuned: NF4 is a fixed 16-entry quantile table -> bit-exact lookup. + if cluster == "QuantTuned" and cid == "nf4": + return (make_nf4_decoder(), + "NF4 (NormalFloat 4-bit, QLoRA/bitsandbytes): 4-bit code indexes " + "a fixed 16-entry quantile table fitted to N(0,1), span [-1,1]", + "no inf/nan; code is a table index; round-trip is the index") + return None # --------------------------------------------------------------------------- @@ -546,8 +739,12 @@ def build_bitexact_pack(rec, decode, notes, specials_desc): encoder = None if cluster in ("Ieee754Binary", "MlLowPrecision", "Microscaling", "GoldenFloat") and e > 0 and m > 0: encoder = lambda val, _e=e, _m=m, _b=bias: ieee_encode_exact(_e, _m, _b, val) - elif cluster == "HistoricalVendor" and e > 0 and m > 0 and not cid.startswith("ibm_hfp"): + elif cluster == "HistoricalVendor" and cid.startswith("ibm_hfp"): + encoder = lambda val, _m=m, _e=e, _b=bias: ibm_hfp_encode_exact(_m, val, e_bits=_e, bias=_b) + elif cluster == "HistoricalVendor" and e > 0 and m > 0: encoder = lambda val, _e=e, _m=m, _b=bias: ieee_encode_exact(_e, _m, _b, val) + elif cluster == "ExtendedFloat" and cid == "x87_fp80": + encoder = lambda val, _e=e, _m=m, _b=bias: x87_encode_exact(val, bias=_b, e_bits=_e, sig_bits=_m) elif cluster == "IntegerFixed" and cid.startswith("int"): encoder = lambda val, _tb=bits: int_encode(val, _tb) elif cluster == "PositUnumIII" and cid.startswith("posit"): diff --git a/conformance/vectors/gfternary_conformance_v0.json b/conformance/vectors/gfternary_conformance_v0.json index b20392c0c..56838b2c9 100644 --- a/conformance/vectors/gfternary_conformance_v0.json +++ b/conformance/vectors/gfternary_conformance_v0.json @@ -2,8 +2,8 @@ "schema": "t27-conformance/v0.1", "format": "GFTERNARY", "format_name": "GFTernary", - "bitexact": false, - "format_notes": "GFTernary -- this work; {-phi, 0, +phi}", + "bitexact": true, + "format_notes": "GFTernary 2-bit discrete set {-phi, 0, +phi}; codes 00=0, 01=+phi, 10=-phi, 11=reserved (duplicate +phi). no inf/nan; discrete ternary levels", "catalog": { "id": "gfternary", "bits": 2, @@ -23,8 +23,60 @@ "ssot": "https://github.com/gHashTag/t27/blob/master/conformance/FORMAT-SPEC-001.json", "preprint": "https://arxiv.org/abs/2606.05017", "anchor_identity": "phi^2 + 1/phi^2 = 3", - "structural_reason": "GFTernary is a 2-bit discrete set {-phi, 0, +phi}; the three values are recorded directly rather than via an S:E:M decode.", - "anchor_note": "Anchor 3.0 arises as phi^2 + 1/phi^2 = 3 from the two nonzero codes +phi and... see GF16 pack; not a single code here.", - "n_vectors": 0, - "vectors": [] + "anchor_check": { + "value": null, + "expected": 3.0, + "ieee754_exact": false, + "note": "3.0 is not an exact grid point of this format at this width" + }, + "round_trip_policy": "decode: exact bits->f64 (exhaustive). encode (reference): round-nearest-ties-even; overflow per format convention. abs_error 0 for representable values.", + "vector_mode": "exhaustive", + "n_vectors": 4, + "max_finite": 1.618033988749895, + "vectors": [ + { + "name": "code_0x00", + "input_f64": 0.0, + "input_f64_hex": "0x0000000000000000", + "gfternary_bits_hex": "0x0", + "gfternary_bits_int": 0, + "decoded_f64": 0.0, + "decoded_f64_hex": "0x0000000000000000", + "abs_error": 0.0, + "category": "zero" + }, + { + "name": "code_0x01", + "input_f64": 1.618033988749895, + "input_f64_hex": "0x3FF9E3779B97F4A8", + "gfternary_bits_hex": "0x1", + "gfternary_bits_int": 1, + "decoded_f64": 1.618033988749895, + "decoded_f64_hex": "0x3FF9E3779B97F4A8", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x02", + "input_f64": -1.618033988749895, + "input_f64_hex": "0xBFF9E3779B97F4A8", + "gfternary_bits_hex": "0x2", + "gfternary_bits_int": 2, + "decoded_f64": -1.618033988749895, + "decoded_f64_hex": "0xBFF9E3779B97F4A8", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x03", + "input_f64": 1.618033988749895, + "input_f64_hex": "0x3FF9E3779B97F4A8", + "gfternary_bits_hex": "0x3", + "gfternary_bits_int": 3, + "decoded_f64": 1.618033988749895, + "decoded_f64_hex": "0x3FF9E3779B97F4A8", + "abs_error": 0.0, + "category": "reserved" + } + ] } \ No newline at end of file diff --git a/conformance/vectors/ibm_hfp128_conformance_v0.json b/conformance/vectors/ibm_hfp128_conformance_v0.json index 556130135..850239cf7 100644 --- a/conformance/vectors/ibm_hfp128_conformance_v0.json +++ b/conformance/vectors/ibm_hfp128_conformance_v0.json @@ -2,8 +2,8 @@ "schema": "t27-conformance/v0.1", "format": "IBM_HFP128", "format_name": "IBM HFP (extended)", - "bitexact": false, - "format_notes": "IBM HFP (extended) -- IBM z/Architecture", + "bitexact": true, + "format_notes": "IBM Hexadecimal Floating Point S1E7M120, excess-64 base-16 exponent: value = 0.M(2) * 16^(E-64). no inf/nan; true zero is all-zero; named small values exact (mantissa exceeds f64 for the full grid)", "catalog": { "id": "ibm_hfp128", "bits": 128, @@ -23,8 +23,103 @@ "ssot": "https://github.com/gHashTag/t27/blob/master/conformance/FORMAT-SPEC-001.json", "preprint": "https://arxiv.org/abs/2606.05017", "anchor_identity": "phi^2 + 1/phi^2 = 3", - "structural_reason": "IBM Hexadecimal Floating Point uses a base-16 exponent (not base-2), so the radix-2 S:E:M decoder does not apply. 3.0 is exactly representable; recorded structurally.", - "anchor_note": "Anchor identity phi^2 + 1/phi^2 = 3 recorded per shared schema.", - "n_vectors": 0, - "vectors": [] + "anchor_check": { + "value": 3.0, + "expected": 3.0, + "ieee754_exact": true, + "ibm_hfp128_bits_hex": "0x41300000000000000000000000000000" + }, + "round_trip_policy": "decode: exact bits->f64 (curated_named). encode (reference): round-nearest-ties-even; overflow per format convention. abs_error 0 for representable values.", + "vector_mode": "curated_named", + "n_vectors": 8, + "vectors": [ + { + "name": "pos_zero", + "input_f64": 0.0, + "input_f64_hex": "0x0000000000000000", + "ibm_hfp128_bits_hex": "0x00000000000000000000000000000000", + "ibm_hfp128_bits_int": 0, + "decoded_f64": 0.0, + "decoded_f64_hex": "0x0000000000000000", + "abs_error": 0.0, + "category": "zero" + }, + { + "name": "pos_one", + "input_f64": 1.0, + "input_f64_hex": "0x3FF0000000000000", + "ibm_hfp128_bits_hex": "0x41100000000000000000000000000000", + "ibm_hfp128_bits_int": 86482896475756088980803946859489918976, + "decoded_f64": 1.0, + "decoded_f64_hex": "0x3FF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_one", + "input_f64": -1.0, + "input_f64_hex": "0xBFF0000000000000", + "ibm_hfp128_bits_hex": "0xC1100000000000000000000000000000", + "ibm_hfp128_bits_int": 256624079936225320712491250575374024704, + "decoded_f64": -1.0, + "decoded_f64_hex": "0xBFF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_two", + "input_f64": 2.0, + "input_f64_hex": "0x4000000000000000", + "ibm_hfp128_bits_hex": "0x41200000000000000000000000000000", + "ibm_hfp128_bits_int": 86565973225492646222860434800757440512, + "decoded_f64": 2.0, + "decoded_f64_hex": "0x4000000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_three", + "input_f64": 3.0, + "input_f64_hex": "0x4008000000000000", + "ibm_hfp128_bits_hex": "0x41300000000000000000000000000000", + "ibm_hfp128_bits_int": 86649049975229203464916922742024962048, + "decoded_f64": 3.0, + "decoded_f64_hex": "0x4008000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_half", + "input_f64": 0.5, + "input_f64_hex": "0x3FE0000000000000", + "ibm_hfp128_bits_hex": "0x40800000000000000000000000000000", + "ibm_hfp128_bits_int": 85735205728127073802295555388082225152, + "decoded_f64": 0.5, + "decoded_f64_hex": "0x3FE0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_four", + "input_f64": 4.0, + "input_f64_hex": "0x4010000000000000", + "ibm_hfp128_bits_hex": "0x41400000000000000000000000000000", + "ibm_hfp128_bits_int": 86732126724965760706973410683292483584, + "decoded_f64": 4.0, + "decoded_f64_hex": "0x4010000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_three", + "input_f64": -3.0, + "input_f64_hex": "0xC008000000000000", + "ibm_hfp128_bits_hex": "0xC1300000000000000000000000000000", + "ibm_hfp128_bits_int": 256790233435698435196604226457909067776, + "decoded_f64": -3.0, + "decoded_f64_hex": "0xC008000000000000", + "abs_error": 0.0, + "category": "normal" + } + ] } \ No newline at end of file diff --git a/conformance/vectors/ibm_hfp32_conformance_v0.json b/conformance/vectors/ibm_hfp32_conformance_v0.json index e74bbecff..c91e5c951 100644 --- a/conformance/vectors/ibm_hfp32_conformance_v0.json +++ b/conformance/vectors/ibm_hfp32_conformance_v0.json @@ -2,8 +2,8 @@ "schema": "t27-conformance/v0.1", "format": "IBM_HFP32", "format_name": "IBM HFP (single)", - "bitexact": false, - "format_notes": "IBM HFP (single) -- IBM System/360 (1964); base-16 exponent", + "bitexact": true, + "format_notes": "IBM Hexadecimal Floating Point S1E7M24, excess-64 base-16 exponent: value = 0.M(2) * 16^(E-64). no inf/nan; true zero is all-zero; exact for the named set", "catalog": { "id": "ibm_hfp32", "bits": 32, @@ -23,8 +23,103 @@ "ssot": "https://github.com/gHashTag/t27/blob/master/conformance/FORMAT-SPEC-001.json", "preprint": "https://arxiv.org/abs/2606.05017", "anchor_identity": "phi^2 + 1/phi^2 = 3", - "structural_reason": "IBM Hexadecimal Floating Point uses a base-16 exponent (not base-2), so the radix-2 S:E:M decoder does not apply. 3.0 is exactly representable; recorded structurally.", - "anchor_note": "Anchor identity phi^2 + 1/phi^2 = 3 recorded per shared schema.", - "n_vectors": 0, - "vectors": [] + "anchor_check": { + "value": 3.0, + "expected": 3.0, + "ieee754_exact": true, + "ibm_hfp32_bits_hex": "0x41300000" + }, + "round_trip_policy": "decode: exact bits->f64 (curated_named). encode (reference): round-nearest-ties-even; overflow per format convention. abs_error 0 for representable values.", + "vector_mode": "curated_named", + "n_vectors": 8, + "vectors": [ + { + "name": "pos_zero", + "input_f64": 0.0, + "input_f64_hex": "0x0000000000000000", + "ibm_hfp32_bits_hex": "0x00000000", + "ibm_hfp32_bits_int": 0, + "decoded_f64": 0.0, + "decoded_f64_hex": "0x0000000000000000", + "abs_error": 0.0, + "category": "zero" + }, + { + "name": "pos_one", + "input_f64": 1.0, + "input_f64_hex": "0x3FF0000000000000", + "ibm_hfp32_bits_hex": "0x41100000", + "ibm_hfp32_bits_int": 1091567616, + "decoded_f64": 1.0, + "decoded_f64_hex": "0x3FF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_one", + "input_f64": -1.0, + "input_f64_hex": "0xBFF0000000000000", + "ibm_hfp32_bits_hex": "0xC1100000", + "ibm_hfp32_bits_int": 3239051264, + "decoded_f64": -1.0, + "decoded_f64_hex": "0xBFF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_two", + "input_f64": 2.0, + "input_f64_hex": "0x4000000000000000", + "ibm_hfp32_bits_hex": "0x41200000", + "ibm_hfp32_bits_int": 1092616192, + "decoded_f64": 2.0, + "decoded_f64_hex": "0x4000000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_three", + "input_f64": 3.0, + "input_f64_hex": "0x4008000000000000", + "ibm_hfp32_bits_hex": "0x41300000", + "ibm_hfp32_bits_int": 1093664768, + "decoded_f64": 3.0, + "decoded_f64_hex": "0x4008000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_half", + "input_f64": 0.5, + "input_f64_hex": "0x3FE0000000000000", + "ibm_hfp32_bits_hex": "0x40800000", + "ibm_hfp32_bits_int": 1082130432, + "decoded_f64": 0.5, + "decoded_f64_hex": "0x3FE0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_four", + "input_f64": 4.0, + "input_f64_hex": "0x4010000000000000", + "ibm_hfp32_bits_hex": "0x41400000", + "ibm_hfp32_bits_int": 1094713344, + "decoded_f64": 4.0, + "decoded_f64_hex": "0x4010000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_three", + "input_f64": -3.0, + "input_f64_hex": "0xC008000000000000", + "ibm_hfp32_bits_hex": "0xC1300000", + "ibm_hfp32_bits_int": 3241148416, + "decoded_f64": -3.0, + "decoded_f64_hex": "0xC008000000000000", + "abs_error": 0.0, + "category": "normal" + } + ] } \ No newline at end of file diff --git a/conformance/vectors/ibm_hfp64_conformance_v0.json b/conformance/vectors/ibm_hfp64_conformance_v0.json index a8efeab63..a627a95e1 100644 --- a/conformance/vectors/ibm_hfp64_conformance_v0.json +++ b/conformance/vectors/ibm_hfp64_conformance_v0.json @@ -2,8 +2,8 @@ "schema": "t27-conformance/v0.1", "format": "IBM_HFP64", "format_name": "IBM HFP (double)", - "bitexact": false, - "format_notes": "IBM HFP (double) -- IBM System/360 (1964)", + "bitexact": true, + "format_notes": "IBM Hexadecimal Floating Point S1E7M56, excess-64 base-16 exponent: value = 0.M(2) * 16^(E-64). no inf/nan; true zero is all-zero; named small values exact (mantissa exceeds f64 for the full grid)", "catalog": { "id": "ibm_hfp64", "bits": 64, @@ -23,8 +23,103 @@ "ssot": "https://github.com/gHashTag/t27/blob/master/conformance/FORMAT-SPEC-001.json", "preprint": "https://arxiv.org/abs/2606.05017", "anchor_identity": "phi^2 + 1/phi^2 = 3", - "structural_reason": "IBM Hexadecimal Floating Point uses a base-16 exponent (not base-2), so the radix-2 S:E:M decoder does not apply. 3.0 is exactly representable; recorded structurally.", - "anchor_note": "Anchor identity phi^2 + 1/phi^2 = 3 recorded per shared schema.", - "n_vectors": 0, - "vectors": [] + "anchor_check": { + "value": 3.0, + "expected": 3.0, + "ieee754_exact": true, + "ibm_hfp64_bits_hex": "0x4130000000000000" + }, + "round_trip_policy": "decode: exact bits->f64 (curated_named). encode (reference): round-nearest-ties-even; overflow per format convention. abs_error 0 for representable values.", + "vector_mode": "curated_named", + "n_vectors": 8, + "vectors": [ + { + "name": "pos_zero", + "input_f64": 0.0, + "input_f64_hex": "0x0000000000000000", + "ibm_hfp64_bits_hex": "0x0000000000000000", + "ibm_hfp64_bits_int": 0, + "decoded_f64": 0.0, + "decoded_f64_hex": "0x0000000000000000", + "abs_error": 0.0, + "category": "zero" + }, + { + "name": "pos_one", + "input_f64": 1.0, + "input_f64_hex": "0x3FF0000000000000", + "ibm_hfp64_bits_hex": "0x4110000000000000", + "ibm_hfp64_bits_int": 4688247212092686336, + "decoded_f64": 1.0, + "decoded_f64_hex": "0x3FF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_one", + "input_f64": -1.0, + "input_f64_hex": "0xBFF0000000000000", + "ibm_hfp64_bits_hex": "0xC110000000000000", + "ibm_hfp64_bits_int": 13911619248947462144, + "decoded_f64": -1.0, + "decoded_f64_hex": "0xBFF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_two", + "input_f64": 2.0, + "input_f64_hex": "0x4000000000000000", + "ibm_hfp64_bits_hex": "0x4120000000000000", + "ibm_hfp64_bits_int": 4692750811720056832, + "decoded_f64": 2.0, + "decoded_f64_hex": "0x4000000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_three", + "input_f64": 3.0, + "input_f64_hex": "0x4008000000000000", + "ibm_hfp64_bits_hex": "0x4130000000000000", + "ibm_hfp64_bits_int": 4697254411347427328, + "decoded_f64": 3.0, + "decoded_f64_hex": "0x4008000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_half", + "input_f64": 0.5, + "input_f64_hex": "0x3FE0000000000000", + "ibm_hfp64_bits_hex": "0x4080000000000000", + "ibm_hfp64_bits_int": 4647714815446351872, + "decoded_f64": 0.5, + "decoded_f64_hex": "0x3FE0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_four", + "input_f64": 4.0, + "input_f64_hex": "0x4010000000000000", + "ibm_hfp64_bits_hex": "0x4140000000000000", + "ibm_hfp64_bits_int": 4701758010974797824, + "decoded_f64": 4.0, + "decoded_f64_hex": "0x4010000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_three", + "input_f64": -3.0, + "input_f64_hex": "0xC008000000000000", + "ibm_hfp64_bits_hex": "0xC130000000000000", + "ibm_hfp64_bits_int": 13920626448202203136, + "decoded_f64": -3.0, + "decoded_f64_hex": "0xC008000000000000", + "abs_error": 0.0, + "category": "normal" + } + ] } \ No newline at end of file diff --git a/conformance/vectors/nf4_conformance_v0.json b/conformance/vectors/nf4_conformance_v0.json index 9c1829919..2dd6831d3 100644 --- a/conformance/vectors/nf4_conformance_v0.json +++ b/conformance/vectors/nf4_conformance_v0.json @@ -2,8 +2,8 @@ "schema": "t27-conformance/v0.1", "format": "NF4", "format_name": "NF4 (NormalFloat 4-bit)", - "bitexact": false, - "format_notes": "NF4 (NormalFloat 4-bit) -- Dettmers 2023 (QLoRA)", + "bitexact": true, + "format_notes": "NF4 (NormalFloat 4-bit, QLoRA/bitsandbytes): 4-bit code indexes a fixed 16-entry quantile table fitted to N(0,1), span [-1,1]. no inf/nan; code is a table index; round-trip is the index", "catalog": { "id": "nf4", "bits": 4, @@ -23,8 +23,192 @@ "ssot": "https://github.com/gHashTag/t27/blob/master/conformance/FORMAT-SPEC-001.json", "preprint": "https://arxiv.org/abs/2606.05017", "anchor_identity": "phi^2 + 1/phi^2 = 3", - "structural_reason": "NF4 is a 16-entry quantile lookup table fitted to N(0,1); values are table entries, not an S:E:M layout. The 16-entry table defines the round-trip, recorded structurally.", - "anchor_note": "Anchor identity phi^2 + 1/phi^2 = 3 recorded per shared schema.", - "n_vectors": 0, - "vectors": [] + "anchor_check": { + "value": null, + "expected": 3.0, + "ieee754_exact": false, + "note": "3.0 is not an exact grid point of this format at this width" + }, + "round_trip_policy": "decode: exact bits->f64 (exhaustive). encode (reference): round-nearest-ties-even; overflow per format convention. abs_error 0 for representable values.", + "vector_mode": "exhaustive", + "n_vectors": 16, + "max_finite": 1.0, + "vectors": [ + { + "name": "code_0x00", + "input_f64": -1.0, + "input_f64_hex": "0xBFF0000000000000", + "nf4_bits_hex": "0x0", + "nf4_bits_int": 0, + "decoded_f64": -1.0, + "decoded_f64_hex": "0xBFF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x01", + "input_f64": -0.6961928009986877, + "input_f64_hex": "0xBFE6473620000000", + "nf4_bits_hex": "0x1", + "nf4_bits_int": 1, + "decoded_f64": -0.6961928009986877, + "decoded_f64_hex": "0xBFE6473620000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x02", + "input_f64": -0.5250730514526367, + "input_f64_hex": "0xBFE0CD6600000000", + "nf4_bits_hex": "0x2", + "nf4_bits_int": 2, + "decoded_f64": -0.5250730514526367, + "decoded_f64_hex": "0xBFE0CD6600000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x03", + "input_f64": -0.39491748809814453, + "input_f64_hex": "0xBFD9465400000000", + "nf4_bits_hex": "0x3", + "nf4_bits_int": 3, + "decoded_f64": -0.39491748809814453, + "decoded_f64_hex": "0xBFD9465400000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x04", + "input_f64": -0.28444138169288635, + "input_f64_hex": "0xBFD23449A0000000", + "nf4_bits_hex": "0x4", + "nf4_bits_int": 4, + "decoded_f64": -0.28444138169288635, + "decoded_f64_hex": "0xBFD23449A0000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x05", + "input_f64": -0.18477343022823334, + "input_f64_hex": "0xBFC7A6A7E0000000", + "nf4_bits_hex": "0x5", + "nf4_bits_int": 5, + "decoded_f64": -0.18477343022823334, + "decoded_f64_hex": "0xBFC7A6A7E0000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x06", + "input_f64": -0.09105003625154495, + "input_f64_hex": "0xBFB74F0E20000000", + "nf4_bits_hex": "0x6", + "nf4_bits_int": 6, + "decoded_f64": -0.09105003625154495, + "decoded_f64_hex": "0xBFB74F0E20000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x07", + "input_f64": 0.0, + "input_f64_hex": "0x0000000000000000", + "nf4_bits_hex": "0x7", + "nf4_bits_int": 7, + "decoded_f64": 0.0, + "decoded_f64_hex": "0x0000000000000000", + "abs_error": 0.0, + "category": "zero" + }, + { + "name": "code_0x08", + "input_f64": 0.07958029955625534, + "input_f64_hex": "0x3FB45F5FE0000000", + "nf4_bits_hex": "0x8", + "nf4_bits_int": 8, + "decoded_f64": 0.07958029955625534, + "decoded_f64_hex": "0x3FB45F5FE0000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x09", + "input_f64": 0.16093020141124725, + "input_f64_hex": "0x3FC4995C60000000", + "nf4_bits_hex": "0x9", + "nf4_bits_int": 9, + "decoded_f64": 0.16093020141124725, + "decoded_f64_hex": "0x3FC4995C60000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x0A", + "input_f64": 0.24611230194568634, + "input_f64_hex": "0x3FCF809BA0000000", + "nf4_bits_hex": "0xA", + "nf4_bits_int": 10, + "decoded_f64": 0.24611230194568634, + "decoded_f64_hex": "0x3FCF809BA0000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x0B", + "input_f64": 0.33791524171829224, + "input_f64_hex": "0x3FD5A06740000000", + "nf4_bits_hex": "0xB", + "nf4_bits_int": 11, + "decoded_f64": 0.33791524171829224, + "decoded_f64_hex": "0x3FD5A06740000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x0C", + "input_f64": 0.44070982933044434, + "input_f64_hex": "0x3FDC349700000000", + "nf4_bits_hex": "0xC", + "nf4_bits_int": 12, + "decoded_f64": 0.44070982933044434, + "decoded_f64_hex": "0x3FDC349700000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x0D", + "input_f64": 0.5626170039176941, + "input_f64_hex": "0x3FE200F560000000", + "nf4_bits_hex": "0xD", + "nf4_bits_int": 13, + "decoded_f64": 0.5626170039176941, + "decoded_f64_hex": "0x3FE200F560000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x0E", + "input_f64": 0.7229568362236023, + "input_f64_hex": "0x3FE7227660000000", + "nf4_bits_hex": "0xE", + "nf4_bits_int": 14, + "decoded_f64": 0.7229568362236023, + "decoded_f64_hex": "0x3FE7227660000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "code_0x0F", + "input_f64": 1.0, + "input_f64_hex": "0x3FF0000000000000", + "nf4_bits_hex": "0xF", + "nf4_bits_int": 15, + "decoded_f64": 1.0, + "decoded_f64_hex": "0x3FF0000000000000", + "abs_error": 0.0, + "category": "normal" + } + ] } \ No newline at end of file diff --git a/conformance/vectors/x87_fp80_conformance_v0.json b/conformance/vectors/x87_fp80_conformance_v0.json index ae3a09389..7e28e437b 100644 --- a/conformance/vectors/x87_fp80_conformance_v0.json +++ b/conformance/vectors/x87_fp80_conformance_v0.json @@ -2,8 +2,8 @@ "schema": "t27-conformance/v0.1", "format": "X87_FP80", "format_name": "x87 FP80", - "bitexact": false, - "format_notes": "x87 FP80 -- Intel x87 (explicit integer bit)", + "bitexact": true, + "format_notes": "Intel x87 80-bit extended S1E15+SIG64 (explicit integer bit as MSB of the 64-bit significand), bias 16383: value = (SIG/2^63) * 2^(E-16383). inf at max exp (int=1, frac=0); nan otherwise at max exp", "catalog": { "id": "x87_fp80", "bits": 80, @@ -23,8 +23,103 @@ "ssot": "https://github.com/gHashTag/t27/blob/master/conformance/FORMAT-SPEC-001.json", "preprint": "https://arxiv.org/abs/2606.05017", "anchor_identity": "phi^2 + 1/phi^2 = 3", - "structural_reason": "Extended-precision layout (explicit integer bit / multi-double components) is not a single S:E:M field; recorded structurally.", - "anchor_note": "Anchor identity phi^2 + 1/phi^2 = 3 recorded per shared schema.", - "n_vectors": 0, - "vectors": [] + "anchor_check": { + "value": 3.0, + "expected": 3.0, + "ieee754_exact": true, + "x87_fp80_bits_hex": "0x4000C000000000000000" + }, + "round_trip_policy": "decode: exact bits->f64 (curated_named). encode (reference): round-nearest-ties-even; overflow per format convention. abs_error 0 for representable values.", + "vector_mode": "curated_named", + "n_vectors": 8, + "vectors": [ + { + "name": "pos_zero", + "input_f64": 0.0, + "input_f64_hex": "0x0000000000000000", + "x87_fp80_bits_hex": "0x00000000000000000000", + "x87_fp80_bits_int": 0, + "decoded_f64": 0.0, + "decoded_f64_hex": "0x0000000000000000", + "abs_error": 0.0, + "category": "zero" + }, + { + "name": "pos_one", + "input_f64": 1.0, + "input_f64_hex": "0x3FF0000000000000", + "x87_fp80_bits_hex": "0x3FFF8000000000000000", + "x87_fp80_bits_int": 302222231531620438900736, + "decoded_f64": 1.0, + "decoded_f64_hex": "0x3FF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_one", + "input_f64": -1.0, + "input_f64_hex": "0xBFF0000000000000", + "x87_fp80_bits_hex": "0xBFFF8000000000000000", + "x87_fp80_bits_int": 906685141338935026253824, + "decoded_f64": -1.0, + "decoded_f64_hex": "0xBFF0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_two", + "input_f64": 2.0, + "input_f64_hex": "0x4000000000000000", + "x87_fp80_bits_hex": "0x40008000000000000000", + "x87_fp80_bits_int": 302240678275694148452352, + "decoded_f64": 2.0, + "decoded_f64_hex": "0x4000000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_three", + "input_f64": 3.0, + "input_f64_hex": "0x4008000000000000", + "x87_fp80_bits_hex": "0x4000C000000000000000", + "x87_fp80_bits_int": 302245289961712575840256, + "decoded_f64": 3.0, + "decoded_f64_hex": "0x4008000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_half", + "input_f64": 0.5, + "input_f64_hex": "0x3FE0000000000000", + "x87_fp80_bits_hex": "0x3FFE8000000000000000", + "x87_fp80_bits_int": 302203784787546729349120, + "decoded_f64": 0.5, + "decoded_f64_hex": "0x3FE0000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "pos_four", + "input_f64": 4.0, + "input_f64_hex": "0x4010000000000000", + "x87_fp80_bits_hex": "0x40018000000000000000", + "x87_fp80_bits_int": 302259125019767858003968, + "decoded_f64": 4.0, + "decoded_f64_hex": "0x4010000000000000", + "abs_error": 0.0, + "category": "normal" + }, + { + "name": "neg_three", + "input_f64": -3.0, + "input_f64_hex": "0xC008000000000000", + "x87_fp80_bits_hex": "0xC000C000000000000000", + "x87_fp80_bits_int": 906708199769027163193344, + "decoded_f64": -3.0, + "decoded_f64_hex": "0xC008000000000000", + "abs_error": 0.0, + "category": "normal" + } + ] } \ No newline at end of file diff --git a/docs/NOW.md b/docs/NOW.md index e1b5a8e7a..de5a60040 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -2,6 +2,12 @@ Last updated: 2026-06-14 +## conformance-structural-to-bitexact -- promote 6 structural packs to bit-precise (IBM HFP, x87, NF4, GFTernary) (Closes #1076) + +- **WHERE** (conformance vectors): extends `conformance/vectors/gen_all_formats.py` with dedicated reference codecs that promote 6 packs from structural (`bitexact: false`, placeholder) to bit-precise (`bitexact: true`, `abs_error = 0` for every recorded vector): `ibm_hfp32/64/128` (IBM Hexadecimal Floating Point, base-16 exponent, layout S1:E7 excess-64:M, value = 0.M(2) * 16^(E-64)); `x87_fp80` (Intel 80-bit extended with the explicit integer bit as the MSB of the 64-bit significand field, S1:E15:SIG64, bias 16383); `nf4` (QLoRA/bitsandbytes NF4 16-entry quantile table over [-1,1], exhaustive 16-code lookup); `gfternary` (2-bit {-phi, 0, +phi}, exhaustive 4-code enumeration). Adds `make_ibm_hfp_decoder`/`ibm_hfp_encode_exact`, `make_x87_decoder`/`x87_encode_exact`, `make_nf4_decoder` + `NF4_TABLE`, `make_gfternary_decoder`, and routes them in `build_decodable`/`build_bitexact_pack`. Regenerates `INDEX_all_formats.json` (`total_packs=83, bitexact_packs=55, structural_packs=28`) and the 6 affected `*_conformance_v0.json` packs. `README.md` index, counts, SHA-256 block, and a new changelog entry updated. The catalog itself is unchanged at 83 formats; only round-trip depth increases. Follows #1070. +- **Why**: turns 6 honest placeholders into citable bit-exact round-trip references. Each codec is independently verified to round-trip with `abs_error = 0`; IBM HFP and x87 hit the 3.0 anchor exactly (3.0 = 0.1875 x 16^1 in HFP; 3.0 = 1.5 x 2^1 in x87), while `gfternary` and `nf4` honestly record a null anchor (3.0 is not a grid point) with a note rather than forcing a false claim. Remaining `ExtendedFloat` entries `double_double` / `quad_double` stay structural (composite multi-double, no single S:E:M field) -- not promoted, honest. No silicon claim beyond the existing GF16 rung; these are conformance data + reproduction scripts. L6 gf16 SSOT untouched; L2 `gen/` untouched. ASCII-only. Context preprint: arXiv:2606.05017. Closes #1076. +- **Anchor**: phi^2 + phi^-2 = 3 + ## repro-numerics-certifying-manifest -- schema-conforming certifying NMSE manifest + seal-hash honesty (Closes #1074) - **WHERE** (`repro/numerics/` + `repro/Makefile` + `docs/NUMERICS_VALIDATION.md`): adds a certifying-manifest mode to `repro/numerics/nmse_gf16.py` and a standalone validator `repro/numerics/validate_manifest.py`. The script now emits a SECOND manifest `repro/numerics/nmse_manifest_protocol_v1.json` that STRICTLY conforms to `schemas/nmse-protocol-v1.json` (`additionalProperties:false`; results restricted to the five schema distributions `D_NORM/D_LOG/D_RELU/D_PHI/D_DEEP`; each result is `nmse_gf16`/`nmse_bf16`/`ratio`; `schema_version`/`protocol_version`/`rng{family:pcg64,seed:0x...}`/`samples_per_distribution`/`bf16_subnormal_policy`/`identity_witness`/`runner`/`timestamp`/`x_extension`). The rich `nmse_manifest.json` (with `D_WIDE`, ULP, overflow) is kept and stays NOT schema-bound. A `--seal` flag re-hashes `bootstrap/src/compiler.rs` and sets `seal_hash` to the `bootstrap/stage0/FROZEN_HASH` digest ONLY on an exact match; otherwise `seal_hash` stays the literal `unsealed`. New `make -C repro repro-numerics-certify` target runs the validator, which checks the schema AND enforces the honesty rule (a non-`unsealed` hash must equal FROZEN_HASH).