# HG changeset patch # User Tuomo Valkonen # Date 1747082568 18000 # Node ID d2994e34a5f55ef3dde7ec7f0a72626652b21ae3 # Parent f75bf34adda0b8df216f055288638f5e00ebae98 Simplify ZeroOp to SimpleZeroOp, only from X to X. Add Prox for ZeroIndicator. Move F parameter to AXPY::Field. diff -r f75bf34adda0 -r d2994e34a5f5 src/convex.rs --- a/src/convex.rs Sun May 11 02:03:45 2025 -0500 +++ b/src/convex.rs Mon May 12 15:42:48 2025 -0500 @@ -5,7 +5,7 @@ use crate::error::DynResult; use crate::euclidean::Euclidean; use crate::instance::{DecompositionMut, Instance, InstanceMut}; -use crate::linops::{IdOp, Scaled}; +use crate::linops::{IdOp, Scaled, SimpleZeroOp, AXPY}; use crate::mapping::{DifferentiableImpl, LipschitzDifferentiableImpl, Mapping, Space}; use crate::norms::*; use crate::operator_arithmetic::{Constant, Weighted}; @@ -333,6 +333,22 @@ } } +impl Prox for ZeroIndicator +where + Domain: AXPY + Normed, + F: Float, +{ + type Prox<'a> + = SimpleZeroOp + where + Self: 'a; + + /// Returns a proximal mapping with weight τ + fn prox_mapping(&self, _τ: F) -> Self::Prox<'_> { + return SimpleZeroOp; + } +} + /// The squared Euclidean norm divided by two #[derive(Copy, Clone, Serialize, Deserialize)] pub struct Norm222(PhantomData); diff -r f75bf34adda0 -r d2994e34a5f5 src/direct_product.rs --- a/src/direct_product.rs Sun May 11 02:03:45 2025 -0500 +++ b/src/direct_product.rs Mon May 12 15:42:48 2025 -0500 @@ -244,13 +244,13 @@ impl_binary_mut!(SubAssign, sub_assign); macro_rules! impl_scalar_mut { - ($trait:ident, $fn:ident, $F:ty) => { - impl<'a, A, B> $trait<$F> for Pair + ($trait:ident, $fn:ident) => { + impl<'a, A, B, F: Num> $trait for Pair where - A: $trait<$F>, - B: $trait<$F>, + A: $trait, + B: $trait, { - fn $fn(&mut self, t: $F) { + fn $fn(&mut self, t: F) { let Pair(ref mut a, ref mut b) = self; a.$fn(t); b.$fn(t); @@ -259,10 +259,8 @@ }; } -impl_scalar_mut!(MulAssign, mul_assign, f32); -impl_scalar_mut!(MulAssign, mul_assign, f64); -impl_scalar_mut!(DivAssign, div_assign, f32); -impl_scalar_mut!(DivAssign, div_assign, f64); +impl_scalar_mut!(MulAssign, mul_assign); +impl_scalar_mut!(DivAssign, div_assign); /// We only support 'closed' `Euclidean` `Pair`s, as more general ones cause /// compiler overflows. @@ -303,17 +301,20 @@ } } -impl AXPY> for Pair +impl AXPY> for Pair where U: Space, V: Space, - A: AXPY, - B: AXPY, + A: AXPY, + B: AXPY, F: Num, Self: MulAssign, Pair: MulAssign, - Pair: AXPY>, + //A::Owned: MulAssign, + //B::Owned: MulAssign, + //Pair: AXPY, Field = F>, { + type Field = F; type Owned = Pair; fn axpy>>(&mut self, α: F, x: I, β: F) { diff -r f75bf34adda0 -r d2994e34a5f5 src/linops.rs --- a/src/linops.rs Sun May 11 02:03:45 2025 -0500 +++ b/src/linops.rs Mon May 12 15:42:48 2025 -0500 @@ -6,7 +6,7 @@ use crate::error::DynResult; use crate::instance::Instance; pub use crate::mapping::{Composition, DifferentiableImpl, Mapping, Space}; -use crate::norms::{Linfinity, Norm, NormExponent, PairNorm, L1, L2}; +use crate::norms::{HasDual, Linfinity, Norm, NormExponent, PairNorm, L1, L2}; use crate::types::*; use numeric_literals::replace_float_literals; use serde::Serialize; @@ -26,16 +26,19 @@ // } /// Efficient in-place summation. -#[replace_float_literals(F::cast_from(literal))] -pub trait AXPY: Space + std::ops::MulAssign +#[replace_float_literals(Self::Field::cast_from(literal))] +pub trait AXPY: Space + std::ops::MulAssign where - F: Num, X: Space, { - type Owned: AXPY; + 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, α: 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) { @@ -43,15 +46,25 @@ } /// 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) } /// 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>(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. @@ -167,7 +180,7 @@ #[replace_float_literals(F::cast_from(literal))] impl GEMV for IdOp where - Y: AXPY, + Y: AXPY, X: Clone + Space, { // Computes `y = αAx + βy`, where `A` is `Self`. @@ -215,42 +228,29 @@ } } -/// The zero operator +/// The zero operator from a space to itself #[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] -pub struct ZeroOp<'a, X, XD, Y, F> { - zero: &'a Y, // TODO: don't pass this in `new`; maybe not even store. - dual_or_predual_zero: XD, - _phantoms: PhantomData<(X, Y, F)>, -} +pub struct SimpleZeroOp; -// TODO: Need to make Zero in Instance. +impl Mapping for SimpleZeroOp +where + X: AXPY + Instance, +{ + type Codomain = X::Owned; -impl<'a, F: Num, X: Space, XD, Y: Space + Clone> ZeroOp<'a, X, XD, Y, F> { - pub fn new(zero: &'a Y, dual_or_predual_zero: XD) -> Self { - ZeroOp { - zero, - dual_or_predual_zero, - _phantoms: PhantomData, - } + fn apply>(&self, x: I) -> X::Owned { + X::similar_origin_inst(x) } } -impl<'a, F: Num, X: Space, XD, Y: AXPY + Clone> Mapping for ZeroOp<'a, X, XD, Y, F> { - type Codomain = Y; - - fn apply>(&self, _x: I) -> Y { - self.zero.clone() - } -} - -impl<'a, F: Num, X: Space, XD, Y: AXPY + Clone> Linear for ZeroOp<'a, X, XD, Y, F> {} +impl Linear for SimpleZeroOp where X: AXPY + Instance {} #[replace_float_literals(F::cast_from(literal))] -impl<'a, F, X, XD, Y> GEMV for ZeroOp<'a, X, XD, Y, F> +impl GEMV for SimpleZeroOp where F: Num, - Y: AXPY + Clone, - X: Space, + Y: AXPY, + X: AXPY + Instance, { // Computes `y = αAx + βy`, where `A` is `Self`. fn gemv>(&self, y: &mut Y, _α: F, _x: I, β: F) { @@ -262,11 +262,10 @@ } } -impl<'a, F, X, XD, Y, E1, E2> BoundedLinear for ZeroOp<'a, X, XD, Y, F> +impl BoundedLinear for SimpleZeroOp where - X: Space + Norm, - Y: AXPY + Clone + Norm, F: Num, + X: AXPY + Instance + Norm, E1: NormExponent, E2: NormExponent, { @@ -275,43 +274,184 @@ } } -impl<'a, F: Num, X, XD, Y, Yprime: Space> Adjointable for ZeroOp<'a, X, XD, Y, F> +impl Adjointable for SimpleZeroOp where - X: Space, - Y: AXPY + Clone + 'static, - XD: AXPY + Clone + 'static, + F: Num, + X: AXPY + Instance + HasDual, + X::DualSpace: AXPY, { - type AdjointCodomain = XD; + type AdjointCodomain = X::DualSpace; type Adjoint<'b> - = ZeroOp<'b, Yprime, (), XD, F> + = SimpleZeroOp where Self: 'b; // () means not (pre)adjointable. fn adjoint(&self) -> Self::Adjoint<'_> { - ZeroOp::new(&self.dual_or_predual_zero, ()) + SimpleZeroOp + } +} + +/* +/// 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, + _phantoms: PhantomData, + } } } -impl<'a, F, X, XD, Y, Ypre> Preadjointable for ZeroOp<'a, X, XD, Y, F> +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, - X: Space, - Y: AXPY + Clone, - Ypre: Space, - XD: AXPY + Clone + 'static, + YOrigin: OriginGenerator, + Y: Space + AXPY, + X: Space + Instance, { - type PreadjointCodomain = XD; - type Preadjoint<'b> - = ZeroOp<'b, Ypre, (), XD, F> + // 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 preadjoint(&self) -> Self::Preadjoint<'_> { - ZeroOp::new(&self.dual_or_predual_zero, ()) + 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 diff -r f75bf34adda0 -r d2994e34a5f5 src/loc.rs --- a/src/loc.rs Sun May 11 02:03:45 2025 -0500 +++ b/src/loc.rs Mon May 12 15:42:48 2025 -0500 @@ -710,7 +710,8 @@ impl Linear> for Loc {} -impl AXPY> for Loc { +impl AXPY> for Loc { + type Field = F; type Owned = Self; #[inline] @@ -729,12 +730,22 @@ x.eval(|x̃| map2_mut(self, x̃, |yi, xi| *yi = *xi)) } + // #[inline] + // fn make_origin_generator(&self) -> StaticEuclideanOriginGenerator { + // StaticEuclideanOriginGenerator + // } + #[inline] fn similar_origin(&self) -> Self::Owned { Self::ORIGIN } #[inline] + fn similar_origin_inst>(_: I) -> Self::Owned { + Self::ORIGIN + } + + #[inline] fn set_zero(&mut self) { *self = Self::ORIGIN; } diff -r f75bf34adda0 -r d2994e34a5f5 src/nalgebra_support.rs --- a/src/nalgebra_support.rs Sun May 11 02:03:45 2025 -0500 +++ b/src/nalgebra_support.rs Mon May 12 15:42:48 2025 -0500 @@ -103,7 +103,7 @@ } } -impl AXPY> for Vector +impl AXPY> for Vector where SM: StorageMut + Clone, SV1: Storage + Clone, @@ -111,6 +111,7 @@ E: Scalar + Zero + One + Float, DefaultAllocator: Allocator, { + type Field = E; type Owned = OVector; #[inline]