franken_numpy: FrankenNumPy: Rebuilding NumPy in Safe Rust, Then Proving It Against NumPy Itself
A clean-room array library with one unusual rule: every edge case has to survive a live oracle check, a conformance ledger, and a zero-unsafe codebase.

Memory-safe, clean-room NumPy reimplementation in Rust. Zero unsafe code. 2,358 tests. Bit-exact RNG parity. Every feature family green.
- FrankenNumPy turns compatibility into a measured property by checking Rust outputs against a live NumPy oracle.
- Its stride engine matters because it rejects illegal array transformations before they become silent semantic drift.
- Strict and hardened mode split fidelity from resilience, which lets the project serve both parity work and safer deployment.
- The repo's evidence trail makes correctness feel auditable, not just asserted.
FrankenNumPy's most interesting move is not that it is written in Rust. It is that it refuses to trust its own behavior unless NumPy agrees.
That turns migration into verification. The project is less a port than a system for proving that a new implementation has not drifted from the old one.
Why NumPy parity is a harder problem than it looks
NumPy compatibility is hard because the visible API is not the real challenge. Broadcasting, dtype promotion, stride semantics, NaN propagation, reshape legality, and random-number behavior all hide tiny rules that real code depends on.
Miss one edge case and you do not get a slightly imperfect replacement. You get code that appears fine until a legacy workload leans on the exact corner you missed.
Inside the Stride Calculus Engine
The Stride Calculus Engine reads like a bureaucracy, but that is the point. Before FrankenNumPy lets an array view, reshape, or broadcast exist, it checks whether the transformation is legal and deterministic.
That fail-closed posture is what keeps the library from pretending that an ambiguous transform is safe. In a numerical stack, maybe is just another word for latent corruption.
#![forbid(unsafe_code)]
The zero-unsafe rule is not cosmetic. It pushes more reasoning into the type system and more invariants into the design, but it also makes the memory-safety claim legible to anyone reading the code.
The conformance harness is the real product
If the stride engine is the skeleton, fnp-conformance is the pulse. It captures a fixture, runs it through FrankenNumPy and a live NumPy process, compares the outputs, and writes the result into parity reports and evidence artifacts.
That artifact trail matters because the project is not only chasing a passing test. It is preserving the history of how a result was reached, which edge case was exercised, and what the oracle returned when the answer was not obvious.
Strict mode, hardened mode
The runtime split is a good example of FrankenNumPy's temperament. Strict mode is there for exact behavioral fidelity. Hardened mode keeps the same core, then adds guardrails for bounded defensive recovery.
That is a serious trade. Strict mode serves compatibility debugging and parity work. Hardened mode serves deployments that want a safety envelope without pretending every input is well-behaved.
| Dimension | Strict mode | Hardened mode |
|---|---|---|
| Behavioral target | Match NumPy as closely as possible | Match NumPy plus protective recovery |
| Failure handling | Surface the same edge-case behavior as the oracle | Intervene with bounded defensive checks |
| Best for | Compatibility debugging and parity work | Riskier deployments that still want NumPy semantics |
| Tradeoff | Less flexibility, more exactness | More resilience, more policy |
What FrankenNumPy is really competing with
The real comparison is not with every Rust array crate. FrankenNumPy sits between a source-of-truth Python library and native Rust tools. Its job is to make old NumPy code safer without making it think differently.
That means it is competing on migration cost, not just on performance charts. For teams with large Python estates, the question is whether semantics survive the move.
| Project | Primary user | Compatibility goal | Safety model | What it is not |
|---|---|---|---|---|
| FrankenNumPy | Python teams migrating numerical code | Drop-in NumPy parity with live oracle checks | Safe Rust, zero unsafe code | Not a faster NumPy clone or a dataframe engine |
| NumPy | Scientific Python users | Baseline behavior and ecosystem standard | Legacy C, C++, and Python runtime | Not memory-safe by construction |
| ndarray | Rust developers | Ergonomic n-dimensional arrays in Rust | Native Rust safety model | Not a Python drop-in |
| Polars | Data and analytics teams | Fast dataframe and query workflows | Rust core with Python bindings | Not a NumPy parity project |
Built like an audit trail
The most distinctive thing about FrankenNumPy may be the paperwork around the code. Parity reports, logging contracts, and durability sidecars turn each run into a record that can be inspected later, not just a transient CI result.
That is where the project stops looking like a library and starts looking like forensic engineering. The evidence trail is not decoration. It is the mechanism that makes the compatibility claim credible.
FrankenNumPy's ambition is simple to state and difficult to fake. It wants the safety of Rust, the semantics of NumPy, and a chain of evidence for every hard edge between them.