--- a/src/linops.rs Mon Sep 01 00:04:22 2025 -0500 +++ b/src/linops.rs Mon Sep 01 13:51:03 2025 -0500 @@ -5,7 +5,7 @@ use crate::direct_product::Pair; use crate::error::DynResult; use crate::instance::Instance; -pub use crate::mapping::{Composition, DifferentiableImpl, Mapping, Space}; +pub use crate::mapping::{ClosedSpace, Composition, DifferentiableImpl, Mapping, Space}; use crate::norms::{HasDual, Linfinity, Norm, NormExponent, PairNorm, L1, L2}; use crate::types::*; use numeric_literals::replace_float_literals; @@ -25,16 +25,10 @@ // } // } -/// Efficient in-place summation. +/// Vector spaces #[replace_float_literals(Self::Field::cast_from(literal))] -pub trait AXPY<X = Self>: - Space - + MulAssign<Self::Field> - + DivAssign<Self::Field> - + AddAssign<Self> - + AddAssign<Self::Owned> - + SubAssign<Self> - + SubAssign<Self::Owned> +pub trait VectorSpace: + Space<OwnedSpace = Self::Owned> + Mul<Self::Field, Output = Self::Owned> + Div<Self::Field, Output = Self::Owned> + Add<Self, Output = Self::Owned> @@ -42,12 +36,42 @@ + Sub<Self, Output = Self::Owned> + Sub<Self::Owned, Output = Self::Owned> + Neg +{ + type Field: Num; + type Owned: ClosedSpace + + AXPY< + Self, + Field = Self::Field, + Owned = Self::Owned, + OwnedVariant = Self::Owned, + OwnedSpace = Self::Owned, + >; + + /// Return a similar zero as `self`. + fn similar_origin(&self) -> Self::Owned; + // { + // self.make_origin_generator().make_origin() + // } + + /// Return a similar zero as `x`. + fn similar_origin_inst<I: Instance<Self>>(x: I) -> Self::Owned { + x.eval(|xr| xr.similar_origin()) + } +} + +/// Efficient in-place summation. +#[replace_float_literals(Self::Field::cast_from(literal))] +pub trait AXPY<X = Self>: + VectorSpace + + MulAssign<Self::Field> + + DivAssign<Self::Field> + + AddAssign<Self> + + AddAssign<Self::Owned> + + SubAssign<Self> + + SubAssign<Self::Owned> where X: Space, { - type Field: Num; - type Owned: AXPY<X, Field = Self::Field>; - /// Computes `y = βy + αx`, where `y` is `Self`. fn axpy<I: Instance<X>>(&mut self, α: Self::Field, x: I, β: Self::Field); @@ -61,21 +85,8 @@ self.axpy(α, x, 0.0) } - /// Return a similar zero as `self`. - fn similar_origin(&self) -> Self::Owned; - // { - // self.make_origin_generator().make_origin() - // } - - /// Return a similar zero as `x`. - fn similar_origin_inst<I: Instance<Self>>(x: I) -> Self::Owned { - x.eval(|xr| xr.similar_origin()) - } - /// Set self to zero. fn set_zero(&mut self); - - //fn make_origin_generator(&self) -> Self::OriginGen<'_>; } /// Efficient in-place application for [`Linear`] operators. @@ -178,21 +189,21 @@ } } -impl<X: Clone + Space> Mapping<X> for IdOp<X> { - type Codomain = X; +impl<X: Space> Mapping<X> for IdOp<X> { + type Codomain = X::OwnedVariant; fn apply<I: Instance<X>>(&self, x: I) -> X { x.own() } } -impl<X: Clone + Space> Linear<X> for IdOp<X> {} +impl<X: Space> Linear<X> for IdOp<X> {} #[replace_float_literals(F::cast_from(literal))] impl<F: Num, X, Y> GEMV<F, X, Y> for IdOp<X> where Y: AXPY<X, Field = F>, - X: Clone + Space, + X: Space, { // Computes `y = αAx + βy`, where `A` is `Self`. fn gemv<I: Instance<X>>(&self, y: &mut Y, α: F, x: I, β: F) { @@ -243,10 +254,7 @@ #[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] pub struct SimpleZeroOp; -impl<X> Mapping<X> for SimpleZeroOp -where - X: AXPY + Instance<X>, -{ +impl<X: VectorSpace> Mapping<X> for SimpleZeroOp { type Codomain = X::Owned; fn apply<I: Instance<X>>(&self, x: I) -> X::Owned { @@ -254,14 +262,14 @@ } } -impl<X> Linear<X> for SimpleZeroOp where X: AXPY + Instance<X> {} +impl<X: VectorSpace> Linear<X> for SimpleZeroOp {} #[replace_float_literals(F::cast_from(literal))] impl<X, Y, F> GEMV<F, X, Y> for SimpleZeroOp where F: Num, Y: AXPY<Field = F>, - X: AXPY<Field = F> + Instance<X>, + X: VectorSpace<Field = F> + Instance<X>, { // Computes `y = αAx + βy`, where `A` is `Self`. fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) { @@ -276,7 +284,7 @@ impl<X, F, E1, E2> BoundedLinear<X, E1, E2, F> for SimpleZeroOp where F: Num, - X: AXPY<Field = F> + Instance<X> + Norm<E1, F>, + X: VectorSpace<Field = F> + Norm<E1, F>, E1: NormExponent, E2: NormExponent, { @@ -288,8 +296,8 @@ impl<X, F> Adjointable<X, X::DualSpace> for SimpleZeroOp where F: Num, - X: AXPY<Field = F> + Instance<X> + HasDual<F>, - X::DualSpace: AXPY<Owned = X::DualSpace>, + X: VectorSpace<Field = F> + HasDual<F>, + X::DualSpace: VectorSpace<Owned = X::DualSpace>, { type AdjointCodomain = X::DualSpace; type Adjoint<'b> @@ -303,7 +311,7 @@ } } -pub trait OriginGenerator<Y: AXPY> { +pub trait OriginGenerator<Y: VectorSpace> { type Ref<'b>: OriginGenerator<Y> where Self: 'b; @@ -312,7 +320,7 @@ fn as_ref(&self) -> Self::Ref<'_>; } -impl<Y: AXPY> OriginGenerator<Y> for Y { +impl<Y: VectorSpace> OriginGenerator<Y> for Y { type Ref<'b> = &'b Y where @@ -329,7 +337,7 @@ } } -impl<'b, Y: AXPY> OriginGenerator<Y> for &'b Y { +impl<'b, Y: VectorSpace> OriginGenerator<Y> for &'b Y { type Ref<'c> = Self where @@ -348,7 +356,7 @@ /// 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>, OY: OriginGenerator<Y>, O, F: Float = f64> { +pub struct ZeroOp<X, Y: VectorSpace<Field = F>, OY: OriginGenerator<Y>, O, F: Float = f64> { codomain_origin_generator: OY, other_origin_generator: O, _phantoms: PhantomData<(X, Y, F)>, @@ -357,8 +365,8 @@ impl<X, Y, OY, F> ZeroOp<X, Y, OY, (), F> where OY: OriginGenerator<Y>, - X: AXPY<Field = F>, - Y: AXPY<Field = F>, + X: VectorSpace<Field = F>, + Y: VectorSpace<Field = F>, F: Float, { pub fn new(y_og: OY) -> Self { @@ -377,7 +385,7 @@ X: HasDual<F, DualSpace = Xprime>, Y: HasDual<F, DualSpace = Yprime>, F: Float, - Xprime: AXPY<Field = F, Owned = Xprime>, + Xprime: VectorSpace<Field = F, Owned = Xprime>, Xprime::Owned: AXPY<Field = F>, Yprime: Space + Instance<Yprime>, { @@ -392,8 +400,8 @@ impl<X, Y, O, OY, F> Mapping<X> for ZeroOp<X, Y, OY, O, F> where - X: Space + Instance<X>, - Y: AXPY<Field = F>, + X: Space, + Y: VectorSpace<Field = F>, F: Float, OY: OriginGenerator<Y>, { @@ -406,8 +414,8 @@ impl<X, Y, OY, O, F> Linear<X> for ZeroOp<X, Y, OY, O, F> where - X: Space + Instance<X>, - Y: AXPY<Field = F>, + X: Space, + Y: VectorSpace<Field = F>, F: Float, OY: OriginGenerator<Y>, { @@ -416,7 +424,7 @@ #[replace_float_literals(F::cast_from(literal))] impl<X, Y, OY, O, F> GEMV<F, X, Y> for ZeroOp<X, Y, OY, O, F> where - X: Space + Instance<X>, + X: Space, Y: AXPY<Field = F, Owned = Y>, F: Float, OY: OriginGenerator<Y>, @@ -434,7 +442,7 @@ 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>, + Y: VectorSpace<Field = F>, Y::Owned: Clone, F: Float, E1: NormExponent, @@ -452,7 +460,7 @@ X: HasDual<F, DualSpace = Xprime>, Y: HasDual<F, DualSpace = Yprime>, F: Float, - Xprime: AXPY<Field = F, Owned = Xprime>, + Xprime: VectorSpace<Field = F, Owned = Xprime>, Xprime::Owned: AXPY<Field = F>, Yprime: Space + Instance<Yprime>, OY: OriginGenerator<Y>,