# bankml: verified low-bit inference on commodity CPUs — a technical report *Professor Codephreak and Gregory L. Magnusson · cryptoAGI · 2026. Written at bankml v0.2.0 (2026-09-29); its status sections (§IV.4, §VI) brought up to date on 2026-10-06, when v0.3.6 is the latest release and 0.3.7–0.3.9 are unreleased on the development branch ([CHANGELOG.md](../CHANGELOG.md) is the source of truth for both). Companion to [PERFORMANCE.md](PERFORMANCE.md), which holds every measurement cited here with the command that reproduces it; [oracles.md](oracles.md) lists every oracle in the release gate, and [BUILD_HISTORY.md](BUILD_HISTORY.md) the phases.* ## Abstract Language models quantized to one bit or to ternary values per weight shrink an 8-billion-parameter network to 1.2–2.3 GB, small enough for a laptop or a two-core server. Whether such models are *useful* there depends less on the arithmetic than on two properties the literature treats separately: the speed of the matrix kernels that consume the packed weights, and the confidence that a fast kernel computes exactly what the reference computes. This report argues that the two must be established together, and that **bit-exactness against the reference implementation's own compiled code is the correctness criterion a low-bit kernel should meet before its speed is reported at all**. We describe bankml, a zero-dependency Rust runtime for the ggml `Q1_0` (1-bit) and `Q2_0_g64` (ternary) formats; its verification discipline (a header guard, a sha256 pin, and an oracle that calls the reference library's exported symbols in-process); and its measured results against llama.cpp b11192. For `Q1_0` the kernel is bit-exact on all 1.72 billion weights of a real model and matches or exceeds the reference speed (1.01× decode, 1.10× prefill, single thread; 1.2–1.3× in prefill over prepared activations since 0.0.4, and bit-exact on all 8.19 billion weights of the 8B 1-bit model). For `Q2_0_g64` the reference ships no vectorised x86 kernel at all; bankml's kernel is bit-exact on all 8.19 billion weights of Ternary-Bonsai-8B and 9.5–9.8× faster per projection (12.5× in prefill). Since these products are about 98 % of the reference's time per token, the gap between the better ternary model and the faster 1-bit one is a kernel gap, now closed at the kernel level: with a zero-dependency thread pool, one ternary token's products take 0.23–0.25 s on three threads of a laptop (0.0.3–0.0.6, with the model resident in memory), less than the reference needs for the *1-bit* model's (0.34 s). A measured memory floor (15–17 GB/s) shows both kernels are compute-bound, and five further bit-exact variants measured no reliable gain, which places them at the instruction-throughput limit of the test core (§IV.5). From 0.0.6 the runtime answered through the reference behind its gates (phase P0). Since 0.3.0 it answers from its own forward pass (phase P3), token-identical to llama-server b11192 wherever the release gate compares the two (§IV.4). Every answer carries a receipt with the sha256 of its text, and the conversation's history is committed by a Merkle root and a CID, so it can be proven without being disclosed (§III.6). Custom agents derived from Savante's template are bundled as THOT manifests and minted as iNFTs, the mint prepared and simulated by the runtime and signed by the owner, and loaded back from a token with their lineage verified (§III.7). Every cryptographic construction is checked against a published value. ## Thesis — Professor Codephreak and Gregory L. Magnusson *The design intent this report tests is that of bankml's authors, Professor Codephreak and Gregory L. Magnusson, stated in their own words over the course of the project (Codephreak and Magnusson 2026). It is recorded here as their thesis; the sections that follow measure the work against it. The thesis also stands alone, with its argument, in [thesis.md](thesis.md).* **Port what works, and only what works.** "We prototyped in python and we switch to rust from working architecture" (2026-07-04). bankml was not begun from a design document. It was begun, on the instruction to "create llama.cpp rust version todo as bankml.rs" (2026-09-25), after a working architecture existed and had been measured: a 1-bit Bonsai-8B served by llama.cpp b11192 on a two-core server. The Rust runtime inherits a proven system's behaviour as its specification, which is why exactness against that system's compiled code (§III.4) is its first criterion. **Three design goals: "optimization, succinct, and verified response"** (2026-09-25). Optimization is measured, never quoted; succinctness is a budget (one crate, no runtime dependencies, one static binary); and a verified response is a property of every answer — a model that cannot be verified does not answer (§III.1). **The standing machine is the CPU you already have.** One server has been shown to be enough to power one autonomous AI system, at a running cost of about one dollar a day, with inference drawn from the local CPU and free tiers. A runtime that makes a commodity CPU sufficient is therefore not an optimization of the system; it is the condition of its economics. Accelerators are rented for events, not owned (§I.1). **Consume the inference, and prefer the better answer.** "If there is inference mindX needs to consume it, however long it takes" (2026-09-26); and, for the review office that runs on these models, "a better answer is more important than speed where speed under one minute is fine for now" (2026-09-26). This ordering — quality first, bounded by a latency the use can bear — is why the ternary model, the better and the slower of the two, is the one this runtime must make fast (§I.2). **Know the limit, and code around it.** "They should know limits and be able to code around them" (2026-09-26). For a runtime this reads two ways, both implemented: it knows the limits of what it may load — the guard refuses, with its reason, a file that would load and answer in nonsense, rather than serving it — and where the reference engine is slow, the answer is not to accept the limit but to write the kernel that removes it. **Improve by increments, with the oracle in the loop.** "Audit and improve with three more incremental release pushes focusing on optimization and performance including oracle feedback" (2026-09-28). Each release ran a gate whose record is published (`testing/results/`). A speed counts only when every oracle has passed on the same code, and a variant that is bit-exact but not reliably faster is recorded and not shipped (`testing/experiments/`). The negative results are part of the evidence: they are how the limit of §IV.5 is known rather than assumed. **Use the machine at hand.** "Use this laptop hardware" (2026-09-28). Every measurement in this report was taken on a two-core laptop, and the runtime serves Savante there. Where the machine disturbs a measurement (swap full, other load), the record says so and the measurement is re-run rather than smoothed. **Prove the data; keep the data.** "Localstorage and hash and CID can work as data reference for proof of data while keeping local data private and still verifiable" (2026-09-28). The transcript, the operator's notes and a viewer's layout stay where they were made: on disk, or in the browser's local storage. What travels is a commitment: a sha256, a CIDv1, a Merkle root. Whoever holds the root can check any single exchange they are shown against it, without holding the rest (§III.6). The same construction binds Savante's canon to her iNFT ledger. ### Contributions What this work contributes, stated so each can be checked against the code (file names are in this repository) and the measurements (PERFORMANCE.md). 1. **A verified-response runtime architecture.** A model is admitted only through three gates: a header guard, a provenance pin, and a bit-exactness oracle. Since 0.0.6 every answer carries a receipt: model hash, guard verdict, token counts, timings, and the sha256 of the answer text (`serve.rs`). The contribution is the ordering: correctness is established before speed is measured, and a model that cannot be verified does not answer (§III.1). 2. **A header-only GGUF guard for the three low-bit traps.** From the file header alone, without reading tensor data, the guard returns *play*, *refuse* or *need more* against a named engine. It refuses (1) fork-only types (`PQ2_0` = 142, `PTQ1_0` = 143), which mainline rejects safely; (2) legacy `Q2_0` whose group-128 bytes are filed under type 42, which mainline reads as group-64 — detectable as a size mismatch; and (3) Bonsai 2 `Q2_0` in a rotated basis, which mainline loads and answers in fluent nonsense — the dangerous case, visible only by name. The Python original (vendored as `testing/gguf_guard.py`) and the Rust port (`gguf.rs`) agree JSON-for-JSON on every case (28 of 28 in the 0.1.5–0.2.0 gates, with the real file; 18 of 18 synthetic in the published tree). 3. **Provenance forks and the pin.** The models are forked with provenance to `PYTHAI/Bonsai-8B-gguf-fork` and `PYTHAI/Ternary-Bonsai-8B-gguf-fork`, each with a `FORK.json` recording the upstream revision and every file's sha256; `bankml pin` refuses a file whose hash differs and names both hashes (`sha256.rs`, FIPS 180-4 vectors). 4. **Exactness against the compiled reference, not its source.** The oracle loads the sha256-checked llama.cpp b11192 release and calls its exported symbols in-process on the same bytes (`testing/ggml_oracle.py`). Reading the shipped binary exposed that its compiler contracts multiply-add pairs into single FMA instructions; a source-faithful port disagrees in the last bit. bankml models both reference builds — the haswell build and the baseline x64 build, which themselves disagree on 19 of 762 ternary cases — so the oracle demonstrably distinguishes float orders. 5. **A bit-exact 1-bit (`Q1_0`) kernel at reference speed.** Every weight of two real models (1.72 billion in the 1.7B, 8.19 billion in the 8B) and every recorded dot product match. Decode is level with the reference (0.93–1.13× across releases and thread counts). Prefill is 1.2–1.3× faster through a 1×4 selection tile over prepared activations (`q1_0.rs`, 0.0.4). 6. **The finding that explains the ternary gap.** llama.cpp b11192 ships no vectorised x86 kernel for `Q2_0`: the generic C is renamed to the x86 symbol in `arch-fallback.h`, there is no repack or sgemm case, and the shipped library runs scalar code with 64 integer multiplies per block. The better ternary model is slow for want of a kernel, not because ternary weights are expensive (§III.5). 7. **A bit-exact ternary (`Q2_0_g64`) kernel, 9.5–9.8× the reference.** Two blocks per 256-bit register, the activation re-laid-out once per token so the inner loop has no shuffles, and ggml's float chain kept serial for exactness: all 8.19 billion weights of Ternary-Bonsai-8B and 762 of 762 dot products match, at 9.5–9.8× the reference per projection and 12.5× in prefill (`q2_0.rs`). 8. **A whole-model decode budget and its floor.** Timing one token's worth of every matrix product at the same clock as the reference's own end-to-end benchmark shows those products are about 98 % of its time per token. On a zero-dependency thread pool (`par.rs`) bankml's ternary products take 0.23–0.25 s at three threads, bounding a complete forward pass at about 4 tokens per second against the reference's 0.4 (§IV.3). A measured read-bandwidth floor (§IV.5) shows the remaining time is compute, not memory. 9. **Succinctness as a budget.** One crate, zero dependencies — SHA-256, the GGUF parse, half-precision conversion, a read-only memory map and all kernels are in-crate — so the whole runtime is auditable end to end. 10. **Measurement that travels with the model.** End-to-end baselines on three machines (a laptop, a one-core server, a sixteen-core container), stamped with an independent clock (chronos) and sequenced per request (kairos), and a *carrier test* that grades form and substance separately. It is that test which showed the ternary model gives the better answers — the reason this runtime targets it. 11. **The runtime's first consumers.** The sAGI engine (a code-enforced verdict contract that any OpenAI-compatible backend can carry) and the improve.skill loop (every measured answer an iteration toward a published skill version) are built to run on this runtime; they define what "verified response" must mean in production. 12. **Savante on the runtime, with proof of data** (0.0.6–0.0.8). A gateway (`bankml serve`) answers only for a verified file, and only through an upstream that is serving that file. A Savante UI reads her canon without writing to it and checks it against her iNFT ledger before she speaks. It records each exchange with its timings and receipt, searches the history with RAGE, keeps the operator's notes (`.memory`), and publishes only commitments, with an inclusion proof per exchange (§III.6). 13. **The testing kept with the code.** A release gate, its record for every version, the end-to-end tests, the UI's data-layer tests, and the measured-and-rejected kernels (`testing/`). 14. **Agents from a template, bound for an iNFT, checked against published values** (0.0.9–0.1.0). Custom agents are derived from Savante's template without writing to her canon. Each carries a ledger whose keccak256 doctrine root is built exactly as her binder builds hers (reproducing her published root). A THOT manifest to `sagi.thot_manifest/1` reproduces the spec's three test vectors. A PostgreSQL connector loads an agent only if every byte matches its manifest. The iNFT path mints from the manifest's contentRoot, loads a token back, and walks the THOT lineage to the minted generation, tested end to end on a local EVM (§III.7). 15. **A forward pass of its own, token-identical to the reference** (0.2.1–0.3.0). The tokenizer, the chat template, each operation of a Qwen3 layer, the whole model, all three of ggml's CPU attention kernels and the sampler were each checked against the shipped b11192 binaries or llama-server before the next was built. Since 0.3.0 `bankml serve --native` answers whole conversations with llama-server's text, counts and cache reuse (`native.rs`, `forward.rs`; [oracles.md](oracles.md) §1b–§1d). 16. **llama-server's request surface, reproduced rather than approximated** (0.3.1–0.3.6 released; 0.3.7–0.3.9 unreleased). Ollama's API, a C API, JSON mode and JSON schemas (llama.cpp's grammar engine and schema converter ported), the penalties, then the rest of the default sampler chain, the context limit, slots, the host prompt cache, logprobs and a `q8_0` KV cache. Each was added with a check against llama.cpp's own code or llama-server's answers; where the reference does not fix a result (a restored slot, the order of simultaneous requests), the check is against bankml's own empty-slot answer, and [oracles.md](oracles.md) §5g says so. What has no check yet is refused with the reason (§IV.4). ## I. The problem ### I.1 Low-bit models are memory-bound on a CPU In autoregressive decoding each generated token multiplies every weight matrix by one activation vector. The operation is a matrix–vector product whose arithmetic intensity — operations per byte moved — is fixed by the weight format and is low. By the roofline argument (Williams, Waterman and Patterson 2009), a kernel of low arithmetic intensity is bound by memory bandwidth, not by peak arithmetic, until its working set fits a cache. Quantization to one or 1.58 bits per weight raises the intensity by moving fewer bytes per multiply-accumulate; it does not change the bound's nature. A CPU runtime for such models therefore wins by moving the packed weights through the core with as little overhead per byte as possible, and loses whenever the unpacking or the bookkeeping per block costs more than the bytes saved. ### I.2 The reference implementation leaves a measured gap llama.cpp and its tensor library ggml are the de-facto reference for CPU inference of quantized language models (Gerganov et al., software). Under its release b11192 we measured the two Bonsai-8B variants — the same network quantized two ways — on identical prompts and hardware (PERFORMANCE.md). The ternary model generates **about five to seven times slower** than the 1-bit model (≈0.4 vs ≈2 tokens/s on a four-thread laptop; ≈3.8 vs ≈26 tokens/s on a sixteen-core container), although its file is only twice as large. A factor of two would be explained by bytes; the remainder is not. The ternary model, meanwhile, is the one that gives the better answers in our application: in a structured review task its verdict agreed with its own reasoning where the 1-bit model's did not (PERFORMANCE.md, "Ternary vs 1-bit"). The practical problem is therefore concrete: the more useful model is the one the reference runtime serves poorly. ### I.3 Speed claims without exactness are not comparable A faster kernel that rounds differently is not the same computation. In a quantized network small differences in accumulation order or activation rounding change logits, and a changed logit changes a sampled token, after which two runs diverge completely. Benchmarks that compare kernels without first establishing equality of results compare different functions. We take the stricter position: a kernel is admitted for comparison only when its outputs are *bit-identical* to the reference library's on the same inputs. ## II. Literature ### II.1 Binary and ternary weights The idea of constraining weights to {−1, +1} during training, while keeping real-valued weights for the gradient update, was established by BinaryConnect (Courbariaux, Bengio and David 2015) and extended to binarized activations in Binarized Neural Networks (Hubara et al. 2016). XNOR-Net (Rastegari et al. 2016) introduced a real-valued scaling factor per filter, recovering much of the accuracy lost to pure signs — the ancestor of the per-group scale every modern low-bit format carries. Ternary Weight Networks (Li, Zhang and Liu 2016) and Trained Ternary Quantization (Zhu et al. 2017) added the zero, arguing that {−1, 0, +1} is a far better approximation of a Gaussian weight distribution than two values at a small additional cost in bits. The strongest version of the binary school's claim is not that one bit is enough in general, but that with a learned scale and training in the loop the network adapts to the constraint. Its strain appears at scale: post-training binarization of large networks loses too much, which is why the language-model work that followed trains *through* the constraint. ### II.2 Low-bit language models For transformers the post-training route matured first: LLM.int8() (Dettmers et al. 2022) isolated outlier features to make 8-bit inference lossless at scale, and GPTQ (Frantar et al. 2023) reached 3–4 bits per weight with second-order error compensation. Below that, training-aware methods dominate. BitNet (Wang et al. 2023) trained transformers with binary weights from scratch, and its successor (Ma et al. 2024) argued that ternary weights — "1.58 bits" — match full-precision models of the same size at scale while replacing multiplications with additions. The Bonsai models studied here belong to this lineage: dense Qwen3-8B networks (Qwen Team 2025) distributed as ggml `Q1_0` (1.125 bits per weight, 1.16 GB) and `Q2_0_g64` (2.25 bits per weight on disk, 2.31 GB) files. ### II.3 Runtimes Runtime engineering for these models has taken two directions. Server engines such as vLLM (Kwon et al. 2023) maximize throughput across many concurrent requests on accelerators, chiefly by managing the key–value cache in pages; their gains come from batching and do not transfer to one user on a CPU. The ggml/llama.cpp direction targets exactly that case: a single process, CPU kernels specialized per quantization format and per instruction set, weights memory-mapped from the file. bankml is a contribution to the second direction, with one change of emphasis: exactness against the reference is proven per kernel before speed is claimed, and every answer is meant to carry the evidence of what produced it. ### II.4 The architecture being served Qwen3-8B is a decoder-only transformer using root-mean-square layer normalization (Zhang and Sennrich 2019), rotary position embeddings (Su et al. 2024), grouped-query attention (Ainslie et al. 2023) and a SwiGLU feed-forward block (Shazeer 2020). Of its per-token work, the projection matrices dominate the bytes moved; they are the tensors the low-bit formats compress, and the subject of this report. ## III. The contribution ### III.1 Verified response: three gates before an answer bankml's design goal is stated as a property of every response rather than of the program: *a model that cannot be verified does not answer.* Three gates enforce it. 1. **The guard.** Before any tensor data is read, the GGUF header is parsed and checked against three traps observed in practice — among them files that load in mainline llama.cpp and then answer in fluent nonsense because a tensor type is misidentified. The guard returns *play*, *refuse* (with the reason) or *need more* (bytes); it never falls back silently. Its Rust implementation agrees with the original Python guard on every case, JSON-identical (28 of 28 in the 0.1.5–0.2.0 gates). 2. **The pin.** The file's sha256 (FIPS 180-4) must equal the value recorded in the provenance manifest of the model's fork. A mislabelled file is refused with both hashes named. 3. **The oracle.** A kernel is admitted only when it is bit-exact against the reference library on real tensors (§III.4). Since 0.0.6 a fourth element closes the loop at the answer. `bankml serve` starts only after the guard and the pin pass. It binds the upstream engine to the verified path (it launches it, or checks that the running engine's `/props` names the same file). It attaches a receipt to each answer: model hash, guard verdict, token counts, time to first token, wall time, the sha256 of the answer text (which the client re-computes) and, since 0.1.7, the sha256 of the request it answered and `"signed": false`. Before every answer it re-checks that the model file is still the one it verified (device, inode, size, modification time) and that the engine still serves it, and refuses otherwise. A receipt proves integrity between a client and its own gateway, not to a third party (it is not signed). In P0 the arithmetic was the reference's. Since 0.3.0 `serve --native` puts bankml's own forward pass behind the same receipt, whose `engine` field names it ([modules/serve.md](modules/serve.md), [modules/native.md](modules/native.md)). ### III.2 The Q1_0 format and its arithmetic ggml's `Q1_0` stores weights in blocks of 128: a 16-bit IEEE 754 half-precision scale *d* followed by 16 bytes of signs, least-significant bit first. The storage cost is (16 + 2) × 8 / 128 = **1.125 bits per weight**. A block's weights are *w*ᵢ = *d* · *s*ᵢ with *s*ᵢ ∈ {−1, +1}. The dot product of a block with an activation segment *x* is *d* · (Σ_{sᵢ=+1} *x*ᵢ − Σ_{sᵢ=−1} *x*ᵢ), a signed sum requiring no multiplication by weights at all. ggml does not compute this on real activations: it first quantizes the activation row to `q8_0` (blocks of 32 signed bytes with their own half-precision scale, computed as 127 / max|*x*| with round-half-to-even), and the kernel `ggml_vec_dot_q1_0_q8_0` accumulates integer products of ±1 and signed bytes, applying both scales at the end. To be bit-exact, bankml reproduces both steps: the same activation quantizer, the same integer accumulation, and the same order of floating-point operations on the scales. The last point is not cosmetic. Reading the disassembly of the shipped generic kernel showed that the compiler had fused a multiply and an add into a single FMA instruction, which rounds once instead of twice; a "faithful" C port that rounded twice disagreed with the shipped library in the last bit. The port was made to match the binary, not the source. ### III.3 Mapping the arithmetic to AVX2 On x86-64 with AVX2 the 32 sign bits that meet one `q8_0` activation block are expanded to 32 bytes by a byte shuffle (`vpshufb`), a per-lane bit mask and a byte compare, then combined with the activation bytes and accumulated with `vpmaddubsw` (unsigned × signed bytes, adjacent pairs summed to 16-bit lanes) and `vpmaddwd` (widened to 32-bit lanes). The integer sum of each activation block is converted to single precision and folded into eight float lanes with one fused multiply-add per `q8_0` block, then per `Q1_0` block, and reduced horizontally at the end — the float order of ggml's own AVX2 kernel, which a scalar model (`vec_dot_ref`) reproduces and the AVX2 path must equal bit for bit (`q1_0.rs`, module header). For decoding, the activation block scales are converted from half to single precision once per token rather than once per weight block (`vec_dot_act`), which is where the decode kernel recovers parity with the reference. For prefill — many activation columns against the same weights — a 1×4 tile loads each weight block once and applies it to four columns, amortizing the sign expansion; this is the source of the 1.10–1.16× prefill gain. ### III.4 The oracle: exactness against the compiled reference The oracle loads the reference library's own shared objects (`libggml-base.so`, `libggml-cpu-haswell.so`) from the sha256-checked b11192 release and calls their exported functions through a foreign-function interface on the same bytes bankml reads. It compares: every weight dequantized (all 197 `Q1_0` tensors of a real 1.7-billion-parameter model, 1,719,904,256 weights); activation rows quantized to `q8_0` (788 rows, byte for byte); and dot products (788, bit for bit, against both the AVX2 and the generic paths). Comparing against the *binary* rather than a re-implementation from the source is the methodological core of this work: it catches exactly the class of discrepancy (§III.2, fused rounding) that a source-level port misses. ### III.5 The Q2_0_g64 (ternary) kernel ggml b11192 defines `Q2_0` (read from the tag's source, not inferred) as blocks of 64 weights: a half-precision scale *d* first, then 16 bytes of 2-bit codes, lowest bits first. A code *c* ∈ {0, 1, 2, 3} decodes to (*c* − 1) · *d*, so the format admits {−1, 0, +1, +2} — not strictly ternary; in the real Ternary-Bonsai-8B file the code for +2 never occurs (the observed split is 31 % / 38 % / 31 % / 0 %). The storage cost is (16 + 2) × 8 / 64 = 2.25 bits per weight. As with `Q1_0`, activations are first quantized to `q8_0`, so one `Q2_0` block meets two activation blocks, and the dot product is an integer sum of small codes times signed bytes, scaled at the end. The decisive finding came from reading the build rather than the kernel: **llama.cpp b11192 ships no x86 kernel for `Q2_0`.** In `ggml/src/ggml-cpu/arch-fallback.h` the generic C function is renamed to the x86 symbol, and neither the weight-repacking path nor the sgemm path has a case for the type; the disassembly of the shipped haswell library is scalar code with 64 integer multiplies per block, used for decoding and prefill alike. The five-to-seven-fold gap of §I.2 is therefore not a property of ternary weights but of a missing kernel. bankml's AVX2 kernel places two weight blocks in one 256-bit register and extracts the codes with a shift and a mask. Because integer sums are exact in any order, the activation — not the weights — is rearranged once per token into the layout the weight codes need, removing every shuffle from the inner loop; the float sequence that combines the per-block integer sums keeps ggml's order exactly, including the fused multiply-adds its compiler emits, which is what keeps the result bit-identical. A read-only memory map (`gguf::Mmap`, no dependency) lets the oracle and the benchmarks walk the 2.3 GB file without copying it. The oracle (§III.4) was extended rather than forked: it selects `Q1_0` or `Q2_0` by the file's tensor types. ### III.6 Proof of data without the data The runtime's records are private by default and verifiable by construction. Every exchange is one line in a local JSONL file (`.history`); the operator's notes are another (`.memory`). Each line is a leaf, hashed as sha256(0x00 ‖ line). The leaves form an RFC 6962 Merkle tree: interior nodes are sha256(0x01 ‖ left ‖ right), and the tree is split at the largest power of two, so an odd node is promoted and never paired with itself. Leaves and nodes cannot be confused, and trees of different sizes do not share a root; the tree before 0.1.7 had neither property. The whole file also has a sha256 and a CIDv1: raw codec, sha2-256, base32, the construction Savante's iNFT ledger uses for her canon files. Only these commitments leave the machine. The LAN view shows the root, the count and the CID, never a line. For any single exchange, the UI emits an inclusion proof: the leaf, its index, the tree size, the sibling path and the root, checked as RFC 9162 §2.1.3.2 prescribes. A holder of the root and the count can check that exchange (and detect a changed byte in it) without the rest of the history. The browser's local storage plays the same part on the client side: the viewer's layout stays in their own browser. The tests (`testing/test_ui.py`) check that every proof verifies, that a changed byte or a proof for another record fails, that the CID equals the house implementation's, and that the view's state carries the commitment and none of the content. These commitments are what a THOT dataset bundle carries (§III.7) and what an iNFT's storage reference will point to (§VI). ### III.7 From a template to a token A custom agent is derived, never copied into place. Savante's canon is read as a template. The derived persona gets a new identity, and its token bindings start empty. The ledger commits each file by sha256 and CIDv1, and commits the fifteen clauses its owner may not edit by a keccak256 doctrine root. The construction is the one Savante's binder uses: pointer, 0x1f, canonical JSON, 0x1e, in a fixed order. The keccak256 is written here in the standard library. Two published values anchor it: it reproduces Savante's doctrine root (`0x92fe83eb…`) from her persona, and it agrees with an independent implementation on every input length from 0 to 400 bytes. The agent's dataset is its THOT manifest (`sagi.thot_manifest/1`). The persona and the prompt are core facets. The card, the history and the notes are declared custom facets, the last two committed by digest only, so the manifest can be published without disclosing a conversation. The bundle root, the 64-leaf keccak Merkle tree and the identity follow the specification to the byte: the builder reproduces the specification's own test vectors for three published bundles. Every facet change is a new generation whose parent is the previous manifest's CID. The mint uses the house ERC-7857 contract's `mintOpenAgent`. The token's `contentRoot` is the manifest's contentRoot, which the contract accepts once and never again, and its `metadataRoot` is the keccak256 of the card. The runtime builds and simulates the call, decodes the contract's own errors, and hands the owner an unsigned transaction. It sends only on a local development chain. Loading reads the token's payload, finds the manifest generation with that root, verifies the bundle, and walks the parent links from the agent's current generation back to the minted one. The genesis stays attached; what came after is proven to descend from it. The whole path is tested on a throwaway local chain (deploy, simulate, refuse without the role, mint, read back, refuse a second mint, load, evolve twice and load again). The contract is not deployed on a public chain, and its audit is not yet cleared: a real mint waits for both, and for a wallet with the minter role. ### III.8 Can a binary computer perform a ternary operation? Yes. It does so exactly, because a trit is stored in bits and the operation on it is ordinary integer arithmetic. It cannot store a trit natively, so it pays for the encoding in space. **Information.** A trit carries log₂ 3 ≈ 1.585 bits. A binary memory must spend a whole number of bits on it (two, leaving one of the four codes unused) or pack several trits into one integer. Since 3⁵ = 243 ≤ 256, five trits fit in one byte (1.6 bits per trit), within 1 % of the bound. `Q2_0_g64` takes the simple route. It uses two bits per weight plus a 16-bit scale per 64 weights, 2.25 bits per weight in all, and the fourth code (+2) is legal but never occurs in Ternary-Bonsai-8B (§III.5). The cost is about 0.66 bits per weight over the information bound, which buys decoding by one shift and one mask. **Operation.** A weight *w* ∈ {−1, 0, +1} times an activation *x* is not really a multiplication. It is a selection: add *x*, skip it, or subtract it. The ternary dot product is therefore Σ_{w=+1} *x* − Σ_{w=−1} *x*, the same signed sum as the binary one (§III.2) with a third case that contributes nothing. Binary hardware can compute it in any of several exact ways: - sign-and-add, in which the sign of the code negates *x* and the zero code masks it out; - two bit-planes, a "+1" mask and a "−1" mask, each a popcount or masked sum, subtracted; - an offset code, which is bankml's. The stored code is *c* = *w* + 1 ∈ {0, 1, 2}, so Σ *w*·*x* = Σ *c*·*x* − Σ *x*. The AVX2 kernel multiplies the unsigned codes by the signed activation bytes with `vpmaddubsw`, and then subtracts Σ *x*. That sum depends only on the activation, so it is computed once per token and shared by every weight row (`q2_0.rs`). Every path is integer arithmetic, so the result is not an approximation of the ternary operation; it *is* the ternary operation, and the oracle confirms it to the bit on 762 of 762 products (§IV.2). **What native ternary would add.** Balanced-ternary machines have been built. Setun (Moscow State University, 1958) used {−1, 0, +1} natively, and it is the precedent for the idea. A ternary cell would store 1.585 bits of information where a binary cell stores one, and ternary logic makes negation free. Neither is a question of *possibility*: binary and ternary machines compute the same functions, and each can simulate the other with constant overhead. The choice is one of cost. On a binary CPU, what limits a ternary model is memory bandwidth (§I.1, §IV.5). Packing closer to 1.585 bits per weight would therefore be the next ternary speed-up. Native ternary gates would not. bankml keeps 2 bits because it must read the reference's file format bit for bit. **The binary choice, compared.** `Q1_0` spends 1.125 bits per weight and has no zero: every weight votes, + or −. `Q2_0_g64` spends 2.25 bits and lets a weight abstain. In this application the extra state gives better answers (PERFORMANCE.md, "Ternary vs 1-bit"). Doubling the bits need not double the time, and on this CPU it does not. Once the missing kernel is written, both formats run close to the rate at which memory can deliver their weights (§IV.5). ## IV. Results and testable propositions ### IV.1 Q1_0 On a single thread of an AMD Ryzen 3 3200U the bankml decode kernel runs a 12288×4096 matrix–vector product at 14.32 ns per block against the reference's 14.43 (1.01×, minima; 1.03× at the median), and the prefill tile at 12.95 against 14.22 ns per block-column (1.10×; 1.16× at the median), with every result bit-identical (§III.4). (Later runs on the same laptop at a higher boost clock read about 10 ns per block for both kernels: the ratio is the result.) Since 0.0.4 a 1×4 selection tile over prepared activations (`mat_mul_act`) brings prefill to 1.2–1.3× the reference. The oracle now also covers the 8B 1-bit model: all 254 tensors (8,188,239,872 weights) are bit-exact, as are 762 of 762 rows and dot products. ### IV.2 Q2_0_g64 All 254 `Q2_0` tensors of Ternary-Bonsai-8B — 8,188,239,872 weights — dequantize bit-identically to the reference; 762 of 762 activation rows and 762 of 762 dot products match its haswell build exactly, and a model without fused multiply-adds matches its baseline x64 build in 762 of 762. The two reference builds disagree with each other on 19 of the 762 cases, which shows the oracle distinguishes float orders rather than passing loosely. On a single core, on real layer-0 weights, alternating the two kernels over the same bytes, bankml computes each projection of the model **9.5 to 9.8 times faster** than the reference (e.g. 4.98 against 48.98 ns per 64-weight block for the attention query projection, minima; 9.1–10.6× across four runs), and the prefill tile **12.5 times faster** (3.96 against 48.90 ns per block-column). Full tables are in PERFORMANCE.md. Proposition P2 of §IV.4 is supported: the reference's ternary slowdown is recoverable in the kernel, because it *is* the kernel. ### IV.3 Where the time goes, end to end Timing one token's worth of all 253 ternary matrix products (2.13 GB of weights) in file order, bracketed by the reference's own end-to-end benchmark at the same clock: on three threads the reference spends 2.54–2.64 s of its 2.59–2.68 s per token in these products — about 98 % of the wall — and bankml computes the same products in 0.36–0.37 s, a matmul-bound ceiling of about 2.8 tokens per second against the reference's 0.37–0.39. On one thread the figures are 4.2–4.4 s against 0.49 s. With the persistent thread pool of 0.0.3 (both engines on the same scheduler), the three-thread figure is 0.23–0.25 s against the reference's 2.18–2.36 s (9.2–9.9×), a ceiling of about 4 tokens per second — measured with the model resident in memory, and reproduced on 2026-09-29 on current code: 0.231 s at three threads, 9.45× the reference (docs/PERFORMANCE.md). When other applications leave too little memory to keep the 2.31 GB file cached, the gates measure the disk instead (4.5–5.2 s). That is less time than the reference spends on the *1-bit* model's products (0.34–0.37 s). What remains — attention with a key–value cache, normalisation, rotary embedding, sampling — is the forward pass. When this section was written it did not exist; since 0.2.8 it does, and the ternary model decodes end to end at 2.32–2.41 tokens per second against llama-server's 0.30 on this laptop (three threads, CHANGELOG 0.2.8; §IV.4). ### IV.4 What bankml answers with today, and what remains *Status on 2026-10-06. "Released" means a tagged version up to 0.3.6; "unreleased" means 0.3.7–0.3.9 on the development branch, whose figures come from [CHANGELOG.md](../CHANGELOG.md) and become a gate record in [`testing/results/`](../testing/results/) when the version is cut.* **Where it started.** From 0.0.6 bankml answered through the reference (phase P0): `bankml serve` verified the file, bound the reference engine to it, and put a receipt on every answer. On the laptop a Savante turn under her roughly 300-token system prompt took 125 s, 113 s of it prefill at 2.8 tokens per second in the reference. That was the wall phase P3, bankml's own forward pass, was aimed at. **Released (0.2.1–0.3.6).** | version | what bankml answers with | evidence ([oracles.md](oracles.md)) | |---|---|---| | 0.2.1–0.2.11 | its own Qwen3 forward pass, built op by op: tokenizer, template, layer 0, the whole model, the ternary model, the tiled and split-KV attention kernels, seeded sampling | each step bit-exact against the shipped ggml or token-identical to llama-server | | 0.2.8 | the ternary model end to end: 2.32–2.41 tokens/s decode against llama-server's 0.30 (laptop, 3 threads) | 6 of 6 prompts token-identical | | 0.2.12–0.2.14 | batched prefill; a GPU worker (Vulkan, bankml's own SPIR-V) that takes a share of each 1-bit product | bit-exact on the Vega 3; decode unchanged within noise there | | **0.3.0** | `bankml serve --native`: Savante answered by bankml's own forward pass | 9 of 9 conversation turns identical to llama-server (text, counts, cache reuse) | | 0.3.1 | Ollama's API, a registry of pinned models, one resident | `/api/chat` = `/v1` = llama-server's record | | 0.3.2 | a C API (`libbankml`) with the same verification, answers and receipts | [CAPI.md](CAPI.md); 9 of 9 turns each way | | 0.3.3 | JSON mode and GBNF grammars (llama.cpp's grammar engine, ported) | 1,645 of 1,645 masks; 23 of 23 and 13 of 13 answers | | 0.3.4 | the Llama graph, F16 weights, tied embeddings: Bonsai-1.7B, SmolLM2-135M-Instruct, `mindx-gen39` | 552,268 of 552,268 F16 elements; whole models bit-exact | | 0.3.5 | any JSON schema; `bankml convert` and `bankml create` | 148 grammars byte-identical per template; answers token-identical on five models | | 0.3.6 | the repeat, frequency and presence penalties | 56 of 56 answers on each of three models | Natively, bankml plays the `qwen3` and `llama` architectures in `Q1_0`, `Q2_0_g64` and F16; `forward::plan` refuses everything else from the header, with the reason ([modules/forward.md](modules/forward.md)). Since 2026-10-04 it is the default engine of mindX on its VPS ([BUILD_HISTORY.md](BUILD_HISTORY.md)). On the 1-bit 8B model llama-server was still faster at 0.3.0 (2.8 tokens/s against 1.9–2.0); one paired check after 0.3.4, on a loaded machine, read 2.30–2.59 against 2.33–2.48, which [PERFORMANCE.md](PERFORMANCE.md) records as a hint, not a result. **Unreleased (0.3.7–0.3.9), from the CHANGELOG.** - **0.3.7.** The rest of llama-server's default sampler chain (typical-p, top-n-σ, XTC, dynamic temperature, DRY): 76 of 76 answers token-identical on `mindx-gen39` and on Bonsai-1.7B, 16 of 16 refusals with llama-server's message; Bonsai-8B still to be recorded ([modules/sampler.md](modules/sampler.md)). Mirostat and a custom sampler order are now refused, not ignored. Also: measurement of itself (`/bankml/metrics`, [modules/metrics.md](modules/metrics.md)), a GPU limiter with per-shape calibration ([modules/gpu.md](modules/gpu.md)), and the bankML console ([modules/console.md](modules/console.md)). - **0.3.8.** The serving contract at its edges: the context limit (8 of 8), slot save, restore and erase (19 of 19), one slot with llama-server's host prompt cache (14 of 14, [modules/prompt_cache.md](modules/prompt_cache.md)), and logprobs, streamed or not (14 of 14). - **0.3.9, in progress.** A `q8_0` KV cache with llama.cpp's Hadamard rotation (6 of 6 answers against llama-server with `--cache-type-k/v q8_0`), and the grammar mask through a trie (median 2.94 ms against 38.8 ms per mask, the same 1,645 masks). 1-bit decode speed is still to be measured on an idle machine. **What remains** ([TODO.md](TODO.md)): 1-bit decode at llama-server's speed, measured pinned and idle; tool calls; more than one slot (continuous batching); context shift past `num_ctx`; `Q8_0` weights and Qwen's own template; NEON and AVX-512 kernels; signed receipts. The gate does not depend on the format. The guard reads any mainline type (it names all of ggml's standard types, from `Q4_0` and the K-quants to the `IQ` family and `MXFP4`), and no architecture is allow-listed. So a standard Qwen3, SmolLM or Granite GGUF at `Q4_K_M` or `Q8_0` is served on exactly the terms of a 1-bit Bonsai: it is guarded, pinned to its publisher's sha256, and carries a receipt. Since 0.1.5 the verification reports the architecture and the weight types it checked. The importer (`sAGI/models.py`) brings such files in, and admits only open-source licences. `Q1_0`, `Q2_0_g64` and F16 have bankml kernels proven against the oracle; other formats are answered by the reference engine alone, behind the same gate and receipt (`bankml serve` without `--native`), which is what P0 means. The propositions this report makes testable are stated at the kernel level, with their status: - **P1.** A low-bit kernel proven bit-exact against the compiled reference can match its speed without giving up exactness (supported for `Q1_0`, §IV.1). - **P2.** The reference runtime's ternary slowdown relative to 1-bit exceeds the ratio of their file sizes, so part of it is recoverable in the kernel (§IV.2–IV.3). - **P3.** An end-to-end bankml answer will be token-identical to the reference's at temperature zero on the same prompts, because every kernel it uses is bit-exact — the criterion for phase P3 (supported since 0.2.7 for the 1-bit model and 0.2.8 for the ternary one, greedy; since 0.2.11 also under seeded sampling; since 0.3.0 for whole conversations through the server). ### IV.5 The floor, and the limit of the test core A read of a 768 MiB buffer on the same pool and scheduler as the matrix products measures the laptop's floor: 14.9–17.3 GB/s. Streaming one token's weights therefore takes at least 0.12–0.14 s (ternary) and 0.06–0.07 s (1-bit). Against it, bankml's ternary products run about 2× above the floor at three threads and the 1-bit products (like the reference's) about 5.5× above it. Both are bound by compute, not memory: the ternary kernel moves about 9 GB/s at three threads, and gains 1.8× from one to three threads on two physical cores. Releases 0.0.4 and 0.0.5 tried five bit-exact variants aimed at that compute; all passed the oracle and none shipped: | variant | kernel | speed | reason | |---|---|---:|---| | two blocks per iteration, interleaved FMA chains | 1-bit decode | 1.00× | not latency-bound | | "pair order": one multiply fewer per block | 1-bit decode | 0.84× | the cross-lane extract costs more than the multiply | | two rows sharing the activation | ternary decode | 0.80× | register pressure | | software prefetch, 256–1024 bytes ahead | ternary decode | ±3 % | the hardware prefetcher already follows the stream | | repacked quads (codes contiguous, scales adjacent) | ternary decode | 0.90–1.075× | within noise across two runs | (With the 2- and 4-row 1-bit tiles of 0.0.1, at 0.81–0.99×.) On this Zen+ core the kernels are therefore at their instruction-throughput limit for bit-exact results. The gains still available lie elsewhere: the forward pass, and a core with wider or better-fed vector units. The code of every rejected variant is kept in `testing/experiments/`. ## V. Objections **"Bit-exactness is the wrong target; accuracy is what matters."** The model's accuracy is fixed by its weights; the runtime's only freedom is to compute the same function faster. Any deviation, however small, is a different function whose accuracy is unmeasured. Exactness is what lets speed be compared at all (§I.3). **"A kernel benchmark is not an inference benchmark."** Agreed, which is why PERFORMANCE.md reports the reference's end-to-end numbers beside the kernel numbers, and why §IV.3 measures how much of a token's wall time the matrix products account for. A kernel win that is invisible end to end is reported as such. **"One machine proves little."** The kernel results are from one laptop core; the deciding measurement for the production server (a Zen3 core) is named as open in [TODO.md](TODO.md). Relative results between two kernels on the same core are less sensitive to the machine than absolute rates, but they are not independent of it. **"Why not adopt the reference and contribute upstream?"** The oracle makes that path easy: every bankml kernel is, by construction, a drop-in replacement for a reference function on the same bits. Owning the runtime serves the second goal — a small, single-binary player with receipts — which upstream does not set out to be. ## VI. Future work The plan continues the phases first written in `bankml.rs` (now [BUILD_HISTORY.md](BUILD_HISTORY.md)); each step ends in a measured, reproducible row or is not done. The live list is [TODO.md](TODO.md). Items written here at 0.2.0 that are done since are marked with the version that did them; "unreleased" means 0.3.7–0.3.9. - **P3 — the forward pass, token-identical: done (0.2.1–0.3.0).** A Qwen3 forward in Rust: the GGUF arrays, a byte-pair tokenizer and the chat template, RMSNorm with Qwen3's query/key norms, rotary embedding with the file's YaRN scaling as the reference applies it, grouped-query attention over an f16 key–value cache in all three of ggml's CPU kernels, SwiGLU and llama-server's sampler. Proposition P3 holds (§IV.4). The Llama graph and F16 weights followed (0.3.4). The `q8_0` key–value cache this item first named is unreleased (0.3.9), with llama.cpp's Hadamard rotation, opt-in through `BANKML_CACHE_TYPE=q8_0`. - **P0, done (0.0.6); the swap, done (0.3.0).** `bankml serve` put the reference behind bankml's guard, pin and receipts; `serve --native` put bankml's own kernels behind the same interface. - **The rest of llama-server's request surface.** Released: Ollama's API (0.3.1), the C API (0.3.2), JSON mode (0.3.3), JSON schemas (0.3.5), the penalties (0.3.6). Unreleased: the rest of the sampler chain (0.3.7); the context limit, slots, the host prompt cache and logprobs (0.3.8). Next: tool calls, more than one slot, context shift ([OLLAMA.md](OLLAMA.md), [TODO.md](TODO.md)). - **Commitments on chain.** Receipts carry the answer's sha256 today, and the history is committed by a Merkle root and a CID (§III.6). Next: an optional THOT8 ternary commitment of each output, whose Keccak-256 leaf matches the on-chain `THOTLib.sol`; and signed receipts (an operator key, in a `GPL-3.0-only` module — LICENSING.md). THOT dataset bundles of the history and notes are done (0.0.9). - **Connectors, done on this machine (0.0.9–0.1.0); next, the public ends.** The agent path is done end to end: THOT bundles, PostgreSQL publish and load, and the iNFT mint and load on a local chain. Next: store bundles where a `storageURI` can name them (Arweave through the permanence rungs) and mint on a public chain once the contract is deployed and audited. Embeddings for the vector column are done (bge-m3, 0.1.7). - **Faster 1-bit, if a core allows it.** On the test core every bit-exact 1-bit variant tried (§IV.5) ran at the reference's speed or slower. A core with AVX-512 VNNI (a single-instruction byte dot product) is where the next measurement belongs. - **GPUs, under the same rule.** A Vulkan worker with bankml's own SPIR-V takes a share of each 1-bit product, and a card is used only after `bankml gpu --verify` finds it bit-exact on layer-shaped data (0.2.12–0.2.14). A limit on its memory and time, and per-shape calibration, are unreleased (0.3.7). Next: F16 and ternary kernels on the card, and cards from other vendors, each proven the same way (0.5.0 in [TODO.md](TODO.md); [modules/gpu.md](modules/gpu.md)). - **Real activations in the kernel oracle.** Dump activations from the reference's own forward pass and verify the kernels against them, replacing the kernel oracle's real-weights × synthetic-activations cases. (The whole-model oracles of 0.2.7 on already carry real activations through every layer, against the shipped ggml graph.) - **The production machine and other CPUs.** A Zen3 row on the one-core server — it loads the same haswell build of the reference, so the same scalar ternary path is expected there, which the row will confirm or refute — NEON for ARM (P5, handheld devices), and AVX-512 where present. - **The mindX seam (P4).** The OpenAI-compatible endpoint exists (`bankml serve`, 0.0.6; native since 0.3.0), and so does Ollama's API (0.3.1). Since 2026-10-04 `serve --native` is mindX's default model server on its VPS, in place of Ollama. Next: mindX's inference discovery using it as a provider with receipts, so its inference budget records real usage, and the sAGI engine and the improve.skill loop on it (0.9.0 in [TODO.md](TODO.md)). - **Upstream (prepared in 0.2.0).** Because every bankml kernel is, by construction, a bit-exact drop-in for a reference function, the ternary kernel is offered back to llama.cpp. `upstream/q2_0_avx2.c` is the drop-in in ggml's C, bit-exact against the shipped library on 200,000 of 200,000 random cases and 3.4× its scalar path per row; the pull request is the authors' decision. - **Voice, done (0.1.3–0.1.5).** Savante speaks in her own licence-clean voice (Piper `en_GB-cori-high`, public-domain data, pitched to Jaimla's template), with eSpeak as the fallback; answers read aloud remain future work. ## References Ainslie, J., Lee-Thorp, J., de Jong, M., Zemlyanskiy, Y., Lebrón, F. and Sanghai, S. (2023). "GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints." *Proceedings of EMNLP 2023*. Codephreak, Professor and Magnusson, G. L. (2026). Design directives for bankml and the mindX runtime, recorded in the project (personal communication and project record, 2026-07-04 to 2026-09-28). Courbariaux, M., Bengio, Y. and David, J.-P. (2015). "BinaryConnect: Training Deep Neural Networks with binary weights during propagations." *Advances in Neural Information Processing Systems 28*. Dettmers, T., Lewis, M., Belkada, Y. and Zettlemoyer, L. (2022). "LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale." *Advances in Neural Information Processing Systems 35*. Frantar, E., Ashkboos, S., Hoefler, T. and Alistarh, D. (2023). "GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers." *International Conference on Learning Representations (ICLR 2023)*. Gerganov, G. et al. *llama.cpp* and *ggml* (software). github.com/ggml-org/llama.cpp, release b11192. Hubara, I., Courbariaux, M., Soudry, D., El-Yaniv, R. and Bengio, Y. (2016). "Binarized Neural Networks." *Advances in Neural Information Processing Systems 29*. Kwon, W., Li, Z., Zhuang, S., Sheng, Y., Zheng, L., Yu, C. H., Gonzalez, J. E., Zhang, H. and Stoica, I. (2023). "Efficient Memory Management for Large Language Model Serving with PagedAttention." *Proceedings of the 29th Symposium on Operating Systems Principles (SOSP 2023)*. Li, F., Zhang, B. and Liu, B. (2016). "Ternary Weight Networks." arXiv:1605.04711. Ma, S., Wang, H., Ma, L., Wang, L., Wang, W., Huang, S., Dong, L., Wang, R., Xue, J. and Wei, F. (2024). "The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits." arXiv:2402.17764. National Institute of Standards and Technology (2015). *Secure Hash Standard (SHS)*. FIPS PUB 180-4. Qwen Team (2025). "Qwen3 Technical Report." arXiv:2505.09388. Rastegari, M., Ordonez, V., Redmon, J. and Farhadi, A. (2016). "XNOR-Net: ImageNet Classification Using Binary Convolutional Neural Networks." *European Conference on Computer Vision (ECCV 2016)*. Shazeer, N. (2020). "GLU Variants Improve Transformer." arXiv:2002.05202. Su, J., Ahmed, M., Lu, Y., Pan, S., Bo, W. and Liu, Y. (2024). "RoFormer: Enhanced Transformer with Rotary Position Embedding." *Neurocomputing* 568. Wang, H., Ma, S., Dong, L., Huang, S., Wang, H., Ma, L., Yang, F., Wang, R., Wu, Y. and Wei, F. (2023). "BitNet: Scaling 1-bit Transformers for Large Language Models." arXiv:2310.11453. Williams, S., Waterman, A. and Patterson, D. (2009). "Roofline: An Insightful Visual Performance Model for Multicore Architectures." *Communications of the ACM* 52(4): 65–76. Zhang, B. and Sennrich, R. (2019). "Root Mean Square Layer Normalization." *Advances in Neural Information Processing Systems 32*. Zhu, C., Han, S., Mao, H. and Dally, W. J. (2017). "Trained Ternary Quantization." *International Conference on Learning Representations (ICLR 2017)*.