Peroxide: a numeric Rust library with R and MATLAB style matrix syntax
Rust numeric library with high performance and friendly syntax
At a glance
- What is it?
- Peroxide is a Rust crate for linear algebra, numerical analysis, statistics and automatic differentiation, with R, MATLAB and Python style macros, and a choice between a pure Rust build and BLAS accelerated backends behind a feature flag. It suits a numerical programmer who wants Rust performance with familiar notation, and it is a single crate rather than a replacement for a full statistics ecosystem.
- Who is it for?
- Peroxide fits a numerical programmer moving to Rust from R, MATLAB or NumPy who wants matrices, decompositions, ODE solvers and forward mode automatic differentiation behind one crate, and it does not fit a project that needs the breadth of a full statistics stack or a maintained plotting and dataframe ecosystem.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 75 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A numeric crate aimed squarely at people arriving from R or MATLAB
Peroxide is a Rust numeric library described in the repository as containing linear algebra, numerical analysis, statistics and machine learning tools with R, MATLAB, Python like macros. The crate description in Cargo.toml is blunter, calling it a comprehensive scientific computation library with familiar syntax.
The problem it solves is stated in the README as a learning and adoption barrier rather than a numerical one. For users familiar with numerical computing libraries like NumPy, MATLAB or R, Rust's syntax might seem unfamiliar at first, which can make it harder to learn and use Rust libraries that rely heavily on Rust's unique features. Peroxide aims to bridge that gap by providing a syntax that resembles the style of popular numerical computing environments.
So the design goal is that a script you would write in MATLAB translates into Rust without a full mental shift. The matrix constructor in the README example is the clearest case, with a MATLAB style literal and an R style literal side by side in the same main function.
#[macro_use]
extern crate peroxide;
use peroxide::prelude::*;
fn main() {
// MATLAB like matrix constructor
let a = ml_matrix("1 2;3 4");
// R like matrix constructor (default)
let b = matrix(c!(1,2,3,4), 2, 2, Row);The two macros are c! for a flat vector and ml_matrix for the semicolon separated MATLAB form, and matrix builds a two dimensional structure with a Row or Column flag. The wider repository shows the same approach continuing into statistics: the repository topics list regression, ordinary differential equations, interpolation, spline, jacobian, determinant, optimization and numerical integration, and the examples directory carries files named for hessian, gradient, integrate, dist, chebyshev, broyden_test and several Lorenz system integrations named after the solvers.
The default build is pure Rust, and the fast build is a different crate graph
The install line in the README comes with an inline comment that answers the first question a Rust numeric user asks.
cargo add peroxide # default profile is pure Rust, no system libraries neededNo system libraries means no BLAS, no LAPACK, no C or C++ or Fortran runtime to install, and it means cross compilation stays simple. That is the point of the default feature, which the README describes as pure Rust with no dependencies of architecture and calls perfect for cross compilation.
Accelerated linear algebra is opt in, through a family of O3 backend flags: O3-openblas, O3-openblas-system, O3-accelerate, O3-mkl and O3-netlib, and the README is explicit that you pick one backend flag. The Cargo.toml shows what that means in dependencies. The blas and lapack crates are optional, and so are blas-src and lapack-src, which are the crates that build the native libraries from source. There is also openblas-src, with a comment in the manifest explaining that it exists only to forward the system feature to the openblas-src instance that blas-src and lapack-src already pull in, which is how the O3-openblas-system variant is assembled.
That is a lot of machinery to bring in for a numerical library, and the README is honest about the trade-off: if you want high performance computation and more linear algebra, choose one of the O3 backend features, and if you do not want to depend on C, C++ or Fortran libraries, choose the default feature.
The other feature flags cover the parts of the ecosystem that are hard to do in pure Rust. plot adds drawing through Python's matplotlib, which means pyo3 is an optional dependency with the auto-initialize feature, so the plot path is a bridge to Python rather than a native renderer. The file format flags are nc for netcdf, csv for CSV and parquet for parquet, all of them optional dependencies of the same name, and all of them operating on the DataFrame type. complex adds complex number support across vectors, matrices and integrals, parallel adds some parallel functions, and serde and rkyv cover the two serialization routes.
prelude and fuga, a choice between convenience and explicitness
Peroxide offers two import styles and the difference is not cosmetic. The README describes prelude as the simple use, and fuga as the way to choose numerical algorithms explicitly.
The example is a norm. In prelude, the call is a.norm(), and the README notes the limitation precisely: it only uses the L2 norm for Vec<f64>, and the Frobenius norm for Matrix. In fuga, you name the norm.
#[macro_use]
extern crate peroxide;
use peroxide::fuga::*;
fn main() {
let a = c!(1, 2, 3);
let l1 = a.norm(Norm::L1);
let l2 = a.norm(Norm::L2);
let l_inf = a.norm(Norm::LInf);
assert_eq!(l1, 6f64);
assert_eq!(l2, 14f64.sqrt());
assert_eq!(l_inf, 3f64);
}In fuga the call is longer, and the README says as much, but the algorithm is stated at the call site instead of being implied by the type.
This is the most Rust-idiomatic thing about the library, and it is also the part that a user arriving from MATLAB will notice first. The default method call is the comfortable one, and the explicit form exists for the cases where a default is wrong. The same split shows up in the quickstart, which uses the fuga import and calls det and inv directly.
One more Rust-idiomatic detail is worth pointing out, because it is the kind of thing that determines whether a port of an R script is pleasant. The matrix indexing uses tuple syntax, z[(0,0)] = 1.0, rather than the double bracket indexing of MATLAB, and the macro c! builds a vector literal.
Automatic differentiation with Jet, and the numerical method catalogue
The numerical content is broad, and two parts of it stand out.
The first is automatic differentiation. The README describes a const-generic Jet<N> type for arbitrary-order forward automatic differentiation, with Dual and HyperDual aliases, an #[ad_function] procedural macro, exact Jacobians through jacobian(), and a Real trait implemented over f64 and over Jet<N>. The examples directory has jet_ad.rs, higher_order_ad.rs, ad.rs, hessian.rs, gradient.rs, broyden_test.rs and clippy_verify.rs, and there is a separate peroxide-ad subcrate in the manifest, version 0.3, so the AD machinery is factored out rather than tangled into the numeric core.
The second is the ODE solver catalogue, which the README organises by method family and states was trait-based since v0.36.0. The explicit methods are Ralston third and fourth order and Runge-Kutta fourth and fifth. The embedded methods are Bogacki-Shampine 3(2), Runge-Kutta-Fehlberg 5(4) and 8(7), Dormand-Prince 5(4) and Tsitouras 5(4), and the implicit method is Gauss-Legendre fourth order. The example filenames match that list exactly, with lorenz_dp45.rs, lorenz_gl4.rs, lorenz_rk4.rs, lorenz_rkf45.rs, lorenz_rkf78.rs and lorenz_tsit45.rs.
The rest of the catalogue covers linear algebra with LU, QR, SVD and Cholesky decompositions, the last three requiring the O3 feature, plus determinant, inverse, block partitioning, reduced row echelon form, eigenvalues and eigenvectors. For numerical analysis there is Lagrange interpolation, cubic, cubic Hermite with Akima and quadratic slope estimation, and B-Spline, and for regression there is gradient descent and Levenberg-Marquardt. The functional programming side covers matrix maps through fmap, col_map and row_map over Vec<f64>.
Citing it, versioning it, and what a pre-1.0 crate number means here
The project takes the academic route to legitimacy, which is unusual for a crate and worth knowing about if you cite it.
There is a JOSS badge pointing at a DOI, a Zenodo badge, and a CITATION.cff file at the top of the repository, plus a paper directory. The README has a Cite Peroxide section in its table of contents. The docs.rs badge and the crates.io badge are also there, and the crate is published on crates.io as peroxide.
The version scheme is the thing to watch. The recent releases are v0.43.1 from 2026-08-02, v0.43.0 from 2026-07-11 and v0.42.0 from 2026-07-06, so this is a project on a 0.x line with frequent minor releases, and the last push was on 2026-08-10. A pre-1.0 crate number in Rust carries a specific meaning: the API is allowed to break on a minor version bump. Three releases in four weeks with version numbers in the forties tells you the project has been iterating heavily and has not yet reached a stability promise.
That is not a criticism so much as a fact to plan around. A project that depends on Peroxide will need to read the release notes when it upgrades, and the repository ships a RELEASES.md and a TODO.md for exactly that purpose.
The licence is dual, MIT OR Apache-2.0, with both LICENSE-MIT and LICENSE-Apache2.0 files in the repository, and the Cargo.toml picks up the crates.io maintenance badge as actively-developed. The dev dependencies are minimal and tell you about the project's own testing: float-cmp for approximate comparisons in tests, and criterion with the html_reports feature for the benchmarks in the benches directory.
Editorial conclusion
Peroxide fits a numerical programmer moving to Rust from R, MATLAB or NumPy who wants matrices, decompositions, ODE solvers and forward mode automatic differentiation behind one crate, and it does not fit a project that needs the breadth of a full statistics stack or a maintained plotting and dataframe ecosystem. Before depending on it, decide which backend you want, because the default feature is pure Rust and enabling an O3 backend pulls in a system BLAS and LAPACK, which changes the cross compilation story, and check the version of the crate you pin against the release notes in RELEASES.md, since the tag sequence shows frequent minor releases and the last push was on 2026-08-10.
Frequently asked questions
How do I add Peroxide to a Rust project?
The quickstart uses cargo add peroxide, and the README notes that the default profile is pure Rust with no system libraries needed. For accelerated linear algebra, plotting, or DataFrame I/O, you enable the matching feature flag such as one of the O3 backend flags, the plot flag, or nc, csv and parquet.
What is the difference between the prelude and fuga modules in Peroxide?
The prelude module is for simple use, where a.norm() gives the L2 norm for a vector and the Frobenius norm for a matrix. The fuga module is for choosing numerical algorithms explicitly, so a.norm(Norm::L1) names the norm at the call site, at the cost of a slightly longer call.
Does Peroxide need BLAS and LAPACK installed?
Not by default. The default feature is pure Rust with no dependencies of architecture, which the README calls perfect for cross compilation. For accelerated linear algebra you pick one O3 backend flag, such as O3-openblas, O3-accelerate, O3-mkl or O3-netlib, and the Cargo.toml shows the optional blas, lapack, blas-src and lapack-src dependencies those flags pull in.
What ODE solvers does Peroxide include?
The README lists explicit methods Ralston 3rd and 4th and Runge-Kutta 4th and 5th, embedded methods Bogacki-Shampine 3(2), Runge-Kutta-Fehlberg 5(4) and 8(7), Dormand-Prince 5(4) and Tsitouras 5(4), and the implicit method Gauss-Legendre 4th. The README notes the solver API has been trait-based since v0.36.0.
What licence is Peroxide released under?
The Cargo.toml declares the licence as MIT OR Apache-2.0, and the repository contains both a LICENSE-MIT and a LICENSE-Apache2.0 file. The current crate version in the manifest is 0.43.1.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/axect-peroxide)Was this useful?