Wed, 07 Dec 2022 07:00:27 +0200
Added tag v0.1.0 for changeset 51bfde513cfa
/*! Abstract linear operators. */ use numeric_literals::replace_float_literals; use std::marker::PhantomData; use crate::types::*; use serde::Serialize; pub use crate::mapping::Apply; /// Trait for linear operators on `X`. pub trait Linear<X> : Apply<X, Output=Self::Codomain> + for<'a> Apply<&'a X, Output=Self::Codomain> { type Codomain; } /// Efficient in-place summation. #[replace_float_literals(F::cast_from(literal))] pub trait AXPY<F : Num, X = Self> { /// Computes `y = βy + αx`, where `y` is `Self`. fn axpy(&mut self, α : F, x : &X, β : F); /// Copies `x` to `self`. fn copy_from(&mut self, x : &X) { self.axpy(1.0, x, 0.0) } /// Computes `y = αx`, where `y` is `Self`. fn scale_from(&mut self, α : F, x : &X) { self.axpy(α, x, 0.0) } } /// Efficient in-place application for [`Linear`] operators. #[replace_float_literals(F::cast_from(literal))] pub trait GEMV<F : Num, X, Y = <Self as Linear<X>>::Codomain> : Linear<X> { /// Computes `y = αAx + βy`, where `A` is `Self`. fn gemv(&self, y : &mut Y, α : F, x : &X, β : F); /// Computes `y = Ax`, where `A` is `Self` fn apply_mut(&self, y : &mut Y, x : &X){ self.gemv(y, 1.0, x, 0.0) } /// Computes `y += Ax`, where `A` is `Self` fn apply_add(&self, y : &mut Y, x : &X){ self.gemv(y, 1.0, x, 1.0) } } /// Bounded linear operators pub trait BoundedLinear<X> : Linear<X> { type FloatType : Float; /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`. /// This is not expected to be the norm, just any bound on it that can be /// reasonably implemented. fn opnorm_bound(&self) -> Self::FloatType; } // Linear operator application into mutable target. The [`AsRef`] bound // is used to guarantee compatibility with `Yʹ` and `Self::Codomain`; // the former is assumed to be e.g. a view into the latter. /*impl<X,Y,T> Fn(&X) -> Y for T where T : Linear<X,Codomain=Y> { fn call(&self, x : &X) -> Y { self.apply(x) } }*/ /// Trait for forming the adjoint operator of `Self`. pub trait Adjointable<X,Yʹ> : Linear<X> { type AdjointCodomain; type Adjoint<'a> : Linear<Yʹ, Codomain=Self::AdjointCodomain> where Self : 'a; /// Form the adjoint operator of `self`. fn adjoint(&self) -> Self::Adjoint<'_>; /*fn adjoint_apply(&self, y : &Yʹ) -> Self::AdjointCodomain { self.adjoint().apply(y) }*/ } /// Trait for forming a preadjoint of an operator. /// /// For an operator $A$ this is an operator $A\_\*$ /// such that its adjoint $(A\_\*)^\*=A$. The space `X` is the domain of the `Self` /// operator. The space `Ypre` is the predual of its codomain, and should be the /// domain of the adjointed operator. `Self::Preadjoint` should be /// [`Adjointable`]`<'a,Ypre,X>`. pub trait Preadjointable<X,Ypre> : Linear<X> { type PreadjointCodomain; type Preadjoint<'a> : Adjointable<Ypre, X, Codomain=Self::PreadjointCodomain> where Self : 'a; /// Form the preadjoint operator of `self`. fn preadjoint(&self) -> Self::Preadjoint<'_>; } /// Adjointable operators $A: X → Y$ on between reflexive spaces $X$ and $Y$. pub trait SimplyAdjointable<X> : Adjointable<X,<Self as Linear<X>>::Codomain> {} impl<'a,X,T> SimplyAdjointable<X> for T where T : Adjointable<X,<Self as Linear<X>>::Codomain> {} /// The identity operator #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] pub struct IdOp<X> (PhantomData<X>); impl<X> IdOp<X> { fn new() -> IdOp<X> { IdOp(PhantomData) } } impl<X> Apply<X> for IdOp<X> { type Output = X; fn apply(&self, x : X) -> X { x } } impl<'a, X> Apply<&'a X> for IdOp<X> where X : Clone { type Output = X; fn apply(&self, x : &'a X) -> X { x.clone() } } impl<X> Linear<X> for IdOp<X> where X : Clone { type Codomain = X; } #[replace_float_literals(F::cast_from(literal))] impl<F : Num, X, Y> GEMV<F, X, Y> for IdOp<X> where Y : AXPY<F, X>, X : Clone { // Computes `y = αAx + βy`, where `A` is `Self`. fn gemv(&self, y : &mut Y, α : F, x : &X, β : F) { y.axpy(α, x, β) } fn apply_mut(&self, y : &mut Y, x : &X){ y.copy_from(x); } } impl<X> BoundedLinear<X> for IdOp<X> where X : Clone { type FloatType = float; fn opnorm_bound(&self) -> float { 1.0 } } impl<X> Adjointable<X,X> for IdOp<X> where X : Clone { type AdjointCodomain=X; type Adjoint<'a> = IdOp<X> where X : 'a; fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } }