use eigenvalues::{self, Eigen, SymEigen};
use solve_linear::{SolveLinear, SymmetricSolveLinear};
use least_squares::{LeastSquares, LeastSquaresType, LeastSquaresSolution};
use super::error::*;
use super::scalar::LinxalScalar;
use impl_prelude::*;
use factorization::{QR, QRFactors, LU, LUFactors, Cholesky};
use svd::{SVD, SVDSolution, SVDComputeVectors};
use properties::{self, default_tol};
pub trait LinxalMatrix<F: LinxalScalar> {
fn eigenvalues(&self) -> Result<Array<F::Complex, Ix1>, EigenError>;
fn eigenvalues_vectors(&self,
compute_left: bool,
compute_right: bool)
-> Result<eigenvalues::Solution<F, F::Complex>, EigenError>;
fn symmetric_eigenvalues(&self, uplo: Symmetric)
-> Result<Array<F::RealPart, Ix1>, EigenError>;
fn symmetric_eigenvalues_vectors(&self, uplo: Symmetric)
-> Result<eigenvalues::Solution<F, F::RealPart>, EigenError>;
fn solve_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix1>)
-> Result<Array<F, Ix1>, SolveError>;
fn solve_symmetric_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix1>,
uplo: Symmetric)
-> Result<Array<F, Ix1>, SolveError>;
fn solve_multi_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix2>)
-> Result<Array<F, Ix2>, SolveError>;
fn solve_symmetric_multi_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix2>,
uplo: Symmetric)
-> Result<Array<F, Ix2>, SolveError>;
fn least_squares<D1, PT>(&self,
b: &ArrayBase<D1, Ix1>,
problem_type: PT)
-> Result<LeastSquaresSolution<F, Ix1>, LeastSquaresError>
where D1: Data<Elem = F>,
PT: Into<Option<LeastSquaresType>>;
fn multi_least_squares<D1, PT>(&self,
b: &ArrayBase<D1, Ix2>,
problem_type: PT)
-> Result<LeastSquaresSolution<F, Ix2>, LeastSquaresError>
where D1: Data<Elem = F>,
PT: Into<Option<LeastSquaresType>>;
fn qr(&self) -> Result<QRFactors<F>, QRError>;
fn lu(&self) -> Result<LUFactors<F>, LUError>;
fn cholesky(&self, uplo: Symmetric) -> Result<Array<F, Ix2>, CholeskyError>;
fn svd_full(&self) -> Result<SVDSolution<F>, SVDError>;
fn svd_econ(&self) -> Result<SVDSolution<F>, SVDError>;
fn singular_values(&self) -> Result<Array<F::RealPart, Ix1>, SVDError>;
fn inverse(&self) -> Result<Array<F, Ix2>, Error>;
fn conj(&self) -> Array<F, Ix2>;
fn conj_t(&self) -> Array<F, Ix2>;
fn is_square(&self) -> bool;
fn is_identity<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;
fn is_diagonal<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;
fn is_symmetric<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;
fn is_unitary<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;
fn is_triangular<T: Into<Option<F::RealPart>>>(&self, uplo: Symmetric, tolerance: T) -> bool;
}
impl<F: LinxalScalar, D: Data<Elem = F>> LinxalMatrix<F> for ArrayBase<D, Ix2> {
fn eigenvalues(&self) -> Result<Array<F::Complex, Ix1>, EigenError> {
Eigen::compute(self, false, false).map(|s| {
let sol: eigenvalues::types::Solution<_, _> = s;
sol.values
})
}
fn eigenvalues_vectors(&self,
compute_left: bool,
compute_right: bool)
-> Result<eigenvalues::Solution<F, F::Complex>, EigenError> {
Eigen::compute(self, compute_left, compute_right)
}
fn symmetric_eigenvalues(&self, uplo: Symmetric)
-> Result<Array<F::RealPart, Ix1>, EigenError> {
SymEigen::compute(self, uplo, false).map(|s| s.values)
}
fn symmetric_eigenvalues_vectors(&self, uplo: Symmetric)
-> Result<eigenvalues::Solution<F, F::RealPart>, EigenError> {
SymEigen::compute(self, uplo, true)
}
fn solve_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix1>)
-> Result<Array<F, Ix1>, SolveError> {
SolveLinear::compute(self, b)
}
fn solve_symmetric_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix1>,
uplo: Symmetric)
-> Result<Array<F, Ix1>, SolveError> {
SymmetricSolveLinear::compute(self, uplo, b)
}
fn solve_multi_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix2>)
-> Result<Array<F, Ix2>, SolveError> {
SolveLinear::compute_multi(self, b)
}
fn solve_symmetric_multi_linear<D1: Data<Elem = F>>(&self,
b: &ArrayBase<D1, Ix2>,
uplo: Symmetric)
-> Result<Array<F, Ix2>, SolveError> {
SymmetricSolveLinear::compute_multi(self, uplo, b)
}
fn least_squares<D1, PT>(&self,
b: &ArrayBase<D1, Ix1>,
_problem_type: PT)
-> Result<LeastSquaresSolution<F, Ix1>, LeastSquaresError>
where D1: Data<Elem = F>,
PT: Into<Option<LeastSquaresType>>
{
LeastSquares::compute(self, b)
}
fn multi_least_squares<D1, PT>(&self,
b: &ArrayBase<D1, Ix2>,
problem_type: PT)
-> Result<LeastSquaresSolution<F, Ix2>, LeastSquaresError>
where D1: Data<Elem = F>,
PT: Into<Option<LeastSquaresType>>
{
match problem_type.into() {
Some(LeastSquaresType::Degenerate) => LeastSquares::compute_multi_degenerate(self, b),
Some(LeastSquaresType::Full) => LeastSquares::compute_multi_full(self, b),
None => LeastSquares::compute_multi(self, b),
}
}
fn qr(&self) -> Result<QRFactors<F>, QRError> {
QR::compute(self)
}
fn lu(&self) -> Result<LUFactors<F>, LUError> {
LU::compute(self)
}
fn cholesky(&self, uplo: Symmetric) -> Result<Array<F, Ix2>, CholeskyError> {
Cholesky::compute(self, uplo)
}
fn svd_full(&self) -> Result<SVDSolution<F>, SVDError> {
SVD::compute(self, SVDComputeVectors::Full)
}
fn svd_econ(&self) -> Result<SVDSolution<F>, SVDError> {
SVD::compute(self, SVDComputeVectors::Economic)
}
fn singular_values(&self) -> Result<Array<F::RealPart, Ix1>, SVDError> {
SVD::compute(self, SVDComputeVectors::None).map(|x| x.values)
}
fn inverse(&self) -> Result<Array<F, Ix2>, Error> {
match LU::compute(self) {
Ok(factors) => factors.inverse_into().map_err(|x| x.into()),
Err(lu_error) => Err(lu_error.into()),
}
}
fn conj(&self) -> Array<F, Ix2> {
self.mapv(|x| x.cj())
}
fn conj_t(&self) -> Array<F, Ix2> {
self.t().conj()
}
fn is_square(&self) -> bool {
match self.dim() {
(a, b) => a == b,
}
}
fn is_diagonal<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
properties::is_diagonal_tol(self, tol)
}
fn is_symmetric<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
properties::is_symmetric_tol(self, tol)
}
fn is_identity<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
properties::is_identity_tol(self, tol)
}
fn is_unitary<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
properties::is_unitary_tol(self, tol)
}
fn is_triangular<T: Into<Option<F::RealPart>>>(&self, uplo: Symmetric, tolerance: T) -> bool {
let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
properties::is_triangular_tol(self, uplo, tol)
}
}