Rust线性代数库ndarray-linalg的使用,ndarray-linalg为Rust提供高性能矩阵运算和线性代数功能

ndarray-linalg

crate docs.rs master

基于外部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);
}

1 回复

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(())
}

性能优化建议

  1. 选择合适后端:根据目标平台选择最优的BLAS/LAPACK后端
  2. 重用内存:尽可能复用数组内存避免不必要的分配
  3. 使用视图操作:利用ndarray的视图功能减少数据拷贝
  4. 并行计算:对于大规模运算考虑使用并行算法

错误处理

ndarray-linalg使用Result类型处理运算错误:

match matrix.inv() {
    Ok(inverse) => println!("逆矩阵:\n{}", inverse),
    Err(e) => eprintln!("矩阵求逆失败: {}", e),
}

注意事项

  • 确保矩阵维度匹配相关运算要求
  • 奇异矩阵求逆等操作可能失败,需要适当错误处理
  • 对于大规模矩阵,注意内存使用和计算复杂度

该库为科学计算和机器学习应用提供了强大的线性代数基础功能,结合Rust的内存安全特性,能够构建高性能且可靠的数据处理应用。

回到顶部