src/convex.rs

Tue, 31 Dec 2024 08:30:02 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Tue, 31 Dec 2024 08:30:02 -0500
branch
dev
changeset 59
9226980e45a7
parent 58
1a38447a89fa
child 60
848ecc05becf
permissions
-rw-r--r--

Significantly simplify Mapping / Apply through Instance

/*!
Some convex analysis basics
*/

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 : 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 : Space> : Mapping<Domain> {
    type DualDomain : Space;
    type Conjugate<'a> : ConvexMapping<Self::DualDomain> where Self : 'a;

    fn conjugate(&self) -> Self::Conjugate<'_>;
}

/// 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<Domain : Space> : ConvexMapping<Domain> {
    type PredualDomain : Space;
    type Preconjugate<'a> : Mapping<Self::PredualDomain> where Self : 'a;

    fn preconjugate(&self) -> Self::Preconjugate<'_>;
}

/// Trait for mappings with a proximap map
///
/// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need
/// not be convex.
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<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())
    }
}

mercurial