--- a/src/convex.rs Sat Dec 14 09:31:27 2024 -0500 +++ b/src/convex.rs Tue Dec 31 08:30:02 2024 -0500 @@ -2,20 +2,24 @@ Some convex analysis basics */ -use crate::mapping::{Apply, Mapping}; +use crate::types::*; +use crate::mapping::{Mapping, Space}; +use crate::instance::{Instance, InstanceMut, DecompositionMut}; +use crate::norms::*; /// Trait for convex mappings. Has no features, just serves as a constraint /// /// TODO: should constrain `Mapping::Codomain` to implement a partial order, /// but this makes everything complicated with little benefit. -pub trait ConvexMapping<Domain> : Mapping<Domain> {} +pub trait ConvexMapping<Domain : Space> : Mapping<Domain> +{} /// Trait for mappings with a Fenchel conjugate /// /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need /// not be convex. -pub trait Conjugable<Domain> : Mapping<Domain> { - type DualDomain; +pub trait Conjugable<Domain : Space> : Mapping<Domain> { + type DualDomain : Space; type Conjugate<'a> : ConvexMapping<Self::DualDomain> where Self : 'a; fn conjugate(&self) -> Self::Conjugate<'_>; @@ -25,8 +29,8 @@ /// /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], /// but a `Preconjugable` mapping has be convex. -pub trait Preconjugable<Domain> : ConvexMapping<Domain> { - type PredualDomain; +pub trait Preconjugable<Domain : Space> : ConvexMapping<Domain> { + type PredualDomain : Space; type Preconjugate<'a> : Mapping<Self::PredualDomain> where Self : 'a; fn preconjugate(&self) -> Self::Preconjugate<'_>; @@ -36,15 +40,78 @@ /// /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need /// not be convex. -pub trait HasProx<Domain> : Mapping<Domain> { +pub trait Prox<Domain : Space> : Mapping<Domain> { type Prox<'a> : Mapping<Domain, Codomain=Domain> where Self : 'a; /// Returns a proximal mapping with weight τ fn prox_mapping(&self, τ : Self::Codomain) -> Self::Prox<'_>; /// Calculate the proximal mapping with weight τ - fn prox(&self, z : Domain, τ : Self::Codomain) -> Domain { + fn prox<I : Instance<Domain>>(&self, τ : Self::Codomain, z : I) -> Domain { self.prox_mapping(τ).apply(z) } + + /// Calculate the proximal mapping with weight τ in-place + fn prox_mut<'b>(&self, τ : Self::Codomain, y : &'b mut Domain) + where + &'b mut Domain : InstanceMut<Domain>, + Domain:: Decomp : DecompositionMut<Domain>, + for<'a> &'a Domain : Instance<Domain>, + { + *y = self.prox(τ, &*y); + } } + +pub struct NormConjugate<F : Float, E : NormExponent>(NormMapping<F, E>); + +impl<Domain, E, F> ConvexMapping<Domain> for NormMapping<F, E> +where + Domain : Space, + E : NormExponent, + F : Float, + Self : Mapping<Domain, Codomain=F> {} + + +impl<Domain, E, F> ConvexMapping<Domain> for NormConjugate<F, E> +where + Domain : Space, + E : NormExponent, + F : Float, + Self : Mapping<Domain, Codomain=F> {} + + +impl<F, E, Domain> Mapping<Domain> for NormConjugate<F, E> +where + Domain : Space + Norm<F, E>, + F : Float, + E : NormExponent, +{ + type Codomain = F; + + fn apply<I : Instance<Domain>>(&self, d : I) -> F { + if d.eval(|x| x.norm(self.0.exponent)) <= F::ONE { + F::ZERO + } else { + F::INFINITY + } + } +} + + + +impl<E, F, Domain> Conjugable<Domain> for NormMapping<F, E> +where + E : NormExponent + Clone, + F : Float, + Domain : Norm<F, E> + Space, +{ + + type DualDomain = Domain; + type Conjugate<'a> = NormConjugate<F, E> where Self : 'a; + + fn conjugate(&self) -> Self::Conjugate<'_> { + NormConjugate(self.clone()) + } +} +