use crate::types::*;
use ndarray::*;
pub mod arnoldi;
pub mod householder;
pub mod mgs;
pub use arnoldi::{arnoldi_householder, arnoldi_mgs, Arnoldi};
pub use householder::{householder, Householder};
pub use mgs::{mgs, MGS};
pub type Q<A> = Array2<A>;
pub type R<A> = Array2<A>;
pub type H<A> = Array2<A>;
pub type Coefficients<A> = Array1<A>;
pub trait Orthogonalizer {
type Elem: Scalar;
fn dim(&self) -> usize;
fn len(&self) -> usize;
fn is_full(&self) -> bool {
self.len() == self.dim()
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn tolerance(&self) -> <Self::Elem as Scalar>::Real;
fn decompose(&self, a: &mut ArrayRef<Self::Elem, Ix1>) -> Coefficients<Self::Elem>;
fn coeff<S>(&self, a: ArrayBase<S, Ix1>) -> Coefficients<Self::Elem>
where
S: Data<Elem = Self::Elem>;
fn append<S>(&mut self, a: ArrayBase<S, Ix1>) -> AppendResult<Self::Elem>
where
S: Data<Elem = Self::Elem>;
fn div_append(&mut self, a: &mut ArrayRef<Self::Elem, Ix1>) -> AppendResult<Self::Elem>;
fn get_q(&self) -> Q<Self::Elem>;
}
pub enum AppendResult<A> {
Added(Coefficients<A>),
Dependent(Coefficients<A>),
}
impl<A: Scalar> AppendResult<A> {
pub fn into_coeff(self) -> Coefficients<A> {
match self {
AppendResult::Added(c) => c,
AppendResult::Dependent(c) => c,
}
}
pub fn is_dependent(&self) -> bool {
match self {
AppendResult::Added(_) => false,
AppendResult::Dependent(_) => true,
}
}
pub fn coeff(&self) -> &Coefficients<A> {
match self {
AppendResult::Added(c) => c,
AppendResult::Dependent(c) => c,
}
}
pub fn residual_norm(&self) -> A::Real {
let c = self.coeff();
c[c.len() - 1].abs()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Strategy {
Terminate,
Skip,
Full,
}
pub fn qr<A, S>(
iter: impl Iterator<Item = ArrayBase<S, Ix1>>,
mut ortho: impl Orthogonalizer<Elem = A>,
strategy: Strategy,
) -> (Q<A>, R<A>)
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
assert_eq!(ortho.len(), 0);
let mut coefs = Vec::new();
for a in iter {
match ortho.append(a.into_owned()) {
AppendResult::Added(coef) => coefs.push(coef),
AppendResult::Dependent(coef) => match strategy {
Strategy::Terminate => break,
Strategy::Skip => continue,
Strategy::Full => coefs.push(coef),
},
}
}
let n = ortho.len();
let m = coefs.len();
let mut r = Array2::zeros((n, m).f());
for j in 0..m {
for i in 0..n {
if i < coefs[j].len() {
r[(i, j)] = coefs[j][i];
}
}
}
(ortho.get_q(), r)
}