molysgaard / russell

Rust Scientific Libary. Matrix-vector laboratory, OpenBLAS, sparse direct solvers.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Russell - Rust Scientific Library

codecov

Bertrand Russell

(CC0. Photo: Bertrand Russell)

Russell assists in the development of scientific computations using the Rust language. We focus on numerical methods and solvers for differential equations; however, anything is possible πŸ˜‰.

An essential goal of this library is to bring the best (fastest) solutions while maintaining a very clean (and idiomatic) code, thoroughly tested (min coverage of 95%), and yet simple to use. The best solutions are brought by wrapping powerful libraries such as OpenBLAS, MUMPS, and SuiteSparse (UMFPACK).

Available crates:

  • Crates.io chk Functions to check vectors and other data in tests
  • Crates.io lab Matrix-vector laboratory including linear algebra tools
  • Crates.io openblas Thin wrapper to some OpenBLAS routines
  • Crates.io sparse Sparse matrix tools and solvers
  • Crates.io stat Statistics calculations, probability distributions, and pseudo random numbers
  • Crates.io tensor Tensor analysis structures and functions for continuum mechanics

External recommended crate:

  • plotpy Plotting tools using Python3/Matplotlib as an engine

Examples

Compute a singular value decomposition

use russell_lab::{mat_svd, Matrix, Vector, StrError};

fn main() -> Result<(), StrError> {
    // set matrix
    let mut a = Matrix::from(&[
        [2.0, 4.0],
        [1.0, 3.0],
        [0.0, 0.0],
        [0.0, 0.0],
    ]);

    // allocate output structures
    let (m, n) = a.dims();
    let min_mn = if m < n { m } else { n };
    let mut s = Vector::new(min_mn);
    let mut u = Matrix::new(m, m);
    let mut vt = Matrix::new(n, n);

    // perform SVD
    mat_svd(&mut s, &mut u, &mut vt, &mut a)?;

    // define correct data
    let s_correct = "β”Œ      ┐\n\
                     β”‚ 5.46 β”‚\n\
                     β”‚ 0.37 β”‚\n\
                     β””      β”˜";
    let u_correct = "β”Œ                         ┐\n\
                     β”‚ -0.82 -0.58  0.00  0.00 β”‚\n\
                     β”‚ -0.58  0.82  0.00  0.00 β”‚\n\
                     β”‚  0.00  0.00  1.00  0.00 β”‚\n\
                     β”‚  0.00  0.00  0.00  1.00 β”‚\n\
                     β””                         β”˜";
    let vt_correct = "β”Œ             ┐\n\
                      β”‚ -0.40 -0.91 β”‚\n\
                      β”‚ -0.91  0.40 β”‚\n\
                      β””             β”˜";

    // check solution
    assert_eq!(format!("{:.2}", s), s_correct);
    assert_eq!(format!("{:.2}", u), u_correct);
    assert_eq!(format!("{:.2}", vt), vt_correct);

    // check SVD: a == u * s * vt
    let mut usv = Matrix::new(m, n);
    for i in 0..m {
        for j in 0..n {
            for k in 0..min_mn {
                usv.add(i, j, u.get(i, k) * s[k] * vt.get(k, j));
            }
        }
    }
    let usv_correct = "β”Œ     ┐\n\
                       β”‚ 2 4 β”‚\n\
                       β”‚ 1 3 β”‚\n\
                       β”‚ 0 0 β”‚\n\
                       β”‚ 0 0 β”‚\n\
                       β””     β”˜";
    assert_eq!(format!("{}", usv), usv_correct);
    Ok(())
}

Solve a linear system

use russell_lab::{solve_lin_sys, Matrix, Vector, StrError};

fn main() -> Result<(), StrError> {
    // set matrix and right-hand side
    let mut a = Matrix::from(&[
        [1.0,  3.0, -2.0],
        [3.0,  5.0,  6.0],
        [2.0,  4.0,  3.0],
    ]);
    let mut b = Vector::from(&[5.0, 7.0, 8.0]);

    // solve linear system b := a⁻¹⋅b
    solve_lin_sys(&mut b, &mut a)?;

    // check
    let x_correct = "β”Œ         ┐\n\
                     β”‚ -15.000 β”‚\n\
                     β”‚   8.000 β”‚\n\
                     β”‚   2.000 β”‚\n\
                     β””         β”˜";
    assert_eq!(format!("{:.3}", b), x_correct);
    Ok(())
}

