A computer algebra system that compiles to a single static binary, verifies its own rewrites with an SMT solver, and JITs your symbolic expressions to native code — written entirely in Rust.
Today we released SciRS2 0.4.4 — the release where scirs2-symbolic stops being an expression library and becomes a real computer algebra system, built on a hash-consed EML intermediate representation with an EML-IR-native canonical form, OxiZ-backed SMT verification, and a Cranelift JIT.
No C. No Fortran. No SymPy. No Mathematica license. The whole CAS — the term graph, the canonicalizer, the SMT-certified rewriter, the symbolic-regression engine, the LaTeX exporter — is pure Rust. It compiles to a single static binary, or to WASM, and runs anywhere your code runs. There is no Python interpreter to ship, no proprietary kernel to license, and nothing to phone home.
This is a patch release by number, but a genuinely large feature drop: 0.4.4 ships 36,446+ tests passing across 29 workspace crates, 4.2 million lines of Rust, 80,800+ public API items, zero warnings (clippy + rustdoc + fmt clean), Apache-2.0. The symbolic side alone gained roughly 564 new tests this release, growing to 800+ symbolic tests through the wave series, plus 8 new tests in the autograd symbolic backend.
Why SciRS2 0.4.4 is a game changer
Symbolic mathematics has long been split between two unhappy choices. SymPy is open and friendly but Python-only and slow, with no path to a compiled artifact and an awkward story for embedding inside a high-performance numerical pipeline. Mathematica and the other commercial systems are fast and complete but proprietary, license-gated, and impossible to vendor into a sovereign Rust application. Neither one JITs your expressions to native code, and neither one drops cleanly into a cargo build.
SciRS2 0.4.4 closes that gap with concrete, tested machinery:
- A hash-consed EML intermediate representation.
eml::treegives youEmlNode/EmlTreewith Arc-shared nodes, a thread-local hash-cons table, and a u128 structural hash — so structurally identical subexpressions are physically shared, and equality is a hash comparison. cas::canonicalize— a world-first EML-IR-native canonical form. Seven algebraic rewrite rules (exp(a)·exp(b)→exp(a+b),a^m·a^n→a^(m+n),(a^m)^n→a^(m·n),exp(ln x)→x,ln(exp x)→x,ln(a·b)→ln a+ln b,ln(a/b)→ln a−ln b) run to a fixed point and are idempotent. 32 tests verify thatx+y == y+xand friends.- Real OxiZ QF_NRA SMT verification.
cas::smtwrapsoxiz::Solverandoxiz::TermManager: a structural-hash fast path, then an SMT fallback with real backtracking push/pop, an Ackermann transcendental encoding for 16 operations, and certified rewriting protected by RAII. 18 tests. - Cranelift CPU JIT and a WGSL GPU JIT.
compile::to_jitcompilesLoweredOpto native CPU code with a hash-keyedJitCache;to_jit_autodispatches CPU below ~100k batch and GPU above;compile::to_gpuemits a WGSL compute shader (@compute @workgroup_size(64)). - Symbolic regression with dimensional analysis.
regression::discoversearches for closed-form formulas, andunits::UnitAwareenforces an SI 7-vector so thatT = L + gis rejected whileT = 2π√(L/g)is accepted. - LaTeX export.
eml::to_latexproduces\frac,\cdot,a^{b},\sqrt,\left|\right|, exact\pi/econstants, and\operatorname{arcsinh}— stack-safe on 1000-deep trees.
The float-tape-to-EML gradient parity is below 1e-10 over 12 operations, and the whole EML substrate is a clean-room native implementation with oxieml v0.1.0 parity at 1e-9 tolerance (ADR-0001).
Technical Deep Dive: A CAS built on EML-IR
(a) The EML substrate. Everything starts with eml::tree. An expression is an EmlTree of Arc-shared EmlNodes, deduplicated through a thread-local hash-cons table and keyed by a u128 structural hash. There are 27 canonical EML constructors. For evaluation and compilation, a tree is lowered to a flat LoweredOp IR plus a stack-machine tape via lower/raise, and an iterative stack-machine evaluator runs it over real f64 or Complex64 — iterative, not recursive, so it stays stack-safe even on 543-deep trees. Differentiation is symbolic: eml::grad (along with grad_all, jacobian, and hessian, all public) produces gradient expressions in the same IR, and outward-rounded interval arithmetic is available for rigorous bounds.
(b) cas::canonicalize + cas::smt. Canonicalization applies the seven rewrite rules to a fixed point, idempotently, so two expressions that are algebraically equal converge to the same normal form. Verification lives in cas::smt: the EmlSmtSolver first tries a structural-hash fast path, then falls back to OxiZ’s QF_NRA decision procedure with real backtracking, encoding transcendental functions through an Ackermann scheme for 16 operations. Rewrites can be certified, with RAII guarding solver state. One important detail (and a tip below): always canonicalize before calling the solver — OxiZ 0.2.1’s NLSAT is incomplete on surface commutativity, so the canonical form does the commutativity work the solver shouldn’t have to.
(c) compile::to_jit / compile::to_gpu. Hot symbolic expressions don’t have to stay interpreted. compile::to_jit runs LoweredOp through Cranelift to native CPU code, cached by structural hash in a JitCache. compile::to_gpu emits a WGSL compute shader for batched evaluation on the GPU. to_jit_auto picks between them by batch size — CPU below ~100k, GPU above.
(d) Symbolic regression and cross-crate integration. regression::discover is ndarray-first with a Config builder (max_depth, learning_rate, tolerance, cv_folds, loss, strategy, seed, parallel); discover_multi handles vector targets (Lorenz, double-pendulum) and discover_ode does SINDy-style RHS discovery. Results come back as a regression::Pareto of DiscoveredFormula. Constraints (with_constraints) are SMT-pruned — monotone_increasing, range_bounded, odd_function, even_function, BoundedOutput, Monotonic — and units::{Units, Dimension, UnitAware} provide the SI 7-vector dimensional check. Prediction is NUMA-aware and parallel.
The CAS reaches across the workspace, too. scirs2-optimize gains symbolic::newton (exact symbolic Hessian and gradient via Gaussian elimination), lbfgs_symbolic, trust_region_symbolic, and a Lagrangian/KKT layer (build_kkt, solve_lagrangian_symbolic). scirs2-integrate gets solve_ivp_symbolic (BDF1 with a JIT-compiled symbolic Jacobian) and quad_gauss_legendre_symbolic. scirs2-linalg adds det_symbolic, eigenvalues_symbolic_2x2, condition_number_symbolic, and einsum/einsum_grad. scirs2-stats adds mle_symbolic/mle::derive, and scirs2-neural gains SymbolicActivation/SymbolicLoss and a closed-form RoPE attention logit. The whole thing is clean-room compatible with oxieml (parity-tested) and leans on OxiZ for verification.
Getting Started
Add SciRS2 to your project:
cargo add scirs2
A minimal taste of the new CAS — build f = x² + sin(x), take its symbolic derivative, canonicalize, JIT-compile, and evaluate:
use scirs2::symbolic::{eml, cas, compile};
fn main() {
// Build f(x) = x^2 + sin(x) as an EML expression.
let x = eml::var("x");
let f = eml::add(
eml::pow(x.clone(), eml::constant(2.0)),
eml::sin(x.clone()),
);
// Symbolic gradient: df/dx = 2*x + cos(x).
let df = eml::grad(&f, "x");
// Canonicalize to the EML-IR normal form (fixed-point, idempotent).
let df = cas::canonicalize(&df);
// Lower to flat IR and JIT-compile for repeated evaluation.
let lowered = eml::lower(&df);
let jit = compile::to_jit(&lowered);
// Evaluate df/dx at x = 1.0.
let value = jit.eval_real(&[("x", 1.0)]);
println!("df/dx at x=1: {value}"); // 2*1 + cos(1) ≈ 2.5403
// Or evaluate the symbolic IR directly without compiling.
let direct = eml::eval_real(&df, &[("x", 1.0)]);
println!("direct: {direct}");
}
Everything here — eml::grad, cas::canonicalize, compile::to_jit, eval_real — is real public API in 0.4.4.
What’s New in 0.4.4
The CAS centerpiece
cas::canonicalize: world-first EML-IR-native canonical form with seven rewrite rules, run to a fixed point.cas::smt: real OxiZ QF_NRA SMT integration with certified rewriting and an Ackermann transcendental encoding.compile::to_jit/to_jit_auto/to_gpu: Cranelift CPU JIT plus a WGSL GPU compute-shader JIT, dispatched by batch size.eml::to_latex: publication-ready LaTeX export, stack-safe on deep trees.- Symbolic regression:
regression::discover,discover_multi,discover_ode,Pareto/DiscoveredFormula, SMT-pruned constraints, and SI-unit dimensional analysis.
Bindings and integrations
- Python
scirs2.symbolic: a native PyO3 sub-namespace withPyEmlTree,PyCanonical,PyLoweredOp,PyDiscoveredFormula, andlower/simplify/grad/eval_real/discover— with a GIL-releasingdiscover. scirs2-autogradsymbolicfeature:eml_scalar_op(op, inputs, g)builds a differentiable scalarTensorwhose forward iseval_realand backward is the exact symbolic gradient, composable with stock autograd ops (8 integration tests, parity < 1e-10 over 12 ops).scirs2-optimizesymbolic Newton, L-BFGS, trust-region, and Lagrangian/KKT.eml_pattern!proc-macro DSL in the newscirs2-symbolic-macroscrate (a mini-DSL for rewrite rules, behind themacrosfeature).
Advanced CAS (later waves landing in 0.4.4)
cas::solve/solve_system(Bareiss / Gröbner / transcendental tiers) andcas::solve_odeacross five ODE families (linear first/second-order, separable, exact, Bernoulli).cas::integrate_rational(Risch-LITE rational integration:∫1/x = ln|x|,∫1/(x²+1) = atan(x), partial fractions).cas::series(Taylor + Padé),cas::cse_dag::CseDag(structural-hash CSE DAG with topological eval), and an e-graph equality-saturation engine.cas::moments_catalog/expected_fisher_catalog/noether_conservation(closed-form moments, Fisher information, Poisson-bracket conservation laws), a differential geometry module (Tensor/Metric/christoffel/ricci/einstein/covariant_derivative), an inverse-symbolic calculator, and symbolic matrix ops /expm/ spectral routines.
Non-symbolic algorithm wins
scirs2-integrate: Pantelides index reduction (Hopcroft-Karp O(E√V) plus iterative Tarjan SCC) and Wiktorsson 2001 Lévy-area for SDE strong order 1.5.scirs2-spatial: 2D and 3D Hilbert curve sort (24-state Butz/Hamilton).scirs2-core: NUMA-awarepar_map_chunks(Linux pthread affinity, rayon fallback on Darwin/WASM).scirs2-autograd:ScalarMulOpgradient repair plus JIT fusion (MatmulEpilogue and batched-matmul→reduction).
Tips
- Always canonicalize before
cas::smt. OxiZ 0.2.1’s NLSAT is incomplete on surface commutativity, so runcas::canonicalizefirst and let the normal form handle commutativity — the solver then only sees the hard part. - JIT your hot expressions. If a symbolic expression is evaluated many times, route it through
compile::to_jit(orto_jit_auto). CPU JIT wins below ~100k batch; the WGSL GPU path takes over above it. - Turn on the
macrosfeature to use theeml_pattern!rewrite-rule DSL — it makes custom canonicalization rules far more readable than building EML trees by hand. - Use
units::UnitAwarein symbolic regression to reject dimensionally inconsistent candidates. It is the cheapest way to keep the search from proposingT = L + g. - Export with
eml::to_latexto drop results straight into papers and notebooks — exact\pi/econstants and\operatorname{...}for the inverse-hyperbolic functions. - Enable the
symbolicfeature onscirs2-autogradso symbolic gradients compose with normal autograd tapes viaeml_scalar_op— forward iseval_real, backward is the exact symbolic gradient.
Part of the COOLJAPAN ecosystem
SciRS2’s new CAS doesn’t stand alone. Verification runs on OxiZ, our pure-Rust SMT solver, through its QF_NRA decision procedure; the JIT is built on Cranelift; the EML substrate is a clean-room, parity-tested twin of oxieml; and the numeric core continues to rest on OxiBLAS and OxiFFT for pure-Rust linear algebra and transforms. Around it sit the rest of the COOLJAPAN peers — torsh, optirs, numrs, pandrs, sklears, and trustformers — so symbolic math, numerics, dataframes, classical ML, and deep learning share one sovereign, C-free, Fortran-free foundation.
Repository: https://github.com/cool-japan/scirs
Star the repo if a pure-Rust computer algebra system — one you can vendor, JIT, verify, and ship as a single binary — is something you’ve been waiting for.
Pure Rust computer algebra is here — fast, safe, verifiable, and sovereign.
— KitaSan at COOLJAPAN OÜ May 15, 2026