--- a/src/prox_penalty.rs Sun Apr 27 15:03:51 2025 -0500 +++ b/src/prox_penalty.rs Thu Feb 26 11:38:43 2026 -0500 @@ -7,13 +7,15 @@ use serde::{Deserialize, Serialize}; use crate::measures::merging::SpikeMergingMethod; -use crate::measures::RNDM; +use crate::measures::DiscreteMeasure; use crate::regularisation::RegTerm; use crate::subproblem::InnerSettings; use crate::tolerance::Tolerance; use crate::types::{IterInfo, RefinementSettings}; +use alg_tools::error::DynResult; +use alg_tools::instance::Space; use alg_tools::iterate::{AlgIterator, AlgIteratorIteration}; -use alg_tools::mapping::RealMapping; +use alg_tools::mapping::Mapping; use alg_tools::nalgebra_support::ToNalgebraRealField; pub mod radon_squared; @@ -23,7 +25,7 @@ /// Settings for the solution of the stepwise optimality condition. #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] #[serde(default)] -pub struct FBGenericConfig<F: Float> { +pub struct InsertionConfig<F: Float> { /// Tolerance for point insertion. pub tolerance: Tolerance<F>, @@ -68,9 +70,9 @@ } #[replace_float_literals(F::cast_from(literal))] -impl<F: Float> Default for FBGenericConfig<F> { +impl<F: Float> Default for InsertionConfig<F> { fn default() -> Self { - FBGenericConfig { + InsertionConfig { tolerance: Default::default(), insertion_cutoff_factor: 1.0, refinement: Default::default(), @@ -88,7 +90,7 @@ } } -impl<F: Float> FBGenericConfig<F> { +impl<F: Float> InsertionConfig<F> { /// Check if merging should be attempted this iteration pub fn merge_now<I: AlgIterator>(&self, state: &AlgIteratorIteration<I>) -> bool { self.merging.enabled && state.iteration() % self.merge_every == 0 @@ -96,20 +98,30 @@ /// Returns the final merging method pub fn final_merging_method(&self) -> SpikeMergingMethod<F> { - SpikeMergingMethod { - enabled: self.final_merging, - ..self.merging - } + SpikeMergingMethod { enabled: self.final_merging, ..self.merging } } } +/// Available proximal terms +#[derive(Copy, Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub enum ProxTerm { + /// Partial-to-wave operator 𝒟. + Wave, + /// Radon-norm squared + RadonSquared, +} + /// Trait for proximal penalties -pub trait ProxPenalty<F, PreadjointCodomain, Reg, const N: usize> +pub trait ProxPenalty<Domain, PreadjointCodomain, Reg, F = f64> where F: Float + ToNalgebraRealField, - Reg: RegTerm<F, N>, + Reg: RegTerm<Domain, F>, + Domain: Space + Clone, { - type ReturnMapping: RealMapping<F, N>; + type ReturnMapping: Mapping<Domain, Codomain = F>; + + /// Returns the type of this proximality penalty + fn prox_type() -> ProxTerm; /// Insert new spikes into `μ` to approximately satisfy optimality conditions /// with the forward step term fixed to `τv`. @@ -120,21 +132,21 @@ /// `μ_base + ν_delta` is the base point, where `μ` and `μ_base` are assumed to have the same /// spike locations, while `ν_delta` may have different locations. /// - /// `τv` is mutable to allow [`alg_tools::bisection_tree::BTFN`] refinement. - /// Actual values of `τv` are not supposed to be mutated. + /// `τv` is mutable to allow [`alg_tools::bounds::MinMaxMapping`] optimisation to + /// refine data. Actual values of `τv` are not supposed to be mutated. fn insert_and_reweigh<I>( &self, - μ: &mut RNDM<F, N>, + μ: &mut DiscreteMeasure<Domain, F>, τv: &mut PreadjointCodomain, - μ_base: &RNDM<F, N>, - ν_delta: Option<&RNDM<F, N>>, + μ_base: &DiscreteMeasure<Domain, F>, + ν_delta: Option<&DiscreteMeasure<Domain, F>>, τ: F, ε: F, - config: &FBGenericConfig<F>, + config: &InsertionConfig<F>, reg: &Reg, state: &AlgIteratorIteration<I>, - stats: &mut IterInfo<F, N>, - ) -> (Option<Self::ReturnMapping>, bool) + stats: &mut IterInfo<F>, + ) -> DynResult<(Option<Self::ReturnMapping>, bool)> where I: AlgIterator; @@ -145,15 +157,15 @@ /// is set. fn merge_spikes( &self, - μ: &mut RNDM<F, N>, + μ: &mut DiscreteMeasure<Domain, F>, τv: &mut PreadjointCodomain, - μ_base: &RNDM<F, N>, - ν_delta: Option<&RNDM<F, N>>, + μ_base: &DiscreteMeasure<Domain, F>, + ν_delta: Option<&DiscreteMeasure<Domain, F>>, τ: F, ε: F, - config: &FBGenericConfig<F>, + config: &InsertionConfig<F>, reg: &Reg, - fitness: Option<impl Fn(&RNDM<F, N>) -> F>, + fitness: Option<impl Fn(&DiscreteMeasure<Domain, F>) -> F>, ) -> usize; /// Merge spikes, if possible. @@ -162,13 +174,13 @@ #[inline] fn merge_spikes_no_fitness( &self, - μ: &mut RNDM<F, N>, + μ: &mut DiscreteMeasure<Domain, F>, τv: &mut PreadjointCodomain, - μ_base: &RNDM<F, N>, - ν_delta: Option<&RNDM<F, N>>, + μ_base: &DiscreteMeasure<Domain, F>, + ν_delta: Option<&DiscreteMeasure<Domain, F>>, τ: F, ε: F, - config: &FBGenericConfig<F>, + config: &InsertionConfig<F>, reg: &Reg, ) -> usize { /// This is a hack to create a `None` of same type as a `Some` @@ -186,7 +198,31 @@ ε, config, reg, - into_none(Some(|_: &RNDM<F, N>| F::ZERO)), + into_none(Some(|_: &DiscreteMeasure<Domain, F>| F::ZERO)), ) } } + +/// Trait to calculate step length bound by `Dat` when the proximal penalty is `Self`, +/// which is typically also a [`ProxPenalty`]. If it is given by a (squared) norm $\|.\|_*$, and +/// and `Dat` respresents the function $f$, then this trait should calculate `L` such that +/// $\|f'(x)-f'(y)\| ≤ L\|x-y\|_*, where the step length is supposed to satisfy $τ L ≤ 1$. +pub trait StepLengthBound<F: Float, Dat> { + /// Returns $L$. + fn step_length_bound(&self, f: &Dat) -> DynResult<F>; +} + +/// A variant of [`StepLengthBound`] for step length parameters for [`Pair`]s of variables. +pub trait StepLengthBoundPair<F: Float, Dat> { + fn step_length_bound_pair(&self, f: &Dat) -> DynResult<(F, F)>; +} + +/// Trait to calculate step length bound by the operator `A` when the proximal penalty is `Self`, +/// which is typically also a [`ProxPenalty`]. If it is given by a (squared) norm $\|.\|_*$, +/// then this trait should calculate `L` such that +/// $\|Ax\| ≤ L\|x\|_*, where the primal-dual step lengths are supposed to satisfy $τσ L^2 ≤ 1$. +/// The domain needs to be specified here, because A can operate on various domains. +pub trait StepLengthBoundPD<F: Float, A, Domain> { + /// Returns $L$. + fn step_length_bound_pd(&self, f: &A) -> DynResult<F>; +}