use impl_prelude::*;
use util::conj_t;
use num_traits::{Float};
pub fn is_square_size(d: &Ix2) -> bool {
d[0] == d[1]
}
pub fn default_tol<T, D>(mat: &ArrayBase<D, Ix2>)
-> T::RealPart
where T: LinxalImplScalar,
D: Data<Elem=T> {
T::tol() * mat.iter().map(|x| x.mag())
.fold(T::RealPart::neg_infinity(), |x, y| if x > y { x } else { y })
}
pub fn is_diagonal<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>) -> bool {
is_diagonal_tol(mat, default_tol(mat))
}
pub fn is_diagonal_tol<T, D, F>(mat: &ArrayBase<D, Ix2>, tolerance: F)
-> bool
where T: LinxalImplScalar,
D: Data<Elem=T>,
F: Into<T::RealPart> {
let tol = tolerance.into();
!mat.indexed_iter().any(|(i, x)| i.0 != i.1 && x.mag() > tol)
}
pub fn is_identity<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>) -> bool {
is_identity_tol(mat, T::tol())
}
pub fn is_identity_tol<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>, tol: T::RealPart) -> bool {
if !is_square_size(&mat.raw_dim()) {
return false;
}
!mat.indexed_iter().any(
|(i, x)| (i.0 != i.1 && x.mag() > tol) || (i.0 == i.1 && (*x - T::one()).mag() > tol))
}
pub fn is_symmetric<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>) -> bool {
is_symmetric_tol(mat, default_tol(mat))
}
pub fn is_symmetric_tol<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>, tol: T::RealPart) -> bool {
let d = mat.dim();
if !is_square_size(&mat.raw_dim()) {
return false;
}
for i in 0..d.0 {
for j in 0..i {
if (mat[(i, j)] - mat[(j, i)].cj()).mag() > tol {
return false;
}
}
}
true
}
pub fn is_unitary_tol<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>, tol: T::RealPart) -> bool {
if !is_square_size(&mat.raw_dim()) {
return false;
}
let prod = mat.dot(&conj_t(&mat));
is_identity_tol(&prod, tol)
}
pub fn is_unitary<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>) -> bool {
is_unitary_tol(mat, default_tol(mat))
}
pub fn is_triangular_tol<T, D, F>(mat: &ArrayBase<D, Ix2>, uplo: Symmetric, tolerance: F)
-> bool
where T: LinxalImplScalar,
D: Data<Elem=T>,
F: Into<T::RealPart> {
match uplo {
Symmetric::Upper => get_lower_bandwidth_tol(mat, tolerance) == 0,
Symmetric::Lower => get_upper_bandwidth_tol(mat, tolerance) == 0
}
}
pub fn is_triangular<T, D>(mat: &ArrayBase<D, Ix2>, uplo: Symmetric)
-> bool
where T: LinxalImplScalar,
D: Data<Elem=T> {
is_triangular_tol(mat, uplo, default_tol(&mat))
}
pub fn get_lower_bandwidth_tol<T: LinxalImplScalar, D: Data<Elem=T>, F: Into<T::RealPart>>(mat: &ArrayBase<D, Ix2>, tol: F) -> usize {
let dim = mat.dim();
let r = dim.0 - 1;
let t = tol.into();
for b in 0..r {
for i in 0..cmp::min(b+1, dim.1) {
let a = mat[[r - b + i, i]];
if a.mag() > t {
return r - b;
}
}
}
0
}
pub fn get_lower_bandwidth<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>) -> usize {
get_lower_bandwidth_tol(mat, default_tol(mat))
}
pub fn get_upper_bandwidth_tol<T: LinxalImplScalar, D: Data<Elem=T>, F: Into<T::RealPart>>(mat: &ArrayBase<D, Ix2>, tol: F) -> usize {
let dim = mat.dim();
let c = dim.1 - 1;
let t = tol.into();
for b in 0..c {
for i in 0..cmp::min(b+1, dim.0) {
let a = mat[[i, c - b + i]];
if a.mag() > t {
return c - b;
}
}
}
0
}
pub fn get_upper_bandwidth<T: LinxalImplScalar, D: Data<Elem=T>>(mat: &ArrayBase<D, Ix2>) -> usize {
get_upper_bandwidth_tol(mat, default_tol(mat))
}