HPC Rust Transformation — porting
adaworldapi/rustynumfeatures into this ndarray fork.
- What: High-performance linear algebra with pluggable BLAS backends (Native SIMD, MKL, OpenBLAS)
- Source:
adaworldapi/rustynum— reference GEMM, SIMD, and FFI implementations - Target: This repo — ndarray fork enhanced with HPC backends
- Rust: stable only — the pinned
rust-toolchain.toml(1.98.1;rust-versioninCargo.tomlis the floor). No nightly features on any default or supported build path.- The one documented exception —
nightly-simd(opt-in, validation-only, since PR #173): a Cargo feature that swaps the SIMD realization forcore::simd(src/simd_nightly/*,#![feature(portable_simd)]) so the realization matrix can witness that backend too. It is never enabled by default, nothing on stable may depend on it, every stable CI row builds without it, and it is exercised only by the dedicated nightly CI rows (nightly-simd-polyfill, thesimd-matrixnightly row) andscripts/masking-parity.sh nightly. Removing the feature would drop that backend from the matrix; enabling it anywhere by default would violate this rule.
- The one documented exception —
This project uses specialized agents in .claude/agents/. Follow these rules:
- Always read
.claude/blackboard.mdbefore starting any task - After completing work, update the blackboard with decisions and loose ends
- Delegate appropriately:
- GEMM kernels, SIMD, memory layout, Backend trait design →
savant-architect unsafecode, FFI audit, benchmarking →sentinel-qa- Embedding ops, distance metrics, vector store bridges →
vector-synthesis - API surface, docs, feature gates, Cargo.toml →
product-engineer - Feature prioritization, gap analysis, phase planning →
l3-strategist
- GEMM kernels, SIMD, memory layout, Backend trait design →
- When encountering
unsafecode, always delegate to sentinel-qa for audit - Write decisions to the blackboard, not just to chat
- Cargo build residue — fan out the Sonnet fleet in the shared checkout (no per-agent worktrees), edit-only; the Opus orchestrator compiles/lints/tests once in the single 7 GB
target/. Opus may run cargo freely. See.claude/rules/agent-cargo-hygiene.md.
- OpenBLAS and MKL are mutually exclusive feature gates. Never both.
- Zero-cost abstractions: generics monomorphize, no
Box<dyn>in hot paths. - Every
unsafeblock needs a// SAFETY:comment. &&-chain a commit to the edit that produces it — never sequence it after. An anchor assertion in an edit script protects the FILE; it does not protect the RECORD. Measured here 2026-09-16: an edit script's assertion fired correctly (a mid-line anchor that did not match), the script aborted, no bad edit landed — and thegit committhat followed it ran anyway, shipping a message claiming two files whilegit show --statshowed one. For one commit a plan was documented as updated while it was not. The narrative remedy (git showthe diff before claiming it) is real but optional;python3 edit.py && git add … && git commit …is mechanical and cannot be forgotten.- All public APIs need
///doc comments with examples. cargo clippy -- -D warningsmust pass.- Every compile runs with
CARGO_PROFILE_DEV_DEBUG=0(operator, 2026-09-16: "use debug 0"). Not a preference — debug info is the disk hog, not the code, and this container's writable allowance is a fixed per-session budget that presents asNo space left on devicemid-link, not as a full disk. Measured here the same day on the identical tree and the identical test run:target/debugis 1.9 GB with debug info and 291 MB without — a 6.5× cut, for a run that passed 2319 tests either way. Export it (plusCARGO_PROFILE_TEST_DEBUG=0andCARGO_INCREMENTAL=0) as ENV, never as a profile edit inCargo.toml: the rule governs the agent's compiles, not the profile a human commits.--releaseis NOT a substitute — it is slower to build and the test runs need the dev path. And because a profile change invalidates the whole cache, deletetarget/debugbefore switching rather than growing a second copy beside it. - All new public
pub fninsrc/simd_*.rsfollows the W1a consumer contract at.claude/knowledge/vertical-simd-consumer-contract.md— struct methods on typed wrappers, closure-parameterized batch primitives, all three backends (AVX*/NEON/scalar) implemented, parity test mandatory, saturating/overflow semantics documented. The Ada stack (lance-graph + downstream) enforces "all SIMD fromndarray::simd" via itssimd-savantagent; missing primitives in ndarray force consumer-side raw-intrinsic violations, so additions here are gating the consumer-side sweep. VPABSB does NOT saturatei8::MIN— see § "VPABSB correction" in the contract doc before implementingsaturating_absor any abs primitive.
When summarizing this conversation, preserve:
- All entries in
.claude/blackboard.md - Current epoch number and loose ends
- Which agents have been consulted and their verdicts
- Any BLOCK findings from sentinel-qa
src/
├── lib.rs # Re-exports, feature gates
├── backend/
│ ├── mod.rs # BlasFloat trait (was planned as LinalgBackend)
│ ├── native.rs # Pure Rust + SIMD microkernels
│ ├── mkl.rs # Intel MKL FFI (feature = "intel-mkl")
│ ├── openblas.rs # OpenBLAS FFI (feature = "openblas")
├── simd.rs # Consumer-facing SIMD module, re-exports all types
├── simd_avx512.rs # AVX-512 type definitions (11 types from rustynum)
├── simd_avx2.rs # AVX2 functions
│ └── kernels_avx512.rs # AVX-512 kernel implementations
├── hpc/ # 55 modules — ALL DONE (880 lib tests)
│ ├── blas_level1.rs # BLAS L1 (dot, axpy, scal, nrm2, asum, etc.)
│ ├── blas_level2.rs # BLAS L2 (gemv, ger, symv, trmv, trsv)
│ ├── blas_level3.rs # BLAS L3 (gemm, syrk, trsm, symm)
│ ├── quantized.rs # BF16 GEMM, Int8 GEMM
│ ├── lapack.rs # LU, Cholesky, QR
│ ├── fft.rs # FFT/IFFT (Cooley-Tukey radix-2)
│ ├── vml.rs # Vector math (exp, ln, sqrt, etc.)
│ ├── statistics.rs # Median, var, std, percentile, top_k
│ ├── activations.rs # Sigmoid, softmax, log_softmax
│ ├── fingerprint.rs, plane.rs, seal.rs, node.rs # Cognitive core
│ ├── cascade.rs, bf16_truth.rs, causality.rs # Truth/cascade
│ ├── blackboard.rs # Typed slot arena
│ ├── bnn.rs, clam.rs, arrow_bridge.rs # Additional crates
│ ├── hdc.rs, nars.rs, qualia.rs, spo_bundle.rs # Cognitive extensions
│ └── ... (27 more modules)
- All "must be ported" items: DONE — see
.claude/blackboard.mdfor full inventory - 880 lib tests passing, 2 doctest failures out of 302
- Build currently fails (exit 101) — needs investigation
- See blackboard for detailed per-module test counts
-
src/hpc/styles/— 34 cognitive primitives (rte, htd, smad, tcp, irs, mcp, tca, cdt, mct, lsi, pso, cdi, cws, are, tcf, ssr, etd, amp, zcf, hpm, cur, mpc, ssam, idr, spp, icr, sdd, dtmf, hkf). Each isfn(Base17, NarsTruth) → result. 49 tests. -
src/hpc/causal_diff.rs— CausalEdge64 (u64 packed), scaffold_to_palette3d_layers(), quality scoring (GOOD/BAD/UNCERTAIN), NARS self-reinforcement LoRA, PAL8 serialization (4101 bytes). -
Build config — the default is
target-cpu=native: it MEASURES THE MACHINE IT RUNS ON, and therefore NAMES NO TIER.⊘ SUPERSEDED 2026-09-16. This bullet read "AVX-512 is NOT the default…
.cargo/config.tomlsetsx86-64-v3(AVX2), deliberately… for AVX-512 you must ask for it, every time." That was accurate for the old default and is now wrong on its main clause. What survives unchanged: v3 IS the portable distribution baseline — it moved out of the unnamed default into.cargo/config-v3.toml, where a row that depends on it says so.Why the flip: a default naming a tier the host is not means every AVX-512 measurement needs an incantation, and a forgotten incantation does not fail — it grades the wrong tier silently. Measured the day of the flip:
scripts/codegen-witness.sh avx512run WITHOUTCARGO_ARGS='--config .cargo/config-v4.toml'built v3 and reported threeFAIL: … has no vpternlog on an AVX-512 buildon probe symbols the change under test never touched. Same command after the flip: PASS, 6 vpternlog.A plain
cargo build/run/testtherefore measures whatever this host is — on an AVX-512 box, AVX-512. So a tier is never inferred from "it was the default"; it is READ from the arm's own report (simd-masking-parityand every probe printavx512f=true|false) or PINNED by the caller:env -u RUSTFLAGS cargo --config .cargo/config-v3.toml <cmd> # portable baseline (AVX2) env -u RUSTFLAGS cargo --config .cargo/config-v4.toml run --release --example <name>
The pin is load-bearing in BOTH directions, measured two-sided the same day on an AVX-512 host:
codegen-witness.sh avx2BARE now FAILS (has no packed logic— it is grading v4 assembly against an assertion that no vpternlog may appear), and PASSES withCARGO_ARGS='--config .cargo/config-v3.toml'. The portable CI row pins it for exactly this reason.env -u RUSTFLAGSis load-bearing: a RUSTFLAGS env var REPLACES every cargo-config rustflags entry, so it silently drops-Ctarget-cpu=x86-64-v4and the arm does NOT measure v4 while claiming to (the trapscripts/masking-parity.shdocuments).⊘ CORRECTED 2026-09-16 (coderabbit, #313). This read "and the arm measures v3". Wrong, and this session's own measurement is what disproves it: RUSTFLAGS replaces every config rustflags entry, so it drops the DEFAULT config's target-cpu too, not just the overlay's. Measured on one unit —
RUSTFLAGS="-D warnings"produced zero-Ctarget-cpuflags, against 65 with the env unset. What you actually get is rustc's own default for the target, i.e. thex86-64baseline (SSE2), which is LOWER than v3 and is the tiersimd_avx2.rs's intrinsics SIGILL on. The sentence was wrong before the native flip as well; the flip only changed which config gets discarded.That same mechanism had silently disabled the whole config in CI, and it is the more serious half (found 2026-09-16).
.github/workflows/ci.yamlsets a workflow-globalRUSTFLAGS: "-D warnings", so none of.cargo/config.toml's flags had ever applied to any job in that workflow — not the target-cpu, and not the two crypto-backend cfgs (curve25519_dalek_backend="serial",poly1305_force_soft) that keep dalek's 57 and poly1305's 424 raw intrinsics OUT of the binary. That is the matryoshka guarantee the config file argues for at length, absent in CI. Measured two-sided on one unit: no RUSTFLAGS → 65×-Ctarget-cpu, 65×poly1305_force_soft;RUSTFLAGS="-D warnings"→ zero of each. Fixed by putting the two arch-neutral cfgs into that global RUSTFLAGS (target-cpu stays out — it is the arch-sensitive part, correctly removed for the i686 / s390x cross rows). The general rule: a config that can be silently replaced is not a guarantee. Before citing any.cargo/config.tomlflag as being in force, check whether the caller sets RUSTFLAGS. Verify the arm you got — the parity program printsavx512f=true|false, and any probe that reports timings should too..cargo/config-avx512.tomlis the stricter Sapphire Rapids EXECUTION config (VNNI/BF16/FP16/AMX) and SIGILLs on earlier AVX-512 silicon;config-native.tomlresolves the host CPUID. (This line previously claimedconfig.tomlwas v4 "AVX-512 mandatory" — it never was, and that error made a whole measurement arc read v3 as v4. Corrected 2026-09-16 against.cargo/config.toml:83.)The v4 config also carries
-D warnings, which makes a DISABLE RUN fail in a way that reads as success. A disable typically removes a use of something; the variable it fed then goes unused;-D warningspromotes that to a hard error; the test binary is never built, so the run emits notest result:line at all. Piped through agrepfor the failing assertion, "did not compile" and "the guard was not load-bearing" look identical — the workspace's known trap (a disable that does not APPLY is indistinguishable from a guard that does not bind) with a second door. Measured 2026-09-16 on thegt_u8_to_masksigned-compare disable: it silently producederror: unused variable: threshold_vand I nearly recorded the falsifier as inert. Always read the disable run's exit status and thetest result:line itself, never only a grep of its assertions — and prefix, don't delete, when a disable orphans a binding. -
src/simd.rs— compile-time AVX-512 dispatch viacfg(target_feature = "avx512f").
scripts/masking-parity.sh takes native | nightly | wasm | wasm-scalar | neon-qemu, and the cross arms are an apt-get away, not an environment
limit. Measured 2026-09-16: neon-qemu failed with a bare
No such file or directory (os error 2) — which reads as "this target is not
available here" and is in fact a missing linker, then a missing
interpreter, in two separate steps:
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user-staticqemu-user alone is NOT enough: the script invokes qemu-aarch64-static,
and the dynamic qemu-aarch64 from qemu-user leaves a second, differently
worded failure (command not found) that looks like a fresh problem rather
than the same one. Install qemu-user-static.
And native is the HOST arm — it names no tier at all.
⊘ SUPERSEDED 2026-09-16. This line read "
nativeis the AVX2 arm, not the AVX-512 one — it takes.cargo/config.toml(v3)". True until the default flipped; false the moment it did, and it is the SAME defect class this whole section warns about — a doc asserting a tier instead of reading the arm's own report. Caught in review, on the PR that caused it.
scripts/masking-parity.sh native builds with the DEFAULT config, which is now
target-cpu=native: on an AVX-512 host that arm is AVX-512, on a v3 host it is
AVX2. So a green native witnesses whatever this machine is — read the
header line to find out which. To witness AVX2 specifically, pin it:
CARGO_ARGS='--config .cargo/config-v3.toml' bash scripts/masking-parity.sh nativeThe AVX-512 arm can also be pinned explicitly, which is what CI does and what you want when the host is not AVX-512:
cd crates/simd-masking-parity
env -u RUSTFLAGS cargo --config ../../.cargo/config-v4.toml run --releaseRead the program's own header line to confirm which arm you actually got
(avx512f=true, neon=true, …) — that line exists precisely because the
config can silently not apply. Five of the six realizations are reachable
without nightly (AVX2, AVX-512, NEON, wasm-simd128, wasm-scalar); only
nightly-simd needs a toolchain this repo does not pin. The same lesson the
sibling lance-graph-java records for the JDK: a stale index or a missing
helper binary reporting absence is not evidence of absence.
- 5 Qwen3.5 models indexed: 685 MB bgz7 from 201 GB BF16 safetensors
- GitHub Release
v0.1.0-bgz-dataon AdaWorldAPI/lance-graph: 41 bgz7 files - 4 diffs: FfnGate dominant (0.6%), v2 reverts v1, K stable at 27B, K shifted at 9B
- SPO Palette Distance: 611M lookups/sec, 1.8 ns/lookup, 388 KB RAM
- 17K tokens/sec (triple model, 4096 heads, Pearl 2³)
- ndarray = hardware (SIMD, Palette, Base17, SpoDistanceMatrices, read_bgz7_file)
- lance-graph = thinking (NarsTruth, NarsEngine, TripleModel, AutocompleteCache)
- causal-edge = protocol (CausalEdge64, NarsTables, forward/learn)
- p64 = convergence highway (both repos meet here)