6 个版本
0.2.0 | 2023年1月31日 |
---|---|
0.1.4 | 2023年1月12日 |
0.1.2 | 2022年12月18日 |
#638 在 数学 分类中
每月 25 次下载
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;
功能
两个主要功能,lambda 和 map,可以用来在用户定义的方式下操作向量或矩阵中的单个值,或者将两个向量或矩阵连接起来。
Lambda 函数
总的来说,这些方法将用户定义的函数应用于向量或矩阵的每个元素。
自定义函数的参数取决于调用的方法,共有三种
- lambda
- 向量/矩阵:Fn(&T) -> T
- 使用对应的元素
- 向量/矩阵:Fn(&T) -> T
- lambda_index
- 向量:Fn(usize) -> T
- 使用索引
- 矩阵:Fn(usize, usize) -> T
- 使用行索引和列索引
- 向量:Fn(usize) -> T
- lambda_enumerate
- 向量:Fn(usize, &T) -> T
- 使用索引和对应的元素
- 矩阵:Fn(usize, usize, &T) -> T
- 使用行索引、列索引和对应的元素
- 向量:Fn(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
- 使用两个对应的元素
- 向量/矩阵:Fn(&T, &T) -> T
- map_enumerate
- 向量:Fn(usize, &T, &T) -> T
- 使用索引和两个对应的元素
- 矩阵:Fn(usize, usize, &T, &T) -> T
- 使用行索引、列索引和两个对应的元素
- 向量:Fn(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]
]);