# HG changeset patch # User Tuomo Valkonen # Date 1745931318 18000 # Node ID 103aa137fcb24ffed2e1d6f21d480ac64f70bb23 # Parent e7f1cb4bec7887cb69da592d5a52eb05de3831b8 sketch diff -r e7f1cb4bec78 -r 103aa137fcb2 src/convex.rs --- a/src/convex.rs Tue Apr 29 00:03:12 2025 -0500 +++ b/src/convex.rs Tue Apr 29 07:55:18 2025 -0500 @@ -319,15 +319,15 @@ } /// The squared Euclidean norm divided by two -pub struct Norm222(PhantomData<(Domain, F)>); +pub struct Norm222(PhantomData); -impl, F: Float> Norm222 { +impl,*/ F: Float> Norm222 { pub fn new() -> Self { Norm222(PhantomData) } } -impl, F: Float> Mapping for Norm222 { +impl, F: Float> Mapping for Norm222 { type Codomain = F; /// Compute the value of `self` at `x`. @@ -336,9 +336,9 @@ } } -impl, F: Float> ConvexMapping for Norm222 {} +impl, F: Float> ConvexMapping for Norm222 {} -impl, F: Float> Conjugable for Norm222 { +impl, F: Float> Conjugable for Norm222 { type Conjugate<'a> = Self where @@ -350,7 +350,7 @@ } } -impl, F: Float> Preconjugable for Norm222 { +impl, F: Float> Preconjugable for Norm222 { type Preconjugate<'a> = Self where @@ -362,7 +362,7 @@ } } -impl Prox for Norm222 +impl Prox for Norm222 where F: Float, Domain: Euclidean, diff -r e7f1cb4bec78 -r 103aa137fcb2 src/mapping.rs --- a/src/mapping.rs Tue Apr 29 00:03:12 2025 -0500 +++ b/src/mapping.rs Tue Apr 29 07:55:18 2025 -0500 @@ -9,6 +9,7 @@ use crate::types::{ClosedMul, Float, Num}; use std::borrow::Cow; use std::marker::PhantomData; +use std::ops::Mul; /// A mapping from `Domain` to `Self::Codomain`. pub trait Mapping { @@ -283,8 +284,39 @@ } } +/// Helper trait for implementing [`DifferentiableMapping`] +impl DifferentiableImpl for Composition +where + X: Space, + T: DifferentiableImpl + Mapping, + S: DifferentiableImpl, + E: Copy, + //Composition: Space, + S::Derivative: Mul, + Y: Space, +{ + //type Derivative = Composition; + type Derivative = Y; + + /// Compute the differential of `self` at `x`, consuming the input. + fn differential_impl>(&self, x: I) -> Self::Derivative { + // Composition { + // outer: self + // .outer + // .differential_impl(self.inner.apply(x.ref_instance())), + // inner: self.inner.differential_impl(x), + // intermediate_norm_exponent: self.intermediate_norm_exponent, + // } + self.outer + .differential_impl(self.inner.apply(x.ref_instance())) + * self.inner.differential_impl(x) + } +} + mod quadratic; pub use quadratic::Quadratic; +mod dataterm; +pub use dataterm::DataTerm; /// Trait for indicating that `Self` is Lipschitz with respect to the (semi)norm `D`. pub trait Lipschitz { diff -r e7f1cb4bec78 -r 103aa137fcb2 src/mapping/dataterm.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mapping/dataterm.rs Tue Apr 29 07:55:18 2025 -0500 @@ -0,0 +1,124 @@ +/*! +General deata terms of the form $g(Ax-b)$ for an operator $A$ +to a [`Euclidean`] space, and a function g on that space. +*/ + +#![allow(non_snake_case)] + +use super::{DifferentiableImpl, DifferentiableMapping, /*LipschitzDifferentiableImpl,*/ Mapping,}; +use crate::convex::ConvexMapping; +use crate::instance::{Instance, Space}; +use crate::linops::{/*BoundedLinear,*/ Linear, Preadjointable}; +//use crate::norms::{Norm, NormExponent, L2}; +use crate::types::Float; +use std::ops::Sub; +//use serde::{Deserialize, Serialize}; + +/// Functions of the form $\frac{1}{2}\|Ax-b\|_2^2$ for an operator $A$ +/// to a [`Euclidean`] space. +pub struct DataTerm< + F: Float, + Domain: Space, + A: Mapping, + G: Mapping, +> { + opA: A, + b: >::Codomain, + g: G, +} + +#[allow(non_snake_case)] +impl, G: Mapping> + DataTerm +{ + pub fn new(opA: A, b: A::Codomain, g: G) -> Self { + DataTerm { opA, b, g } + } + + pub fn operator(&self) -> &'_ A { + &self.opA + } + + pub fn data(&self) -> &'_ >::Codomain { + &self.b + } + + pub fn fidelity(&self) -> &'_ G { + &self.g + } +} + +//+ AdjointProductBoundedBy, P, FloatType = F>, + +impl Mapping for DataTerm +where + F: Float, + X: Space, + A: Mapping, + G: Mapping, + A::Codomain: for<'a> Sub<&'a A::Codomain, Output = A::Codomain>, +{ + type Codomain = F; + + fn apply>(&self, x: I) -> F { + // TODO: possibly (if at all more effcient) use GEMV once generalised + // to not require preallocation. However, Rust should be pretty efficient + // at not doing preallocations or anything here, as the result of self.opA.apply() + // can be consumed, so maybe GEMV is no use. + self.g.apply(self.opA.apply(x) - &self.b) + } +} + +impl ConvexMapping for DataTerm +where + F: Float, + X: Space, + A: Linear, + G: ConvexMapping, + A::Codomain: for<'a> Sub<&'a A::Codomain, Output = A::Codomain>, +{ +} + +impl DifferentiableImpl for DataTerm +where + F: Float, + X: Space, + Y: Space + for<'a> Sub<&'a Y, Output = Y>, + //>::Codomain: Euclidean, + A: Linear + Preadjointable, + //<>::Codomain as Euclidean>::Output: Instance<>::Codomain>, + G: DifferentiableMapping, +{ + type Derivative = A::PreadjointCodomain; + + fn differential_impl>(&self, x: I) -> Self::Derivative { + // TODO: possibly (if at all more effcient) use GEMV once generalised + // to not require preallocation. However, Rust should be pretty efficient + // at not doing preallocations or anything here, as the result of self.opA.apply() + // can be consumed, so maybe GEMV is no use. + //self.opA.preadjoint().apply(self.opA.apply(x) - self.b) + self.opA + .preadjoint() + .apply(self.g.diff_ref().apply(self.opA.apply(x) - &self.b)) + } +} + +/* +impl<'a, F, X, ExpX, Y, ExpY, A, G> LipschitzDifferentiableImpl for DataTerm +where + F: Float, + X: Space + Clone + Norm, + Y: Space + Norm, + ExpX: NormExponent, + ExpY: NormExponent, + A: Clone + BoundedLinear, + G: Mapping + LipschitzDifferentiableImpl, + Self: DifferentiableImpl, +{ + type FloatType = F; + + fn diff_lipschitz_factor(&self, seminorm: ExpX) -> Option { + Some(self.opA.opnorm_bound(seminorm, L2).powi(2)) + } +} +*/