This crate is part of Russell - Rust Scientific Library
This repository is a "rust laboratory" for vectors and matrices.
Documentation:
Install some libraries:
bash
sudo apt-get install \
liblapacke-dev \
libopenblas-dev
In macOS, you may use Homebrew to install the dependencies:
bash
brew install openblas lapack
Note In macOS, we have to set the LIBRARY_PATH
all the time.
bash
export LIBRARY_PATH=$LIBRARY_PATH:$(brew --prefix)/opt/openblas/lib:$(brew --prefix)/opt/lapack/lib
👆 Check the crate version and update your Cargo.toml accordingly:
toml
[dependencies]
russell_lab = "*"
By default OpenBLAS will use all available threads, including Hyper-Threads that make the performance worse. Thus, it is best to set the following environment variable:
bash
export OPENBLAS_NUM_THREADS=<real-core-count>
Furthermore, if working on a multi-threaded application, it is recommended to set:
bash
export OPENBLAS_NUM_THREADS=1
```rust use russelllab::{matpseudo_inverse, Matrix, StrError};
fn main() -> Result<(), StrError> { // set matrix let mut a = Matrix::from(&[[1.0, 0.0], [0.0, 1.0], [0.0, 1.0]]); let a_copy = a.clone();
// compute pseudo-inverse matrix (because it's square)
let mut ai = Matrix::new(2, 3);
mat_pseudo_inverse(&mut ai, &mut a)?;
// compare with solution
let ai_correct = "┌ ┐\n\
│ 1.00 0.00 0.00 │\n\
│ 0.00 0.50 0.50 │\n\
└ ┘";
assert_eq!(format!("{:.2}", ai), ai_correct);
// compute a⋅ai
let (m, n) = a.dims();
let mut a_ai = Matrix::new(m, m);
for i in 0..m {
for j in 0..m {
for k in 0..n {
a_ai.add(i, j, a_copy.get(i, k) * ai.get(k, j));
}
}
}
// check if a⋅ai⋅a == a
let mut a_ai_a = Matrix::new(m, n);
for i in 0..m {
for j in 0..n {
for k in 0..m {
a_ai_a.add(i, j, a_ai.get(i, k) * a_copy.get(k, j));
}
}
}
let a_ai_a_correct = "┌ ┐\n\
│ 1.00 0.00 │\n\
│ 0.00 1.00 │\n\
│ 0.00 1.00 │\n\
└ ┘";
assert_eq!(format!("{:.2}", a_ai_a), a_ai_a_correct);
Ok(())
} ```
```rust use russellchk::approxeq; use russelllab::{matadd, mateigen, matmatmul, matnorm, Matrix, Norm, StrError, Vector};
fn main() -> Result<(), StrError> { // set matrix let data = [[2.0, 0.0, 0.0], [0.0, 3.0, 4.0], [0.0, 4.0, 9.0]]; let mut a = Matrix::from(&data);
// allocate output arrays
let m = a.nrow();
let mut l_real = Vector::new(m);
let mut l_imag = Vector::new(m);
let mut v_real = Matrix::new(m, m);
let mut v_imag = Matrix::new(m, m);
// perform the eigen-decomposition
mat_eigen(&mut l_real, &mut l_imag, &mut v_real, &mut v_imag, &mut a)?;
// check results
assert_eq!(
format!("{:.1}", l_real),
"┌ ┐\n\
│ 11.0 │\n\
│ 1.0 │\n\
│ 2.0 │\n\
└ ┘"
);
assert_eq!(
format!("{}", l_imag),
"┌ ┐\n\
│ 0 │\n\
│ 0 │\n\
│ 0 │\n\
└ ┘"
);
// check eigen-decomposition (similarity transformation) of a
// symmetric matrix with real-only eigenvalues and eigenvectors
let a_copy = Matrix::from(&data);
let lam = Matrix::diagonal(l_real.as_data());
let mut a_v = Matrix::new(m, m);
let mut v_l = Matrix::new(m, m);
let mut err = Matrix::filled(m, m, f64::MAX);
mat_mat_mul(&mut a_v, 1.0, &a_copy, &v_real)?;
mat_mat_mul(&mut v_l, 1.0, &v_real, &lam)?;
mat_add(&mut err, 1.0, &a_v, -1.0, &v_l)?;
approx_eq(mat_norm(&err, Norm::Max), 0.0, 1e-15);
Ok(())
} ```