Tue, 29 Apr 2025 07:55:18 -0500
sketch
/*! 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<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: Space, A: Linear<X>, G: ConvexMapping<A::Codomain, F>, A::Codomain: 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, ExpX, Y, ExpY, A, G> LipschitzDifferentiableImpl<X, ExpX> for DataTerm<F, X, A, G> where F: Float, X: Space + Clone + Norm<F, ExpX>, Y: Space + Norm<F, ExpY>, ExpX: NormExponent, ExpY: NormExponent, A: Clone + BoundedLinear<X, ExpX, L2, F, Codomain = Y>, G: Mapping<Y, Codomain = F> + LipschitzDifferentiableImpl<Y, ExpY>, Self: DifferentiableImpl<X>, { type FloatType = F; fn diff_lipschitz_factor(&self, seminorm: ExpX) -> Option<F> { Some(self.opA.opnorm_bound(seminorm, L2).powi(2)) } } */