diff -r edb95d2b83cc -r d2acaaddd9af src/linops.rs --- a/src/linops.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/linops.rs Tue Dec 31 09:12:43 2024 -0500 @@ -10,7 +10,8 @@ /// Trait for linear operators on `X`. pub trait Linear : Apply - + for<'a> Apply<&'a X, Output=Self::Codomain> { + + for<'a> Apply<&'a X, Output=Self::Codomain> + + HasScalarField { type Codomain; } @@ -18,32 +19,32 @@ #[replace_float_literals(F::cast_from(literal))] pub trait AXPY { /// Computes `y = βy + αx`, where `y` is `Self`. - fn axpy(&mut self, α : F, x : &X, β : F); + fn axpy(&mut self, α : F, x : X, β : F); /// Copies `x` to `self`. - fn copy_from(&mut self, x : &X) { + 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) { + 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>::Codomain> : Linear { +pub trait GEMV>::Output> : Apply { /// Computes `y = αAx + βy`, where `A` is `Self`. - fn gemv(&self, y : &mut Y, α : F, x : &X, β : F); + 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){ + 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){ + fn apply_add(&self, y : &mut Y, x : X){ self.gemv(y, 1.0, x, 1.0) } } @@ -51,11 +52,10 @@ /// Bounded linear operators pub trait BoundedLinear : Linear { - 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; + fn opnorm_bound(&self) -> Self::Field; } // Linear operator application into mutable target. The [`AsRef`] bound @@ -70,7 +70,7 @@ /// Trait for forming the adjoint operator of `Self`. pub trait Adjointable : Linear { - type AdjointCodomain; + type AdjointCodomain : HasScalarField; type Adjoint<'a> : Linear where Self : 'a; /// Form the adjoint operator of `self`. @@ -89,7 +89,7 @@ /// domain of the adjointed operator. `Self::Preadjoint` should be /// [`Adjointable`]`<'a,Ypre,X>`. pub trait Preadjointable : Linear { - type PreadjointCodomain; + type PreadjointCodomain : HasScalarField; type Preadjoint<'a> : Adjointable where Self : 'a; /// Form the preadjoint operator of `self`. @@ -100,55 +100,49 @@ pub trait SimplyAdjointable : Adjointable>::Codomain> {} impl<'a,X,T> SimplyAdjointable for T where T : Adjointable>::Codomain> {} -/// The identity operator +/// The identity operator on `X` with scalar field `F`. #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] -pub struct IdOp (PhantomData); +pub struct IdOp (PhantomData<(X, F)>); -impl IdOp { - fn new() -> IdOp { IdOp(PhantomData) } +impl HasScalarField for IdOp { + type Field = F; } -impl Apply for IdOp { +impl IdOp { + fn new() -> IdOp { IdOp(PhantomData) } +} + +impl> Apply for IdOp { type Output = X; - fn apply(&self, x : X) -> X { - x + fn apply(&self, x : T) -> X { + x.clone_if_needed() } } -impl<'a, X> Apply<&'a X> for IdOp where X : Clone { - type Output = X; - - fn apply(&self, x : &'a X) -> X { - x.clone() - } -} - -impl Linear for IdOp where X : Clone { +impl Linear for IdOp { type Codomain = X; } - #[replace_float_literals(F::cast_from(literal))] -impl GEMV for IdOp where Y : AXPY, X : Clone { +impl GEMV for IdOp where Y : AXPY { // Computes `y = αAx + βy`, where `A` is `Self`. - fn gemv(&self, y : &mut Y, α : F, x : &X, β : F) { + fn gemv(&self, y : &mut Y, α : F, x : X, β : F) { y.axpy(α, x, β) } - fn apply_mut(&self, y : &mut Y, x : &X){ + fn apply_mut(&self, y : &mut Y, x : X){ y.copy_from(x); } } -impl BoundedLinear for IdOp where X : Clone { - type FloatType = float; - fn opnorm_bound(&self) -> float { 1.0 } +impl BoundedLinear for IdOp where X : Clone { + fn opnorm_bound(&self) -> F { F::ONE } } -impl Adjointable for IdOp where X : Clone { +impl Adjointable for IdOp where X : Clone + HasScalarField { type AdjointCodomain=X; - type Adjoint<'a> = IdOp where X : 'a; + type Adjoint<'a> = IdOp where X : 'a; fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } }