Rust线性代数库ndarray-linalg的使用,ndarray-linalg为Rust提供高性能矩阵运算和线性代数功能
ndarray-linalg
基于外部LAPACK实现的Rust线性代数包,与ndarray配合使用。
示例
查看示例目录。
注意:要运行示例,必须指定使用的后端(如下所述)。例如,可以使用OpenBLAS后端执行求解示例:
cargo run --example solve --features=openblas
并使用OpenBLAS运行ndarray-linalg的所有测试:
cargo test --features=openblas
后端功能
有三个LAPACK源crate:
- openblas-src
- netlib-src
- intel-mkl-src
ndarray_linalg必须链接仅一个用于LAPACK FFI。
[dependencies]
ndarray = "0.14"
ndarray-linalg = { version = "0.13", features = ["openblas-static"] }
支持的功能如下:
功能 | 链接类型 | 要求 | 描述 |
---|---|---|---|
openblas-static | 静态 | gcc, gfortran, make | 在项目中构建OpenBLAS,并静态链接 |
openblas-system | 动态/静态 | libopenblas-dev | 在系统中查找OpenBLAS并链接 |
netlib-static | 静态 | gfortran, make | 与openblas-static相同,但使用参考LAPACK |
netlib-system | 动态/静态 | liblapack-dev | 与openblas-system相同,但使用参考LAPACK |
intel-mkl-static | 静态 | (pkg-config) | 从系统中查找Intel MKL静态库,如果未找到则下载,并静态链接 |
intel-mkl-system | 动态 | (pkg-config) | 从系统中查找Intel MKL共享库,并动态链接 |
- 必须使用仅一个功能。
- 动态/静态表示取决于系统中找到的内容。当系统有/usr/lib/libopenblas.so时,将动态链接;/usr/lib/libopenblas.a将静态链接。动态链接优先于静态链接。
- 要求说明:
- gcc和gfortran可以是其他编译器,例如icc和ifort。
- libopenblas-dev是Debian、Ubuntu和其他衍生发行版中的包名。有几个OpenBLAS二进制包,即libopenblas-{openmp,pthread,serial}-dev。在其他发行版(如Fedora、ArchLinux等)中可能有其他名称。
- pkg-config用于在系统中搜索Intel MKL包,是可选的。
对于库开发者
如果您创建依赖此crate的库,建议不要链接任何后端:
[dependencies]
ndarray = "0.13"
ndarray-linalg = "0.12"
Cargo的功能是累加的。如果您的库(例如lib1)设置了功能openblas-static,使用lib1的应用程序将使用openblas-static功能构建ndarray_linalg,尽管他们希望使用intel-mkl-static后端。
测试环境
目前仅支持x86_64系统。
后端 | Linux | Windows | macOS |
---|---|---|---|
OpenBLAS | ✔️ | - | - |
Netlib | ✔️ | - | - |
Intel MKL | ✔️ | ✔️ | ✔️ |
许可证
注意:如果您使用intel-mkl-src后端,除了MIT许可证或Apache-2.0许可证外,还必须接受Intel简化软件许可证。
双重许可以与Rust项目兼容。根据Apache许可证版本2.0或MIT许可证许可,由您选择。
完整示例代码:
// Cargo.toml
[dependencies]
ndarray = "0.14"
ndarray-linalg = { version = "0.13", features = ["openblas-static"] }
// main.rs
use ndarray::Array2;
use ndarray_linalg::Solve;
fn main() {
// 创建一个2x2矩阵
let a: Array2<f64> = array![[1.0, 2.0], [3.0, 4.0]];
// 创建右侧向量
let b: Array1<f64> = array![5.0, 6.0];
// 求解线性方程组 Ax = b
let x = a.solve(&b).expect("Solution failed");
println!("Solution x = {}", x);
}
Rust线性代数库ndarray-linalg使用指南
概述
ndarray-linalg是Rust生态中基于ndarray库的高性能线性代数工具包,提供矩阵运算、线性方程组求解、特征值计算等核心功能。该库支持多种后端实现(如OpenBLAS、Intel MKL等),能够充分发挥硬件性能。
安装配置
在Cargo.toml中添加依赖:
[dependencies]
ndarray = "0.15"
ndarray-linalg = "0.16"
根据需求选择后端(以OpenBLAS为例):
[dependencies]
ndarray-linalg = { version = "0.16", features = ["openblas"] }
核心功能示例
1. 矩阵创建与基本运算
use ndarray::prelude::*;
use ndarray_linalg::*;
fn main() -> Result<(), error::LinalgError> {
// 创建矩阵
let a = array![[1.0, 2.0], [3.0, 4.0]];
let b = array![[5.0, 6.0], [7.0, 8.0]];
// 矩阵加法
let sum = &a + &b;
println!("矩阵加法:\n{}", sum);
// 矩阵乘法
let product = a.dot(&b);
println!("矩阵乘法:\n{}", product);
Ok(())
}
2. 线性方程组求解
use ndarray::prelude::*;
use ndarray_linalg::*;
fn solve_linear_system() -> Result<(), error::LinalgError> {
// 系数矩阵A和常数向量b
let a: Array2<f64> = array![[2.0, 1.0], [1.0, 3.0]];
let b: Array1<f64> = array![1.0, 2.0];
// 求解Ax = b
let x = a.solve(&b)?;
println!("解向量: {:?}", x);
Ok(())
}
3. 特征值与特征向量计算
use ndarray::prelude::*;
use ndarray_linalg::*;
fn eigenvalue_decomposition() -> Result<(), error::LinalgError> {
let matrix: Array2<f64> = array![[4.0, 1.0], [2.0, 3.0]];
// 计算特征值
let eigenvalues = matrix.eigvals()?;
println!("特征值: {:?}", eigenvalues);
// 计算特征值和特征向量
let (eigenvalues, eigenvectors) = matrix.eig()?;
println!("特征值: {:?}", eigenvalues);
println!("特征向量:\n{}", eigenvectors);
Ok(())
}
4. 矩阵分解
use ndarray::prelude::*;
use ndarray_linalg::*;
fn matrix_decomposition() -> Result<(), error::LinalgError> {
let matrix: Array2<f64> = array![[4.0, 12.0, -16.0],
[12.0, 37.0, -43.0],
[-16.0, -43.0, 98.0]];
// Cholesky分解
let l = matrix.cholesky(UPLO::Lower)?;
println!("Cholesky下三角矩阵:\n{}", l);
// QR分解
let (q, r) = matrix.qr()?;
println!("Q矩阵:\n{}", q);
println!("R矩阵:\n{}", r);
Ok(())
}
5. 奇异值分解(SVD)
use ndarray::prelude::*;
use ndarray_linalg::*;
fn svd_example() -> Result<(), error::LinalgError> {
let matrix: Array2<f64> = array![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
// 进行SVD分解
let (u, s, vt) = matrix.svd(true, true)?;
println!("U矩阵:\n{}", u.unwrap());
println!("奇异值: {:?}", s);
println!("V转置矩阵:\n{}", vt.unwrap());
Ok(())
}
完整示例demo
use ndarray::prelude::*;
use ndarray_linalg::*;
fn main() -> Result<(), error::LinalgError> {
// 示例1: 矩阵创建与基本运算
println!("=== 矩阵创建与基本运算 ===");
let a = array![[1.0, 2.0], [3.0, 4.0]];
let b = array![[5.0, 6.0], [7.0, 8.0]];
let sum = &a + &b;
println!("矩阵加法:\n{}", sum);
let product = a.dot(&b);
println!("矩阵乘法:\n{}", product);
// 示例2: 线性方程组求解
println!("\n=== 线性方程组求解 ===");
let a_solve: Array2<f64> = array![[2.0, 1.0], [1.0, 3.0]];
let b_solve: Array1<f64> = array![1.0, 2.0];
let x = a_solve.solve(&b_solve)?;
println!("解向量: {:?}", x);
// 示例3: 特征值与特征向量计算
println!("\n=== 特征值与特征向量计算 ===");
let matrix_eig: Array2<f64> = array![[4.0, 1.0], [2.0, 3.0]];
let eigenvalues = matrix_eig.eigvals()?;
println!("特征值: {:?}", eigenvalues);
let (eigenvalues_full, eigenvectors) = matrix_eig.eig()?;
println!("特征值: {:?}", eigenvalues_full);
println!("特征向量:\n{}", eigenvectors);
// 示例4: 矩阵分解
println!("\n=== 矩阵分解 ===");
let matrix_decomp: Array2<f64> = array![[4.0, 12.0, -16.0],
[12.0, 37.0, -43.0],
[-16.0, -43.0, 98.0]];
let l = matrix_decomp.cholesky(UPLO::Lower)?;
println!("Cholesky下三角矩阵:\n{}", l);
let (q, r) = matrix_decomp.qr()?;
println!("Q矩阵:\n{}", q);
println!("R矩阵:\n{}", r);
// 示例5: 奇异值分解(SVD)
println!("\n=== 奇异值分解(SVD) ===");
let matrix_svd: Array2<f64> = array![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
let (u, s, vt) = matrix_svd.svd(true, true)?;
println!("U矩阵:\n{}", u.unwrap());
println!("奇异值: {:?}", s);
println!("V转置矩阵:\n{}", vt.unwrap());
Ok(())
}
性能优化建议
- 选择合适后端:根据目标平台选择最优的BLAS/LAPACK后端
- 重用内存:尽可能复用数组内存避免不必要的分配
- 使用视图操作:利用ndarray的视图功能减少数据拷贝
- 并行计算:对于大规模运算考虑使用并行算法
错误处理
ndarray-linalg使用Result类型处理运算错误:
match matrix.inv() {
Ok(inverse) => println!("逆矩阵:\n{}", inverse),
Err(e) => eprintln!("矩阵求逆失败: {}", e),
}
注意事项
- 确保矩阵维度匹配相关运算要求
- 奇异矩阵求逆等操作可能失败,需要适当错误处理
- 对于大规模矩阵,注意内存使用和计算复杂度
该库为科学计算和机器学习应用提供了强大的线性代数基础功能,结合Rust的内存安全特性,能够构建高性能且可靠的数据处理应用。