use ndarray::*;
use num_traits::Float;
use crate::convert::*;
use crate::error::*;
use crate::layout::*;
use crate::triangular::IntoTriangular;
use crate::types::*;
pub use lax::UPLO;
pub struct CholeskyFactorized<S: Data> {
pub factor: ArrayBase<S, Ix2>,
pub uplo: UPLO,
}
impl<A, S> CholeskyFactorized<S>
where
A: Scalar + Lapack,
S: DataMut<Elem = A>,
{
pub fn into_lower(self) -> ArrayBase<S, Ix2> {
match self.uplo {
UPLO::Lower => self.factor,
UPLO::Upper => self.factor.reversed_axes().mapv_into(|elem| elem.conj()),
}
}
pub fn into_upper(self) -> ArrayBase<S, Ix2> {
match self.uplo {
UPLO::Lower => self.factor.reversed_axes().mapv_into(|elem| elem.conj()),
UPLO::Upper => self.factor,
}
}
}
impl<A, S> DeterminantC for CholeskyFactorized<S>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
type Output = <A as Scalar>::Real;
fn detc(&self) -> Self::Output {
Float::exp(self.ln_detc())
}
fn ln_detc(&self) -> Self::Output {
self.factor
.diag()
.iter()
.map(|elem| Float::ln(elem.square()))
.sum::<Self::Output>()
}
}
impl<A, S> DeterminantCInto for CholeskyFactorized<S>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
type Output = <A as Scalar>::Real;
fn detc_into(self) -> Self::Output {
self.detc()
}
fn ln_detc_into(self) -> Self::Output {
self.ln_detc()
}
}
impl<A, S> InverseC for CholeskyFactorized<S>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
type Output = Array2<A>;
fn invc(&self) -> Result<Self::Output> {
let f = CholeskyFactorized {
factor: replicate(&self.factor),
uplo: self.uplo,
};
f.invc_into()
}
}
impl<A, S> InverseCInto for CholeskyFactorized<S>
where
A: Scalar + Lapack,
S: DataMut<Elem = A>,
{
type Output = ArrayBase<S, Ix2>;
fn invc_into(self) -> Result<Self::Output> {
let mut a = self.factor;
A::inv_cholesky(a.square_layout()?, self.uplo, a.as_allocated_mut()?)?;
triangular_fill_hermitian(&mut a, self.uplo);
Ok(a)
}
}
impl<A, S> SolveC<A> for CholeskyFactorized<S>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
fn solvec_inplace<'a, Sb>(
&self,
b: &'a mut ArrayBase<Sb, Ix1>,
) -> Result<&'a mut ArrayBase<Sb, Ix1>>
where
Sb: DataMut<Elem = A>,
{
A::solve_cholesky(
self.factor.square_layout()?,
self.uplo,
self.factor.as_allocated()?,
b.as_slice_mut().unwrap(),
)?;
Ok(b)
}
}
pub trait Cholesky {
type Output;
fn cholesky(&self, uplo: UPLO) -> Result<Self::Output>;
}
pub trait CholeskyInto {
type Output;
fn cholesky_into(self, uplo: UPLO) -> Result<Self::Output>;
}
pub trait CholeskyInplace {
fn cholesky_inplace(&mut self, uplo: UPLO) -> Result<&mut Self>;
}
impl<A, S> Cholesky for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
type Output = Array2<A>;
fn cholesky(&self, uplo: UPLO) -> Result<Array2<A>> {
let a = replicate(self);
a.cholesky_into(uplo)
}
}
impl<A, S> CholeskyInto for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: DataMut<Elem = A>,
{
type Output = Self;
fn cholesky_into(mut self, uplo: UPLO) -> Result<Self> {
self.cholesky_inplace(uplo)?;
Ok(self)
}
}
impl<A, S> CholeskyInplace for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: DataMut<Elem = A>,
{
fn cholesky_inplace(&mut self, uplo: UPLO) -> Result<&mut Self> {
A::cholesky(self.square_layout()?, uplo, self.as_allocated_mut()?)?;
Ok(self.into_triangular(uplo))
}
}
pub trait FactorizeC<S: Data> {
fn factorizec(&self, uplo: UPLO) -> Result<CholeskyFactorized<S>>;
}
pub trait FactorizeCInto<S: Data> {
fn factorizec_into(self, uplo: UPLO) -> Result<CholeskyFactorized<S>>;
}
impl<A, S> FactorizeCInto<S> for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: DataMut<Elem = A>,
{
fn factorizec_into(self, uplo: UPLO) -> Result<CholeskyFactorized<S>> {
Ok(CholeskyFactorized {
factor: self.cholesky_into(uplo)?,
uplo,
})
}
}
impl<A, Si> FactorizeC<OwnedRepr<A>> for ArrayBase<Si, Ix2>
where
A: Scalar + Lapack,
Si: Data<Elem = A>,
{
fn factorizec(&self, uplo: UPLO) -> Result<CholeskyFactorized<OwnedRepr<A>>> {
Ok(CholeskyFactorized {
factor: self.cholesky(uplo)?,
uplo,
})
}
}
pub trait SolveC<A: Scalar> {
fn solvec<S: Data<Elem = A>>(&self, b: &ArrayBase<S, Ix1>) -> Result<Array1<A>> {
let mut b = replicate(b);
self.solvec_inplace(&mut b)?;
Ok(b)
}
fn solvec_into<S: DataMut<Elem = A>>(
&self,
mut b: ArrayBase<S, Ix1>,
) -> Result<ArrayBase<S, Ix1>> {
self.solvec_inplace(&mut b)?;
Ok(b)
}
fn solvec_inplace<'a, S: DataMut<Elem = A>>(
&self,
b: &'a mut ArrayBase<S, Ix1>,
) -> Result<&'a mut ArrayBase<S, Ix1>>;
}
impl<A, S> SolveC<A> for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
fn solvec_inplace<'a, Sb>(
&self,
b: &'a mut ArrayBase<Sb, Ix1>,
) -> Result<&'a mut ArrayBase<Sb, Ix1>>
where
Sb: DataMut<Elem = A>,
{
self.factorizec(UPLO::Upper)?.solvec_inplace(b)
}
}
pub trait InverseC {
type Output;
fn invc(&self) -> Result<Self::Output>;
}
pub trait InverseCInto {
type Output;
fn invc_into(self) -> Result<Self::Output>;
}
impl<A, S> InverseC for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
type Output = Array2<A>;
fn invc(&self) -> Result<Self::Output> {
self.factorizec(UPLO::Upper)?.invc_into()
}
}
impl<A, S> InverseCInto for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: DataMut<Elem = A>,
{
type Output = Self;
fn invc_into(self) -> Result<Self::Output> {
self.factorizec_into(UPLO::Upper)?.invc_into()
}
}
pub trait DeterminantC {
type Output;
fn detc(&self) -> Self::Output;
fn ln_detc(&self) -> Self::Output;
}
pub trait DeterminantCInto {
type Output;
fn detc_into(self) -> Self::Output;
fn ln_detc_into(self) -> Self::Output;
}
impl<A, S> DeterminantC for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: Data<Elem = A>,
{
type Output = Result<<A as Scalar>::Real>;
fn detc(&self) -> Self::Output {
Ok(Float::exp(self.ln_detc()?))
}
fn ln_detc(&self) -> Self::Output {
Ok(self.factorizec(UPLO::Upper)?.ln_detc())
}
}
impl<A, S> DeterminantCInto for ArrayBase<S, Ix2>
where
A: Scalar + Lapack,
S: DataMut<Elem = A>,
{
type Output = Result<<A as Scalar>::Real>;
fn detc_into(self) -> Self::Output {
Ok(Float::exp(self.ln_detc_into()?))
}
fn ln_detc_into(self) -> Self::Output {
Ok(self.factorizec_into(UPLO::Upper)?.ln_detc_into())
}
}