use super::*;
#[cfg(feature = "data_trace")]
use serde::Serialize;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "data_trace", derive(Serialize))]
pub struct Dense<Scalar> {
x: Scalar,
pivots: Vec<usize>,
last_flag: usize,
}
impl<Scalar> LSolver<Scalar> for Dense<Scalar>
where
Scalar: num_traits::Float
+ num_traits::NumRef
+ num_traits::NumAssignRef
+ num_traits::Zero
+ std::fmt::Debug,
{
fn new(size: usize) -> Self {
Dense {
x: Scalar::zero(),
pivots: vec![0; size],
last_flag: 0,
}
}
fn get_type(&self) -> LSolverType {
LSolverType::Direct
}
fn setup<S1>(&mut self, mat_a: ArrayBase<S1, Ix2>) -> Result<(), failure::Error>
where
S1: ndarray::DataMut<Elem = Scalar>,
{
use failure::format_err;
self.last_flag = dense_get_rf(mat_a, &mut self.pivots);
if self.last_flag > 0 {
Err(format_err!("LUFACT_FAIL"))
} else {
Ok(())
}
}
fn solve<S1, S2, S3>(
&self,
mat_a: ArrayBase<S1, Ix2>,
mut x: ArrayBase<S2, Ix1>,
b: ArrayBase<S3, Ix1>,
_tol: Scalar,
) -> Result<(), failure::Error>
where
S1: ndarray::Data<Elem = Scalar>,
S2: ndarray::DataMut<Elem = Scalar>,
S3: ndarray::Data<Elem = Scalar>,
{
x.assign(&b);
dense_get_rs(mat_a, &self.pivots, x);
Ok(())
}
}
fn dense_get_rf<Scalar, S1>(mut mat_a: ArrayBase<S1, Ix2>, p: &mut [usize]) -> usize
where
Scalar: num_traits::Float + num_traits::NumRef + num_traits::NumAssignRef + num_traits::Zero,
S1: ndarray::DataMut<Elem = Scalar>,
{
let m = mat_a.rows();
let n = mat_a.cols();
assert!(m >= n, "Number of rows must be >= number of columns");
assert!(
p.len() == n,
"Partition slice length must be equal to the number of columns"
);
for k in 0..n {
let col_k = mat_a.column(k);
let mut l = k;
for i in (k + 1)..m {
if col_k[i].abs() > col_k[l].abs() {
l = i;
}
}
p[k] = l;
if col_k[l] == Scalar::zero() {
return k + 1;
}
if l != k {
for i in 0..n {
mat_a.swap([k, i], [l, i]);
}
}
let mult = mat_a[[k, k]].recip();
for i in (k + 1)..m {
mat_a[[i, k]] *= mult;
}
for j in (k + 1)..n {
let a_kj = mat_a[[k, j]];
if a_kj != Scalar::zero() {
for i in (k + 1)..m {
let a_ik = mat_a[[i, k]];
mat_a[[i, j]] -= a_kj * a_ik;
}
}
}
}
0
}
fn dense_get_rs<Scalar, S1, S2>(mat_a: ArrayBase<S1, Ix2>, p: &[usize], mut b: ArrayBase<S2, Ix1>)
where
Scalar: num_traits::Float + num_traits::NumRef + num_traits::NumAssignRef,
S1: ndarray::Data<Elem = Scalar>,
S2: ndarray::DataMut<Elem = Scalar>,
{
let n = mat_a.cols();
for (k, &pk) in p.iter().enumerate().take(n) {
if pk != k {
b.swap([k], [pk]);
}
}
for k in 0..(n - 1) {
let col_k = mat_a.column(k);
let bk = b[k];
for i in (k + 1)..n {
b[i] -= col_k[i] * bk;
}
}
for k in (1..n).rev() {
let col_k = mat_a.column(k);
b[k] /= col_k[k];
let bk = b[k];
for i in 0..k {
b[i] -= col_k[i] * bk;
}
}
b[0] /= mat_a[[0, 0]];
}
#[cfg(test)]
mod tests {
use super::*;
use ndarray::array;
use nearly_eq::assert_nearly_eq;
#[test]
fn test_get_rs1() {
let mat_a = array![
[1.0, 0.040000000000000001, -0.040655973218655501],
[1.0, -9562.0329139608493, -0.99881984364015208],
[1.0, -0.041880782326080723, 0.00070539909027303449]
]
.reversed_axes();
let mut b = array![
-0.00000018658722011386564,
0.0000001791760359416981,
0.000000000000015432100042289676
];
dense_get_rs(mat_a, &vec![2, 1, 2], b.view_mut());
let expect = array![
0.000010806109402745275,
0.000000000028591564117644602,
-0.000010806137978877292
];
assert_eq!(b, expect);
}
#[test]
fn test_get_rs2() {
let mat_a = array![
[1.0, 0.040000000000000001, -0.041180751793579905],
[1.0, -9376.8756693193609, -0.99825358822328103],
[1.0, -0.04272931434962135, 0.0012553747713712066],
]
.reversed_axes();
let mut b = array![
-0.00000092446647014019954,
0.0000009098297931611867,
0.000000000000010769163338864018
];
dense_get_rs(mat_a, &vec![2, 1, 2], b.view_mut());
let expect = array![
0.000012924954909363613,
-0.000000000038131780122501411,
-0.000012924916766814327
];
assert_eq!(b, expect);
}
#[test]
fn test_get_rf1() {
let mut mat_a = array![
[-0.09593473862037126, 0.040000000000000001, 1.0],
[5274.5976183265557, -5485.2758397300222, 1.0],
[0.035103714444140913, -0.035103714444140913, 1.0]
]
.reversed_axes();
let mut pivot = vec![0, 0, 0];
let ret = dense_get_rf(mat_a.view_mut(), &mut pivot);
let expect = array![
[1.0, 0.040000000000000001, -0.09593473862037126],
[1.0, -5485.3158397300222, -0.96160252338811314],
[1.0, -0.075103714444140907, 0.058818531739205995]
]
.reversed_axes();
assert_eq!(mat_a, expect);
assert_eq!(pivot, vec![2, 1, 2]);
assert_eq!(ret, 0);
}
#[test]
fn test_get_rf2() {
let mut mat_a = array![
[-0.042361503587159809, 0.040000000000000001, 1.0],
[9313.8399601148321, -9331.507477848012, 1.0],
[0.0029441927049318833, -0.0029441927049318833, 1.0],
]
.reversed_axes();
let mut pivot = vec![0, 0, 0];
let ret = dense_get_rf(mat_a.view_mut(), &mut pivot);
let expect = array![
[1.0, 0.040000000000000001, -0.042361503587159809],
[1.0, -9331.5474778480129, -0.99810694246891751],
[1.0, -0.042944192704931883, 0.0024427994145761397]
]
.reversed_axes();
assert_eq!(mat_a, expect);
assert_eq!(pivot, vec![2, 1, 2]);
assert_eq!(ret, 0);
}
#[test]
fn test_dense1() {
let mut mat_a = array![
[5.0, 0.0, 0.0, 1.0],
[2.0, 2.0, 2.0, 1.0],
[4.0, 5.0, 5.0, 5.0],
[1.0, 6.0, 4.0, 5.0]
];
let b = array![9.0, 16.0, 49.0, 45.0];
let expected = array![1.0, 2.0, 3.0, 4.0];
let mut dense = Dense::new(4);
let mut x = Array1::zeros(4);
dense.setup(mat_a.view_mut()).unwrap();
dense.solve(mat_a, x.view_mut(), b, 0.0).unwrap();
assert_nearly_eq!(x, expected);
}
}