use ndarray::{
ArrayBase,
Array2,
Data,
Dim,
Ix,
Ix2,
ShapeBuilder,
};
use std::error;
use std::result;
use std::fmt;
#[cfg(test)]
#[macro_use]
mod test_macros;
mod cgs;
mod cgs2;
mod mgs;
pub(crate) mod utils;
pub use cgs::Classical;
pub use cgs2::Reorthogonalized;
pub use mgs:: Modified;
#[derive(Debug)]
pub enum Error {
IncompatibleLayouts,
NonContiguous,
}
pub type Result<T> = result::Result<T, Error>;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match self {
IncompatibleLayouts => write!(f, "The arrays representing the matrices don't have the same layouts."),
NonContiguous => write!(f, "Array shape is not contiguous"),
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
pub trait GramSchmidt: Sized {
fn from_shape<T>(shape: T) -> Result<Self>
where T: ShapeBuilder<Dim = Dim<[Ix; 2]>>;
fn compute<S>(&mut self, a: &ArrayBase<S, Ix2>) -> Result<()>
where S: Data<Elem = f64>;
fn q(&self) -> &Array2<f64>;
fn r(&self) -> &Array2<f64>;
fn compute_once<S>(a: &ArrayBase<S, Ix2>) -> Result<(Array2<f64>, Array2<f64>)>
where S: Data<Elem=f64>,
{
let mut gram_schmidt = Self::from_matrix(a)?;
gram_schmidt.compute(a)?;
Ok((gram_schmidt.q().clone(), gram_schmidt.r().clone()))
}
fn from_matrix<S>(a: &ArrayBase<S, Ix2>) -> Result<Self>
where S: Data<Elem = f64>
{
use cblas::Layout::*;
let dim = a.dim();
let shape = match utils::get_layout(a) {
Some(ColumnMajor) => dim.f(),
Some(RowMajor) => dim.into_shape(),
None => Err(Error::NonContiguous)?,
};
Self::from_shape(shape)
}
}
pub fn cgs<S>(a: &ArrayBase<S, Ix2>) -> Result<(Array2<f64>, Array2<f64>)>
where S: Data<Elem=f64>
{
Classical::compute_once(a)
}
pub fn cgs2<S>(a: &ArrayBase<S, Ix2>) -> Result<(Array2<f64>, Array2<f64>)>
where S: Data<Elem=f64>
{
Reorthogonalized::compute_once(a)
}
pub fn mgs<S>(a: &ArrayBase<S, Ix2>) -> Result<(Array2<f64>, Array2<f64>)>
where S: Data<Elem=f64>
{
Modified::compute_once(a)
}