feat: extends interface of Matrix to support for broad range of types

This commit is contained in:
Volodymyr Orlov
2020-03-26 15:28:26 -07:00
parent 84ffd331cd
commit 02b85415d9
27 changed files with 1021 additions and 868 deletions
+156 -150
View File
@@ -2,16 +2,18 @@
use num::complex::Complex;
use crate::linalg::BaseMatrix;
use crate::math::num::FloatExt;
use std::fmt::Debug;
#[derive(Debug, Clone)]
pub struct EVD<M: BaseMatrix> {
pub d: Vec<f64>,
pub e: Vec<f64>,
pub struct EVD<T: FloatExt + Debug, M: BaseMatrix<T>> {
pub d: Vec<T>,
pub e: Vec<T>,
pub V: M
}
impl<M: BaseMatrix> EVD<M> {
pub fn new(V: M, d: Vec<f64>, e: Vec<f64>) -> EVD<M> {
impl<T: FloatExt + Debug, M: BaseMatrix<T>> EVD<T, M> {
pub fn new(V: M, d: Vec<T>, e: Vec<T>) -> EVD<T, M> {
EVD {
d: d,
e: e,
@@ -20,21 +22,21 @@ impl<M: BaseMatrix> EVD<M> {
}
}
pub trait EVDDecomposableMatrix: BaseMatrix {
pub trait EVDDecomposableMatrix<T: FloatExt + Debug>: BaseMatrix<T> {
fn evd(&self, symmetric: bool) -> EVD<Self>{
fn evd(&self, symmetric: bool) -> EVD<T, Self>{
self.clone().evd_mut(symmetric)
}
fn evd_mut(mut self, symmetric: bool) -> EVD<Self>{
fn evd_mut(mut self, symmetric: bool) -> EVD<T, Self>{
let(nrows, ncols) = self.shape();
if ncols != nrows {
panic!("Matrix is not square: {} x {}", nrows, ncols);
}
let n = nrows;
let mut d = vec![0f64; n];
let mut e = vec![0f64; n];
let mut d = vec![T::zero(); n];
let mut e = vec![T::zero(); n];
let mut V;
if symmetric {
@@ -66,7 +68,7 @@ pub trait EVDDecomposableMatrix: BaseMatrix {
}
}
fn tred2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
fn tred2<T: FloatExt + Debug, M: BaseMatrix<T>>(V: &mut M, d: &mut Vec<T>, e: &mut Vec<T>) {
let (n, _) = V.shape();
for i in 0..n {
@@ -76,34 +78,34 @@ fn tred2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
// Householder reduction to tridiagonal form.
for i in (1..n).rev() {
// Scale to avoid under/overflow.
let mut scale = 0f64;
let mut h = 0f64;
let mut scale = T::zero();
let mut h = T::zero();
for k in 0..i {
scale = scale + d[k].abs();
}
if scale == 0f64 {
if scale == T::zero() {
e[i] = d[i - 1];
for j in 0..i {
d[j] = V.get(i - 1, j);
V.set(i, j, 0.0);
V.set(j, i, 0.0);
V.set(i, j, T::zero());
V.set(j, i, T::zero());
}
} else {
// Generate Householder vector.
for k in 0..i {
d[k] /= scale;
h += d[k] * d[k];
d[k] = d[k] / scale;
h = h + d[k] * d[k];
}
let mut f = d[i - 1];
let mut g = h.sqrt();
if f > 0f64 {
if f > T::zero() {
g = -g;
}
e[i] = scale * g;
h = h - f * g;
d[i - 1] = f - g;
for j in 0..i {
e[j] = 0f64;
e[j] = T::zero();
}
// Apply similarity transformation to remaining columns.
@@ -112,19 +114,19 @@ fn tred2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
V.set(j, i, f);
g = e[j] + V.get(j, j) * f;
for k in j + 1..=i - 1 {
g += V.get(k, j) * d[k];
e[k] += V.get(k, j) * f;
g = g + V.get(k, j) * d[k];
e[k] = e[k] + V.get(k, j) * f;
}
e[j] = g;
}
f = 0.0;
f = T::zero();
for j in 0..i {
e[j] /= h;
f += e[j] * d[j];
e[j] = e[j] / h;
f = f + e[j] * d[j];
}
let hh = f / (h + h);
for j in 0..i {
e[j] -= hh * d[j];
e[j] = e[j] - hh * d[j];
}
for j in 0..i {
f = d[j];
@@ -133,7 +135,7 @@ fn tred2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
V.sub_element_mut(k, j, f * e[k] + g * d[k]);
}
d[j] = V.get(i - 1, j);
V.set(i, j, 0.0);
V.set(i, j, T::zero());
}
}
d[i] = h;
@@ -142,16 +144,16 @@ fn tred2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
// Accumulate transformations.
for i in 0..n-1 {
V.set(n - 1, i, V.get(i, i));
V.set(i, i, 1.0);
V.set(i, i, T::one());
let h = d[i + 1];
if h != 0f64 {
if h != T::zero() {
for k in 0..=i {
d[k] = V.get(k, i + 1) / h;
}
for j in 0..=i {
let mut g = 0f64;
let mut g = T::zero();
for k in 0..=i {
g += V.get(k, i + 1) * V.get(k, j);
g = g + V.get(k, i + 1) * V.get(k, j);
}
for k in 0..=i {
V.sub_element_mut(k, j, g * d[k]);
@@ -159,35 +161,35 @@ fn tred2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
}
}
for k in 0..=i {
V.set(k, i + 1, 0.0);
V.set(k, i + 1, T::zero());
}
}
for j in 0..n {
d[j] = V.get(n - 1, j);
V.set(n - 1, j, 0.0);
V.set(n - 1, j, T::zero());
}
V.set(n - 1, n - 1, 1.0);
e[0] = 0.0;
V.set(n - 1, n - 1, T::one());
e[0] = T::zero();
}
fn tql2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
fn tql2<T: FloatExt + Debug, M: BaseMatrix<T>>(V: &mut M, d: &mut Vec<T>, e: &mut Vec<T>) {
let (n, _) = V.shape();
for i in 1..n {
e[i - 1] = e[i];
}
e[n - 1] = 0f64;
e[n - 1] = T::zero();
let mut f = 0f64;
let mut tst1 = 0f64;
let mut f = T::zero();
let mut tst1 = T::zero();
for l in 0..n {
// Find small subdiagonal element
tst1 = f64::max(tst1, d[l].abs() + e[l].abs());
tst1 = T::max(tst1, d[l].abs() + e[l].abs());
let mut m = l;
loop {
if m < n {
if e[m].abs() <= tst1 * std::f64::EPSILON {
if e[m].abs() <= tst1 * T::epsilon() {
break;
}
m += 1;
@@ -208,9 +210,9 @@ fn tql2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
// Compute implicit shift
let mut g = d[l];
let mut p = (d[l + 1] - g) / (2.0 * e[l]);
let mut r = p.hypot(1.0);
if p < 0f64 {
let mut p = (d[l + 1] - g) / (T::two() * e[l]);
let mut r = p.hypot(T::one());
if p < T::zero() {
r = -r;
}
d[l] = e[l] / (p + r);
@@ -218,18 +220,18 @@ fn tql2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
let dl1 = d[l + 1];
let mut h = g - d[l];
for i in l+2..n {
d[i] -= h;
d[i] = d[i] - h;
}
f = f + h;
// Implicit QL transformation.
p = d[m];
let mut c = 1.0;
let mut c = T::one();
let mut c2 = c;
let mut c3 = c;
let el1 = e[l + 1];
let mut s = 0.0;
let mut s2 = 0.0;
let mut s = T::zero();
let mut s2 = T::zero();
for i in (l..m).rev() {
c3 = c2;
c2 = c;
@@ -255,13 +257,13 @@ fn tql2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
d[l] = c * p;
// Check for convergence.
if e[l].abs() <= tst1 * std::f64::EPSILON {
if e[l].abs() <= tst1 * T::epsilon() {
break;
}
}
}
d[l] = d[l] + f;
e[l] = 0f64;
e[l] = T::zero();
}
// Sort eigenvalues and corresponding vectors.
@@ -286,43 +288,45 @@ fn tql2<M: BaseMatrix>(V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
}
}
fn balance<M: BaseMatrix>(A: &mut M) -> Vec<f64> {
let radix = 2f64;
fn balance<T: FloatExt + Debug, M: BaseMatrix<T>>(A: &mut M) -> Vec<T> {
let radix = T::two();
let sqrdx = radix * radix;
let (n, _) = A.shape();
let mut scale = vec![1f64; n];
let mut scale = vec![T::one(); n];
let t = T::from(0.95).unwrap();
let mut done = false;
while !done {
done = true;
for i in 0..n {
let mut r = 0f64;
let mut c = 0f64;
let mut r = T::zero();
let mut c = T::zero();
for j in 0..n {
if j != i {
c += A.get(j, i).abs();
r += A.get(i, j).abs();
c = c + A.get(j, i).abs();
r = r + A.get(i, j).abs();
}
}
if c != 0f64 && r != 0f64 {
if c != T::zero() && r != T::zero() {
let mut g = r / radix;
let mut f = 1.0;
let mut f = T::one();
let s = c + r;
while c < g {
f *= radix;
c *= sqrdx;
f = f * radix;
c = c * sqrdx;
}
g = r * radix;
while c > g {
f /= radix;
c /= sqrdx;
f = f / radix;
c = c / sqrdx;
}
if (c + r) / f < 0.95 * s {
if (c + r) / f < t * s {
done = false;
g = 1.0 / f;
scale[i] *= f;
g = T::one() / f;
scale[i] = scale[i] * f;
for j in 0..n {
A.mul_element_mut(i, j, g);
}
@@ -337,12 +341,12 @@ fn balance<M: BaseMatrix>(A: &mut M) -> Vec<f64> {
return scale;
}
fn elmhes<M: BaseMatrix>(A: &mut M) -> Vec<usize> {
fn elmhes<T: FloatExt + Debug, M: BaseMatrix<T>>(A: &mut M) -> Vec<usize> {
let (n, _) = A.shape();
let mut perm = vec![0; n];
for m in 1..n-1 {
let mut x = 0f64;
let mut x = T::zero();
let mut i = m;
for j in m..n {
if A.get(j, m - 1).abs() > x.abs() {
@@ -363,11 +367,11 @@ fn elmhes<M: BaseMatrix>(A: &mut M) -> Vec<usize> {
A.set(j, m, swap);
}
}
if x != 0f64 {
if x != T::zero() {
for i in (m + 1)..n {
let mut y = A.get(i, m - 1);
if y != 0f64 {
y /= x;
if y != T::zero() {
y = y / x;
A.set(i, m - 1, y);
for j in m..n {
A.sub_element_mut(i, j, y * A.get(m, j));
@@ -383,7 +387,7 @@ fn elmhes<M: BaseMatrix>(A: &mut M) -> Vec<usize> {
return perm;
}
fn eltran<M: BaseMatrix>(A: &M, V: &mut M, perm: &Vec<usize>) {
fn eltran<T: FloatExt + Debug, M: BaseMatrix<T>>(A: &M, V: &mut M, perm: &Vec<usize>) {
let (n, _) = A.shape();
for mp in (1..n - 1).rev() {
for k in mp + 1..n {
@@ -393,41 +397,41 @@ fn eltran<M: BaseMatrix>(A: &M, V: &mut M, perm: &Vec<usize>) {
if i != mp {
for j in mp..n {
V.set(mp, j, V.get(i, j));
V.set(i, j, 0.0);
V.set(i, j, T::zero());
}
V.set(i, mp, 1.0);
V.set(i, mp, T::one());
}
}
}
fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>) {
fn hqr2<T: FloatExt + Debug, M: BaseMatrix<T>>(A: &mut M, V: &mut M, d: &mut Vec<T>, e: &mut Vec<T>) {
let (n, _) = A.shape();
let mut z = 0f64;
let mut s = 0f64;
let mut r = 0f64;
let mut q = 0f64;
let mut p = 0f64;
let mut anorm = 0f64;
let mut z = T::zero();
let mut s = T::zero();
let mut r = T::zero();
let mut q = T::zero();
let mut p = T::zero();
let mut anorm = T::zero();
for i in 0..n {
for j in i32::max(i as i32 - 1, 0)..n as i32 {
anorm += A.get(i, j as usize).abs();
anorm = anorm + A.get(i, j as usize).abs();
}
}
let mut nn = n - 1;
let mut t = 0.0;
let mut t = T::zero();
'outer: loop {
let mut its = 0;
loop {
let mut l = nn;
while l > 0 {
s = A.get(l - 1, l - 1).abs() + A.get(l, l).abs();
if s == 0.0 {
if s == T::zero() {
s = anorm;
}
if A.get(l, l - 1).abs() <= std::f64::EPSILON * s {
A.set(l, l - 1, 0.0);
if A.get(l, l - 1).abs() <= T::epsilon() * s {
A.set(l, l - 1, T::zero());
break;
}
l -= 1;
@@ -445,17 +449,17 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
let mut y = A.get(nn - 1, nn - 1);
let mut w = A.get(nn, nn - 1) * A.get(nn - 1, nn);
if l == nn - 1 {
p = 0.5 * (y - x);
p = T::half() * (y - x);
q = p * p + w;
z = q.abs().sqrt();
x += t;
x = x + t;
A.set(nn, nn, x );
A.set(nn - 1, nn - 1, y + t);
if q >= 0.0 {
if q >= T::zero() {
z = p + z.copysign(p);
d[nn - 1] = x + z;
d[nn] = x + z;
if z != 0.0 {
if z != T::zero() {
d[nn] = x - w / z;
}
x = A.get(nn, nn - 1);
@@ -463,8 +467,8 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
p = x / s;
q = z / s;
r = (p * p + q * q).sqrt();
p /= r;
q /= r;
p = p / r;
q = q / r;
for j in nn-1..n {
z = A.get(nn - 1, j);
A.set(nn - 1, j, q * z + p * A.get(nn, j));
@@ -497,14 +501,14 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
panic!("Too many iterations in hqr");
}
if its == 10 || its == 20 {
t += x;
t = t + x;
for i in 0..nn+1 {
A.sub_element_mut(i, i, x);
}
s = A.get(nn, nn - 1).abs() + A.get(nn - 1, nn - 2).abs();
y = 0.75 * s;
x = 0.75 * s;
w = -0.4375 * s * s;
y = T::from(0.75).unwrap() * s;
x = T::from(0.75).unwrap() * s;
w = T::from(-0.4375).unwrap() * s * s;
}
its += 1;
let mut m = nn - 2;
@@ -516,42 +520,42 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
q = A.get(m + 1, m + 1) - z - r - s;
r = A.get(m + 2, m + 1);
s = p.abs() + q.abs() + r.abs();
p /= s;
q /= s;
r /= s;
p = p / s;
q = q / s;
r = r / s;
if m == l {
break;
}
let u = A.get(m, m - 1).abs() * (q.abs() + r.abs());
let v = p.abs() * (A.get(m - 1, m - 1).abs() + z.abs() + A.get(m + 1, m + 1).abs());
if u <= std::f64::EPSILON * v {
if u <= T::epsilon() * v {
break;
}
m -= 1;
}
for i in m..nn-1 {
A.set(i + 2, i , 0.0);
A.set(i + 2, i , T::zero());
if i != m {
A.set(i + 2, i - 1, 0.0);
A.set(i + 2, i - 1, T::zero());
}
}
for k in m..nn {
if k != m {
p = A.get(k, k - 1);
q = A.get(k + 1, k - 1);
r = 0.0;
r = T::zero();
if k + 1 != nn {
r = A.get(k + 2, k - 1);
}
x = p.abs() + q.abs() +r.abs();
if x != 0.0 {
p /= x;
q /= x;
r /= x;
if x != T::zero() {
p = p / x;
q = q / x;
r = r / x;
}
}
let s = (p * p + q * q + r * r).sqrt().copysign(p);
if s != 0.0 {
if s != T::zero() {
if k == m {
if l != m {
A.set(k, k - 1, -A.get(k, k - 1));
@@ -559,16 +563,16 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
} else {
A.set(k, k - 1, -s * x);
}
p += s;
p = p + s;
x = p / s;
y = q / s;
z = r / s;
q /= p;
r /= p;
q = q / p;
r = r / p;
for j in k..n {
p = A.get(k, j) + q * A.get(k + 1, j);
if k + 1 != nn {
p += r * A.get(k + 2, j);
p = p + r * A.get(k + 2, j);
A.sub_element_mut(k + 2, j, p * z);
}
A.sub_element_mut(k + 1, j, p * y);
@@ -583,7 +587,7 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
for i in 0..mmin+1 {
p = x * A.get(i, k) + y * A.get(i, k + 1);
if k + 1 != nn {
p += z * A.get(i, k + 2);
p = p + z * A.get(i, k + 2);
A.sub_element_mut(i, k + 2, p * r);
}
A.sub_element_mut(i, k + 1, p * q);
@@ -592,7 +596,7 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
for i in 0..n {
p = x * V.get(i, k) + y * V.get(i, k + 1);
if k + 1 != nn {
p += z * V.get(i, k + 2);
p = p + z * V.get(i, k + 2);
V.sub_element_mut(i, k + 2, p * r);
}
V.sub_element_mut(i, k + 1, p * q);
@@ -608,38 +612,38 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
};
}
if anorm != 0f64 {
if anorm != T::zero() {
for nn in (0..n).rev() {
p = d[nn];
q = e[nn];
let na = nn.wrapping_sub(1);
if q == 0f64 {
if q == T::zero() {
let mut m = nn;
A.set(nn, nn, 1.0);
A.set(nn, nn, T::one());
if nn > 0 {
let mut i = nn - 1;
loop {
let w = A.get(i, i) - p;
r = 0.0;
r = T::zero();
for j in m..=nn {
r += A.get(i, j) * A.get(j, nn);
r = r + A.get(i, j) * A.get(j, nn);
}
if e[i] < 0.0 {
if e[i] < T::zero() {
z = w;
s = r;
} else {
m = i;
if e[i] == 0.0 {
if e[i] == T::zero() {
t = w;
if t == 0.0 {
t = std::f64::EPSILON * anorm;
if t == T::zero() {
t = T::epsilon() * anorm;
}
A.set(i, nn, -r / t);
} else {
let x = A.get(i, i + 1);
let y = A.get(i + 1, i);
q = (d[i] - p).powf(2f64) + e[i].powf(2f64);
q = (d[i] - p).powf(T::two()) + e[i].powf(T::two());
t = (x * s - z * r) / q;
A.set(i, nn, t);
if x.abs() > z.abs() {
@@ -649,7 +653,7 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
}
}
t = A.get(i, nn).abs();
if std::f64::EPSILON * t * t > 1f64 {
if T::epsilon() * t * t > T::one() {
for j in i..=nn {
A.div_element_mut(j, nn, t);
}
@@ -662,44 +666,44 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
}
}
}
} else if q < 0f64 {
} else if q < T::zero() {
let mut m = na;
if A.get(nn, na).abs() > A.get(na, nn).abs() {
A.set(na, na, q / A.get(nn, na));
A.set(na, nn, -(A.get(nn, nn) - p) / A.get(nn, na));
} else {
let temp = Complex::new(0.0, -A.get(na, nn)) / Complex::new(A.get(na, na) - p, q);
let temp = Complex::new(T::zero(), -A.get(na, nn)) / Complex::new(A.get(na, na) - p, q);
A.set(na, na, temp.re);
A.set(na, nn, temp.im);
}
A.set(nn, na, 0.0);
A.set(nn, nn, 1.0);
A.set(nn, na, T::zero());
A.set(nn, nn, T::one());
if nn >= 2 {
for i in (0..nn - 1).rev() {
let w = A.get(i, i) - p;
let mut ra = 0f64;
let mut sa = 0f64;
let mut ra = T::zero();
let mut sa = T::zero();
for j in m..=nn {
ra += A.get(i, j) * A.get(j, na);
sa += A.get(i, j) * A.get(j, nn);
ra = ra + A.get(i, j) * A.get(j, na);
sa = sa + A.get(i, j) * A.get(j, nn);
}
if e[i] < 0.0 {
if e[i] < T::zero() {
z = w;
r = ra;
s = sa;
} else {
m = i;
if e[i] == 0.0 {
if e[i] == T::zero() {
let temp = Complex::new(-ra, -sa) / Complex::new(w, q);
A.set(i, na, temp.re);
A.set(i, nn, temp.im);
} else {
let x = A.get(i, i + 1);
let y = A.get(i + 1, i);
let mut vr = (d[i] - p).powf(2f64) + (e[i]).powf(2.0) - q * q;
let vi = 2.0 * q * (d[i] - p);
if vr == 0.0 && vi == 0.0 {
vr = std::f64::EPSILON * anorm * (w.abs() + q.abs() + x.abs() + y.abs() + z.abs());
let mut vr = (d[i] - p).powf(T::two()) + (e[i]).powf(T::two()) - q * q;
let vi = T::two() * q * (d[i] - p);
if vr == T::zero() && vi == T::zero() {
vr = T::epsilon() * anorm * (w.abs() + q.abs() + x.abs() + y.abs() + z.abs());
}
let temp = Complex::new(x * r - z * ra + q * sa, x * s - z * sa - q * ra) / Complex::new(vr, vi);
A.set(i, na, temp.re);
@@ -714,8 +718,8 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
}
}
}
t = f64::max(A.get(i, na).abs(), A.get(i, nn).abs());
if std::f64::EPSILON * t * t > 1f64 {
t = T::max(A.get(i, na).abs(), A.get(i, nn).abs());
if T::epsilon() * t * t > T::one() {
for j in i..=nn {
A.div_element_mut(j, na, t);
A.div_element_mut(j, nn, t);
@@ -728,9 +732,9 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
for j in (0..n).rev() {
for i in 0..n {
z = 0f64;
z = T::zero();
for k in 0..=j {
z += V.get(i, k) * A.get(k, j);
z = z + V.get(i, k) * A.get(k, j);
}
V.set(i, j, z);
}
@@ -738,7 +742,7 @@ fn hqr2<M: BaseMatrix>(A: &mut M, V: &mut M, d: &mut Vec<f64>, e: &mut Vec<f64>)
}
}
fn balbak<M: BaseMatrix>(V: &mut M, scale: &Vec<f64>) {
fn balbak<T: FloatExt + Debug, M: BaseMatrix<T>>(V: &mut M, scale: &Vec<T>) {
let (n, _) = V.shape();
for i in 0..n {
for j in 0..n {
@@ -747,9 +751,9 @@ fn balbak<M: BaseMatrix>(V: &mut M, scale: &Vec<f64>) {
}
}
fn sort<M: BaseMatrix>(d: &mut Vec<f64>, e: &mut Vec<f64>, V: &mut M) {
fn sort<T: FloatExt + Debug, M: BaseMatrix<T>>(d: &mut Vec<T>, e: &mut Vec<T>, V: &mut M) {
let n = d.len();
let mut temp = vec![0f64; n];
let mut temp = vec![T::zero(); n];
for j in 1..n {
let real = d[j];
let img = e[j];
@@ -789,7 +793,7 @@ mod tests {
&[0.4000, 0.5000, 0.3000],
&[0.7000, 0.3000, 0.8000]]);
let eigen_values = vec![1.7498382, 0.3165784, 0.1335834];
let eigen_values: Vec<f64> = vec![1.7498382, 0.3165784, 0.1335834];
let eigen_vectors = DenseMatrix::from_array(&[
&[0.6881997, -0.07121225, 0.7220180],
@@ -817,7 +821,7 @@ mod tests {
&[0.4000, 0.5000, 0.3000],
&[0.8000, 0.3000, 0.8000]]);
let eigen_values = vec![1.79171122, 0.31908143, 0.08920735];
let eigen_values: Vec<f64> = vec![1.79171122, 0.31908143, 0.08920735];
let eigen_vectors = DenseMatrix::from_array(&[
&[0.7178958, 0.05322098, 0.6812010],
@@ -826,6 +830,8 @@ mod tests {
]);
let evd = A.evd(false);
println!("{}", &evd.V.abs());
assert!(eigen_vectors.abs().approximate_eq(&evd.V.abs(), 1e-4));
for i in 0..eigen_values.len() {
@@ -846,8 +852,8 @@ mod tests {
&[1.0, 1.0, 3.0, -2.0],
&[1.0, 1.0, 4.0, -1.0]]);
let eigen_values_d = vec![0.0, 2.0, 2.0, 0.0];
let eigen_values_e = vec![2.2361, 0.9999, -0.9999, -2.2361];
let eigen_values_d: Vec<f64> = vec![0.0, 2.0, 2.0, 0.0];
let eigen_values_e: Vec<f64> = vec![2.2361, 0.9999, -0.9999, -2.2361];
let eigen_vectors = DenseMatrix::from_array(&[
&[-0.9159, -0.1378, 0.3816, -0.0806],