Repository navigation
feat(rust): expression graph, typed IR, evaluator and forward-mode AD - #5956
Open
BradyPlanden wants to merge 1 commit into
Open
BradyPlanden wants to merge 1 commit into
BradyPlanden wants to merge 1 commit into
Conversation
This was referenced Oct 22, 2026
This was referenced Oct 22, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5956 +/- ##
=======================================
Coverage 98.23% 98.24%
=======================================
Files 350 350
Lines 36104 36104
=======================================
+ Hits 35468 35469 +1
+ Misses 636 635 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
BradyPlanden
force-pushed
the
stack/01-rust-core-graph
branch
from
October 28, 2026 09:55
591ec68 to
96e653a
Compare
BradyPlanden
force-pushed
the
stack/01-rust-core-graph
branch
from
October 28, 2026 15:28
96e653a to
1923d05
Compare
The packages/pybamm-rust cargo workspace with the first pybamm-core layer: arena, typed IR, scalar and lane-batched interpreters, conditional branch regions, rewrite passes and forward-mode tangents. Nothing in Python uses it yet. CI gains rust_tests and rust_msrv; pre-commit gains cargo fmt/clippy.
BradyPlanden
force-pushed
the
stack/01-rust-core-graph
branch
from
October 29, 2026 08:01
1923d05 to
73c0262
Compare
BradyPlanden
marked this pull request as ready for review
October 29, 2026 08:55
Contributor
|
| Project | PyBaMM |
| Branch | stack/01-rust-core-graph |
| Testbed | bare-metal |
🐰 View full continuous benchmarking report in Bencher
⚠️ WARNING: Truncated view!The full continuous benchmarking report exceeds the maximum length allowed on this platform.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds
pybamm-core, a Rust crate in a new Cargo workspace atpackages/pybamm-rust, which compiles a PyBaMM expression into a tape and evaluates it. This PR is the compiler on its own: an arena DAG, rewrite passes, forward-mode differentiation, a typed slot-addressed IR, and scalar and lane-batched interpreters. Nothing in Python uses it yet; the bindings arrive in #5958 andSymbol.to_rustin #5959.Arenais append-only and stores every child before its parent, so a graph is acyclic by construction, and deserialising one re-checks the order.Nodehas 51 kinds. Its checked constructors (state_vector,state_vector_dot,index,conditional,interpolant_nd, andtry_newon the matrix and interpolant data) return aCoreErrorrather than build an invalid node. A 1D linear table may repeat an interior knot, which makes a right-continuous step as in CasADi, but not its first or last knot; cubic and N-D tables need strictly increasing breakpoints.ParamRegistryis the one place an input parameter's registration index and packed slot are decided, through typedParamIdx,ParamSlotandPackedWidth. It sits outsideArenabecause the rewrite passes build fresh arenas.simplify_pipelineruns CasADi-style folds, shape-aware zero propagation, and CSE on a bitwise structural hash. A constant power is rewritten asx*xor1/xonly for the exponents where that takespow's value bitwise (0, 1, 2 and −1). Folds such as0*xandx/xreturn 0 and 1 where the original gives NaN (0*inf,0/0), so the rewrites keep values where every intermediate is finite, up to the sign of zero.tangent_wrt_states,tangent_wrt_paramsandtangent_wrt_subsetbuild forward-mode JVP graphs. Step functions, the Heavisides and derivative-only nodes differentiate to 0, so there are no second derivatives, andModuloignores its jumps.tangent_wrt_subsetis public here, and feat(rust): sparsity, coloured Jacobians, compiled models and the C ABI #5957 narrows it to the crate once the Jacobian builder calls it.TypedIris a tape of 24-byte instructions with a constant pool and a liveness-based slot allocator.CompiledExprevaluates through&selfinto caller-owned scratch, so one compiled tape can be shared across concurrent solves. The scalar interpreter runs only the active branch of a top-levelConditional, provided privatising its branches stays within 4× the node count; over that budget it still skips the nodes only one branch owns.eval_batchevaluates K lanes of values andrun_tangent_batch4 or 8 lanes of tangents, both bitwise equal to the scalar interpreter. The batched interpreter runs every branch block that some lane selects.minimum/maximumare evaluated through thelibmcrate, not the platform's maths library.rust-version = "1.89", has nounsafe, and depends onrustc-hash,thiserrorandlibm, plusserdeandbincodebehind aserializefeature. Clippy'spedanticandnurserylints warn andcorrectnessdenies.suboptimal_flopsis allowed, becausemul_addrounds once and so breaks CasADi parity; on baseline x86-64 wheels it is also a slow libm call.CI gains
rust_msrv(cargo +1.89 check --locked --all-targets --all-features) andrust_tests(cargo test --locked --workspace --all-features), both required byci_gate, andpackages/pybamm-rust/**joins thepybammpath filter. Pre-commit gainscargo fmtandcargo clippy --all-targets --all-features -- -D warnings, as checks rather than--fix, sincecargo clippy --fixexits 0 even when-D warningsfires. They run through.github/scripts/run_cargo.py, which skips them with a message wherecargois not installed, and pre-commit.ci skips them. Thestylejob therefore now runscargo fmtandcargo clippy, on a pinned Rust 1.99.1 so that a new stable release's lints cannot break CI. The rootpyproject.tomlexcludespackages/pybamm-rustfrom the uv workspace.TypedIr::from_dagandCompiledExpr::newmay panic on a graph thatvalidaterejects, so callers validate first.validaterefuses anInputParameterwhose packed slot ends pastu32::MAX. The left operand of aMatMulmust be a constant matrix. Scalarevaldoes no length checks; callers size their buffers fromscratch_lenandReadExtents.Review on #5732
try_news are innode.rs, and the bindings in feat(rust)!: ship pybamm.rust in the pybamm wheel #5958 call them.input_mapandinput_widthsas one struct:ParamRegistry.CompiledExprhas no interior mutability and evaluates through&selfinto the caller's scratch.Type of change
New feature, under
## FeaturesinCHANGELOG.md.Key checklist
pre-commit run, includingcargo fmtandcargo clippy--all-features, including 2 doctests)cargo +1.89 check --locked --all-targets --all-featureslibmon every path, withlibm's outputs pinned. Proptests check that batched evaluation equals scalar evaluation bitwise, that a slot-reusing layout equals the SSA layout, that CSE is bitwise exact and the folds exact where every intermediate is finite, that split evaluation equals monolithic, and that 4- and 8-lane tangent batches equal scalar tangents, with a fixed case for a zero-width node. Acompile_faildoctest proves a split expression cannot be batch-evaluatedRust execution engine stack: proposal #5667, showcase #5732
Each PR is one commit on the one above it.
Function.create_copykeeps the function's classRegPowerand uniform-grid interpolant lookups matchevaluatepybamm-core: expression graph, typed IR, interpreters, forward-mode AD ← this PRpybamm-core:CompiledModel, coloured Jacobians, the C ABIpybamm.rustbindings, built into thepybammwheelSymbol.to_rustconvert_to_format = "rust"forScipySolver,AlgebraicSolverand EISpybammsolvers: IDAKLU over the C ABIIDAKLUSolveron rust modelspybamm-core: diffsol DAE solverpybamm.DiffsolSolver"rust"as the defaultconvert_to_format