A scientific-computing stack whose gradients are now provably correct, whose error types are stable by contract, and which just deleted its last C and MPFR dependencies — all in pure Rust.
Today we released SciRS2 0.5.1 — a correctness, API-stability, and Pure-Rust hardening release. Where 0.4.4 built a computer algebra system and 0.5.0 made the GPU story real, 0.5.1 is the release that goes back through the stack and makes the hard parts right: exact spectral gradients, honest device reporting, a stable error contract, and a cleaner pure-Rust dependency tree.
No C. No Fortran. No OpenBLAS. No NumPy/SciPy system dependencies — and now, no MPFR either. 0.5.1 removes the C/MPFR-backed rug, the C-backed rusqlite, and the tokenizers dependency, along with the external either, hex, urlencoding, and data-encoding crates. Arbitrary precision now runs on oxinum-* (scirs2-special’s arbitrary_precision migrated rug → oxinum-float), SQLite runs on oxisql-sqlite-compat, blake3 builds with its no-ASM pure feature, and scirs2-io vendors its own encoding_utils (hex / percent-encode / base64). The default build is, once again, 100% pure Rust — only now there is even less C lurking behind the feature flags.
This is a patch release by number, but a meaningful one: 36,606 tests passing plus 4,999 doc-tests across 29 workspace crates, roughly 3.9 million lines of Rust, 80,800+ public API items, zero warnings (clippy + rustdoc + fmt clean), Apache-2.0.
Why SciRS2 0.5.1 is a game changer
Feature counts are easy. Correctness is hard — and it is exactly where most scientific libraries quietly cut corners. A gradient that silently returns all-zeros, a “GPU context” that fabricates throughput numbers it never measured, an error enum that breaks downstream code the moment you add a variant: these are the bugs that don’t show up in a feature matrix but cost you a week when they bite. 0.5.1 hunts them down.
Concrete 0.5.1 wins:
- Exact autograd gradients for matrix functions. A new
tensor_ops/decomposition_backward.rsmodule lands real, exact spectral gradients:MatrixSqrtBackwardOpvia a Sylvester equation,MatrixLogBackwardOp/MatrixPowBackwardOpvia Daleckii–Krein divided differences, andSVDBackwardOpas a Townsend / Wan–Zhang reduced-SVD VJP with degenerate-singular-value detection. A newTraceBackwardOpgivestraceits exact reverse-mode gradient (gy·Iₙ). - Gradients that used to be wrong are now right.
matrix_sqrt/matrix_log/matrix_power, the SVD component extractors (U / S / Vᵀ), and the linear-solver gradient w.r.t.A(now−grad_b·xᵀ) previously returned all-zeros or wrong shapes. They are corrected and regression-tested. - A restored
#[non_exhaustive]contract. The#[non_exhaustive]attribute onscirs2-core’sCoreErrorhad been lost — silently making future error variants a breaking change. It is restored, and a newcore_error_non_exhaustivecompile-fail test in thescirs2-stability-testscrate now guards the contract forever. - GPU/CUDA honesty. Across scirs2-core, scirs2-linalg, and scirs2-fft, CUDA/GPU paths now report
BackendNotAvailable/NotImplemented/Option<f64>metrics when no real device or measurement exists — instead of returning fabricated contexts, zero/identity results, or invented throughput numbers that silently produced wrong values. - Public Zarr v2/v3.
scirs2-ionow exportspub mod zarr: directory stores, the codec pipeline, and chunk-boundary slice I/O. - A new GPU device-capability query.
GpuDevice::get_info() -> GpuDeviceInfoexposes device name/type, memory, work-group limits, andfp64/fp16support — so you can validate a device before you dispatch to it.
Technical Deep Dive: getting the gradients right
Spectral gradients done properly. Differentiating a matrix function is not the same as differentiating it elementwise. The derivative of A^{1/2}, log(A), or A^p couples every eigen-pair of A, and the textbook-correct formulas are nontrivial. 0.5.1 implements them as written: the matrix-square-root backward solves a Sylvester equation relating the output gradient to the input; the matrix-log and matrix-power backwards use Daleckii–Krein divided differences over the spectrum; and the SVD backward is the Townsend / Wan–Zhang reduced-SVD VJP, complete with detection of degenerate (repeated) singular values — the case where the naive formula blows up. These live in scirs2-autograd’s new decomposition_backward.rs alongside the existing cholesky_backward, lu_backward, qr_backward, and svd_backward primitives, so the whole matrix-factorization family now backpropagates correctly.
Honesty over optimism. The GPU/CUDA cleanup is a philosophy as much as a patch. The old code, when a real device or measurement was missing, would rather return something — a default context, an identity result, a plausible-looking throughput number. That is the worst possible failure mode: it produces wrong answers silently. 0.5.1 changes the contract across scirs2-core, scirs2-linalg, and scirs2-fft so those paths return BackendNotAvailable / NotImplemented or an honest Option<f64> instead. If SciRS2 didn’t measure it, it won’t claim it.
Stability as a feature. The restored CoreError #[non_exhaustive] is small in diff and large in consequence. With it, adding a new error variant in a future release is a non-breaking change — downstream match expressions are required to carry a wildcard _ arm, so they keep compiling. The new core_error_non_exhaustive compile-fail test in scirs2-stability-tests makes that guarantee executable: the contract can no longer be lost by accident.
Pure Rust, deeper. The dependency purge is the quiet headline. rug pulled in GMP/MPFR — C and assembly — for arbitrary precision; scirs2-special’s arbitrary_precision now runs on oxinum-float instead. rusqlite linked libsqlite3; it is replaced by oxisql-sqlite-compat. tokenizers is gone. blake3 now builds with its pure (no-ASM) feature to respect the no-assembly default. And four small encoding crates (either, hex, urlencoding, data-encoding) were replaced by a crate-local Either<L, R> sum type in scirs2-stats and a vendored encoding_utils in scirs2-io. The ecosystem deps moved forward in lockstep: OxiArc 0.3.3, OxiSQL 0.3.1, OxiNum 0.1.2 (plus a new oxinum-complex), OxiH5 0.1.3, OxiZ 0.2.3, OxiCode 0.2.4, and OxiEML 0.1.2.
Getting Started
Add the crate:
cargo add scirs2
A minimal autograd example exercising the corrected matrix-function gradients — build a symmetric positive-definite matrix, take its matrix square root inside the tape, and get an exact gradient back:
use scirs2_autograd as ag;
use ag::tensor_ops as T;
fn main() {
ag::run(|ctx| {
// A small symmetric positive-definite matrix.
let a = T::convert_to_tensor(
ndarray::array![[4.0_f64, 1.0], [1.0, 3.0]].into_dyn(),
ctx,
);
// Matrix square root, differentiated correctly via the
// Sylvester-equation backward (MatrixSqrtBackwardOp).
let s = T::matrix_sqrt(a);
// A scalar objective: the trace of sqrt(A).
// trace now has an exact reverse-mode gradient (gy * I_n).
let loss = T::trace(&s);
// Exact gradient dloss/dA — no all-zeros, no wrong shapes.
let grad = &T::grad(&[loss], &[a])[0];
println!("loss = {:?}", loss.eval(ctx));
println!("dloss/dA =\n{:?}", grad.eval(ctx));
});
}
Every gradient above is exact in 0.5.1 — the same code in an earlier release would have silently returned zeros.
What’s New in 0.5.1
Added
scirs2-autograd:TraceBackwardOp(exact reverse-mode gradient fortrace); newtensor_ops/decomposition_backward.rswithMatrixSqrtBackwardOp(Sylvester equation),MatrixLogBackwardOp/MatrixPowBackwardOp(Daleckii–Krein), andSVDBackwardOp(reduced-SVD VJP).scirs2-neural: new publicmodel_evaluationmodule —ModelEvaluator,EvaluationMetric, classification/regression metrics, cross-validation, statistical-significance utilities.scirs2-core: GPU device-capability query —GpuDevice::get_info() -> GpuDeviceInfo(name/type, memory, work-group limits,fp64/fp16).scirs2-special: closed-form nth-order Bessel derivativesjvp/yvp/ivp/kvp(DLMF 10.6.7, 10.29.5 recurrences, with negative-order reflection).scirs2-optimize: closure-capturing constraints (Constraint::new) and optional analytical constraint Jacobians (Constraint::with_jacobian), used by the interior-point solver (issues #126 / #127).scirs2-io: Zarr v2/v3 chunked-array support is now public (pub mod zarr).scirs2-stats: a crate-localEither<L, R>sum type replacing the externaleithercrate.scirs2-vision/scirs2-datasets/scirs2-optimize: real GPU compute kernels (vision multi-head attention, dataset-generationgpu_dispatch, distributed differential-evolution), all with transparent CPU fallback.
Changed
- Pure-Rust hardening: removed
rug(C/MPFR),rusqlite(C),tokenizers, andeither/hex/urlencoding/data-encoding— replaced byoxinum-*,oxisql-sqlite-compat, a no-ASMblake3, and vendored encoding utilities. - GPU/CUDA honesty: fabricated contexts and invented throughput numbers replaced by
BackendNotAvailable/NotImplemented/Option<f64>across scirs2-core, scirs2-linalg, scirs2-fft. scirs2-spatial: duplicate alpha-shape implementations consolidated into onealphashapesmodule (publicAlphaShapeAPI unchanged).scirs2-python: the Rust crate was renamedscirs2→scirs2_pythonto avoid an rlib name collision — the Python import path staysimport scirs2.- Ecosystem dep bumps: OxiArc 0.3.3, OxiSQL 0.3.1, OxiNum 0.1.2, OxiH5 0.1.3, OxiZ 0.2.3, OxiCode 0.2.4, OxiEML 0.1.2.
Fixed
scirs2-core: restoredCoreError’s#[non_exhaustive], guarded by a newcore_error_non_exhaustivecompile-fail test inscirs2-stability-tests.scirs2-autograd: correctedmatrix_sqrt/matrix_log/matrix_power, the SVD U/S/Vᵀ extractors, and the linear-solver gradient w.r.t.A(now−grad_b·xᵀ); lazyto_ndarrayno longer fabricates dummy[1, 2, 3, …]data (issue #128).scirs2-series: the Augmented Dickey–Fuller test now solves its OLS via a Moore–Penrose (SVD-based) pseudo-inverse, returning a finite statistic and a p-value in [0, 1] for rank-deficient designs.scirs2-special: corrected verified expected values in Bessel (k0_complex,k1) and hypergeometric (hyp1f1,hyp2f1) doctests/tests against SciPy.scirs2-optimize:augmented_lagrangianoptimality measure now includes the constraint-Jacobian contribution to the Lagrangian gradient, aligning convergence with KKT stationarity.
Tips
- Add a wildcard arm to
CoreErrormatches. With#[non_exhaustive]restored, any exhaustivematchoverCoreErrormust include a_ => { ... }arm — that is the whole point, and it keeps your code compiling when new variants land. Thecore_error_non_exhaustivecompile-fail test enforces the contract upstream. - Query the device before you dispatch. Call
GpuDevice::get_info()and check the returnedGpuDeviceInfoforfp64support and work-group limits before sending an f64 GPU workload — it is the cheapest way to avoid a silent precision downgrade or an over-sized dispatch. - Trust the matrix-function gradients now.
matrix_sqrt,matrix_log,matrix_power,trace, and the SVD extractors backpropagate exactly in 0.5.1. If you pinned an earlier version specifically because these gradients were wrong, upgrade and delete your workaround. - Reach for
scirs2_io::zarrfor chunked arrays. The Zarr v2/v3 module is now public — use it for directory-backed, codec-compressed, chunk-sliceable array storage that interoperates with the wider Zarr ecosystem. - The Python import path is unchanged. The internal Rust crate is now
scirs2_python, but Python users keep writingimport scirs2. Nothing changes for downstream Python code. - If you depended on
eithertransitively through scirs2-stats, switch toscirs2_stats::Either— the external crate is gone, replaced by an allocation-free crate-local sum type.
This is the foundation
SciRS2 0.5.1 is the sovereign scientific-computing layer of the COOLJAPAN ecosystem — and a correctness release matters most precisely because so much is built on top of it:
- NumRS2 — NumPy-compatible N-dimensional arrays in pure Rust.
- PandRS — Pandas-compatible DataFrames.
- OptiRS — advanced ML optimizers extending SciRS2.
- ToRSh — a PyTorch-compatible deep-learning framework.
- SkleaRS — a scikit-learn-compatible ML library.
- TrustformeRS — Hugging Face Transformers in pure Rust.
Every one of these inherits SciRS2’s gradients, its error types, and its dependency tree — so when 0.5.1 makes a matrix-function gradient exact, restores an error contract, or deletes a C dependency, the entire stack above it gets more correct and more sovereign at once. The numeric core still rests on OxiBLAS and OxiFFT; verification on OxiZ; arbitrary precision now on OxiNum; compression on OxiARC; storage on OxiSQL and OxiH5. No C. No Fortran. No exceptions in the default build.
Repository: https://github.com/cool-japan/scirs
Star the repo if a scientific-computing foundation whose correctness you can actually trust — pure Rust, no C, no Fortran, no MPFR — is what you’ve been waiting for.
Pure Rust scientific computing — now correct, stable, and sovereign to the core.
— KitaSan at COOLJAPAN OÜ June 25, 2026