diff -r 9226980e45a7 -r 848ecc05becf src/convex.rs --- a/src/convex.rs Tue Dec 31 08:30:02 2024 -0500 +++ b/src/convex.rs Tue Dec 31 09:02:55 2024 -0500 @@ -2,8 +2,10 @@ Some convex analysis basics */ +use std::marker::PhantomData; use crate::types::*; use crate::mapping::{Mapping, Space}; +use crate::linops::IdOp; use crate::instance::{Instance, InstanceMut, DecompositionMut}; use crate::norms::*; @@ -11,16 +13,15 @@ /// /// TODO: should constrain `Mapping::Codomain` to implement a partial order, /// but this makes everything complicated with little benefit. -pub trait ConvexMapping : Mapping +pub trait ConvexMapping : Mapping {} /// 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 : Mapping { - type DualDomain : Space; - type Conjugate<'a> : ConvexMapping where Self : 'a; +pub trait Conjugable, F : Num = f64> : Mapping { + type Conjugate<'a> : ConvexMapping where Self : 'a; fn conjugate(&self) -> Self::Conjugate<'_>; } @@ -28,10 +29,13 @@ /// Trait for mappings with a Fenchel preconjugate /// /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], -/// but a `Preconjugable` mapping has be convex. -pub trait Preconjugable : ConvexMapping { - type PredualDomain : Space; - type Preconjugate<'a> : Mapping where Self : 'a; +/// but a `Preconjugable` mapping has to be convex. +pub trait Preconjugable : ConvexMapping +where + Domain : Space, + Predual : HasDual +{ + type Preconjugate<'a> : Mapping where Self : 'a; fn preconjugate(&self) -> Self::Preconjugate<'_>; } @@ -65,20 +69,13 @@ pub struct NormConjugate(NormMapping); -impl ConvexMapping for NormMapping +impl ConvexMapping for NormMapping where Domain : Space, E : NormExponent, F : Float, - Self : Mapping {} - - -impl ConvexMapping for NormConjugate -where - Domain : Space, - E : NormExponent, - F : Float, - Self : Mapping {} + Self : Mapping +{} impl Mapping for NormConjugate @@ -98,20 +95,121 @@ } } +impl ConvexMapping for NormConjugate +where + Domain : Space, + E : NormExponent, + F : Float, + Self : Mapping +{} + + +impl Conjugable for NormMapping +where + E : HasDualExponent, + F : Float, + Domain : HasDual + Norm + Space, + >::DualSpace : Norm +{ + type Conjugate<'a> = NormConjugate where Self : 'a; + + fn conjugate(&self) -> Self::Conjugate<'_> { + NormConjugate(self.exponent.dual_exponent().as_mapping()) + } +} -impl Conjugable for NormMapping -where - E : NormExponent + Clone, - F : Float, - Domain : Norm + Space, -{ +/// The zero mapping +pub struct Zero(PhantomData<(Domain, F)>); + +impl Zero { + pub fn new() -> Self { + Zero(PhantomData) + } +} + +impl Mapping for Zero { + type Codomain = F; - type DualDomain = Domain; - type Conjugate<'a> = NormConjugate where Self : 'a; + /// Compute the value of `self` at `x`. + fn apply>(&self, _x : I) -> Self::Codomain { + F::ZERO + } +} + +impl ConvexMapping for Zero { } + +impl, F : Float> Conjugable for Zero { + type Conjugate<'a> = ZeroIndicator where Self : 'a; + + #[inline] fn conjugate(&self) -> Self::Conjugate<'_> { - NormConjugate(self.clone()) + ZeroIndicator::new() } } +impl Preconjugable for Zero +where + Domain : Space, + Predual : HasDual +{ + type Preconjugate<'a> = ZeroIndicator where Self : 'a; + + #[inline] + fn preconjugate(&self) -> Self::Preconjugate<'_> { + ZeroIndicator::new() + } +} + +impl Prox for Zero { + type Prox<'a> = IdOp where Self : 'a; + + #[inline] + fn prox_mapping(&self, _τ : Self::Codomain) -> Self::Prox<'_> { + IdOp::new() + } +} + + +/// The zero indicator +pub struct ZeroIndicator(PhantomData<(Domain, F)>); + +impl ZeroIndicator { + pub fn new() -> Self { + ZeroIndicator(PhantomData) + } +} + +impl, F : Float> Mapping for ZeroIndicator { + type Codomain = F; + + /// Compute the value of `self` at `x`. + fn apply>(&self, x : I) -> Self::Codomain { + x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY }) + } +} + +impl, F : Float> ConvexMapping for ZeroIndicator { } + +impl, F : Float> Conjugable for ZeroIndicator { + type Conjugate<'a> = Zero where Self : 'a; + + #[inline] + fn conjugate(&self) -> Self::Conjugate<'_> { + Zero::new() + } +} + +impl Preconjugable for ZeroIndicator +where + Domain : Normed, + Predual : HasDual +{ + type Preconjugate<'a> = Zero where Self : 'a; + + #[inline] + fn preconjugate(&self) -> Self::Preconjugate<'_> { + Zero::new() + } +}