# HG changeset patch # User Tuomo Valkonen # Date 1747143881 18000 # Node ID 26df914dda6720e01bfe2ea8cc42ae4f3dfa8d1a # Parent f78885441218cbb08af89f7566f581a53c51983c Generalise ZeroOp diff -r f78885441218 -r 26df914dda67 src/linops.rs --- a/src/linops.rs Tue May 13 00:24:51 2025 -0500 +++ b/src/linops.rs Tue May 13 08:44:41 2025 -0500 @@ -47,9 +47,6 @@ { type Field: Num; type Owned: AXPY; - // type OriginGen<'a>: OriginGenerator - // where - // Self: 'a; /// Computes `y = βy + αx`, where `y` is `Self`. fn axpy>(&mut self, α: Self::Field, x: I, β: Self::Field); @@ -306,57 +303,123 @@ } } +pub trait OriginGenerator { + type Ref<'b>: OriginGenerator + where + Self: 'b; + + fn origin(&self) -> Y::Owned; + fn as_ref(&self) -> Self::Ref<'_>; +} + +impl OriginGenerator for Y { + type Ref<'b> + = &'b Y + where + Self: 'b; + + #[inline] + fn origin(&self) -> Y::Owned { + return self.similar_origin(); + } + + #[inline] + fn as_ref(&self) -> Self::Ref<'_> { + self + } +} + +impl<'b, Y: AXPY> OriginGenerator for &'b Y { + type Ref<'c> + = Self + where + Self: 'c; + + #[inline] + fn origin(&self) -> Y::Owned { + return self.similar_origin(); + } + + #[inline] + fn as_ref(&self) -> Self::Ref<'_> { + self + } +} + /// A zero operator that can be eitherh dualised or predualised (once). /// This is achieved by storing an oppropriate zero. -pub struct ZeroOp, C, O, F: Float = f64> { - codomain_sample: C, - other_sample: O, +pub struct ZeroOp, OY: OriginGenerator, O, F: Float = f64> { + codomain_origin_generator: OY, + other_origin_generator: O, _phantoms: PhantomData<(X, Y, F)>, } -impl<'b, X, Y, F> ZeroOp +impl ZeroOp where - X: HasDual, - Y: HasDual, - Y::Owned: Clone, + OY: OriginGenerator, + X: AXPY, + Y: AXPY, F: Float, { - pub fn new_dualisable(x_dual_sample: &'b X::DualSpace, y_sample: &'b Y) -> Self { + pub fn new(y_og: OY) -> Self { ZeroOp { - codomain_sample: y_sample, - other_sample: x_dual_sample, + codomain_origin_generator: y_og, + other_origin_generator: (), _phantoms: PhantomData, } } } -impl<'b, X, Y, O, F> Mapping for ZeroOp +impl ZeroOp +where + OY: OriginGenerator, + OXprime: OriginGenerator, + X: HasDual, + Y: HasDual, + F: Float, + Xprime: AXPY, + Xprime::Owned: AXPY, + Yprime: Space + Instance, +{ + pub fn new_dualisable(y_og: OY, xprime_og: OXprime) -> Self { + ZeroOp { + codomain_origin_generator: y_og, + other_origin_generator: xprime_og, + _phantoms: PhantomData, + } + } +} + +impl Mapping for ZeroOp where X: Space + Instance, Y: AXPY, F: Float, + OY: OriginGenerator, { type Codomain = Y::Owned; fn apply>(&self, _x: I) -> Y::Owned { - self.codomain_sample.similar_origin() + self.codomain_origin_generator.origin() } } -impl<'b, X, Y, O, F> Linear for ZeroOp +impl Linear for ZeroOp where X: Space + Instance, Y: AXPY, F: Float, + OY: OriginGenerator, { } #[replace_float_literals(F::cast_from(literal))] -impl<'b, X, Y, O, F> GEMV for ZeroOp +impl GEMV for ZeroOp where X: Space + Instance, - Y: AXPY, + Y: AXPY, F: Float, + OY: OriginGenerator, { // Computes `y = αAx + βy`, where `A` is `Self`. fn gemv>(&self, y: &mut Y, _α: F, _x: I, β: F) { @@ -368,7 +431,7 @@ } } -impl<'b, X, Y, O, F, E1, E2> BoundedLinear for ZeroOp +impl BoundedLinear for ZeroOp where X: Space + Instance + Norm, Y: AXPY, @@ -376,13 +439,15 @@ F: Float, E1: NormExponent, E2: NormExponent, + OY: OriginGenerator, { fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult { Ok(F::ZERO) } } -impl<'b, X, Y, Xprime, Yprime, F> Adjointable for ZeroOp +impl<'b, X, Y, OY, OXprime, Xprime, Yprime, F> Adjointable + for ZeroOp where X: HasDual, Y: HasDual, @@ -390,184 +455,25 @@ Xprime: AXPY, Xprime::Owned: AXPY, Yprime: Space + Instance, + OY: OriginGenerator, + OXprime: OriginGenerator, { type AdjointCodomain = Xprime; type Adjoint<'c> - = ZeroOp + = ZeroOp, (), F> where Self: 'c; // () means not (pre)adjointable. fn adjoint(&self) -> Self::Adjoint<'_> { ZeroOp { - codomain_sample: self.other_sample, - other_sample: (), - _phantoms: PhantomData, - } - } -} - -/* -/// Trait for forming origins (zeroes) in vector spaces -pub trait OriginGenerator { - fn make_origin(&self) -> X; -} - -/// Origin generator for statically sized Euclidean spaces. -pub struct StaticEuclideanOriginGenerator; - -impl OriginGenerator for StaticEuclideanOriginGenerator -where - X: StaticEuclidean + Euclidean, -{ - #[inline] - fn make_origin(&self) -> X { - X::origin() - } -} - -/// Origin generator arbitrary spaces that implement [`AXPY`], based on a sample vector. -pub struct SimilarOriginGenerator<'a, X>(&'a X); - -impl<'a, X, F: Float> OriginGenerator for SimilarOriginGenerator<'a, X> -where - X: AXPY, -{ - #[inline] - fn make_origin(&self) -> X { - self.0.similar_origin() - } -} - -pub struct NotAnOriginGenerator; - -/// The zero operator -#[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] -pub struct ZeroOp { - y_origin: YOrigin, - xd_origin: XDOrigin, - _phantoms: PhantomData<(X, Y, F)>, -} - -// TODO: Need to make Zero in Instance. - -impl ZeroOp -where - F: Num, - YOrigin: OriginGenerator, -{ - pub fn new(y_origin: YOrigin, xd_origin: XDOrigin) -> Self { - ZeroOp { - y_origin, - xd_origin, + codomain_origin_generator: self.other_origin_generator.as_ref(), + other_origin_generator: (), _phantoms: PhantomData, } } } -impl Mapping for ZeroOp -where - F: Num, - YOrigin: OriginGenerator, - Y: Space, - X: Space + Instance, -{ - type Codomain = Y; - - fn apply>(&self, _: I) -> Y { - self.y_origin.make_origin() - } -} - -impl Linear for ZeroOp -where - F: Num, - YOrigin: OriginGenerator, - Y: Space, - X: Space + Instance, -{ -} - -#[replace_float_literals(F::cast_from(literal))] -impl GEMV for ZeroOp -where - F: Num, - YOrigin: OriginGenerator, - Y: Space + AXPY, - X: Space + Instance, -{ - // Computes `y = αAx + βy`, where `A` is `Self`. - fn gemv>(&self, y: &mut Y, _α: F, _x: I, β: F) { - *y *= β; - } - - fn apply_mut>(&self, y: &mut Y, _x: I) { - y.set_zero(); - } -} - -impl BoundedLinear - for ZeroOp -where - F: Num, - YOrigin: OriginGenerator, - Y: Space + AXPY + Norm, - X: Space + Instance + Norm, - E1: NormExponent, - E2: NormExponent, -{ - fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult { - Ok(F::ZERO) - } -} - -impl Adjointable - for ZeroOp -where - F: Num, - YOrigin: OriginGenerator, - Y: Space + AXPY, - X: Space + Instance + HasDual, - XDOrigin: OriginGenerator + Clone, - Yprime: Space + Instance, -{ - type AdjointCodomain = X::DualSpace; - type Adjoint<'b> - = ZeroOp - where - Self: 'b; - // () means not (pre)adjointable. - - fn adjoint(&self) -> Self::Adjoint<'_> { - ZeroOp::new(self.xd_origin.clone(), NotAnOriginGenerator) - } -} -*/ - -/* -impl Preadjointable - for ZeroOp -where - F: Num, - YOrigin: OriginGenerator, - Y: Space + AXPY, - X: Space + Instance + HasDual, - XDOrigin: OriginGenerator + Clone, - Ypre: Space + Instance + HasDual, -{ - type PreadjointCodomain = Xpre; - type Preadjoint<'b> - = ZeroOp - where - Self: 'b; - // () means not (pre)adjointable. - - fn adjoint(&self) -> Self::Adjoint<'_> { - ZeroOp::new(self.xpre_origin.clone(), NotAnOriginGenerator) - } -} -*/ - impl Linear for Composition where X: Space,