initial commit

This commit is contained in:
2023-12-28 14:07:00 +08:00
commit 6edb6a95b3
16 changed files with 4401 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

186
Cargo.lock generated Normal file
View File

@@ -0,0 +1,186 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "libc"
version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "opimps"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "857dabe64a7afe2e51ac9962dc3c008e74ae050dd47e21a7e7b1fc69a67a0229"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rmath"
version = "0.1.0"
dependencies = [
"num-bigint",
"num-traits",
"opimps",
"rand",
"sealed",
"trait-group",
]
[[package]]
name = "sealed"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "trait-group"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b362975c6f0f21a41fbb9ca91fe5dcb7e01e12331360374347476b45f5cb9c"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

28
Cargo.toml Normal file
View File

@@ -0,0 +1,28 @@
[package]
name = "rmath"
version = "0.1.0"
edition = "2021"
authors = ["Walter Oggioni <oggioni.walter@gmail.com>"]
license = "MIT"
rust-version = "1.60"
[dependencies]
trait-group = "0.1.0"
sealed = "0.5"
num-traits = "0.2.17"
opimps = "0.2.2"
[dev-dependencies]
num-bigint = "0.4.4"
rand = "0.8.5"
[lib]
name = "rmath"
crate-type = ["lib"]
bench = false
[profile.release]
strip = true
lto = true
debug-assertions = false
codegen-units = 1

42
examples/benchmark.rs Normal file
View File

@@ -0,0 +1,42 @@
use std::env;
use num_bigint::BigInt;
use num_traits::One;
use num_traits::Zero;
use rmath::HMatrix;
use rmath::Rational;
use rmath::NumericalMatrix;
use rand::rngs::StdRng;
use rand::SeedableRng;
use rand::RngCore;
fn main( ) {
let size = env::args().skip(1).map(|it| {
it.parse::<u32>().unwrap()
}).take(1).collect::<Vec<u32>>()[0];
let mut rand = {
let seed = [
1,0,1,3,
2,5,0,0,
200,1,0,0,
210,30,0,0,
78,134,31,0,
253,11,7,0,
120,169,89,48,
200,0,202,0
];
StdRng::from_seed(seed)
};
let mtx = HMatrix::<Rational<BigInt>>::new(
usize::try_from(size).unwrap(),usize::try_from(size).unwrap(), |_| {
Rational::new(BigInt::from(rand.next_u32() % (size * 20)) - size * 10, BigInt::one())
});
let b = HMatrix::<Rational<BigInt>>::new(
usize::try_from(size).unwrap(),usize::try_from(size).unwrap(), |_| {
Rational::new(BigInt::from(rand.next_u32() % (size * 10)) - (size * 5), BigInt::one())
});
let lu = mtx.clone().lu().unwrap();
let x = lu.solve(&b).unwrap();
assert!((mtx * x - b).is_zero());
}

View File

@@ -0,0 +1,51 @@
use rmath::HMatrix;
use rmath::SMatrix;
fn main() {
let mut acc = 0;
let mut m1 = HMatrix::new(3, 3, |_| {
let res = acc;
acc += 1;
res
});
println!("{}", m1);
println!("{}", &m1 + &m1);
println!("{}", m1.clone() - m1.clone());
println!("{}", &m1 * &m1);
acc = 0;
let mut m2: SMatrix<i32, 3, 3> = SMatrix::new(|_| {
let res = acc;
acc += 1;
res
});
println!("{}", m2);
println!("{}", m2 + m2);
println!("{}", m2 - m2);
println!("{}", m2 * m2);
for (i, j, v) in m2 {
println!("{} {} {}", i, j, v);
}
for (i, j, v) in &mut m2 {
println!("{} {} {}", i, j, v);
*v = 5;
}
println!("{}", m2);
println!("{}", m1 == m1);
println!("{}", m1 == &m1 + &m1);
println!("{}", m2 == m2);
println!("{}", m2 == m2 + m2);
for (i, j, v) in &mut m1 {
println!("{} {} {}", i, j, v);
*v = 0;
}
let a: SMatrix<i32, 3, 2> =
SMatrix::new(|(i, j)| i32::try_from(i).unwrap() - i32::try_from(j).unwrap());
let b: SMatrix<i32, 2, 3> =
SMatrix::new(|(i, j)| i32::try_from(i).unwrap() - i32::try_from(j).unwrap());
println!("{}", a * b);
println!("{}", b * a);
}

50
src/err.rs Normal file
View File

@@ -0,0 +1,50 @@
use std::fmt::Debug;
pub trait RmathError {
fn msg(&self) -> String;
}
#[derive(Default)]
pub struct SingularMatrixError {}
impl Debug for SingularMatrixError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.msg())
}
}
impl RmathError for SingularMatrixError {
fn msg(&self) -> String {
String::from("Matrix is singular")
}
}
pub struct SizeError {
msg: String,
}
impl Debug for dyn RmathError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.msg())
}
}
impl RmathError for SizeError {
fn msg(&self) -> String {
self.msg.clone()
}
}
impl SizeError {
pub fn new(msg: &str) -> SizeError {
SizeError {
msg: String::from(msg),
}
}
}
impl Debug for SizeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.msg())
}
}

215
src/hludecomposition.rs Normal file
View File

@@ -0,0 +1,215 @@
use num_traits::One;
use num_traits::Zero;
use std::ops::Add;
use std::ops::Div;
use std::ops::DivAssign;
use std::ops::Mul;
use std::ops::MulAssign;
use std::ops::Neg;
use std::ops::SubAssign;
use crate::err::RmathError;
use super::hpivot::HPivot;
use super::matrix::LUDecompositionImpl;
use super::matrix::NumericalMatrixImpl;
use super::HMatrix;
use super::LUDecomposition;
use super::Matrix;
use super::NumericalMatrix;
use super::Pivot;
use super::SingularMatrixError;
use super::misc::EnhancedOption;
pub struct HLUDecomposition<TYPE> {
matrix: HMatrix<TYPE>,
pivot: HPivot,
}
impl<TYPE> HLUDecomposition<TYPE>
where TYPE : Zero + SubAssign<TYPE> + Clone,
for<'a> &'a TYPE : Mul<&'a TYPE, Output = TYPE>,
for<'a> TYPE : DivAssign<&'a TYPE> {
pub (crate) fn new(matrix: HMatrix<TYPE>, pivot: Option<HPivot>) -> Self {
let size = matrix.rows();
HLUDecomposition {
matrix,
pivot: pivot.otherwise(|| HPivot::new(size)),
}
}
pub fn solve(&self, b : &HMatrix<TYPE>) -> Result<HMatrix<TYPE>, Box<dyn RmathError>> {
let mut x = HMatrix::<TYPE>::new(b.rows(), b.columns(), |_| TYPE::zero());
for n in 0..b.columns() {
for i in 0..self.matrix.rows() {
x[(i, n)] = b[(self.pivot[i], n)].clone();
for k in 0..i {
let sub = &self.matrix[(i, k)] * &x[(k, n)];
x[(i, n)] -= sub;
}
}
for i in (0..self.matrix.rows()).rev() {
for k in (i + 1)..self.matrix.rows() {
let sub = &self.matrix[(i, k)] * &x[(k, n)];
x[(i, n)] -= sub;
}
if self.matrix[(i, i)].is_zero() {
return Err(Box::<SingularMatrixError>::default());
} else {
x[(i, n)] /= &self.matrix[(i, i)];
}
}
}
Ok(x)
}
}
impl<TYPE> LUDecompositionImpl<TYPE, HMatrix<TYPE>, HPivot> for HLUDecomposition<TYPE>
where
for<'a> TYPE: 'a + One + MulAssign<&'a TYPE> + Neg<Output = TYPE>,
{
fn get_matrix(&self) -> &HMatrix<TYPE> {
&self.matrix
}
fn get_pivot(&self) -> &HPivot {
&self.pivot
}
}
impl<TYPE> LUDecomposition<TYPE, HMatrix<TYPE>, HPivot> for HLUDecomposition<TYPE>
where
for<'b> TYPE: 'b
+ Clone
+ Zero
+ One
+ PartialEq
+ PartialOrd
+ Add<&'b TYPE, Output = TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>
+ SubAssign<TYPE>
+ SubAssign<&'b TYPE>
+ DivAssign<TYPE>
+ DivAssign<&'b TYPE>
+ MulAssign<&'b TYPE>,
for<'c> &'c TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
fn l(&self) -> HMatrix<TYPE> {
self.matrix.clone().tril_replace(TYPE::one())
}
fn u(&self) -> HMatrix<TYPE> {
self.matrix.clone().triu()
}
fn invert(&self) -> HMatrix<TYPE> {
let mut result =
HMatrix::<TYPE>::new(self.matrix.rows(), self.matrix.columns(), |_| TYPE::zero());
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::lu_invert(
&self.matrix,
&mut result,
&mut self.pivot.clone(),
);
result
}
fn pivot(&self, m: HMatrix<TYPE>) -> HMatrix<TYPE> {
&self.pivot * m
}
// fn p<'a>(&'a self) -> &'a HPivot {
// &self.pivot
// }
}
#[cfg(test)]
mod test {
use rand::rngs::StdRng;
use rand::RngCore;
use rand::SeedableRng;
use crate::NumericalMatrix;
use crate::Rational;
use crate::HMatrix;
use num_traits::Zero;
use rand;
#[test]
fn solve_linear_system() {
let mut rand = {
let seed = [
1,0,1,3,
2,5,0,0,
200,1,0,0,
210,30,0,0,
78,134,31,0,
253,11,7,0,
120,169,89,48,
200,0,202,0
];
StdRng::from_seed(seed)
};
let mtx = HMatrix::<Rational<i64>>::new(5, 5, |_| {
Rational::new(i64::try_from(rand.next_u32() % 40).unwrap() - 20, 1)
});
let b = HMatrix::<Rational<i64>>::new(5, 5, |_| {
Rational::new(i64::try_from(rand.next_u32() % 20).unwrap() - 10, 1)
});
let lu = mtx.clone().lu().unwrap();
let x = lu.solve(&b).unwrap();
assert!((mtx * x - b).is_zero());
}
}
#[cfg(test)]
mod test_big_int {
use num_traits::Zero;
use rand::rngs::StdRng;
use rand::RngCore;
use rand::SeedableRng;
use crate::NumericalMatrix;
use crate::Rational;
use crate::HMatrix;
use rand;
#[test]
fn solve_linear_system() {
use num_bigint::BigInt;
use num_traits::One;
let mut rand = {
let seed = [
1,0,1,3,
2,5,0,0,
200,1,0,0,
210,30,0,0,
78,134,31,0,
253,11,7,0,
120,169,89,48,
200,0,202,0
];
StdRng::from_seed(seed)
};
let mtx = HMatrix::<Rational<BigInt>>::new(10, 10, |_| {
Rational::new(BigInt::from(rand.next_u32() % 200) - 100, BigInt::one())
});
let b = HMatrix::<Rational<BigInt>>::new(10, 10, |_| {
Rational::new(BigInt::from(rand.next_u32() % 100) - 50, BigInt::one())
});
let lu = mtx.clone().lu().unwrap();
let x = lu.solve(&b).unwrap();
assert!((mtx * x - b).is_zero());
}
}

1057
src/hmatrix.rs Normal file

File diff suppressed because it is too large Load Diff

87
src/hpivot.rs Normal file
View File

@@ -0,0 +1,87 @@
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Mul;
use super::hmatrix::HMatrix;
use super::matrix::MatrixImpl;
use super::Matrix;
use super::Pivot;
pub struct HPivot {
data: Vec<usize>,
permutations: usize,
}
impl Index<usize> for HPivot {
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
type Output = usize;
}
impl IndexMut<usize> for HPivot {
fn index_mut(&mut self, index: usize) -> &mut <Self as Index<usize>>::Output {
&mut self.data[index]
}
}
impl Pivot for HPivot {
fn swap(&mut self, i1: usize, i2: usize) {
self.data.swap(i1, i2);
self.permutations += 1;
}
fn permutations(&self) -> usize {
self.permutations
}
fn new(size: usize) -> Self {
HPivot {
data: (0..size).collect(),
permutations: 0,
}
}
}
impl<TYPE> Mul<HMatrix<TYPE>> for HPivot
where
TYPE: Clone,
{
fn mul(self, matrix: HMatrix<TYPE>) -> Self::Output {
&self * matrix
}
type Output = HMatrix<TYPE>;
}
impl<TYPE> Mul<HMatrix<TYPE>> for &HPivot
where
TYPE: Clone,
{
fn mul(self, matrix: HMatrix<TYPE>) -> Self::Output {
if self.data.len() != matrix.rows() {
panic!("Pivot len must equal matrix rows")
}
let mut result = matrix.clone();
let mut pclone = self.clone();
for i in 0..matrix.rows() {
while i != pclone[i] {
let j = pclone[i];
result.swap_rows_pivot(&mut pclone, i, j);
}
}
result
}
type Output = HMatrix<TYPE>;
}
impl Clone for HPivot {
fn clone(&self) -> Self {
HPivot {
data: self.data.clone(),
permutations: self.permutations,
}
}
}

97
src/lib.rs Normal file
View File

@@ -0,0 +1,97 @@
#[macro_use]
extern crate trait_group;
use num_traits::One;
use num_traits::Zero;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::MulAssign;
use std::ops::Neg;
mod rational;
pub use self::rational::Rational;
mod matrix;
pub use self::matrix::LUDecomposition;
mod hpivot;
pub use hpivot::HPivot;
mod hludecomposition;
pub use hludecomposition::HLUDecomposition;
mod hmatrix;
pub use self::hmatrix::HMatrix;
mod spivot;
pub use spivot::SPivot;
mod sludecomposition;
pub use sludecomposition::SLUDecomposition;
mod smatrix;
pub use self::smatrix::SMatrix;
mod err;
pub use self::err::SingularMatrixError;
pub use self::err::SizeError;
mod misc;
pub trait Pivot: Index<usize, Output = usize> + IndexMut<usize, Output = usize> + Sized {
fn swap(&mut self, i1: usize, i2: usize);
fn permutations(&self) -> usize;
fn new(size: usize) -> Self;
}
pub trait Vector<TYPE> : Index<usize, Output = TYPE> + IndexMut<usize, Output = TYPE> {
fn new<F : FnMut(usize) -> TYPE>(size : usize, cb : F) -> Self;
fn length(&self) -> usize;
}
pub trait NumericalVector<TYPE> : Vector<TYPE> {
fn norm() -> TYPE;
}
pub trait Matrix<TYPE>
where
Self: Index<(usize, usize), Output = TYPE> + IndexMut<(usize, usize), Output = TYPE> + Sized,
{
fn rows(&self) -> usize;
fn columns(&self) -> usize;
fn size(&self) -> (usize, usize) {
(self.rows(), self.columns())
}
fn transpose(self) -> Result<Self, SizeError>;
}
pub trait NumericalMatrix<TYPE, PIVOT: Pivot, LU: LUDecomposition<TYPE, Self, PIVOT>>:
Matrix<TYPE>
where
for<'a> TYPE: Clone + One + Zero + MulAssign<&'a TYPE> + Neg<Output = TYPE>,
{
fn identity(size: usize) -> Self;
fn tril(self) -> Self;
fn triu(self) -> Self;
fn tril_replace(self, diag_replacement: TYPE) -> Self;
fn triu_replace(self, diag_replacement: TYPE) -> Self;
fn gauss_jordan_high(self) -> Self;
fn gauss_jordan_low(self) -> Self;
fn det(self) -> TYPE;
fn invert(&mut self) -> Self;
fn lup(self) -> Result<LU, SingularMatrixError>;
fn lu(self) -> Result<LU, SingularMatrixError>;
}

489
src/matrix.rs Normal file
View File

@@ -0,0 +1,489 @@
use super::Matrix;
use super::Pivot;
use super::SingularMatrixError;
use super::SizeError;
use num_traits::One;
use num_traits::Zero;
use std::ops::Add;
use std::ops::Div;
use std::ops::DivAssign;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Mul;
use std::ops::MulAssign;
use std::ops::Neg;
use std::ops::SubAssign;
pub trait MatrixImpl<'a, TYPE>: Matrix<TYPE>
where
TYPE: 'a,
Self: Index<(usize, usize), Output = TYPE>
+ IndexMut<(usize, usize), Output = TYPE>
+ IntoIterator<Item = (usize, usize, TYPE), IntoIter = Self::IteratorType>
+ 'a,
&'a Self: IntoIterator<Item = (usize, usize, &'a TYPE), IntoIter = Self::RefIteratorType<'a>>,
&'a mut Self:
IntoIterator<Item = (usize, usize, &'a mut TYPE), IntoIter = Self::MutRefIteratorType<'a>>,
Self::IteratorType: Iterator<Item = (usize, usize, TYPE)>,
Self::RefIteratorType<'a>: Iterator<Item = (usize, usize, &'a TYPE)>,
Self::MutRefIteratorType<'a>: Iterator<Item = (usize, usize, &'a mut TYPE)>,
{
fn swap(&mut self, idx1: (usize, usize), idx2: (usize, usize)) {
unsafe {
// Can't take two mutable loans from one matrix, so instead just cast
// them to their raw pointers to do the swap
let pa: *mut TYPE = &mut self[idx1];
let pb: *mut TYPE = &mut self[idx2];
std::ptr::swap(pa, pb);
}
}
fn transpose_in_place(&mut self) -> Result<(), SizeError>
where
Self: Sized,
{
for i in 0..self.rows() {
for j in 0..self.columns() {
self.swap((i, j), (j, i));
}
}
Ok(())
}
fn swap_rows(&mut self, row1: usize, row2: usize) {
for i in 0..self.columns() {
self.swap((row1, i), (row2, i))
}
}
fn swap_rows_pivot<P: Pivot>(&mut self, pivot: &mut P, row1: usize, row2: usize) {
self.swap_rows(row1, row2);
pivot.swap(row1, row2);
}
fn swap_rows_mul_pivot<P: Pivot>(
&mut self,
other: &mut Self,
pivot: &mut P,
row1: usize,
row2: usize,
) {
self.swap_rows_pivot(pivot, row1, row2);
other.swap_rows(row1, row2);
}
fn swap_rows_mul(&mut self, other: &mut Self, row1: usize, row2: usize) {
self.swap_rows(row1, row2);
other.swap_rows(row1, row2);
}
fn swap_columns(&mut self, col1: usize, col2: usize) {
for i in 0..self.rows() {
self.swap((i, col1), (i, col2))
}
}
type IteratorType;
type RefIteratorType<'b>;
type MutRefIteratorType<'b>;
}
pub trait LUDecompositionImpl<TYPE, MATRIX, PIVOT: Pivot>
where
MATRIX: Matrix<TYPE>,
for<'b> TYPE: One + MulAssign<&'b TYPE> + Neg<Output = TYPE>,
{
fn get_matrix(&self) -> &MATRIX;
fn get_pivot(&self) -> &PIVOT;
fn det(&self) -> TYPE {
let mut result = TYPE::one();
for i in 0..self.get_matrix().rows() {
result *= &self.get_matrix()[(i, i)];
}
if self.get_pivot().permutations() % 2 != 0 {
result = -result;
}
result
}
}
pub trait LUDecomposition<TYPE, MATRIX: Matrix<TYPE>, PIVOT: Pivot>:
LUDecompositionImpl<TYPE, MATRIX, PIVOT>
where
for<'b> TYPE: One + MulAssign<&'b TYPE> + Neg<Output = TYPE>,
{
fn l(&self) -> MATRIX;
fn u(&self) -> MATRIX;
fn invert(&self) -> MATRIX;
fn pivot(&self, m: MATRIX) -> MATRIX;
fn det(&self) -> TYPE {
LUDecompositionImpl::det(self)
}
}
pub trait NumericalMatrixImpl<'a, TYPE, PIVOT: Pivot, LU: LUDecomposition<TYPE, Self, PIVOT>>:
MatrixImpl<'a, TYPE>
where
for<'b> TYPE: Zero
+ One
+ PartialEq
+ Neg<Output = TYPE>
+ Div<TYPE, Output = TYPE>
+ MulAssign<&'b TYPE>,
for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE>
+ Add<&'c TYPE, Output = TYPE>
+ Div<&'c TYPE, Output = TYPE>
+ Neg<Output = TYPE>,
Self: Sized,
TYPE: 'a,
Self: Index<(usize, usize), Output = TYPE>
+ IndexMut<(usize, usize), Output = TYPE>
+ IntoIterator<Item = (usize, usize, TYPE), IntoIter = Self::IteratorType>
+ 'a,
&'a Self: IntoIterator<Item = (usize, usize, &'a TYPE), IntoIter = Self::RefIteratorType<'a>>,
&'a mut Self:
IntoIterator<Item = (usize, usize, &'a mut TYPE), IntoIter = Self::MutRefIteratorType<'a>>,
Self::IteratorType: Iterator<Item = (usize, usize, TYPE)>,
Self::RefIteratorType<'a>: Iterator<Item = (usize, usize, &'a TYPE)>,
Self::MutRefIteratorType<'a>: Iterator<Item = (usize, usize, &'a mut TYPE)>,
{
fn identity(size: usize) -> Self;
fn add_row(&mut self, source_index: usize, dest_index: usize, factor: &TYPE)
where
TYPE: Mul<Output = TYPE> + Add<Output = TYPE>,
for<'f> &'f TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
for i in 0..self.columns() {
let tmp = &(self[(source_index, i)]) * factor;
self[(dest_index, i)] = &(self[(dest_index, i)]) + &tmp;
}
}
fn add_row_mul(
&mut self,
other: &mut Self,
source_index: usize,
dest_index: usize,
factor: &TYPE,
) where
TYPE: Add<Output = TYPE> + Mul<Output = TYPE>,
for<'f> &'f TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
self.add_row(source_index, dest_index, factor);
other.add_row(source_index, dest_index, factor);
}
fn gauss_jordan_low<P: Pivot>(&mut self, pivot: &mut P)
where
TYPE: Zero
+ PartialEq
+ Add<Output = TYPE>
+ Mul<Output = TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>,
for<'f> &'f TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
for i in 0..self.rows() {
if self[(i, i)] == TYPE::zero() {
for j in (i + 1)..self.columns() {
if self[(j, i)] != TYPE::zero() {
self.swap_rows_pivot(pivot, i, j);
break;
}
}
}
for j in (i + 1)..self.rows() {
if self[(i, i)] != TYPE::zero() {
let neg = -(&self[(j, i)]);
let factor = &neg / &(self[(i, i)]);
self.add_row(i, j, &factor)
}
}
}
}
fn gauss_jordan_low_mul<P: Pivot>(&mut self, other: &mut Self, pivot: &mut P)
where
TYPE: Zero
+ PartialEq
+ Add<Output = TYPE>
+ Mul<Output = TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>,
for<'f> &'f TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
for i in 0..self.rows() {
if self[(i, i)] == TYPE::zero() {
for j in (i + 1)..self.columns() {
if self[(j, i)] != TYPE::zero() {
self.swap_rows_mul_pivot(other, pivot, i, j);
break;
}
}
}
for j in (i + 1)..self.rows() {
if self[(i, i)] != TYPE::zero() {
let neg = -(&self[(j, i)]);
let factor = &neg / &(self[(i, i)]);
self.add_row_mul(other, i, j, &factor)
}
}
}
}
fn gauss_jordan_high<P: Pivot>(&mut self, pivot: &mut P)
where
TYPE: Zero
+ PartialEq
+ Add<Output = TYPE>
+ Mul<Output = TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>,
for<'f> &'f TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
for i in (usize::zero()..self.rows()).rev() {
if self[(i, i)] == TYPE::zero() {
for j in (usize::zero()..i).rev() {
if self[(j, i)] != TYPE::zero() {
self.swap_rows_pivot(pivot, i, j);
break;
}
}
}
for j in (usize::zero()..i).rev() {
if self[(i, i)] != TYPE::zero() {
let neg = -(&self[(j, i)]);
let factor = &neg / &(self[(i, i)]);
self.add_row(i, j, &factor)
}
}
}
}
fn gauss_jordan_high_mul<P: Pivot>(&mut self, other: &mut Self, pivot: &mut P)
where
TYPE: Zero
+ PartialEq
+ Add<Output = TYPE>
+ Mul<Output = TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>,
for<'f> &'f TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
for i in (usize::zero()..self.rows()).rev() {
if self[(i, i)] == TYPE::zero() {
for j in i..usize::zero() {
if self[(j, i)] != TYPE::zero() {
self.swap_rows_mul_pivot(other, pivot, i, j);
break;
}
}
}
for j in (usize::zero()..i).rev() {
if self[(i, i)] != TYPE::zero() {
let neg = -(&self[(j, i)]);
let factor = &neg / &(self[(i, i)]);
self.add_row_mul(other, i, j, &factor)
}
}
}
}
fn triu_impl(&'a mut self, diag_replacement: Option<TYPE>)
where
TYPE: Zero + Clone,
{
match diag_replacement {
Some(replacement) => {
for (i, j, value) in self {
match &i.cmp(&j) {
std::cmp::Ordering::Equal => *value = replacement.clone(),
std::cmp::Ordering::Greater => *value = TYPE::zero(),
_ => {}
}
}
}
None => {
for (i, j, value) in self {
if i > j {
*value = TYPE::zero()
}
}
}
}
}
fn tril_impl(&'a mut self, diag_replacement: Option<TYPE>)
where
TYPE: Zero + Clone,
{
match diag_replacement {
Some(replacement) => {
for (i, j, value) in self {
match i.cmp(&j) {
std::cmp::Ordering::Equal => *value = replacement.clone(),
std::cmp::Ordering::Less => *value = TYPE::zero(),
_ => {}
}
}
}
None => {
for (i, j, value) in self {
if i < j {
*value = TYPE::zero()
}
}
}
}
}
fn invert(&mut self, pivot: &mut PIVOT, result: &mut Self)
where
TYPE: Clone + Zero + One + PartialEq + Neg<Output = TYPE> + Div<Output = TYPE>,
for<'f> &'f TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
self.gauss_jordan_low_mul(result, pivot);
self.gauss_jordan_high_mul(result, pivot);
for i in 0..result.rows() {
let f = self[(i, i)].clone();
for j in 0..result.columns() {
result[(i, j)] = &(result[(i, j)]) / &f;
}
}
}
fn det(mut self, mut pivot: PIVOT) -> TYPE {
self.gauss_jordan_low(&mut pivot);
(0..self.rows())
.map(|i| &self[(i, i)])
.fold(TYPE::one(), |a, b| &a * b)
}
fn lu_pivot(&mut self, i: usize, pivot: &mut PIVOT)
where
TYPE: PartialOrd + Zero + Clone,
for<'f> &'f TYPE: Neg<Output = TYPE>,
{
let mut max = abs(&self[(i, i)]);
let mut max_index = i;
for j in (i + 1)..self.rows() {
if abs(&self[(j, i)]) > max {
max = abs(&self[(i, j)]);
max_index = j;
}
}
if max_index != i {
self.swap_rows_pivot(pivot, i, max_index)
}
}
fn lu(&mut self) -> Result<(), SingularMatrixError>
where
TYPE: Zero + Clone,
for<'b> &'b TYPE: Mul<&'b TYPE, Output = TYPE>,
TYPE: SubAssign<TYPE> + DivAssign<TYPE>,
{
for i in 0..self.rows() {
self.lu_row(i)?
}
Ok(())
}
fn lup(&mut self, p: &mut PIVOT) -> Result<(), SingularMatrixError>
where
TYPE: Zero + Clone + PartialOrd,
for<'b> &'b TYPE: Mul<&'b TYPE, Output = TYPE> + Neg<Output = TYPE>,
TYPE: SubAssign<TYPE> + DivAssign<TYPE>,
{
for i in 0..self.rows() {
self.lu_pivot(i, p);
self.lu_row(i)?
}
Ok(())
}
fn lu_invert(&self, result: &mut Self, p: &mut PIVOT)
where
TYPE: Zero + One + Clone + PartialOrd,
for<'b> &'b TYPE: Mul<&'b TYPE, Output = TYPE>,
for<'c> TYPE: DivAssign<&'c TYPE>,
TYPE: SubAssign<TYPE>,
{
for i in 0..self.rows() {
for j in 0..self.rows() {
if p[j] == i {
result[(j, i)] = TYPE::one();
} else {
result[(j, i)] = TYPE::zero();
}
for k in 0..j {
let delta = &self[(j, k)] * &result[(k, i)];
result[(j, i)] -= delta;
}
}
for j in (0..self.rows()).rev() {
for k in (j + 1)..self.rows() {
let delta = &self[(j, k)] * &result[(k, i)];
result[(j, i)] -= delta;
}
result[(j, i)] /= &self[(j, j)];
}
}
}
fn lu_row(&mut self, i: usize) -> Result<(), SingularMatrixError>
where
TYPE: Zero + Clone,
for<'b> &'b TYPE: Mul<&'b TYPE, Output = TYPE>,
TYPE: SubAssign<TYPE> + DivAssign<TYPE>,
{
if self[(i, i)].is_zero() {
return Err(SingularMatrixError {});
}
for j in i..self.columns() {
for k in 0..i {
let delta = &self[(i, k)] * &self[(k, j)];
self[(i, j)] -= delta;
}
}
for j in (i + 1)..self.columns() {
for k in 0..i {
let delta = &self[(j, k)] * &self[(k, i)];
self[(j, i)] -= delta;
}
let div = self[(i, i)].clone();
self[(j, i)] /= div;
}
Ok(())
}
fn squared_norm2(&'a self) -> TYPE {
self.into_iter().fold(TYPE::zero(), move |acc, (_, _, v)| { acc + v * v })
}
}
fn abs<TYPE>(value: &TYPE) -> TYPE
where
TYPE: PartialOrd + Zero + Clone,
for<'a> &'a TYPE: Neg<Output = TYPE>,
{
if value >= &TYPE::zero() {
value.clone()
} else {
-value
}
}

49
src/misc.rs Normal file
View File

@@ -0,0 +1,49 @@
use std::fmt::Debug;
use std::ops::Index;
use std::ops::IndexMut;
use crate::Matrix;
pub trait EnhancedOption<U> {
fn otherwise<F>(self, cb: F) -> U
where
F: Fn() -> U;
}
impl<T> EnhancedOption<T> for Option<T> {
fn otherwise<F>(self, cb: F) -> T
where
F: Fn() -> T,
{
if let Some(value) = self {
value
} else {
cb()
}
}
}
pub fn debug_fmt<'a, M: Matrix<TYPE>, TYPE: 'a + Debug>(
m: &M,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result
where
M: Index<(usize, usize), Output = TYPE> + IndexMut<(usize, usize), Output = TYPE>,
M: IntoIterator<Item = (usize, usize, TYPE)>,
{
write!(f, "[")?;
for i in 0..m.rows() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "[")?;
for j in 0..m.columns() {
if j > 0 {
write!(f, ", ")?;
}
write!(f, "{:?}", m[(i, j)])?
}
write!(f, "]")?;
}
write!(f, "]")
}

791
src/rational.rs Normal file
View File

@@ -0,0 +1,791 @@
use num_traits::sign::Signed;
use num_traits::Num;
use num_traits::NumOps;
use num_traits::One;
use num_traits::Pow;
use num_traits::Signed as SignedOps;
use num_traits::Zero;
use std::cmp::Ordering;
use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::fmt::Debug;
use std::fmt::Display;
use std::ops::Add;
use std::ops::AddAssign;
use std::ops::Div;
use std::ops::DivAssign;
use std::ops::Mul;
use std::ops::MulAssign;
use std::ops::Neg;
use std::ops::Rem;
use std::ops::Sub;
use std::ops::SubAssign;
trait_group! {
pub trait RationalInt
: NumOps
+ Debug
+ PartialEq
+ PartialOrd
+ Zero<Output = Self>
+ One<Output = Self>
+ Pow<u32, Output = Self>
+ Neg<Output = Self>
+ Clone
+ Default
}
fn gcd<T>(a: &T, b: &T) -> T
where
T: Rem<Output = T> + Clone + Zero,
{
let mut n1 = a.clone();
let mut n2 = b.clone();
let mut tmp: T;
while !n2.is_zero() {
tmp = n1;
n1 = n2.clone();
n2 = tmp % n2;
}
n1
}
fn mcm<'a, T>(n1: &'a T, n2: &'a T) -> T
where
T: Div<Output = T> + Rem<Output = T> + Clone + Zero,
&'a T: Mul<Output = T>,
{
let den = gcd(n1, n2);
n1 * n2 / den
}
#[derive(Debug)]
pub struct Rational<TYPE> {
num: TYPE,
den: TYPE,
}
impl<TYPE> Rational<TYPE>
where
TYPE: Zero + One + Clone + Rem<Output = TYPE> + PartialOrd + Neg<Output = TYPE>,
for<'a> &'a TYPE: Div<&'a TYPE, Output = TYPE>,
{
fn simplify(&mut self) {
if self.num.is_zero() {
self.den = TYPE::one();
} else if self.den.is_zero() {
} else {
(self.num, self.den) = {
let n1_opt: TYPE;
let n1 = if self.den < TYPE::zero() {
n1_opt = -self.num.clone();
&n1_opt
} else {
&self.num
};
let n2_opt: TYPE;
let n2 = if self.den < TYPE::zero() {
n2_opt = -self.den.clone();
&n2_opt
} else {
&self.den
};
let num_abs_opt: TYPE;
let num_abs = if self.num < TYPE::zero() {
num_abs_opt = -self.num.clone();
&num_abs_opt
} else {
&self.num
};
let gcd = gcd(num_abs, n2);
(n1 / &gcd, n2 / &gcd)
};
}
}
}
impl<TYPE> Rational<TYPE>
where
TYPE: RationalInt,
{
pub fn new(num: TYPE, den: TYPE) -> Rational<TYPE> {
let res = den.partial_cmp(&TYPE::zero());
match res {
Some(Ordering::Greater) => Rational { num, den },
Some(Ordering::Less) => Rational {
num: -num,
den: -den,
},
_ => {
panic!("Rational denominator cannot be zero or NaN")
}
}
}
}
#[opimps::impl_op(Pow)]
fn pow<TYPE>(self: Rational<TYPE>, exp: u32) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: Pow<u32, Output = TYPE>,
{
Rational {
num: self.num.pow(exp),
den: self.den.pow(exp),
}
}
#[opimps::impl_op(Pow)]
fn pow<TYPE>(self: &Rational<TYPE>, exp: u32) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: Pow<u32, Output = TYPE>,
{
Rational {
num: (&self.num).pow(exp),
den: (&self.den).pow(exp),
}
}
#[opimps::impl_ops(Add)]
fn add<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den + &b / &rhs.den;
let mut result: Rational<TYPE> = Rational { num, den };
result.simplify();
result
}
#[opimps::impl_ops(Sub)]
fn sub<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den - &b / &rhs.den;
let mut result: Rational<TYPE> = Rational { num, den };
result.simplify();
result
}
#[opimps::impl_ops(Mul)]
fn mul<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let num = &self.num * &rhs.num;
let den = &self.den * &rhs.den;
let mut result = Rational { num, den };
result.simplify();
result
}
#[opimps::impl_ops(Div)]
fn div<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let den = &self.den * &rhs.num;
let num = &self.num * &rhs.den;
let mut result = Rational::new(num, den);
result.simplify();
result
}
#[opimps::impl_ops(Rem)]
fn rem<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
match self.partial_cmp(&rhs) {
Some(std::cmp::Ordering::Less) => rhs.clone(),
Some(std::cmp::Ordering::Equal) => Rational::<TYPE>::zero(),
Some(std::cmp::Ordering::Greater) => {
let div = self / rhs;
let num = &div.num / &div.den;
div - Rational::new(num, TYPE::one())
}
None => {
panic!("Cannot compare")
}
}
}
impl<'a, TYPE> AddAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
TYPE: Zero
+ One
+ Clone
+ Rem<Output = TYPE>
+ PartialOrd
+ Neg<Output = TYPE>
+ Div<Output = TYPE>,
for<'b> &'b TYPE: Mul<&'b TYPE, Output = TYPE> + Div<&'b TYPE, Output = TYPE>,
{
fn add_assign(&mut self, rhs: &'a Self) {
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den + &b / &rhs.den;
self.num = num;
self.den = den;
self.simplify();
}
}
impl<TYPE> AddAssign for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn add_assign(&mut self, rhs: Self) {
*self += &rhs;
}
}
impl<'a, TYPE> SubAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
TYPE: Div<Output = TYPE>
+ Sub<Output = TYPE>
+ Rem<Output = TYPE>
+ Neg<Output = TYPE>
+ Clone
+ Zero
+ One
+ PartialOrd,
for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE> + Div<&'c TYPE, Output = TYPE>,
for<'b> TYPE: SubAssign<&'b TYPE>,
{
fn sub_assign(&mut self, rhs: &'a Self) {
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den - &b / &rhs.den;
self.num = num;
self.den = den;
self.simplify();
}
}
impl<TYPE> SubAssign for Rational<TYPE>
where
TYPE: Div<Output = TYPE>
+ Sub<Output = TYPE>
+ Rem<Output = TYPE>
+ Neg<Output = TYPE>
+ Clone
+ Zero
+ One
+ PartialOrd,
for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE> + Div<&'c TYPE, Output = TYPE>,
for<'b> TYPE: SubAssign<&'b TYPE>,
{
fn sub_assign(&mut self, rhs: Self) {
*self -= &rhs;
}
}
impl<'a, TYPE> MulAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
for<'b> TYPE: MulAssign<&'b TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn mul_assign(&mut self, rhs: &'a Self) {
self.num *= &rhs.num;
self.den *= &rhs.den;
self.simplify();
}
}
impl<TYPE> MulAssign for Rational<TYPE>
where
for<'a> TYPE: MulAssign<&'a TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn mul_assign(&mut self, rhs: Self) {
*self *= &rhs;
}
}
impl<'a, TYPE> DivAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
for<'b> TYPE: MulAssign<&'b TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn div_assign(&mut self, rhs: &'a Self) {
self.num *= &rhs.den;
self.den *= &rhs.num;
self.simplify()
}
}
impl<TYPE> DivAssign for Rational<TYPE>
where
for<'a> TYPE: MulAssign<&'a TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn div_assign(&mut self, rhs: Self) {
*self /= &rhs;
self.simplify()
}
}
impl<TYPE> Display for Rational<TYPE>
where
TYPE: RationalInt + Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}/{}", self.num, self.den)
}
}
impl<TYPE> PartialEq for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl<TYPE> Eq for Rational<TYPE>
where
TYPE: RationalInt + Eq,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
}
impl<TYPE> PartialOrd for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
(&self.num * &other.den).partial_cmp(&(&other.num * &self.den))
}
}
impl<TYPE> Ord for Rational<TYPE>
where
TYPE: RationalInt + Ord,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn cmp(&self, other: &Self) -> Ordering {
(&self.num * &other.den).cmp(&(&other.num * &self.den))
}
}
impl<TYPE> Clone for Rational<TYPE>
where
TYPE: Clone,
{
fn clone(&self) -> Self {
Rational {
num: self.num.clone(),
den: self.den.clone(),
}
}
}
impl<TYPE> Copy for Rational<TYPE> where TYPE: Copy {}
impl<TYPE> Zero for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn zero() -> Rational<TYPE> {
Rational {
num: TYPE::zero(),
den: TYPE::one(),
}
}
fn is_zero(&self) -> bool {
self.num.is_zero() && !self.den.is_zero()
}
}
impl<TYPE> One for Rational<TYPE>
where
TYPE: RationalInt + Display,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn one() -> Self {
Rational {
num: TYPE::one(),
den: TYPE::one(),
}
}
fn is_one(&self) -> bool {
self.num == self.den
}
}
impl<TYPE> Default for Rational<TYPE>
where
TYPE: RationalInt + Display,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn default() -> Self {
Rational::<TYPE>::zero()
}
}
#[opimps::impl_uni_op(Neg)]
fn neg<TYPE>(self: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
{
Rational::new(-self.num, self.den)
}
#[opimps::impl_uni_op(Neg)]
fn neg<TYPE>(self: &Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
{
Rational::new(-self.num.clone(), self.den.clone())
}
impl<TYPE> Num for Rational<TYPE>
where
TYPE: Num + RationalInt + Display,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn from_str_radix(_: &str, _: u32) -> Result<Self, Self::FromStrRadixErr> {
Result::Err(Rational::<TYPE>::default())
}
type FromStrRadixErr = Self;
}
impl<TYPE> SignedOps for Rational<TYPE>
where
TYPE: Signed + SignedOps + Display + RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn abs(&self) -> Self {
Rational::new(self.num.abs(), self.den.abs())
}
fn abs_sub(&self, other: &Self) -> Self {
if self <= other {
Rational::<TYPE>::zero()
} else {
self.clone() - other.clone()
}
}
fn is_negative(&self) -> bool {
!self.num.is_zero() && self.num.is_negative() ^ self.den.is_negative()
}
fn is_positive(&self) -> bool {
!self.num.is_zero() && !(self.num.is_positive() ^ self.den.is_positive())
}
fn signum(&self) -> Self {
if self.is_positive() {
Rational::<TYPE>::one()
} else if self.is_negative() {
-Rational::<TYPE>::one()
} else {
Rational::<TYPE>::zero()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn test_simplify() {
let mut r1 = Rational::new(15, 105);
assert_eq!(Rational::new(1, 7), r1);
r1.simplify();
assert_eq!(Rational::new(1, 7), r1);
}
#[test]
fn test_add() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::new(1, 7);
let one: Rational<i32> = Rational::<i32>::one();
assert_eq!(one, r1 + r2);
assert_eq!(r2 + r1, r1 + r2);
assert_eq!(r1 + r2 + r3, r3 + r2 + r1);
}
#[test]
fn test_add_assign() {
let mut r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::<i32>::one();
r1 += r2;
assert_eq!(r3, r1);
}
#[test]
fn test_sub() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::new(1, 7);
assert_eq!(Rational::<i32>::zero(), r1 - r1);
assert_eq!(Rational::new(-1, 5), r2 - r1);
assert!(Rational::<i32>::zero() > r3 - r1);
assert!(Rational::<i32>::zero() > r3 - r2);
assert!(Rational::<i32>::zero() > r3 - r1);
}
#[test]
fn test_sub_assign() {
let mut r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::new(1, 5);
r1 -= r2;
assert_eq!(r3, r1);
}
#[test]
fn test_mul() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(1, 7);
assert_eq!(Rational::new(9, 25), r1 * r1);
assert_eq!(Rational::new(-12, 50), r2 * r1);
assert_eq!(Rational::new(2, -35), r2 * r3);
}
#[test]
fn test_mul_assign() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(-12, 50);
let mut r4 = r1.clone();
r4 *= r1;
assert_eq!(Rational::<i32>::new(9, 25), r4);
let mut r5 = r1.clone();
r5 *= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_div() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(1, 7);
assert_eq!(Rational::<i32>::one(), r1 / r1);
assert_eq!(Rational::new(-2, 3), r2 / r1);
assert_eq!(Rational::new(28, -10), r2 / r3);
}
#[test]
fn test_div_assign() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(30, -20);
let mut r4 = r1.clone();
r4 /= r1;
assert_eq!(Rational::<i32>::one(), r4);
let mut r5 = r1.clone();
r5 /= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_eq() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(6, 10);
let r3 = Rational::new(300, 500);
let r4 = Rational::new(300, -500);
assert!(r1 == r2);
assert!(r1 == r3);
assert!(r1 != r4);
}
#[test]
fn test_ord() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(7, 10);
let r3 = Rational::new(301, 500);
let r4 = Rational::new(300, -500);
let values: Vec<Rational<i32>> = BTreeSet::from([r1, r2, r3, r4])
.iter()
.map(|it| it.clone())
.collect();
let expected_order = Vec::from([r4, r1, r3, r2]);
assert_eq!(expected_order, values);
}
#[test]
fn test_gcd() {
let a = 14;
let b = 21;
assert_eq!(7, gcd(&a, &b));
}
#[test]
fn test_mcm() {
let a = 14;
let b = 21;
assert_eq!(42, mcm::<i32>(&a, &b));
}
}
#[cfg(test)]
mod big_int_tests {
use super::*;
use num_bigint::BigInt;
use std::collections::BTreeSet;
#[test]
fn test_gcd() {
assert_eq!(6, gcd(&12, &18));
assert_eq!(6, gcd(&18, &12));
}
#[test]
fn test_simplify() {
let mut r1 = Rational::new(BigInt::from(15), BigInt::from(105));
assert_eq!(Rational::new(BigInt::from(1), BigInt::from(7)), r1);
r1.simplify();
assert_eq!(Rational::new(BigInt::from(1), BigInt::from(7)), r1);
}
#[test]
fn test_add() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::<BigInt>::one(), &r1 + &r2);
assert_eq!(&r2 + &r1, &r1 + &r2);
assert_eq!(&r1 + &r2 + &r3, &r3 + &r2 + &r1);
}
#[test]
fn test_add_assign() {
let mut r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
r1 += r2;
assert_eq!(Rational::<BigInt>::one(), r1);
}
#[test]
fn test_sub() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::<BigInt>::zero(), &r1 - &r1);
assert_eq!(Rational::new(BigInt::from(-1), BigInt::from(5)), &r2 - &r1);
assert!(Rational::<BigInt>::zero() > &r3 - &r1);
assert!(Rational::<BigInt>::zero() > &r3 - &r2);
assert!(Rational::<BigInt>::zero() > r3 - r1);
}
#[test]
fn test_sub_assign() {
let mut r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
r1 -= r2;
assert_eq!(Rational::<BigInt>::new(BigInt::one(), BigInt::from(5)), r1);
}
#[test]
fn test_mul() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::new(BigInt::from(9), BigInt::from(25)), &r1 * &r1);
assert_eq!(
Rational::new(BigInt::from(-12), BigInt::from(50)),
&r2 * &r1
);
assert_eq!(Rational::new(BigInt::from(2), BigInt::from(-35)), r2 * r3);
}
#[test]
fn test_mul_assign() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(-12), BigInt::from(50));
let mut r4 = r1.clone();
r4 *= &r1;
assert_eq!(
Rational::<BigInt>::new(BigInt::from(9), BigInt::from(25)),
r4
);
let mut r5 = r1.clone();
r5 *= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_div() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::<BigInt>::one(), &r1 / &r1);
assert_eq!(Rational::new(BigInt::from(-2), BigInt::from(3)), &r2 / r1);
assert_eq!(Rational::new(BigInt::from(28), BigInt::from(-10)), r2 / r3);
}
#[test]
fn test_div_assign() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(30), BigInt::from(-20));
let mut r4 = r1.clone();
r4 /= &r1;
assert_eq!(Rational::<BigInt>::one(), r4);
let mut r5 = r1.clone();
r5 /= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_eq() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(6), BigInt::from(10));
let r3 = Rational::new(BigInt::from(300), BigInt::from(500));
let r4 = Rational::new(BigInt::from(300), BigInt::from(-500));
assert!(r1 == r2);
assert!(r1 == r3);
assert!(r1 != r4);
}
#[test]
fn test_ord() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(7), BigInt::from(10));
let r3 = Rational::new(BigInt::from(301), BigInt::from(500));
let r4 = Rational::new(BigInt::from(300), BigInt::from(-500));
let values: Vec<&Rational<BigInt>> = BTreeSet::from([&r1, &r2, &r3, &r4])
.iter()
.map(|it| *it)
.collect();
let expected_order = Vec::from([&r4, &r1, &r3, &r2]);
assert_eq!(expected_order, values);
}
}

