Wed, 30 Apr 2025 01:06:25 -0500
More Normed usage
/*! 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::{Normed, 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<Domain>, G: Mapping<A::Codomain, Codomain = F>, > { opA: A, b: <A as Mapping<Domain>>::Codomain, g: G, } #[allow(non_snake_case)] impl<F: Float, Domain: Space, A: Mapping<Domain>, G: Mapping<A::Codomain, Codomain = F>> DataTerm<F, Domain, A, G> { 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) -> &'_ <A as Mapping<Domain>>::Codomain { &self.b } pub fn fidelity(&self) -> &'_ G { &self.g } } //+ AdjointProductBoundedBy<RNDM<F, N>, P, FloatType = F>, impl<F, X, A, G> Mapping<X> for DataTerm<F, X, A, G> where F: Float, X: Space, A: Mapping<X>, G: Mapping<A::Codomain, Codomain = F>, A::Codomain: for<'a> Sub<&'a A::Codomain, Output = A::Codomain>, { type Codomain = F; fn apply<I: Instance<X>>(&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<F, X, A, G> ConvexMapping<X, F> for DataTerm<F, X, A, G> where F: Float, X: Normed<F>, A: Linear<X>, G: ConvexMapping<A::Codomain, F>, A::Codomain: Normed<F> + for<'a> Sub<&'a A::Codomain, Output = A::Codomain>, { } impl<F, X, Y, A, G> DifferentiableImpl<X> for DataTerm<F, X, A, G> where F: Float, X: Space, Y: Space + for<'a> Sub<&'a Y, Output = Y>, //<A as Mapping<X>>::Codomain: Euclidean<F>, A: Linear<X, Codomain = Y> + Preadjointable<X, G::DerivativeDomain>, //<<A as Mapping<X>>::Codomain as Euclidean<F>>::Output: Instance<<A as Mapping<X>>::Codomain>, G: DifferentiableMapping<Y, Codomain = F>, { type Derivative = A::PreadjointCodomain; fn differential_impl<I: Instance<X>>(&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, Y, A, G> LipschitzDifferentiableImpl<X, X::NormExp> for DataTerm<F, X, A, G> where F: Float, X: Normed<F> + Clone, Y: Normed<F>, A: Clone + BoundedLinear<X, X::NormExp, L2, F, Codomain = Y>, G: Mapping<Y, Codomain = F> + LipschitzDifferentiableImpl<Y, Y::NormExp>, Self: DifferentiableImpl<X>, { type FloatType = F; fn diff_lipschitz_factor(&self, seminorm: X::NormExp) -> Option<F> { Some(self.opA.opnorm_bound(seminorm, L2).powi(2)) } }