diff -r 2e4517b55442 -r 9e5b9fc81c52 src/mapping/quadratic.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mapping/quadratic.rs Mon Apr 28 08:26:04 2025 -0500 @@ -0,0 +1,98 @@ +/*! +Quadratic functions of the form $\frac{1}{2}\|Ax-b\|_2^2$ for an operator $A$ +to a [`Euclidean`] space. +*/ + +#![allow(non_snake_case)] + +use super::{DifferentiableImpl, Differential, Lipschitz, Mapping}; +use crate::convex::ConvexMapping; +use crate::euclidean::Euclidean; +use crate::instance::{Instance, Space}; +use crate::linops::{BoundedLinear, Linear, Preadjointable}; +use crate::norms::{Norm, NormExponent, L2}; +use crate::types::Float; +use std::marker::PhantomData; + +/// Functions of the form $\frac{1}{2}\|Ax-b\|_2^2$ for an operator $A$ +/// to a [`Euclidean`] space. +#[derive(Clone, Copy)] +pub struct Quadratic<'a, F: Float, Domain: Space, A: Mapping> { + opA: &'a A, + b: &'a >::Codomain, + _phantoms: PhantomData, +} + +#[allow(non_snake_case)] +impl<'a, F: Float, Domain: Space, A: Mapping> Quadratic<'a, F, Domain, A> { + pub fn new(opA: &'a A, b: &'a A::Codomain) -> Self { + Quadratic { + opA, + b, + _phantoms: PhantomData, + } + } + + pub fn operator(&self) -> &'a A { + self.opA + } + + pub fn data(&self) -> &'a >::Codomain { + self.b + } +} + +//+ AdjointProductBoundedBy, P, FloatType = F>, + +impl<'a, F: Float, X: Space, A: Mapping> Mapping for Quadratic<'a, F, X, A> +where + A::Codomain: Euclidean, +{ + 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.opA.apply(x) - self.b).norm2_squared() / F::TWO + } +} + +impl<'a, F: Float, X: Space, A: Linear> ConvexMapping for Quadratic<'a, F, X, A> where + A::Codomain: Euclidean +{ +} + +impl<'a, F, X, A> DifferentiableImpl for Quadratic<'a, F, X, A> +where + F: Float, + X: Space, + >::Codomain: Euclidean, + A: Linear + Preadjointable, + <>::Codomain as Euclidean>::Output: Instance<>::Codomain>, +{ + 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) + } +} + +impl<'a, 'b, F, X, ExpX, A> Lipschitz for Differential<'b, X, Quadratic<'a, F, X, A>> +where + F: Float, + X: Space + Clone + Norm, + ExpX: NormExponent, + A: Clone + BoundedLinear, +{ + type FloatType = F; + + fn lipschitz_factor(&self, seminorm: ExpX) -> Option { + Some((*self.g).opA.opnorm_bound(seminorm, L2).powi(2)) + } +}