#线性代数 #矩阵 #矩阵-向量 #向量

simp_linalg

一个轻量级的通用线性代数库,用于向量和矩阵的简单加法和乘法

6 个版本

0.2.0 2023年1月31日
0.1.4 2023年1月12日
0.1.2 2022年12月18日

#638数学 分类中

每月 25 次下载

MIT 许可证

70KB
793

Simp_LinAlg

一个轻量级的通用线性代数库,用于向量和矩阵的简单加法和乘法。

文档

开发笔记
0.2.0
  • 创建公共宏
    • vector!
    • matrix!
  • 重命名模块
    • simp_linalg::vector => simp_linalg::vector_impl
    • simp_linalg::matrix => simp_linalg::matrix_impl

用法

将以下内容添加到您的 Cargo.toml

[dependencies]
simp_linalg = "0.2.0"

构造宏

有两个公开可用的宏,vector!matrix!,用于轻松构建 Vector<_T_>Matrix<_T_>

use simp_linalg::prelude::*;

let v1 = vector![1, 2, 3];
let v2 = Vector::from(vec![1, 2, 3]);

let m1 = matrix![
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];
let m2 = Matrix::from(vec![
    vec![1, 2, 3],
    vec![4, 5, 6],
    vec![7, 8, 9]
]);

assert_eq!(v1, v2);
assert_eq!(m1, m2);

操作符重载

向量和矩阵的乘法和加法需要它们的相对大小是 兼容的

乘法

  • 向量和矩阵可以与标量相乘。 注意:标量必须在右侧
    • &向量<T> *T-> 向量<T>
    • &矩阵<T> *T-> 矩阵<T>
  • 矩阵可以与兼容的矩阵或向量相乘。
    • &矩阵<T> * &向量<T> -> 向量<T>
    • &矩阵<T> * &矩阵<T> -> 矩阵<T>
  • 向量可以与兼容的向量相乘。
    • &向量<T> * &向量<T> ->T

加法

  • 向量可以与兼容的向量相加。
    • &向量<T> + &向量<T> -> 向量<T>
  • 矩阵可以与兼容的矩阵相加。
    • &矩阵<T> + &矩阵<T> -> 矩阵<T>

与借用检查器作斗争

技术上...上述操作符重载功能经常使用借用。这仅在您打算在计算后继续变量的生命周期时才是必要的(这很可能是经常)。

如果这不是必要条件,那么借用是不需要的,计算将按预期工作。

例如

use simp_linalg::prelude::*;

//Create two vectors
let vector1 = vector![1, 2, 3];

let vector2 = vector![4, 5, 6];

// Note: vector2 is dropped after this calculation, but vector1 is not.
let dot_prod: i32 = &vector1 * vector2;
为什么它会消失?这是因为 Rust 的 移动 语义。Rust 的标准库类型 Vec 没有实现 Copy 特性,因此当调用时将值移动到乘法/加法函数中,并在该函数退出作用域时丢弃。通过借用值,所有权返回到原始作用域,并且没有值被丢弃。
为什么允许不借用?这是因为它允许代码更易于阅读。

例如,假设您有一个向量 vector_1,它通过矩阵 matrix 转换,其结果将加到另一个向量 vector_2 上。

在版本 0.1.1 (旧版):

let result: Vector<i32> = &(&matrix * &vector_1) + &vector_2;

在版本 0.1.2+:

let result: Vector<i32> = &matrix * &vector_1 + &vector_2;

此外,通过新增的功能,向量矩阵乘以标量,这可以让程序员避免不必要的借用。以上面的例子为例,现在假设你希望在相加之前对 vector_2 进行缩放。

在版本 0.1.1 (旧版本和假设标量乘法被包括在内的情况):

let result: Vector<i32> = &(&matrix * &vector_1) + &(&vector_2 * 4);

在版本 0.1.2+:

let result: Vector<i32> = &matrix * &vector_1 + &vector_2 * 4;

功能

两个主要功能,lambdamap,可以用来在用户定义的方式下操作向量或矩阵中的单个值,或者将两个向量或矩阵连接起来。

Lambda 函数

总的来说,这些方法将用户定义的函数应用于向量或矩阵的每个元素。

自定义函数的参数取决于调用的方法,共有三种

  • lambda
    • 向量/矩阵:Fn(&T) -> T
      • 使用对应的元素
  • lambda_index
    • 向量:Fn(usize) -> T
      • 使用索引
    • 矩阵:Fn(usize, usize) -> T
      • 使用行索引和列索引
  • lambda_enumerate
    • 向量:Fn(usize, &T) -> T
      • 使用索引和对应的元素
    • 矩阵:Fn(usize, usize, &T) -> T
      • 使用行索引、列索引和对应的元素

示例

use simp_linalg::prelude::*;

// initialization
let vector: Vector<i32> = vector![1, 2, 3];

let matrix: Matrix<i32> = matrix![[1,2],
                                  [3,4]];

// squaring each element inside
let new_vector = vector.lambda(|val| val * val);
let new_matrix = matrix.lambda(|val| val * val);

// tests
assert_eq!(new_vector, vector![1, 4, 9]);
assert_eq!(new_matrix, matrix![[1,4],
                               [9,16]])

Map 函数

总的来说,这些方法使用用户定义的函数将两个向量或矩阵结合起来。

自定义函数映射的参数取决于调用的映射方法,共有两种

  • map
    • 向量/矩阵:Fn(&T, &T) -> T
      • 使用两个对应的元素
  • map_enumerate
    • 向量:Fn(usize, &T, &T) -> T
      • 使用索引和两个对应的元素
    • 矩阵:Fn(usize, usize, &T, &T) -> T
      • 使用行索引、列索引和两个对应的元素

示例

use simp_linalg::prelude::*;

// initialization
// Note: this process is similar to matrix
// Also: the two vectors or matrices must be the same size
let lhs_vector: Vector<f64> = vector![1.5, 2.0];
let rhs_vector: Vector<f64> = vector![3.0, 4.0];

let lhs_matrix: Matrix<i32> = matrix![
  [1, 2, 3 ],
  [4, 5, 6 ],
  [8, 9, 10]
];

let rhs_matrix: Matrix<i32> = matrix![
  [2, 2, 2],
  [1, 2, 1],
  [0, 3, 0]
];

// multiplying each corresponding element
let meshed_vector = lhs_vector.map(&rhs_vector, |lhs_val, rhs_val| lhs_val * rhs_val);
let meshed_matrix = lhs_matrix.map(&rhs_matrix, |lhs_val, rhs_val| lhs_val * rhs_val);

// test
assert_eq!(meshed_vector, vector![4.5, 8.0]);
assert_eq!(meshed_matrix, matrix![
  [2, 4,  6],
  [4, 10, 6],
  [0, 27, 0]
]);

无运行时依赖