NumRS2 is a high-performance numerical computing library for Rust, designed as a Rust-native alternative to NumPy. It provides N-dimensional arrays, linear algebra operations, and comprehensive mathematical functions with a focus on performance, safety, and ease of use.
Version 0.4.0 - Major release (2026-06-05): SciRS2 ecosystem updated to v0.5.0; adds skew/kurtosis, F-distribution sampling, instance normalization, BFGS Python optimizer, VECM Johansen fitting, FEM 2D point evaluation; real eigendecomposition via QR iteration with Wilkinson shifts; full Golub–Kahan bidiagonal SVD. Features 128+ SIMD-vectorized functions (AVX2, AVX512, ARM NEON), 3,921+ tests passing, 225,975+ lines of production Rust code, 5,813+ public API items, zero stubs, built on pure Rust SciRS2 v0.5.0 ecosystem.
Array type with efficient memory layout and NumPy-compatible broadcastingNumRS2 includes several optional features that can be enabled in your Cargo.toml:
To enable a feature:
[dependencies]
numrs2 = { version = "0.4.0", features = ["arrow"] }
Or, when building:
cargo build --features scirs
NumRS2 leverages SciRS2-Core (v0.5.0) for cutting-edge performance optimizations:
See the optimization example for usage details.
The SciRS2 integration provides additional advanced statistical distributions:
For examples, see scirs_integration_example.rs
The GPU acceleration feature provides:
For examples, see gpu_example.rs
Numerical Optimization (scipy.optimize equivalent) - BFGS & L-BFGS: Quasi-Newton methods for large-scale optimization - Trust Region: Robust optimization with dogleg path - Nelder-Mead: Derivative-free simplex method - Levenberg-Marquardt: Nonlinear least squares - Constrained optimization: Projected gradient, penalty methods
Root-Finding Algorithms (scipy.optimize.root_scalar) - Bracketing methods: Bisection, Brent, Ridder, Illinois - Open methods: Newton-Raphson, Secant, Halley - Fixed-point iteration for implicit equations
Numerical Differentiation - Gradient, Jacobian, and Hessian computation - Forward, backward, central differences - Richardson extrapolation for high accuracy
SIMD Optimization Infrastructure - 86 AVX2-optimized functions with automatic threshold-based dispatch - 4-way loop unrolling and FMA (fused multiply-add) instructions - ARM NEON support with 42 vectorized f64 operations - Support for both f32 and f64 numeric types
Production-Ready Features - Complete multi-array NPZ support for NumPy compatibility - Zero clippy warnings and zero critical errors - 3,921+ comprehensive tests (default features) - Enhanced scheduler with critical deadlock fix (1,143x speedup) - 225,975+ lines of production Rust code (674 Rust files) - 5,813+ public API items; zero unimplemented stubs
Enhanced Modules - Linear algebra: Extended iterative solvers (CG, GMRES, BiCGSTAB, FGMRES, MINRES) - Mathematical functions: 1,187 lines of enhanced operations - Statistics: 1,397 lines of enhanced distributions and testing - Polynomial operations: Complete NumPy polynomial compatibility - Special functions: Spherical harmonics, Jacobi elliptic, Lambert W, and more
use numrs2::prelude::*;
fn main() -> Result<()> {
// Create arrays
let a = Array::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let b = Array::from_vec(vec![5.0, 6.0, 7.0, 8.0]).reshape(&[2, 2]);
// Basic operations with broadcasting
let c = a.add(&b);
let d = a.multiply_broadcast(&b)?;
// Matrix multiplication
let e = a.matmul(&b)?;
println!("a @ b = {}", e);
// Linear algebra operations
let (u, s, vt) = a.svd_compute()?;
println!("SVD components: U = {}, S = {}, Vt = {}", u, s, vt);
// Eigenvalues and eigenvectors
let symmetric = Array::from_vec(vec![2.0, 1.0, 1.0, 2.0]).reshape(&[2, 2]);
let (eigenvalues, eigenvectors) = symmetric.eigh("lower")?;
println!("Eigenvalues: {}", eigenvalues);
// Polynomial interpolation
let x = Array::linspace(0.0, 1.0, 5)?;
let y = Array::from_vec(vec![0.0, 0.1, 0.4, 0.9, 1.6]);
let poly = PolynomialInterpolation::lagrange(&x, &y)?;
println!("Interpolated value at 0.5: {}", poly.evaluate(0.5));
// FFT operations
let signal = Array::from_vec(vec![1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
// Window the signal before transforming
let windowed_signal = signal.apply_window("hann")?;
// Compute FFT
let spectrum = windowed_signal.fft()?;
// Shift frequencies to center the spectrum
let centered = spectrum.fftshift_complex()?;
println!("FFT magnitude: {}", spectrum.power_spectrum()?);
// Statistical operations
let data = Array::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
println!("mean = {}", data.mean()?);
println!("std = {}", data.std()?);
// Sparse array operations
let mut sparse = SparseArray::new(&[10, 10]);
sparse.set(&[0, 0], 1.0)?;
sparse.set(&[5, 5], 2.0)?;
println!("Density: {}", sparse.density());
// SIMD-accelerated operations
let result = simd_ops::apply_simd(&data, |x| x * x + 2.0 * x + 1.0)?;
println!("SIMD result: {}", result);
// Random number generation
let rng = random::default_rng();
let uniform = rng.random::<f64>(&[3])?;
let normal = rng.normal(0.0, 1.0, &[3])?;
println!("Random uniform [0,1): {}", uniform);
println!("Random normal: {}", normal);
Ok(())
}
NumRS is designed with performance as a primary goal:
NumRS2 provides a powerful expression templates system for lazy evaluation and performance optimization:
use numrs2::prelude::*;
// Create shared arrays with natural operator syntax
let a: SharedArray<f64> = SharedArray::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
let b: SharedArray<f64> = SharedArray::from_vec(vec![10.0, 20.0, 30.0, 40.0]);
// Cheap cloning (O(1) - just increments reference count)
let a_clone = a.clone();
// Natural operator overloading
let sum = a.clone() + b.clone(); // [11.0, 22.0, 33.0, 44.0]
let product = a.clone() * b.clone(); // [10.0, 40.0, 90.0, 160.0]
let scaled = a.clone() * 2.0; // [2.0, 4.0, 6.0, 8.0]
let result = (a.clone() + b.clone()) * 2.0 - 5.0; // Chained operations
use numrs2::expr::{SharedExpr, SharedExprBuilder};
// Build expressions lazily - no computation until eval()
let c: SharedArray<f64> = SharedArray::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
let expr = SharedExprBuilder::from_shared_array(c);
let squared = expr.map(|x| x * x); // Expression built, not evaluated
let result = squared.eval(); // [1.0, 4.0, 9.0, 16.0] - evaluated here
use numrs2::expr::{CachedExpr, ExprCache};
// Automatic caching of repeated computations
let cache: ExprCache<f64> = ExprCache::new();
let cached_expr = CachedExpr::new(sum_expr.into_expr(), cache.clone());
let result1 = cached_expr.eval(); // Computes and caches
let result2 = cached_expr.eval(); // Uses cached result
```rust use numrs2::memory_optimize::access_patterns::*;
// Detect memory layout for optimization let layout = detect_layout(&[100, 100], &[100, 1]); // CContiguous
// Get optimization hints for array shapes let hints = OptimizationHints::default_for::(10000); println!("Block size: {}", hints.block_size); println!("Use parallel: {}", hints.use_parallel);
// Cache-aware iteration for large arrays let block_iter = BlockedIterator::new(10000, 64); for block in block_iter { // Process block.start..blo
$ claude mcp add numrs \
-- python -m otcore.mcp_server <graph>