# HG changeset patch # User Tuomo Valkonen # Date 1734729257 18000 # Node ID d63e40672dd6c8e55c29df60206929c779273063 # Parent cebedc4a83312ca8c55a21a02896a3b4c5232676 AXPY as LinSpace attempts, difficulties with Pairs and nalgebra nalgebra should allow various storages, so InstanceMut as &self, but that won't work. diff -r cebedc4a8331 -r d63e40672dd6 src/direct_product.rs --- a/src/direct_product.rs Sat Dec 21 14:27:14 2024 -0500 +++ b/src/direct_product.rs Fri Dec 20 16:14:17 2024 -0500 @@ -279,28 +279,27 @@ } } -impl AXPY> for Pair +impl AXPY for Pair where - U : Space, - V : Space, - A : AXPY, - B : AXPY, - F : Num + A : AXPY, + B : AXPY, + F : Num + AXPY { + type Field = F; - fn axpy>>(&mut self, α : F, x : I, β : F) { + fn axpy>>(&mut self, α : F, x : I, β : F) { let Pair(u, v) = x.decompose(); self.0.axpy(α, u, β); self.1.axpy(α, v, β); } - fn copy_from>>(&mut self, x : I) { + fn copy_from>>(&mut self, x : I) { let Pair(u, v) = x.decompose(); self.0.copy_from(u); self.1.copy_from(v); } - fn scale_from>>(&mut self, α : F, x : I) { + fn scale_from>>(&mut self, α : F, x : I) { let Pair(u, v) = x.decompose(); self.0.scale_from(α, u); self.1.scale_from(α, v); diff -r cebedc4a8331 -r d63e40672dd6 src/linops.rs --- a/src/linops.rs Sat Dec 21 14:27:14 2024 -0500 +++ b/src/linops.rs Fri Dec 20 16:14:17 2024 -0500 @@ -12,53 +12,66 @@ use crate::norms::{NormExponent, PairNorm, L1, L2, Linfinity, Norm, HasDual}; /// Trait for linear operators on `X`. -pub trait Linear : Mapping -{ } +pub trait Linear : Mapping { + type LinCodomain : AXPY; // = Self::Codomain, but with AXPY enforced without trait bound bloat. +} /// Efficient in-place summation. -#[replace_float_literals(F::cast_from(literal))] -pub trait AXPY : Space -where - F : Num, - X : Space, -{ +#[replace_float_literals(Self::Field::cast_from(literal))] +pub trait AXPY : Space { + type Field : Num; + /// Computes `y = βy + αx`, where `y` is `Self`. - fn axpy>(&mut self, α : F, x : I, β : F); + fn axpy>(&mut self, α : Self::Field, x : I, β : Self::Field); /// Copies `x` to `self`. - fn copy_from>(&mut self, x : I) { + fn copy_from>(&mut self, x : I) { self.axpy(1.0, x, 0.0) } /// Computes `y = αx`, where `y` is `Self`. - fn scale_from>(&mut self, α : F, x : I) { + fn scale_from>(&mut self, α : Self::Field, x : I) { self.axpy(α, x, 0.0) } } +macro_rules! impl_axpy { + ($($type:ty)*) => { $( + impl AXPY for $type { + type Field = $type; + fn axpy>(&mut self, α : $type, x : I, β : $type) { + *self = *self * α + x.own() * β; + } + } + )* }; +} + +impl_axpy!(i8 i16 i32 i64 i128 isize f32 f64); + + /// Efficient in-place application for [`Linear`] operators. -#[replace_float_literals(F::cast_from(literal))] -pub trait GEMV>::Codomain> : Linear { +#[replace_float_literals(X::Field::cast_from(literal))] +pub trait GEMV : Linear { /// Computes `y = αAx + βy`, where `A` is `Self`. - fn gemv>(&self, y : &mut Y, α : F, x : I, β : F); + fn gemv>(&self, y : &mut Self::LinCodomain, α : ::Field, x : I, β : ::Field); /// Computes `y = Ax`, where `A` is `Self` - fn apply_mut>(&self, y : &mut Y, x : I){ + fn apply_mut>(&self, y : &mut Self::LinCodomain, x : I){ self.gemv(y, 1.0, x, 0.0) } /// Computes `y += Ax`, where `A` is `Self` - fn apply_add>(&self, y : &mut Y, x : I){ + fn apply_add>(&self, y : &mut Self::LinCodomain, x : I){ self.gemv(y, 1.0, x, 1.0) } } /// Bounded linear operators -pub trait BoundedLinear : Linear +pub trait BoundedLinear : Linear where F : Num, - X : Space + Norm, + X : AXP + Norm, XExp : NormExponent, CodExp : NormExponent { @@ -66,7 +79,7 @@ /// This is not expected to be the norm, just any bound on it that can be /// reasonably implemented. The [`NormExponent`] `xexp` indicates the norm /// in `X`, and `codexp` in the codomain. - fn opnorm_bound(&self, xexp : XExp, codexp : CodExp) -> F; + fn opnorm_bound(&self, xexp : XExp, codexp : CodExp) -> X::Field; // TODO: Should pick real subfield } // Linear operator application into mutable target. The [`AsRef`] bound @@ -105,27 +118,26 @@ /// /// We do not set further restrictions on the spacds, to allow preadjointing when `X` /// is on the dual space of `Ypre`, but a subset of it. -pub trait Preadjointable : Linear +pub trait Preadjointable : Linear //where // Ypre : HasDual, { - type PreadjointCodomain : Space; + type PreadjointCodomain : AXPY; type Preadjoint<'a> : Linear where Self : 'a; /// Form the adjoint operator of `self`. fn preadjoint(&self) -> Self::Preadjoint<'_>; } - /// The identity operator #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] -pub struct IdOp (PhantomData); +pub struct IdOp (PhantomData); -impl IdOp { +impl IdOp { pub fn new() -> IdOp { IdOp(PhantomData) } } -impl Mapping for IdOp { +impl Mapping for IdOp { type Codomain = X; fn apply>(&self, x : I) -> X { @@ -133,32 +145,29 @@ } } -impl Linear for IdOp -{ } +impl Linear for IdOp { + type LinCodomain = X; +} #[replace_float_literals(F::cast_from(literal))] -impl GEMV for IdOp -where - Y : AXPY, - X : Clone + Space -{ +impl GEMV for IdOp { // Computes `y = αAx + βy`, where `A` is `Self`. - fn gemv>(&self, y : &mut Y, α : F, x : I, β : F) { + fn gemv>(&self, y : &mut Self::LinCodomain, α : X::Field, x : I, β : X::Field) { y.axpy(α, x, β) } - fn apply_mut>(&self, y : &mut Y, x : I){ + fn apply_mut>(&self, y : &mut X, x : I){ y.copy_from(x); } } -impl BoundedLinear for IdOp +impl BoundedLinear for IdOp where - X : Space + Clone + Norm, - F : Num, + X : AXPY + Clone + Norm, + F : Num + AXPY, E : NormExponent { - fn opnorm_bound(&self, _xexp : E, _codexp : E) -> F { F::ONE } + fn opnorm_bound(&self, _xexp : E, _codexp : E) -> X::Field { F::ONE } } impl, F : Float> Adjointable for IdOp { @@ -168,7 +177,7 @@ fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } } -impl Preadjointable for IdOp { +impl Preadjointable for IdOp { type PreadjointCodomain = X; type Preadjoint<'a> = IdOp where X : 'a; @@ -178,10 +187,12 @@ impl Linear for Composition where - X : Space, + X : AXPY, T : Linear, - S : Linear -{ } + S : Linear +{ + type LinCodomain = S::LinCodomain; +} impl GEMV for Composition where @@ -227,17 +238,16 @@ use std::ops::Add; -impl Mapping> for RowOp +impl Mapping> for RowOp where A : Space, B : Space, + Y : Space, S : Mapping, T : Mapping, - S::Codomain : Add, - >::Output : Space, - + S::Codomain : Add, { - type Codomain = >::Output; + type Codomain = Y; fn apply>>(&self, x : I) -> Self::Codomain { let Pair(a, b) = x.decompose(); @@ -245,25 +255,30 @@ } } -impl Linear> for RowOp +impl Linear> for RowOp where - A : Space, - B : Space, + F : Num + AXPY, + A : AXPY, + B : AXPY, + Y : AXPY, S : Linear, T : Linear, - S::Codomain : Add, - >::Output : Space, -{ } + S::LinCodomain : Add, +{ + type LinCodomain = Y; +} -impl<'b, F, S, T, Y, U, V> GEMV, Y> for RowOp +impl<'b, F, S, T, Y, G, U, V> GEMV> for RowOp where - U : Space, - V : Space, - S : GEMV, - T : GEMV, - F : Num, - Self : Linear, Codomain=Y> + U : AXPY, + V : AXPY, + Y : AXPY, + S : GEMV, + T : GEMV, + F : Num + AXPY, + G : Num + AXPY, + S::LinCodomain : Add, { fn gemv>>(&self, y : &mut Y, α : F, x : I, β : F) { let Pair(u, v) = x.decompose(); @@ -288,33 +303,39 @@ /// “Column operator” $(S; T)$; $(S; T)x=(Sx, Tx)$. pub struct ColOp(pub S, pub T); -impl Mapping for ColOp +impl Mapping for ColOp where - A : Space, - S : Mapping, - T : Mapping, + X : AXPY, + S : Mapping, + T : Mapping, { type Codomain = Pair; - fn apply>(&self, a : I) -> Self::Codomain { + fn apply>(&self, a : I) -> Self::Codomain { Pair(self.0.apply(a.ref_instance()), self.1.apply(a)) } } -impl Linear for ColOp +impl Linear for ColOp where - A : Space, - S : Mapping, - T : Mapping, -{ } + F : Num + AXPY, + X : AXPY, + S : Linear, + T : Linear, + A : AXPY, + B : AXPY, +{ + type LinCodomain = Pair; +} -impl GEMV> for ColOp +impl GEMV for ColOp where - X : Space, - S : GEMV, - T : GEMV, - F : Num, - Self : Linear> + F : Num + AXPY, + X : AXPY, + S : GEMV, + T : GEMV, + A : AXPY, + B : AXPY, { fn gemv>(&self, y : &mut Pair, α : F, x : I, β : F) { self.0.gemv(&mut y.0, α, x.ref_instance(), β); @@ -341,7 +362,7 @@ B : HasDual, S : Adjointable, T : Adjointable, - Yʹ : Space, + Yʹ : AXPY, S :: Codomain : HasDual, T :: Codomain : HasDual, S::Codomain : Add, @@ -361,15 +382,15 @@ } } -impl Preadjointable, Yʹ> for RowOp -where - A : Space, - B : Space, - Yʹ : Space, +impl Preadjointable, Yʹ> for RowOp +wherea + A : AXPY, + B : AXPY, + Yʹ : AXPY, S : Preadjointable, T : Preadjointable, S::Codomain : Add, - >::Output : Space, + >::Output : AXPY, //Self : Linear, Codomain=Y>, //for<'a> ColOp, T::Preadjoint<'a>> : Adjointable, { @@ -407,10 +428,10 @@ impl Preadjointable> for ColOp where - A : Space, - Aʹ : Space, - Xʹ : Space, - Yʹ : Space, + A : AXPY, + Aʹ : AXPY, + Xʹ : AXPY, + Yʹ : AXPY, S : Preadjointable, T : Preadjointable, Aʹ : ClosedAdd, @@ -429,8 +450,8 @@ impl Mapping> for DiagOp where - A : Space, - B : Space, + A : AXPY, + B : AXPY, S : Mapping, T : Mapping, { @@ -442,26 +463,32 @@ } } -impl Linear> for DiagOp -where - A : Space, - B : Space, - S : Linear, - T : Linear, -{ } - -impl GEMV, Pair> for DiagOp +impl Linear> for DiagOp where - A : Space, - B : Space, - U : Space, - V : Space, - S : GEMV, - T : GEMV, - F : Num, - Self : Linear, Codomain=Pair>, + F : Num + AXPY, + G : Num + AXPY, + A : AXPY, + B : AXPY, + U : AXPY, + V : AXPY, + S : Linear, + T : Linear, { - fn gemv>>(&self, y : &mut Pair, α : F, x : I, β : F) { + type LinCodomain = Pair; +} + +impl GEMV> for DiagOp +where + F : Num + AXPY, + G : Num + AXPY, + A : AXPY, + B : AXPY, + U : AXPY, + V : AXPY, + S : GEMV, + T : GEMV, +{ + fn gemv>>(&self, y : &mut Pair, α : G, x : I, β : G) { let Pair(u, v) = x.decompose(); self.0.gemv(&mut y.0, α, u, β); self.1.gemv(&mut y.1, α, v, β); @@ -501,10 +528,10 @@ impl Preadjointable, Pair> for DiagOp where - A : Space, - B : Space, - Xʹ : Space, - Yʹ : Space, + A : AXPY, + B : AXPY, + Xʹ : AXPY, + Yʹ : AXPY, S : Preadjointable, T : Preadjointable, { @@ -523,16 +550,16 @@ macro_rules! pairnorm { ($expj:ty) => { impl - BoundedLinear, PairNorm, ExpR, F> + BoundedLinear, PairNorm, ExpR> for RowOp where F : Float, - A : Space + Norm, - B : Space + Norm, + A : AXPY + Norm, + B : AXPY + Norm, S : BoundedLinear, T : BoundedLinear, S::Codomain : Add, - >::Output : Space, + >::Output : AXPY, ExpA : NormExponent, ExpB : NormExponent, ExpR : NormExponent, @@ -541,7 +568,7 @@ &self, PairNorm(expa, expb, _) : PairNorm, expr : ExpR - ) -> F { + ) -> as AXPY>::Field { // An application of the triangle inequality bounds the norm by the maximum // of the individual norms. A simple observation shows this to be exact. let na = self.0.opnorm_bound(expa, expr); @@ -550,12 +577,12 @@ } } - impl - BoundedLinear, F> + impl + BoundedLinear> for ColOp where F : Float, - A : Space + Norm, + A : AXPY + Norm, S : BoundedLinear, T : BoundedLinear, ExpA : NormExponent, @@ -566,7 +593,7 @@ &self, expa : ExpA, PairNorm(exps, expt, _) : PairNorm - ) -> F { + ) -> A::Field { // This is based on the rule for RowOp and ‖A^*‖ = ‖A‖, hence, // for A=[S; T], ‖A‖=‖[S^*, T^*]‖ ≤ max{‖S^*‖, ‖T^*‖} = max{‖S‖, ‖T‖} let ns = self.0.opnorm_bound(expa, exps); diff -r cebedc4a8331 -r d63e40672dd6 src/loc.rs --- a/src/loc.rs Sat Dec 21 14:27:14 2024 -0500 +++ b/src/loc.rs Fri Dec 20 16:14:17 2024 -0500 @@ -709,9 +709,12 @@ } } -impl Linear> for Loc { } +impl Linear> for Loc { + type LinCodomain = F; +} -impl AXPY> for Loc { +impl AXPY for Loc { + type Field = F; #[inline] fn axpy>>(&mut self, α : F, x : I, β : F) { x.eval(|x̃| { diff -r cebedc4a8331 -r d63e40672dd6 src/nalgebra_support.rs --- a/src/nalgebra_support.rs Sat Dec 21 14:27:14 2024 -0500 +++ b/src/nalgebra_support.rs Fri Dec 20 16:14:17 2024 -0500 @@ -61,11 +61,13 @@ DefaultAllocator : Allocator, DefaultAllocator : Allocator, DefaultAllocator : Allocator, - DefaultAllocator : Allocator { + DefaultAllocator : Allocator +{ + type LinCodomain = OMatrix; } -impl GEMV, Matrix> for Matrix -where SM: Storage, SV1: Storage + Clone, SV2: StorageMut, +impl GEMV> for Matrix +where SM: Storage, SV1: Storage + Clone, N : Dim, M : Dim, K : Dim, E : Scalar + Zero + One + Float, DefaultAllocator : Allocator, DefaultAllocator : Allocator, @@ -85,18 +87,19 @@ } } -impl AXPY> for Vector -where SM: StorageMut + Clone, SV1: Storage + Clone, +impl AXPY for Vector +where SM: StorageMut + Clone, M : Dim, E : Scalar + Zero + One + Float, DefaultAllocator : Allocator { + type Field = E; #[inline] - fn axpy>>(&mut self, α : E, x : I, β : E) { + fn axpy>>(&mut self, α : E, x : I, β : E) { x.eval(|x̃| Matrix::axpy(self, α, x̃, β)) } #[inline] - fn copy_from>>(&mut self, y : I) { + fn copy_from>>(&mut self, y : I) { y.eval(|ỹ| Matrix::copy_from(self, ỹ)) } } diff -r cebedc4a8331 -r d63e40672dd6 src/norms.rs --- a/src/norms.rs Sat Dec 21 14:27:14 2024 -0500 +++ b/src/norms.rs Fri Dec 20 16:14:17 2024 -0500 @@ -7,6 +7,7 @@ use crate::types::*; use crate::euclidean::*; use crate::mapping::{Mapping, Space, Instance}; +use crate::linops::AXPY; // // Abstract norms @@ -202,7 +203,7 @@ } } -pub trait Normed : Space + Norm { +pub trait Normed : AXPY + Norm { type NormExp : NormExponent; fn norm_exponent(&self) -> Self::NormExp;