208
src/sludecomposition.rs Normal file
View File

@@ -0,0 +1,208 @@
use num_traits::One;
use num_traits::Zero;
use std::ops::Add;
use std::ops::Div;
use std::ops::DivAssign;
use std::ops::Mul;
use std::ops::MulAssign;
use std::ops::Neg;
use std::ops::SubAssign;
use crate::Matrix;
use crate::SingularMatrixError;
use super::matrix::LUDecompositionImpl;
use super::matrix::LUDecomposition;
use super::matrix::NumericalMatrixImpl;
use super::spivot::SPivot;
use super::NumericalMatrix;
use super::Pivot;
use super::SMatrix;
use super::misc::EnhancedOption;
pub struct SLUDecomposition<TYPE, const SIZE: usize> {
matrix: SMatrix<TYPE, SIZE, SIZE>,
pivot: SPivot<SIZE>,
}
impl<TYPE, const SIZE: usize> SLUDecomposition<TYPE, SIZE>
where TYPE : Zero + SubAssign<TYPE> + Clone,
for<'a> &'a TYPE : Mul<&'a TYPE, Output = TYPE>,
for<'a> TYPE : DivAssign<&'a TYPE> {
pub (crate) fn new(matrix: SMatrix<TYPE, SIZE, SIZE>, pivot: Option<SPivot<SIZE>>) -> Self {
SLUDecomposition {
matrix,
pivot: pivot.otherwise(|| SPivot::new(SIZE)),
}
}
pub fn solve<const COLUMNS : usize>(&self, b : &SMatrix<TYPE, SIZE, COLUMNS>) -> Result<SMatrix<TYPE, SIZE, COLUMNS>, SingularMatrixError> {
let mut x = SMatrix::<TYPE, SIZE, COLUMNS>::new(|_| TYPE::zero());
for n in 0..b.columns() {
for i in 0..self.matrix.rows() {
x[(i, n)] = b[(self.pivot[i], n)].clone();
for k in 0..i {
let sub = &self.matrix[(i, k)] * &x[(k, n)];
x[(i, n)] -= sub;
}
}
for i in (0..self.matrix.rows()).rev() {
for k in (i + 1)..self.matrix.rows() {
let sub = &self.matrix[(i, k)] * &x[(k, n)];
x[(i, n)] -= sub;
}
if self.matrix[(i, i)].is_zero() {
return Err(SingularMatrixError::default());
} else {
x[(i, n)] /= &self.matrix[(i, i)];
}
}
}
Ok(x)
}
}
impl<TYPE, const SIZE: usize> LUDecomposition<TYPE, SMatrix<TYPE, SIZE, SIZE>, SPivot<SIZE>>
for SLUDecomposition<TYPE, SIZE>
where
for<'b> TYPE: Clone
+ Zero
+ One
+ PartialEq
+ PartialOrd
+ Neg<Output = TYPE>
+ Div<Output = TYPE>
+ SubAssign<TYPE>
+ SubAssign<&'b TYPE>
+ DivAssign<TYPE>
+ DivAssign<&'b TYPE>
+ MulAssign<&'b TYPE>,
for<'c> &'c TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
fn l(&self) -> SMatrix<TYPE, SIZE, SIZE> {
self.matrix.clone().tril_replace(TYPE::one())
}
fn u(&self) -> SMatrix<TYPE, SIZE, SIZE> {
self.matrix.clone().triu()
}
fn invert(&self) -> SMatrix<TYPE, SIZE, SIZE> {
let mut result = SMatrix::<TYPE, SIZE, SIZE>::new(|_| TYPE::zero());
self.matrix.lu_invert(&mut result, &mut self.pivot.clone());
result
}
fn pivot(&self, m: SMatrix<TYPE, SIZE, SIZE>) -> SMatrix<TYPE, SIZE, SIZE> {
&self.pivot * m
}
// fn p<'a>(&'a self) -> &'a HPivot {
// &self.pivot
// }
}
impl<TYPE, const SIZE: usize> LUDecompositionImpl<TYPE, SMatrix<TYPE, SIZE, SIZE>, SPivot<SIZE>>
for SLUDecomposition<TYPE, SIZE>
where
for<'b> TYPE: One + MulAssign<&'b TYPE> + Neg<Output = TYPE>,
{
fn get_matrix(&self) -> &SMatrix<TYPE, SIZE, SIZE> {
&self.matrix
}
fn get_pivot(&self) -> &SPivot<SIZE> {
&self.pivot
}
}
#[cfg(test)]
mod test {
use rand::rngs::StdRng;
use rand::RngCore;
use rand::SeedableRng;
use crate::NumericalMatrix;
use crate::Rational;
use crate::SMatrix;
use num_traits::Zero;
use rand;
#[test]
fn solve_linear_system() {
let mut rand = {
let seed = [
1,0,1,3,
2,5,0,0,
200,1,0,0,
210,30,0,0,
78,134,31,0,
253,11,7,0,
120,169,89,48,
200,0,202,0
];
StdRng::from_seed(seed)
};
let mtx = SMatrix::<Rational<i64>, 5, 5>::new(|_| {
Rational::new(i64::try_from(rand.next_u32() % 40).unwrap() - 20, 1)
});
let b = SMatrix::<Rational<i64>, 5, 5>::new(|_| {
Rational::new(i64::try_from(rand.next_u32() % 20).unwrap() - 10, 1)
});
let lu = mtx.clone().lu().unwrap();
let x = lu.solve(&b).unwrap();
assert!((mtx * x - b).is_zero());
}
}
#[cfg(test)]
mod test_big_int {
use num_traits::Zero;
use rand::rngs::StdRng;
use rand::RngCore;
use rand::SeedableRng;
use crate::NumericalMatrix;
use crate::Rational;
use crate::SMatrix;
use rand;
#[test]
fn solve_linear_system() {
use num_bigint::BigInt;
use num_traits::One;
let mut rand = {
let seed = [
1,0,1,3,
2,5,0,0,
200,1,0,0,
210,30,0,0,
78,134,31,0,
253,11,7,0,
120,169,89,48,
200,0,202,0
];
StdRng::from_seed(seed)
};
let mtx = SMatrix::<Rational<BigInt>, 10, 10>::new(|_| {
Rational::new(BigInt::from(rand.next_u32() % 200) - 100, BigInt::one())
});
let b = SMatrix::<Rational<BigInt>, 10, 10>::new(|_| {
Rational::new(BigInt::from(rand.next_u32() % 100) - 50, BigInt::one())
});
let lu = mtx.clone().lu().unwrap();
let x = lu.solve(&b).unwrap();
assert!((mtx * x - b).is_zero());
}
}

956
src/smatrix.rs Normal file
View File

@@ -0,0 +1,956 @@
use num_traits::One;
use num_traits::Zero;
use std::cmp::PartialEq;
use std::fmt::Debug;
use std::fmt::Display;
use std::iter::Enumerate;
use std::iter::Flatten;
use std::iter::IntoIterator;
use std::ops::Add;
use std::ops::Div;
use std::ops::DivAssign;
use std::ops::FnMut;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Mul;
use std::ops::MulAssign;
use std::ops::Neg;
use std::ops::Sub;
use std::ops::SubAssign;
use super::err::SizeError;
use super::matrix::MatrixImpl;
use super::matrix::NumericalMatrixImpl;
use super::misc::debug_fmt;
use super::sludecomposition::SLUDecomposition;
use super::Matrix;
use super::NumericalMatrix;
use super::Pivot;
use super::SingularMatrixError;
use super::spivot::SPivot;
pub struct SMatrix<TYPE, const ROWS: usize, const COLUMNS: usize> {
values: [[TYPE; COLUMNS]; ROWS],
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: Clone,
{
pub fn transpose(&self) -> SMatrix<TYPE, COLUMNS, ROWS> {
SMatrix::<TYPE, COLUMNS, ROWS>::new(|(i, j)| self[(j, i)].clone())
}
}
impl<TYPE, const SIZE: usize> SMatrix<TYPE, SIZE, SIZE> {
pub fn transpose_in_place(mut self)
where
Self: Sized,
{
for i in 0..self.rows() {
for j in 0..self.columns() {
self.swap((i, j), (j, i));
}
}
}
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Index<(usize, usize)>
for SMatrix<TYPE, ROWS, COLUMNS>
{
fn index(&self, index: (usize, usize)) -> &TYPE {
&self.values[index.0][index.1]
}
type Output = TYPE;
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> IndexMut<(usize, usize)>
for SMatrix<TYPE, ROWS, COLUMNS>
{
fn index_mut(&mut self, index: (usize, usize)) -> &mut TYPE {
&mut self.values[index.0][index.1]
}
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Default for SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: Default,
{
fn default() -> Self {
Self::new(|_| TYPE::default())
}
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Clone for SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: Clone,
{
fn clone(&self) -> Self {
SMatrix::new(|it| self[it].clone())
}
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Copy for SMatrix<TYPE, ROWS, COLUMNS> where
TYPE: Copy
{
}
impl<'a, TYPE, const ROWS: usize, const COLUMNS: usize> MatrixImpl<'a, TYPE>
for SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: 'a,
{
type IteratorType = SMatrixIterator<TYPE, ROWS, COLUMNS>;
type RefIteratorType<'b> = SMatrixIteratorRef<'a, TYPE, ROWS, COLUMNS>;
type MutRefIteratorType<'b> = SMatrixIteratorMut<'a, TYPE, ROWS, COLUMNS>;
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Matrix<TYPE> for SMatrix<TYPE, ROWS, COLUMNS> {
fn columns(&self) -> usize {
COLUMNS
}
fn rows(&self) -> usize {
ROWS
}
fn transpose(mut self) -> Result<Self, crate::SizeError> {
if ROWS != COLUMNS {
Err(SizeError::new("Matrix must be squared"))
} else {
self.transpose_in_place()?;
Ok(self)
}
}
}
#[opimps::impl_ops(Add)]
fn add<TYPE, const ROWS: usize, const COLUMNS: usize>(
self: SMatrix<TYPE, ROWS, COLUMNS>,
rhs: SMatrix<TYPE, ROWS, COLUMNS>,
) -> SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: Add<Output = TYPE>,
for<'a> &'a TYPE: Add<&'a TYPE, Output = TYPE>,
{
SMatrix::new(|position| &self[position] + &rhs[position])
}
#[opimps::impl_ops(Sub)]
fn sub<TYPE, const ROWS: usize, const COLUMNS: usize>(
self: SMatrix<TYPE, ROWS, COLUMNS>,
rhs: SMatrix<TYPE, ROWS, COLUMNS>,
) -> SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: Sub<Output = TYPE>,
for<'a> &'a TYPE: Sub<&'a TYPE, Output = TYPE>,
{
SMatrix::new(|position| &self[position] - &rhs[position])
}
#[opimps::impl_ops(Mul)]
fn mul<
TYPE,
const L_ROWS: usize,
const L_COLUMNS: usize,
const R_ROWS: usize,
const R_COLUMNS: usize,
>(
self: SMatrix<TYPE, L_ROWS, L_COLUMNS>,
rhs: SMatrix<TYPE, R_ROWS, R_COLUMNS>,
) -> SMatrix<TYPE, L_ROWS, R_COLUMNS>
where
TYPE: Mul<Output = TYPE> + Add<Output = TYPE> + Zero,
for<'a> &'a TYPE: Add<&'a TYPE, Output = TYPE> + Mul<&'a TYPE, Output = TYPE>,
{
let mut result: SMatrix<TYPE, L_ROWS, R_COLUMNS> = SMatrix::new(|_| TYPE::zero());
for i in 0..result.rows() {
for j in 0..result.columns() {
for k in 0..self.columns() {
let prod = &self[(i, k)] * &rhs[(k, j)];
result[(i, j)] = &result[(i, j)] + &prod;
}
}
}
result
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Display for SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let lim = self.rows() * self.columns() - 1;
writeln!(f, "[")?;
for i in 0..self.rows() {
write!(f, " ")?;
for j in 0..self.columns() {
let index = i * self.columns() + j;
write!(f, "{}", self[(i, j)])?;
if index < lim {
write!(f, ", ")?;
}
}
writeln!(f)?;
}
write!(f, "]")
}
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> SMatrix<TYPE, ROWS, COLUMNS> {
pub fn new<INITIALIZER>(mut cb: INITIALIZER) -> Self
where
INITIALIZER: FnMut((usize, usize)) -> TYPE,
{
let values: [[TYPE; COLUMNS]; ROWS] =
std::array::from_fn(|i| std::array::from_fn(|j| cb((i, j))));
SMatrix { values }
}
}
pub struct SMatrixIterator<TYPE, const ROWS: usize, const COLUMNS: usize> {
it: Enumerate<Flatten<std::array::IntoIter<[TYPE; COLUMNS], ROWS>>>,
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Iterator
for SMatrixIterator<TYPE, ROWS, COLUMNS>
{
fn next(&mut self) -> Option<Self::Item> {
self.it
.next()
.map(|(index, value)| (index / COLUMNS, index % COLUMNS, value))
}
type Item = (usize, usize, TYPE);
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> IntoIterator for SMatrix<TYPE, ROWS, COLUMNS> {
fn into_iter(self) -> SMatrixIterator<TYPE, ROWS, COLUMNS> {
SMatrixIterator {
it: self.values.into_iter().flatten().enumerate(),
}
}
type IntoIter = SMatrixIterator<TYPE, ROWS, COLUMNS>;
type Item = (usize, usize, TYPE);
}
pub struct SMatrixIteratorRef<'a, TYPE, const ROWS: usize, const COLUMNS: usize> {
it: Enumerate<Flatten<std::slice::Iter<'a, [TYPE; COLUMNS]>>>,
}
impl<'a, TYPE, const ROWS: usize, const COLUMNS: usize> Iterator
for SMatrixIteratorRef<'a, TYPE, ROWS, COLUMNS>
{
fn next(&mut self) -> Option<Self::Item> {
self.it
.next()
.map(|(index, value)| (index / COLUMNS, index % COLUMNS, value))
}
type Item = (usize, usize, &'a TYPE);
}
impl<'a, TYPE, const ROWS: usize, const COLUMNS: usize> IntoIterator
for &'a SMatrix<TYPE, ROWS, COLUMNS>
{
fn into_iter(self) -> SMatrixIteratorRef<'a, TYPE, ROWS, COLUMNS> {
SMatrixIteratorRef {
it: (self.values).iter().flatten().enumerate(),
}
}
type IntoIter = SMatrixIteratorRef<'a, TYPE, ROWS, COLUMNS>;
type Item = (usize, usize, &'a TYPE);
}
pub struct SMatrixIteratorMut<'a, TYPE, const ROWS: usize, const COLUMNS: usize> {
it: Enumerate<Flatten<std::slice::IterMut<'a, [TYPE; COLUMNS]>>>,
}
impl<'a, TYPE, const ROWS: usize, const COLUMNS: usize> Iterator
for SMatrixIteratorMut<'a, TYPE, ROWS, COLUMNS>
{
fn next(&mut self) -> Option<Self::Item> {
self.it
.next()
.map(|(index, value)| (index / COLUMNS, index % COLUMNS, value))
}
type Item = (usize, usize, &'a mut TYPE);
}
impl<'a, TYPE, const ROWS: usize, const COLUMNS: usize> IntoIterator
for &'a mut SMatrix<TYPE, ROWS, COLUMNS>
{
fn into_iter(self) -> SMatrixIteratorMut<'a, TYPE, ROWS, COLUMNS> {
SMatrixIteratorMut {
it: self.values.iter_mut().flatten().enumerate(),
}
}
type IntoIter = SMatrixIteratorMut<'a, TYPE, ROWS, COLUMNS>;
type Item = (usize, usize, &'a mut TYPE);
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> PartialEq for SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
(0..ROWS)
.flat_map(|i| (0..COLUMNS).map(move |j| (i, j)))
.all(|index| self[index] == other[index])
}
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Debug for SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
debug_fmt(self, f)
}
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Zero for SMatrix<TYPE, ROWS, COLUMNS>
where
TYPE: PartialEq + One + Zero + Add<TYPE, Output = TYPE>,
for<'a> &'a TYPE: Add<&'a TYPE, Output = TYPE>,
{
fn zero() -> Self {
SMatrix::new(|_| TYPE::zero())
}
fn is_zero(&self) -> bool {
*self == Self::zero()
}
}
impl<TYPE, const SIZE: usize> One for SMatrix<TYPE, SIZE, SIZE>
where
for<'b> TYPE: Clone
+ Zero
+ One
+ PartialEq
+ PartialOrd
+ DivAssign<TYPE>
+ SubAssign<TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>
+ SubAssign<&'b TYPE>
+ DivAssign<&'b TYPE>
+ MulAssign<&'b TYPE>,
for<'a> &'a TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
fn one() -> Self {
<Self as NumericalMatrix<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>>::identity(SIZE)
}
}
impl<'a, TYPE, const SIZE: usize>
NumericalMatrixImpl<'a, TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>
for SMatrix<TYPE, SIZE, SIZE>
where
for<'b> TYPE: Clone
+ 'a
+ Zero
+ One
+ PartialEq
+ PartialOrd
+ DivAssign<TYPE>
+ SubAssign<TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>
+ SubAssign<&'b TYPE>
+ DivAssign<&'b TYPE>
+ MulAssign<&'b TYPE>,
for<'c> &'c TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
fn identity(_: usize) -> Self {
Self::new(|(i, j)| if i == j { TYPE::one() } else { TYPE::zero() })
}
}
impl<'a, TYPE, const SIZE: usize> NumericalMatrix<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>
for SMatrix<TYPE, SIZE, SIZE>
where
for<'b> TYPE: Clone
+ 'a
+ Zero
+ One
+ PartialEq
+ PartialOrd
+ DivAssign<TYPE>
+ SubAssign<TYPE>
+ Neg<Output = TYPE>
+ Div<Output = TYPE>
+ SubAssign<&'b TYPE>
+ DivAssign<&'b TYPE>
+ MulAssign<&'b TYPE>,
for<'c> &'c TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
fn identity(size: usize) -> Self {
NumericalMatrixImpl::<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>::identity(size)
}
fn tril(mut self) -> Self {
self.tril_impl(None);
self
}
fn triu(mut self) -> Self {
self.triu_impl(None);
self
}
fn tril_replace(mut self, diag_replacement: TYPE) -> Self {
self.tril_impl(Some(diag_replacement));
self
}
fn triu_replace(mut self, diag_replacement: TYPE) -> Self {
self.triu_impl(Some(diag_replacement));
self
}
fn gauss_jordan_high(mut self) -> Self {
let mut pivot = SPivot::<SIZE>::new(self.rows());
NumericalMatrixImpl::<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>::gauss_jordan_high(
&mut self, &mut pivot,
);
self
}
fn gauss_jordan_low(mut self) -> Self {
let mut pivot = SPivot::<SIZE>::new(self.rows());
NumericalMatrixImpl::<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>::gauss_jordan_low(
&mut self, &mut pivot,
);
self
}
fn det(self) -> TYPE {
let pivot = SPivot::new(self.rows());
NumericalMatrixImpl::<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>::det(self, pivot)
}
fn invert(&mut self) -> Self {
let mut result = NumericalMatrix::identity(self.rows());
let mut pivot = SPivot::new(self.rows());
NumericalMatrixImpl::<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>::invert(
self,
&mut pivot,
&mut result,
);
result
}
fn lup(mut self) -> Result<SLUDecomposition<TYPE, SIZE>, SingularMatrixError> {
let mut pivot = SPivot::new(self.columns());
NumericalMatrixImpl::<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>::lup(
&mut self, &mut pivot,
)?;
Ok(SLUDecomposition::<TYPE, SIZE>::new(self, Some(pivot)))
}
fn lu(mut self) -> Result<SLUDecomposition<TYPE, SIZE>, SingularMatrixError> {
NumericalMatrixImpl::<TYPE, SPivot<SIZE>, SLUDecomposition<TYPE, SIZE>>::lu(&mut self)?;
Ok(SLUDecomposition::<TYPE, SIZE>::new(self, None))
}
}
#[cfg(test)]
mod tests {
use crate::LUDecomposition;
use crate::Matrix;
use crate::NumericalMatrix;
use crate::Rational;
use crate::SMatrix;
use num_traits::One;
use num_traits::Zero;
#[test]
fn test_new() {
let mut idx = 0;
let m1 = SMatrix::<i32, 3, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
idx = 0;
for (_, _, value) in m1 {
assert_eq!(idx, value);
idx += 1;
}
}
#[test]
fn test_eq() {
let mut idx = 0;
let m1 = SMatrix::<i32, 3, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
idx = 0;
for (_, _, value) in m1 {
assert_eq!(idx, value);
idx += 1;
}
let m2 = m1.clone();
assert!(m1 == m2);
}
#[test]
fn test_sum() {
let mut idx = 0;
let m1 = SMatrix::<i32, 3, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
let m2 = SMatrix::<i32, 3, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
let m3 = m1 + m2;
for i in 0..m1.rows() {
for j in 0..m1.columns() {
assert_eq!(m3[(i, j)], m1[(i, j)] + m2[(i, j)]);
}
}
}
#[test]
fn test_sub() {
let mut idx = 0;
let m1 = SMatrix::<i32, 3, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
let m2 = SMatrix::<i32, 3, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
let m3 = m1 - m2;
for i in 0..m1.rows() {
for j in 0..m1.columns() {
assert_eq!(m3[(i, j)], m1[(i, j)] - m2[(i, j)]);
}
}
}
#[test]
fn test_mul() {
let mut idx = 0;
let m1 = SMatrix::<i32, 3, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
idx = 0;
let m2 = SMatrix::<i32, 5, 2>::new(|_| {
let res = idx;
idx += 1;
res
});
let m3 = m1 * m2;
let expected = {
let mut idx = 0;
let values = [60, 70, 160, 195, 260, 320];
SMatrix::<i32, 3, 2>::new(|_| {
let res = values[idx];
idx += 1;
res
})
};
assert!(expected == m3);
}
#[test]
fn test_one() {
let mut idx = 0;
let m1 = SMatrix::<i32, 5, 5>::new(|_| {
let res = idx;
idx += 1;
res
});
let m2 = SMatrix::<i32, 5, 5>::one();
let m3 = m1 * m2;
assert!(m1 == m3);
}
#[test]
fn test_inv() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<Rational<i64>, 3, 3>::new(|_| {
let res = Rational::new(arr[idx], i64::one());
idx += 1;
res
});
let m2 = NumericalMatrix::invert(&mut m1.clone());
let m3 = m1 * m2;
assert!(m3.is_one());
}
#[test]
fn test_det() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<Rational<i64>, 3, 3>::new(|_| {
let res = Rational::new(arr[idx], 1);
idx += 1;
res
});
assert_eq!(Rational::new(-9, 1), NumericalMatrix::det(m1));
}
#[test]
fn test_tril() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<i64, 3, 3>::new(|_| {
let res = arr[idx];
idx += 1;
res
});
let diag_value = 42;
let lt = m1.tril_replace(diag_value);
for (i, j, value) in lt {
if i == j {
assert_eq!(value, diag_value);
} else if i < j {
assert_eq!(value, i64::zero())
} else {
assert_eq!(value, i64::from(arr[i * 3 + j]))
}
}
}
#[test]
fn test_triu() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<i64, 3, 3>::new(|_| {
let res = arr[idx];
idx += 1;
res
});
let diag_value = 42;
let lt = m1.triu_replace(diag_value);
for (i, j, value) in lt {
if i == j {
assert_eq!(value, diag_value);
} else if i > j {
assert_eq!(value, i64::zero())
} else {
assert_eq!(value, i64::from(arr[i * 3 + j]))
}
}
}
#[test]
fn test_lu_decomposition() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let orig = SMatrix::<Rational<i64>, 3, 3>::new(|_| {
let res = Rational::new(arr[idx], i64::one());
idx += 1;
res
});
let m1 = orig.clone();
let lu = m1.lup().unwrap();
let tril = lu.l();
let triu = lu.u();
let m2 = lu.pivot(tril * triu);
assert_eq!(orig, m2);
}
#[test]
fn test_lu_invert() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let orig = SMatrix::<Rational<i64>, 3, 3>::new(|_| {
let res = Rational::new(arr[idx], i64::one());
idx += 1;
res
});
let m1 = orig.clone();
let lud = m1.lup().unwrap();
let m2 = lud.invert();
let m3 = orig * m2;
assert!(m3.is_one());
}
#[test]
fn test_lu_det() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<Rational<i64>, 3, 3>::new(|_| {
let res = Rational::new(arr[idx], 1);
idx += 1;
res
});
assert_eq!(Rational::new(-9, 1), m1.lup().unwrap().det());
}
}
#[cfg(test)]
mod big_int_tests {
use num_bigint::BigInt;
use crate::LUDecomposition;
use crate::Matrix;
use crate::NumericalMatrix;
use crate::Rational;
use crate::SMatrix;
use num_traits::One;
use num_traits::Zero;
#[test]
fn test_new() {
let mut idx = 0;
let m1 = SMatrix::<BigInt, 3, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
idx = 0;
for (_, _, value) in m1 {
assert_eq!(BigInt::from(idx), value);
idx += 1;
}
}
#[test]
fn test_eq() {
let mut idx = 0;
let m1 = SMatrix::<BigInt, 3, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
idx = 0;
let m2 = m1.clone();
assert!(m1 == m2);
for (_, _, value) in &m1 {
assert_eq!(BigInt::from(idx), *value);
idx += 1;
}
}
#[test]
fn test_sum() {
let mut idx = 0;
let m1 = SMatrix::<BigInt, 3, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m2 = SMatrix::<BigInt, 3, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m3 = &m1 + &m2;
for i in 0..m1.rows() {
for j in 0..m1.columns() {
assert_eq!(m3[(i, j)], &m1[(i, j)] + &m2[(i, j)]);
}
}
}
#[test]
fn test_sub() {
let mut idx = 0;
let m1 = SMatrix::<BigInt, 3, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m2 = SMatrix::<BigInt, 3, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m3 = &m1 - &m2;
for i in 0..m1.rows() {
for j in 0..m1.columns() {
assert_eq!(m3[(i, j)], &m1[(i, j)] - &m2[(i, j)]);
}
}
}
#[test]
fn test_mul() {
let mut idx = 0;
let m1 = SMatrix::<BigInt, 3, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
idx = 0;
let m2 = SMatrix::<BigInt, 5, 2>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m3 = m1 * m2;
let expected = {
let mut idx = 0;
let values = [60, 70, 160, 195, 260, 320];
SMatrix::<BigInt, 3, 2>::new(|_| {
let res = BigInt::from(values[idx]);
idx += 1;
res
})
};
assert!(expected == m3);
}
#[test]
fn test_one() {
let mut idx = 0;
let m1 = SMatrix::<BigInt, 5, 5>::new(|_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m2 = SMatrix::<BigInt, 5, 5>::one();
let m3 = &m1 * &m2;
assert!(m1 == m3);
}
#[test]
fn test_inv() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<Rational<BigInt>, 3, 3>::new(|_| {
let res = Rational::new(BigInt::from(arr[idx]), BigInt::one());
idx += 1;
res
});
let m2 = NumericalMatrix::invert(&mut m1.clone());
let m3 = m1 * m2;
assert!(m3.is_one());
}
#[test]
fn test_det() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<Rational<BigInt>, 3, 3>::new(|_| {
let res = Rational::new(BigInt::from(arr[idx]), BigInt::one());
idx += 1;
res
});
assert_eq!(
Rational::new(BigInt::from(9), -BigInt::one()),
NumericalMatrix::det(m1)
);
}
#[test]
fn test_tril() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<BigInt, 3, 3>::new(|_| {
let res = BigInt::from(arr[idx]);
idx += 1;
res
});
let diag_value = BigInt::from(42);
let lt = m1.tril_replace(diag_value.clone());
for (i, j, value) in lt {
if i == j {
assert_eq!(value, diag_value);
} else if i < j {
assert_eq!(value, BigInt::zero())
} else {
assert_eq!(value, BigInt::from(arr[i * 3 + j]))
}
}
}
#[test]
fn test_triu() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<BigInt, 3, 3>::new(|_| {
let res = BigInt::from(arr[idx]);
idx += 1;
res
});
let diag_value = BigInt::from(42);
let lt = m1.triu_replace(diag_value.clone());
for (i, j, value) in lt {
if i == j {
assert_eq!(value, diag_value);
} else if i > j {
assert_eq!(value, BigInt::zero())
} else {
assert_eq!(value, BigInt::from(arr[i * 3 + j]))
}
}
}
#[test]
fn test_lu_decomposition() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let orig = SMatrix::<Rational<BigInt>, 3, 3>::new(|_| {
let res = Rational::new(BigInt::from(arr[idx]), BigInt::one());
idx += 1;
res
});
let m1 = orig.clone();
let lu = m1.lup().unwrap();
let tril = lu.l();
let triu = lu.u();
let m2 = lu.pivot(tril * triu);
assert_eq!(orig, m2);
}
#[test]
fn test_lu_invert() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let orig = SMatrix::<Rational<BigInt>, 3, 3>::new(|_| {
let res = Rational::new(BigInt::from(arr[idx]), BigInt::one());
idx += 1;
res
});
let m1 = orig.clone();
let lu = m1.lup().unwrap();
let m2 = lu.invert();
let m3 = orig * m2;
assert!(m3.is_one());
}
#[test]
fn test_lu_det() {
let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9];
let mut idx = 0;
let m1 = SMatrix::<Rational<BigInt>, 3, 3>::new(|_| {
let res = Rational::new(BigInt::from(arr[idx]), BigInt::one());
idx += 1;
res
});
assert_eq!(
Rational::new(BigInt::from(-9), BigInt::one()),
m1.lup().unwrap().det()
);
}
}

94
src/spivot.rs Normal file
View File

@@ -0,0 +1,94 @@
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Mul;
use super::matrix::MatrixImpl;
use super::smatrix::SMatrix;
use super::Matrix;
use super::Pivot;
pub struct SPivot<const SIZE: usize> {
data: [usize; SIZE],
permutations: usize,
}
impl<const SIZE: usize> Index<usize> for SPivot<SIZE> {
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
type Output = usize;
}
impl<const SIZE: usize> IndexMut<usize> for SPivot<SIZE> {
fn index_mut(&mut self, index: usize) -> &mut <Self as Index<usize>>::Output {
&mut self.data[index]
}
}
impl<const SIZE: usize> Pivot for SPivot<SIZE> {
fn swap(&mut self, i1: usize, i2: usize) {
self.data.swap(i1, i2);
self.permutations += 1;
}
fn permutations(&self) -> usize {
self.permutations
}
fn new(_: usize) -> Self {
SPivot {
data: std::array::from_fn(|i| i),
permutations: 0,
}
}
}
impl<const ROWS: usize, const COLUMNS: usize, TYPE> Mul<SMatrix<TYPE, ROWS, COLUMNS>>
for SPivot<ROWS>
where
TYPE: Clone,
{
fn mul(self, matrix: SMatrix<TYPE, ROWS, COLUMNS>) -> Self::Output {
let mut result = matrix.clone();
let mut pclone = self.clone();
for i in 0..ROWS {
while i != pclone[i] {
let j = pclone[i];
result.swap_rows_pivot(&mut pclone, i, j);
}
}
result
}
type Output = SMatrix<TYPE, ROWS, COLUMNS>;
}
impl<TYPE, const ROWS: usize, const COLUMNS: usize> Mul<SMatrix<TYPE, ROWS, COLUMNS>>
for &SPivot<ROWS>
where
TYPE: Clone,
{
fn mul(self, matrix: SMatrix<TYPE, ROWS, COLUMNS>) -> Self::Output {
let mut result = matrix.clone();
let mut pclone = self.clone();
for i in 0..matrix.rows() {
while i != pclone[i] {
let j = pclone[i];
result.swap_rows_pivot(&mut pclone, i, j);
}
}
result
}
type Output = SMatrix<TYPE, ROWS, COLUMNS>;
}
impl<const SIZE: usize> Clone for SPivot<SIZE> {
fn clone(&self) -> Self {
SPivot {
data: self.data,
permutations: self.permutations,
}
}
}