Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
86
Task/LU-decomposition/Rust/lu-decomposition-1.rust
Normal file
86
Task/LU-decomposition/Rust/lu-decomposition-1.rust
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#![allow(non_snake_case)]
|
||||
use ndarray::{Array, Axis, Array2, arr2, Zip, NdFloat, s};
|
||||
|
||||
fn main() {
|
||||
println!("Example 1:");
|
||||
let A: Array2<f64> = arr2(&[
|
||||
[1.0, 3.0, 5.0],
|
||||
[2.0, 4.0, 7.0],
|
||||
[1.0, 1.0, 0.0],
|
||||
]);
|
||||
println!("A \n {}", A);
|
||||
let (L, U, P) = lu_decomp(A);
|
||||
println!("L \n {}", L);
|
||||
println!("U \n {}", U);
|
||||
println!("P \n {}", P);
|
||||
|
||||
println!("\nExample 2:");
|
||||
let A: Array2<f64> = arr2(&[
|
||||
[11.0, 9.0, 24.0, 2.0],
|
||||
[1.0, 5.0, 2.0, 6.0],
|
||||
[3.0, 17.0, 18.0, 1.0],
|
||||
[2.0, 5.0, 7.0, 1.0],
|
||||
]);
|
||||
println!("A \n {}", A);
|
||||
let (L, U, P) = lu_decomp(A);
|
||||
println!("L \n {}", L);
|
||||
println!("U \n {}", U);
|
||||
println!("P \n {}", P);
|
||||
}
|
||||
|
||||
fn pivot<T>(A: &Array2<T>) -> Array2<T>
|
||||
where T: NdFloat {
|
||||
let matrix_dimension = A.rows();
|
||||
let mut P: Array2<T> = Array::eye(matrix_dimension);
|
||||
for (i, column) in A.axis_iter(Axis(1)).enumerate() {
|
||||
// find idx of maximum value in column i
|
||||
let mut max_pos = i;
|
||||
for j in i..matrix_dimension {
|
||||
if column[max_pos].abs() < column[j].abs() {
|
||||
max_pos = j;
|
||||
}
|
||||
}
|
||||
// swap rows of P if necessary
|
||||
if max_pos != i {
|
||||
swap_rows(&mut P, i, max_pos);
|
||||
}
|
||||
}
|
||||
P
|
||||
}
|
||||
|
||||
fn swap_rows<T>(A: &mut Array2<T>, idx_row1: usize, idx_row2: usize)
|
||||
where T: NdFloat {
|
||||
// to swap rows, get two ArrayViewMuts for the corresponding rows
|
||||
// and apply swap elementwise using ndarray::Zip
|
||||
let (.., mut matrix_rest) = A.view_mut().split_at(Axis(0), idx_row1);
|
||||
let (row0, mut matrix_rest) = matrix_rest.view_mut().split_at(Axis(0), 1);
|
||||
let (_matrix_helper, mut matrix_rest) = matrix_rest.view_mut().split_at(Axis(0), idx_row2 - idx_row1 - 1);
|
||||
let (row1, ..) = matrix_rest.view_mut().split_at(Axis(0), 1);
|
||||
Zip::from(row0).and(row1).apply(std::mem::swap);
|
||||
}
|
||||
|
||||
fn lu_decomp<T>(A: Array2<T>) -> (Array2<T>, Array2<T>, Array2<T>)
|
||||
where T: NdFloat {
|
||||
|
||||
let matrix_dimension = A.rows();
|
||||
assert_eq!(matrix_dimension, A.cols(), "Tried LU decomposition with a non-square matrix.");
|
||||
let P = pivot(&A);
|
||||
let pivotized_A = P.dot(&A);
|
||||
|
||||
let mut L: Array2<T> = Array::eye(matrix_dimension);
|
||||
let mut U: Array2<T> = Array::zeros((matrix_dimension, matrix_dimension));
|
||||
for idx_col in 0..matrix_dimension {
|
||||
// fill U
|
||||
for idx_row in 0..idx_col+1 {
|
||||
U[[idx_row, idx_col]] = pivotized_A[[idx_row, idx_col]] -
|
||||
U.slice(s![0..idx_row,idx_col]).dot(&L.slice(s![idx_row,0..idx_row]));
|
||||
}
|
||||
// fill L
|
||||
for idx_row in idx_col+1..matrix_dimension {
|
||||
L[[idx_row, idx_col]] = (pivotized_A[[idx_row, idx_col]] -
|
||||
U.slice(s![0..idx_col,idx_col]).dot(&L.slice(s![idx_row,0..idx_col]))) /
|
||||
U[[idx_col, idx_col]];
|
||||
}
|
||||
}
|
||||
(L, U, P)
|
||||
}
|
||||
261
Task/LU-decomposition/Rust/lu-decomposition-2.rust
Normal file
261
Task/LU-decomposition/Rust/lu-decomposition-2.rust
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
use abstalg::*;
|
||||
pub struct Matrix2D<'a, F>
|
||||
where
|
||||
F: Field,
|
||||
{
|
||||
field: MatrixRing<F>,
|
||||
data: &'a mut Vec<<F as Domain>::Elem>,
|
||||
rows: usize,
|
||||
cols: usize,
|
||||
}
|
||||
|
||||
impl<'a, F: Field + Clone> Matrix2D<'a, F> {
|
||||
pub fn new(field: F, data: &'a mut Vec<<F as Domain>::Elem>, rows: usize, cols: usize) -> Self {
|
||||
assert_eq!(rows * cols, data.len(), "Data does not match dimensions");
|
||||
Matrix2D {
|
||||
field: MatrixRing::<F>::new(field, rows),
|
||||
data,
|
||||
rows,
|
||||
cols,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, row: usize, col: usize) -> &<F as Domain>::Elem {
|
||||
assert!(row < self.rows && col < self.cols, "Index out of bounds");
|
||||
&self.data[row * self.cols + col]
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, row: usize, col: usize) -> &mut <F as Domain>::Elem {
|
||||
assert!(row < self.rows && col < self.cols, "Index out of bounds");
|
||||
&mut self.data[row * self.cols + col]
|
||||
}
|
||||
|
||||
pub fn get_row(&self, row: usize) -> Vec<<F as Domain>::Elem> {
|
||||
assert!(row < self.rows, "Row index out of bounds");
|
||||
let mut result = Vec::new();
|
||||
for col in 0..self.cols {
|
||||
result.push(self.get(row, col).clone());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_col(&self, col: usize) -> Vec<<F as Domain>::Elem> {
|
||||
assert!(col < self.cols, "Column index out of bounds");
|
||||
let mut result = Vec::new();
|
||||
for row in 0..self.rows {
|
||||
result.push(self.get(row, col).clone());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn set_row(&mut self, row: usize, new_row: Vec<<F as Domain>::Elem>) {
|
||||
assert!(row < self.rows, "Row index out of bounds");
|
||||
assert_eq!(new_row.len(), self.cols, "New row has wrong length");
|
||||
for col in 0..self.cols {
|
||||
*self.get_mut(row, col) = new_row[col].clone();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_col(&mut self, col: usize, new_col: Vec<<F as Domain>::Elem>) {
|
||||
assert!(col < self.cols, "Column index out of bounds");
|
||||
assert_eq!(new_col.len(), self.rows, "New column has wrong length");
|
||||
for row in 0..self.rows {
|
||||
*self.get_mut(row, col) = new_col[row].clone();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_rows(&mut self, row1: usize, row2: usize) {
|
||||
assert!(
|
||||
row1 < self.rows && row2 < self.rows,
|
||||
"Row index out of bounds"
|
||||
);
|
||||
if row1 != row2 {
|
||||
for col in 0..self.cols {
|
||||
let temp = self.get(row1, col).clone();
|
||||
*self.get_mut(row1, col) = self.get(row2, col).clone();
|
||||
*self.get_mut(row2, col) = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn l_u_decomposition(&mut self) -> Result<Vec<<F as Domain>::Elem>, String>
|
||||
where
|
||||
F: Clone,
|
||||
{
|
||||
// Let base = field.base()
|
||||
let base = self.field.base().clone();
|
||||
// Let v_a = VectorAlgebra(base, cols)
|
||||
let v_a = VectorAlgebra::new(base.clone(), self.cols);
|
||||
// Let the_l_matrix = I (creates an identity matrix)
|
||||
let mut the_l_matrix: Vec<_> = self.field.int(1);
|
||||
// Let l_matrix = Matrix2D(base, the_l_matrix, rows, cols)
|
||||
let mut l_matrix = Matrix2D::new(base.clone(), &mut the_l_matrix, self.rows, self.cols);
|
||||
|
||||
// For each pivot in min(rows, cols)
|
||||
for pivot in 0..std::cmp::min(self.rows, self.cols) {
|
||||
// Let pivot_row = self.get_row(pivot)
|
||||
let pivot_row = self.get_row(pivot);
|
||||
// If pivot element (pivot_row[pivot]) is zero, LU decomposition is not possible
|
||||
if base.is_zero(&pivot_row[pivot]) {
|
||||
return Err(
|
||||
"LU decomposition without pivoting is not possible for this matrix".into(),
|
||||
);
|
||||
}
|
||||
// Let pivot_entry_inv = 1 / pivot_row[pivot]
|
||||
let pivot_entry_inv = base.inv(&pivot_row[pivot]);
|
||||
|
||||
// For each row_idx in (pivot + 1) to rows
|
||||
for row_idx in (pivot + 1)..self.rows {
|
||||
// Let row = self.get_row(row_idx)
|
||||
let mut row = self.get_row(row_idx);
|
||||
// Let scale = row[pivot] * pivot_entry_inv
|
||||
let scale = base.mul(&row[pivot], &pivot_entry_inv);
|
||||
|
||||
// row += -scale * pivot_row (Vector addition and scalar multiplication)
|
||||
v_a.add_assign(
|
||||
&mut row,
|
||||
&v_a.neg(&mul_vector(&v_a, scale.clone(), pivot_row.clone())),
|
||||
);
|
||||
|
||||
// l_matrix[row_idx][pivot] = scale
|
||||
*l_matrix.get_mut(row_idx, pivot) = scale;
|
||||
// self.set_row(row_idx, row) (Sets the modified row back into the matrix)
|
||||
self.set_row(row_idx, row);
|
||||
}
|
||||
}
|
||||
// Returns the L matrix
|
||||
Ok(the_l_matrix)
|
||||
}
|
||||
|
||||
pub fn p_l_u_decomposition(
|
||||
&self,
|
||||
) -> Result<
|
||||
(
|
||||
Vec<<F as Domain>::Elem>,
|
||||
Vec<<F as Domain>::Elem>,
|
||||
Vec<<F as Domain>::Elem>,
|
||||
),
|
||||
String,
|
||||
>
|
||||
where
|
||||
F: Clone,
|
||||
{
|
||||
let base = self.field.base().clone();
|
||||
let mut self2 = (*self.data).clone();
|
||||
let mut cloned_vector = Matrix2D::new(base.clone(), &mut self2, self.rows, self.cols);
|
||||
let mut pivot_row = 0;
|
||||
|
||||
let mut the_p_matrix: Vec<_> = self.field.zero();
|
||||
let mut p_matrix = Matrix2D::new(base.clone(), &mut the_p_matrix, self.rows, self.cols);
|
||||
//let mut u_matrix = self.clone(); //Initializes the U matrix as a copy of the original matrix
|
||||
|
||||
for pivot_col in 0..self.cols {
|
||||
// Find a non-zero entry in the pivot column
|
||||
let swap_row = (pivot_row..self.rows)
|
||||
.find(|&row| !base.equals(cloned_vector.get(row, pivot_col), &base.zero()));
|
||||
match swap_row {
|
||||
Some(swap_row) => {
|
||||
// Swap rows in U and P matrices to bring the non-zero entry to the pivot position
|
||||
cloned_vector.swap_rows(pivot_row, swap_row);
|
||||
p_matrix.swap_rows(pivot_row, swap_row);
|
||||
pivot_row += 1;
|
||||
}
|
||||
None => {
|
||||
// If there are no non-zero entries in the pivot column, just proceed to the next column
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the diagonals of P to 1
|
||||
for i in 0..self.rows {
|
||||
*p_matrix.get_mut(i, i) = base.one();
|
||||
}
|
||||
|
||||
// Run the LU decomposition on the permuted U matrix
|
||||
let l_u_result = cloned_vector.l_u_decomposition();
|
||||
|
||||
match l_u_result {
|
||||
Ok(the_l_matrix) => Ok((the_p_matrix, the_l_matrix, cloned_vector.data.clone())),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use std::{error::Error, fmt};
|
||||
impl<'a, T> fmt::Display for Matrix2D<'a, T>
|
||||
where
|
||||
<T as Domain>::Elem: fmt::Display,
|
||||
T: Field,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for row in 0..self.rows {
|
||||
for col in 0..self.cols {
|
||||
write!(f, "{} ", self.get(row, col))?;
|
||||
}
|
||||
writeln!(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn mul_vector<T>(
|
||||
f: &VectorAlgebra<T>,
|
||||
a: <T as Domain>::Elem,
|
||||
d: Vec<<T as Domain>::Elem>,
|
||||
) -> <VectorAlgebra<T> as Domain>::Elem
|
||||
where
|
||||
T: Field,
|
||||
{
|
||||
f.mul(&d, &f.diagonal(a))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*; // bring into scope everything from the parent module
|
||||
use abstalg::ReducedFractions;
|
||||
use abstalg::I32;
|
||||
|
||||
fn test_p_l_u_decomposition(matrix: Vec<isize>, size: usize) {
|
||||
// This test assumes that the base field is rational numbers.
|
||||
// Create a test 4x4 matrix
|
||||
let (matrix, size): (Vec<isize>, usize) =
|
||||
(vec![11, 9, 24, 2, 1, 5, 2, 6, 3, 17, 18, 1, 2, 5, 7, 1], 4);
|
||||
let field = abstalg::ReducedFractions::new(abstalg::I32);
|
||||
let matrix_ring = MatrixRing::new(field.clone(), size);
|
||||
let mut matrix: Vec<_> = matrix.clone().into_iter().map(|i| field.int(i)).collect();
|
||||
let mut matrix2d = Matrix2D::new(field.clone(), &mut matrix, size, size);
|
||||
|
||||
// Decompose the matrix using the p_l_u_decomposition function
|
||||
let p_l_u_decomposition_result = matrix2d.p_l_u_decomposition().unwrap();
|
||||
let (mut p_matrix, mut l_matrix, mut u_matrix) = p_l_u_decomposition_result;
|
||||
|
||||
// Convert the matrices back to Matrix2D form for printing
|
||||
let p_matrix2d = Matrix2D::new(field.clone(), &mut p_matrix, size, size);
|
||||
let l_matrix2d = Matrix2D::new(field.clone(), &mut l_matrix, size, size);
|
||||
let u_matrix2d = Matrix2D::new(field.clone(), &mut u_matrix, size, size);
|
||||
|
||||
println!("P={} L={} U={}", p_matrix2d, l_matrix2d, u_matrix2d,);
|
||||
|
||||
// Multiply the resulting P, L, and U matrices
|
||||
let p_l = matrix_ring.mul(&p_matrix, &l_matrix);
|
||||
let mut p_l_u = matrix_ring.mul(&p_l, &u_matrix);
|
||||
|
||||
//let p_l_u_2d = Matrix2D::new(field.clone(), &mut p_l_u, 4, 4);
|
||||
// Check that the product of P, L, and U is equal to the original matrix
|
||||
assert_eq!(matrix, p_l_u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_p_l_u_decomposition_example() {
|
||||
test_p_l_u_decomposition(vec![
|
||||
11, 9, 24, 2,
|
||||
1, 5, 2, 6,
|
||||
3, 17, 18, 1,
|
||||
2, 5, 7, 1,
|
||||
], 4);
|
||||
test_p_l_u_decomposition(vec![
|
||||
1, 3, 5,
|
||||
2, 4, 7,
|
||||
1, 1, 0,
|
||||
], 3);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue