peroxide

repository·master·Indexed 20 days ago

https://github.com/axect/peroxide

A high-performance Rust scientific computation library providing tools for linear algebra, numerical analysis, statistics, and machine learning. It features a syntax familiar to R, MATLAB, and NumPy users and covers domains including ODE solvers, adaptive quadrature, spline interpolation, root-finding, high-order forward-mode automatic differentiation, and DataFrame I/O (CSV, NetCDF, Parquet). Supports hardware-accelerated linear algebra via BLAS/LAPACK backends and plotting via matplotlib.

Tokens
18K
Snippets
73
Records
94
Agent score
71%

What's inside peroxide

  1. Overview of Peroxide capabilities

    master

    Peroxide is a comprehensive numerical library including:

    • Linear Algebra: Matrix structures, LU/QR/SVD/Cholesky decompositions, eigenvalues/vectors, and determinants.
    • Automatic Differentiation: Forward AD using Jet<N> (aliases Dual, HyperDual) and the #[ad_function] macro.
    • Numerical Analysis: Interpolation (Lagrange, Splines), Non-linear regression (Gradient Descent, Levenberg-Marquardt), ODE solvers (Explicit/Implicit), and Root finding.
    • Statistics: Probability distributions, RNG algorithms, and ordered statistics.
    • DataFrame: Mixed-type columns with support for CSV, NetCDF, and Parquet I/O.
    • Functional Programming: Matrix mapping via fmap, col_map, and row_map.
  2. Core domains covered by Peroxide

    master

    Peroxide is an integrated numerical computing library that covers eight primary domains in a single crate:

    • Linear Algebra: Matrix operations and storage.
    • ODE Solvers: Ordinary Differential Equation integration (including fixed-step, adaptive pairs, and implicit methods).
    • Adaptive Quadrature: Numerical integration.
    • Spline Interpolation: Cubic, cubic Hermite, and B-spline interpolation with exact polynomial calculus.
    • Root-finding: Solving for roots in univariate and multivariate systems.
    • Automatic Differentiation (AD): High-order forward-mode AD using Taylor-mode propagation.
    • Statistics: Probability distributions with sample, pdf, and cdf methods.
    • DataFrame I/O: Multi-format support for CSV, NetCDF, and Parquet.
  3. Overview of Peroxide-num traits

    master

    The peroxide-num crate provides a set of traits for mathematical computations, enabling generic programming for numeric types. It covers basic arithmetic, powers, trigonometry, and exponential/logarithmic functions.

    Key traits include:

    • PowOps: Operations for powers and roots (e.g., powi, powf, pow, sqrt).
    • TrigOps: Trigonometric functions (e.g., sin, cos).
    • ExpLogOps: Exponential and logarithmic functions.
    • Float: A trait to define custom floating-point types (standard f32 and f64 are provided by default).
    • Numeric: A comprehensive trait that aggregates all the above traits along with standard arithmetic operations (Add, Sub, Mul, Div, Neg).
  4. Understand Peroxide's validation and accuracy

    master
    Peroxide's Automatic Differentiation (AD) module uses Jet<N> types to achieve machine-epsilon relative errors ($\sim 10^{-15}$) for orders $N=1$ through $10$. This is verified against symbolic reference values. Note that central finite differences are less accurate, degrading to $O(1)$ by order four due to truncation and cancellation trade-offs. ODE integrators are validated against analytic solutions.
  5. How Spline Calculus works in Peroxide

    master

    Peroxide provides cubic, cubic Hermite, and B-spline interpolation. Unlike many other libraries, it supports exact symbolic calculus on these splines:

    • PolynomialSpline trait: Exposes the polynomial_at(x) method, which returns the specific Polynomial governing a given interval.
    • Calculus trait: Enables symbolic operations on splines. You can call .derivative() to return a new spline representing the analytic derivative, or .integrate((a, b)) to evaluate the exact definite integral via antidifferentiation rather than finite differencing.
  6. How Automatic Differentiation (AD) works in Peroxide

    master

    Peroxide implements high-order forward-mode automatic differentiation using the Jet<N> type.

    • Jet<N>: A const generic type that stores a function value $c_0 = f(a)$ and $N$ normalized Taylor coefficients $c_k = f^{(k)}(a)/k!$.
    • Efficiency: By storing pre-divided coefficients, Peroxide achieves $O(N^2)$ Taylor-mode propagation and avoids factorial overflow at higher orders.
    • #[ad_function] macro: Provided by the peroxide-ad crate, this procedural macro transforms a standard function fn(f64) -> f64 into versions that accept Jet<N>, automatically generating first- and second-derivative functions.
    • Real trait: This trait abstracts over f64 and AD (e.g., Jet<2>), allowing the same function code to compute both values and derivatives seamlessly.
  7. How Peroxide's dual-module API works

    master

    Peroxide provides two ways to interact with its numerical algorithms, allowing you to choose between ease of use and explicit control:

    1. prelude module: Provides sensible defaults for most operations. This is ideal for quick tasks where you want the library to choose the most appropriate algorithm and tolerance automatically.
    2. fuga module: Allows for explicit algorithm selection. Use this when you need to specify a particular method (e.g., a specific quadrature order or an ODE integrator) to match your scientific requirements.

    This design addresses Rust's lack of default function arguments by providing two distinct entry points for the same functional tasks.

    // Using prelude for sensible defaults (e.g., Gauss-Kronrod G7K15R, tol = 1e-4)
    use peroxide::prelude::*;
    let area = integrate(|x| x.sin(), (0.0, std::f64::consts::PI));
    
    // Using fuga for explicit algorithm selection
    use peroxide::fuga::*;
    use std::f64::consts::PI;
    let area = integrate(|x| x.sin(), (0.0, PI), GaussLegendre(15));
  8. Choose between `prelude` and `fuga` coding styles

    master

    Peroxide offers two distinct ways to interact with its API depending on your needs for simplicity vs. explicit control:

    1. prelude (Simple/High-level)

    Best for quick computations. It uses sensible defaults for many operations. For example, calling .norm() on a vector defaults to the L2 norm.

    2. fuga (Explicit/Numerical)

    Best for scientific precision where you need to specify exact algorithms or norms. You must explicitly pass the desired type, such as Norm::L1 or Norm::LInf.

    Example Comparison (Norms):

    // Using prelude (L2 is default for vectors)
    use peroxide::prelude::*;
    let l2 = a.norm();
    
    // Using fuga (Explicitly choosing the norm)
    use peroxide::fuga::*;
    let l1 = a.norm(Norm::L1);
    let l_inf = a.norm(Norm::LInf);
    # Using prelude (L2 is default for vectors)
    use peroxide::prelude::*;
    let l2 = a.norm();
    
    // Using fuga (Explicitly choosing the norm)
    use peroxide::fuga::*;
    let l1 = a.norm(Norm::L1);
    let l_inf = a.norm(Norm::LInf);
  9. Quickstart: Basic Matrix Operations

    master

    Peroxide provides R and MATLAB-style macros for easy matrix construction and arithmetic. Use #[macro_use] extern crate peroxide; to enable these macros.

    Key functions:

    • ml_matrix("..."): Creates a matrix from a string literal (MATLAB/R style).
    • c!(...): Creates a vector or matrix from a list of elements.
    • .print(): Pretty-prints the matrix or vector to the console.
    • .det(): Calculates the determinant.
    • .inv(): Calculates the inverse.
    #! [macro_use]
    extern crate peroxide;
    use peroxide::fuga::*;
    
    fn main() {
        // R / MATLAB-style matrix literals
        let a = ml_matrix("1 2; 3 4");
        let b = c!(5, 6);
    
        // matrix-vector product
        let c = &a * &b;
    
        a.print(); // pretty-formatted matrix
        c.print(); // [17, 39]
        a.det().print(); // -2
        a.inv().print();
    }
  10. Cite Peroxide in research or projects

    master

    If you use Peroxide in your research or projects, you can cite the project using its DOI via Zenodo. Citation information is available in BibTeX, RIS, and APA formats on the Zenodo page.

    https://doi.org/10.5281/zenodo.10815823
  11. Configure hardware-accelerated linear algebra (O3)

    master

    To enable hardware-accelerated linear algebra (LU, QR, SVD, Cholesky, GEMV/GEMM dispatch), you must enable one of the O3 convenience flags. These flags link to blas and lapack FFI crates.

    FlagBackendRequirements
    O3-openblasOpenBLAS (compiled from source)C + Fortran toolchain, make, network access
    O3-openblas-systemSystem-installed OpenBLASpkg-config + OpenBLAS system package
    O3-accelerateApple AcceleratemacOS only
    O3-mklIntel MKLIntel's redistributable (fetched automatically)
    O3-netlibNetlib referencecmake + Fortran toolchain (lowest performance)

    Installing System OpenBLAS for O3-openblas-system

    If using O3-openblas-system, install the package for your platform:

    • Debian / Ubuntu: sudo apt install libopenblas-dev
    • Fedora / RHEL: sudo dnf install openblas-devel
    • Arch Linux: sudo pacman -S openblas
    • macOS (Homebrew): brew install openblas
    cargo add peroxide --features O3-openblas
  12. Implement the Numeric trait for a custom type

    master

    To make a custom type compatible with the peroxide-num ecosystem, you must implement the required mathematical traits. A common pattern is to wrap a primitive type (like f64) and implement PowOps, TrigOps, ExpLogOps, and finally Numeric.

    Note: Numeric is a generic trait that requires specifying the floating-point type used for certain operations (e.g., Numeric<f64>).

    #[derive(Debug, Clone, Copy, PartialOrd)]
    struct SimpleNumber(f64);
    
    impl PowOps for SimpleNumber {
        type Float = Self;
    
        fn powi(&self, n: i32) -> Self {
            SimpleNumber(self.0.powi(n))
        }
    
        fn powf(&self, f: Self::Float) -> Self {
            SimpleNumber(self.0.powf(f.0))
        }
    
        fn pow(&self, f: Self) -> Self {
            SimpleNumber(self.0.powf(f.0))
        }
    
        fn sqrt(&self) -> Self {
            SimpleNumber(self.0.sqrt())
        }
    }
    
    // You must also implement:
    // - Add, Sub, Mul, Div, Neg
    // - TrigOps
    // - ExpLogOps
    
    impl Numeric<f64> for SimpleNumber {}