src/linops.rs

branch
dev
changeset 140
26df914dda67
parent 139
f78885441218
child 150
c4e394a9c84c
--- 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<X, Field = Self::Field>;
-    // type OriginGen<'a>: OriginGenerator<Self::Owned, F>
-    // where
-    //     Self: 'a;
 
     /// Computes  `y = βy + αx`, where `y` is `Self`.
     fn axpy<I: Instance<X>>(&mut self, α: Self::Field, x: I, β: Self::Field);
@@ -306,57 +303,123 @@
     }
 }
 
+pub trait OriginGenerator<Y: AXPY> {
+    type Ref<'b>: OriginGenerator<Y>
+    where
+        Self: 'b;
+
+    fn origin(&self) -> Y::Owned;
+    fn as_ref(&self) -> Self::Ref<'_>;
+}
+
+impl<Y: AXPY> OriginGenerator<Y> 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<Y> 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<X, Y: AXPY<Field = F>, C, O, F: Float = f64> {
-    codomain_sample: C,
-    other_sample: O,
+pub struct ZeroOp<X, Y: AXPY<Field = F>, OY: OriginGenerator<Y>, O, F: Float = f64> {
+    codomain_origin_generator: OY,
+    other_origin_generator: O,
     _phantoms: PhantomData<(X, Y, F)>,
 }
 
-impl<'b, X, Y, F> ZeroOp<X, Y, &'b Y, &'b X::DualSpace, F>
+impl<X, Y, OY, F> ZeroOp<X, Y, OY, (), F>
 where
-    X: HasDual<F>,
-    Y: HasDual<F>,
-    Y::Owned: Clone,
+    OY: OriginGenerator<Y>,
+    X: AXPY<Field = F>,
+    Y: AXPY<Field = F>,
     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<X> for ZeroOp<X, Y, &'b Y, O, F>
+impl<X, Y, OY, OXprime, Xprime, Yprime, F> ZeroOp<X, Y, OY, OXprime, F>
+where
+    OY: OriginGenerator<Y>,
+    OXprime: OriginGenerator<Xprime>,
+    X: HasDual<F, DualSpace = Xprime>,
+    Y: HasDual<F, DualSpace = Yprime>,
+    F: Float,
+    Xprime: AXPY<Field = F, Owned = Xprime>,
+    Xprime::Owned: AXPY<Field = F>,
+    Yprime: Space + Instance<Yprime>,
+{
+    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<X, Y, O, OY, F> Mapping<X> for ZeroOp<X, Y, OY, O, F>
 where
     X: Space + Instance<X>,
     Y: AXPY<Field = F>,
     F: Float,
+    OY: OriginGenerator<Y>,
 {
     type Codomain = Y::Owned;
 
     fn apply<I: Instance<X>>(&self, _x: I) -> Y::Owned {
-        self.codomain_sample.similar_origin()
+        self.codomain_origin_generator.origin()
     }
 }
 
-impl<'b, X, Y, O, F> Linear<X> for ZeroOp<X, Y, &'b Y, O, F>
+impl<X, Y, OY, O, F> Linear<X> for ZeroOp<X, Y, OY, O, F>
 where
     X: Space + Instance<X>,
     Y: AXPY<Field = F>,
     F: Float,
+    OY: OriginGenerator<Y>,
 {
 }
 
 #[replace_float_literals(F::cast_from(literal))]
-impl<'b, X, Y, O, F> GEMV<F, X, Y> for ZeroOp<X, Y, &'b Y, O, F>
+impl<X, Y, OY, O, F> GEMV<F, X, Y> for ZeroOp<X, Y, OY, O, F>
 where
     X: Space + Instance<X>,
-    Y: AXPY<Field = F>,
+    Y: AXPY<Field = F, Owned = Y>,
     F: Float,
+    OY: OriginGenerator<Y>,
 {
     // Computes  `y = αAx + βy`, where `A` is `Self`.
     fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) {
@@ -368,7 +431,7 @@
     }
 }
 
-impl<'b, X, Y, O, F, E1, E2> BoundedLinear<X, E1, E2, F> for ZeroOp<X, Y, &'b Y, O, F>
+impl<X, Y, OY, O, F, E1, E2> BoundedLinear<X, E1, E2, F> for ZeroOp<X, Y, OY, O, F>
 where
     X: Space + Instance<X> + Norm<E1, F>,
     Y: AXPY<Field = F>,
@@ -376,13 +439,15 @@
     F: Float,
     E1: NormExponent,
     E2: NormExponent,
+    OY: OriginGenerator<Y>,
 {
     fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> {
         Ok(F::ZERO)
     }
 }
 
-impl<'b, X, Y, Xprime, Yprime, F> Adjointable<X, Yprime> for ZeroOp<X, Y, &'b Y, &'b Xprime, F>
+impl<'b, X, Y, OY, OXprime, Xprime, Yprime, F> Adjointable<X, Yprime>
+    for ZeroOp<X, Y, OY, OXprime, F>
 where
     X: HasDual<F, DualSpace = Xprime>,
     Y: HasDual<F, DualSpace = Yprime>,
@@ -390,184 +455,25 @@
     Xprime: AXPY<Field = F, Owned = Xprime>,
     Xprime::Owned: AXPY<Field = F>,
     Yprime: Space + Instance<Yprime>,
+    OY: OriginGenerator<Y>,
+    OXprime: OriginGenerator<X::DualSpace>,
 {
     type AdjointCodomain = Xprime;
     type Adjoint<'c>
-        = ZeroOp<Yprime, Xprime, &'b Xprime, (), F>
+        = ZeroOp<Yprime, Xprime, OXprime::Ref<'c>, (), 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<X, F: Num = f64> {
-    fn make_origin(&self) -> X;
-}
-
-/// Origin generator for statically sized Euclidean spaces.
-pub struct StaticEuclideanOriginGenerator;
-
-impl<X, F: Float> OriginGenerator<X, F> for StaticEuclideanOriginGenerator
-where
-    X: StaticEuclidean<F> + Euclidean<F, Output = X>,
-{
-    #[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<X, F> for SimilarOriginGenerator<'a, X>
-where
-    X: AXPY<F, Owned = X>,
-{
-    #[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<X, Y, YOrigin, XDOrigin = NotAnOriginGenerator, F: Num = f64> {
-    y_origin: YOrigin,
-    xd_origin: XDOrigin,
-    _phantoms: PhantomData<(X, Y, F)>,
-}
-
-// TODO: Need to make Zero in Instance.
-
-impl<X, Y, F, YOrigin, XDOrigin> ZeroOp<X, Y, YOrigin, XDOrigin, F>
-where
-    F: Num,
-    YOrigin: OriginGenerator<Y, F>,
-{
-    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<X, Y, F, YOrigin, XDOrigin> Mapping<X> for ZeroOp<X, Y, YOrigin, XDOrigin, F>
-where
-    F: Num,
-    YOrigin: OriginGenerator<Y, F>,
-    Y: Space,
-    X: Space + Instance<X>,
-{
-    type Codomain = Y;
-
-    fn apply<I: Instance<X>>(&self, _: I) -> Y {
-        self.y_origin.make_origin()
-    }
-}
-
-impl<X, Y, F, YOrigin, XDOrigin> Linear<X> for ZeroOp<X, Y, YOrigin, XDOrigin, F>
-where
-    F: Num,
-    YOrigin: OriginGenerator<Y, F>,
-    Y: Space,
-    X: Space + Instance<X>,
-{
-}
-
-#[replace_float_literals(F::cast_from(literal))]
-impl<X, Y, F, YOrigin, XDOrigin> GEMV<F, X, Y> for ZeroOp<X, Y, YOrigin, XDOrigin, F>
-where
-    F: Num,
-    YOrigin: OriginGenerator<Y, F>,
-    Y: Space + AXPY<F>,
-    X: Space + Instance<X>,
-{
-    // Computes  `y = αAx + βy`, where `A` is `Self`.
-    fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) {
-        *y *= β;
-    }
-
-    fn apply_mut<I: Instance<X>>(&self, y: &mut Y, _x: I) {
-        y.set_zero();
-    }
-}
-
-impl<X, Y, F, YOrigin, XDOrigin, E1, E2> BoundedLinear<X, E1, E2, F>
-    for ZeroOp<X, Y, YOrigin, XDOrigin, F>
-where
-    F: Num,
-    YOrigin: OriginGenerator<Y, F>,
-    Y: Space + AXPY<F> + Norm<E2, F>,
-    X: Space + Instance<X> + Norm<E1, F>,
-    E1: NormExponent,
-    E2: NormExponent,
-{
-    fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> {
-        Ok(F::ZERO)
-    }
-}
-
-impl<X, Y, Yprime, F, YOrigin, XDOrigin> Adjointable<X, Yprime>
-    for ZeroOp<X, Y, YOrigin, XDOrigin, F>
-where
-    F: Num,
-    YOrigin: OriginGenerator<Y, F>,
-    Y: Space + AXPY<F>,
-    X: Space + Instance<X> + HasDual<F>,
-    XDOrigin: OriginGenerator<X::DualSpace, F> + Clone,
-    Yprime: Space + Instance<Yprime>,
-{
-    type AdjointCodomain = X::DualSpace;
-    type Adjoint<'b>
-        = ZeroOp<Yprime, X::DualSpace, XDOrigin, NotAnOriginGenerator, F>
-    where
-        Self: 'b;
-    // () means not (pre)adjointable.
-
-    fn adjoint(&self) -> Self::Adjoint<'_> {
-        ZeroOp::new(self.xd_origin.clone(), NotAnOriginGenerator)
-    }
-}
-*/
-
-/*
-impl<X, Y, Ypre, Xpre, F, YOrigin, XDOrigin> Preadjointable<X, Ypre>
-    for ZeroOp<X, Y, YOrigin, XDOrigin, F>
-where
-    F: Num,
-    YOrigin: OriginGenerator<Y, F>,
-    Y: Space + AXPY<F>,
-    X: Space + Instance<X> + HasDual<F>,
-    XDOrigin: OriginGenerator<Xpre, F> + Clone,
-    Ypre: Space + Instance<Ypre> + HasDual<DualSpace = X>,
-{
-    type PreadjointCodomain = Xpre;
-    type Preadjoint<'b>
-        = ZeroOp<Ypre, Xpre, XDOrigin, NotAnOriginGenerator, F>
-    where
-        Self: 'b;
-    // () means not (pre)adjointable.
-
-    fn adjoint(&self) -> Self::Adjoint<'_> {
-        ZeroOp::new(self.xpre_origin.clone(), NotAnOriginGenerator)
-    }
-}
-*/
-
 impl<S, T, E, X> Linear<X> for Composition<S, T, E>
 where
     X: Space,

mercurial