Solve a sparse linear system

use russell_lab::{Matrix, Vector, StrError};
use russell_sparse::{ConfigSolver, Solver, SparseTriplet};

fn main() -> Result<(), StrError> {

    // allocate a square matrix
    let neq = 5; // number of equations
    let nnz = 13; // number of non-zeros
    let mut trip = SparseTriplet::new(neq, nnz)?;
    trip.put(0, 0,  1.0)?; // << (0, 0, a00/2)
    trip.put(0, 0,  1.0)?; // << (0, 0, a00/2)
    trip.put(1, 0,  3.0)?;
    trip.put(0, 1,  3.0)?;
    trip.put(2, 1, -1.0)?;
    trip.put(4, 1,  4.0)?;
    trip.put(1, 2,  4.0)?;
    trip.put(2, 2, -3.0)?;
    trip.put(3, 2,  1.0)?;
    trip.put(4, 2,  2.0)?;
    trip.put(2, 3,  2.0)?;
    trip.put(1, 4,  6.0)?;
    trip.put(4, 4,  1.0)?;

    // print matrix
    let mut a = Matrix::new(neq, neq);
    trip.to_matrix(&mut a)?;
    let correct = "β”Œ                ┐\n\
                   β”‚  2  3  0  0  0 β”‚\n\
                   β”‚  3  0  4  0  6 β”‚\n\
                   β”‚  0 -1 -3  2  0 β”‚\n\
                   β”‚  0  0  1  0  0 β”‚\n\
                   β”‚  0  4  2  0  1 β”‚\n\
                   β””                β”˜";
    assert_eq!(format!("{}", a), correct);

    // allocate x and rhs
    let mut x = Vector::new(neq);
    let rhs = Vector::from(&[8.0, 45.0, -3.0, 3.0, 19.0]);

    // initialize, factorize, and solve
    let config = ConfigSolver::new();
    let mut solver = Solver::new(config, neq, nnz, None)?;
    solver.factorize(&trip)?;
    solver.solve(&mut x, &rhs)?;
    let correct = "β”Œ          ┐\n\
                   β”‚ 1.000000 β”‚\n\
                   β”‚ 2.000000 β”‚\n\
                   β”‚ 3.000000 β”‚\n\
                   β”‚ 4.000000 β”‚\n\
                   β”‚ 5.000000 β”‚\n\
                   β””          β”˜";
    assert_eq!(format!("{:.6}", x), correct);
    Ok(())
}

Todo list

  • Add complex numbers functions to russell_openblas
  • Add more complex numbers functions to russell_lab
  • Add fundamental functions to russell_lab
    • Implement the modified Bessel functions
  • Implement some numerical methods in russell_lab
    • Implement Brent's solver
    • Implement solver for the cubic equation
    • Implement numerical derivation
    • Implement numerical Jacobian function
    • Implement Newton's method for nonlinear systems
    • Implement numerical quadrature
  • Add interpolation and polynomials to russell_lab
    • Implement Chebyshev interpolation and polynomials
    • Implement Orthogonal polynomials
    • Implement Lagrange interpolation
  • Add probability distribution functions to russell_stat
  • Finalize drawing of ASCII histogram in russell_stat
  • Implement standard continuum mechanics tensors in russell_tensor
  • Implement more integration tests for linear algebra
  • Implement more examples

Benchmarks

Jacobi Rotation versus LAPACK DSYEV

Comparison of the performances of mat_eigen_sym_jacobi (Jacobi rotation) versus mat_eigen_sym (calling LAPACK DSYEV).

Jacobi Rotation versus LAPACK DSYEV (1-5)

Jacobi Rotation versus LAPACK DSYEV (1-32)

About

Rust Scientific Libary. Matrix-vector laboratory, OpenBLAS, sparse direct solvers.

License:MIT License


Languages

Language:Rust 98.4%Language:C 1.5%Language:Shell 0.1%