diff -r 9738b51d90d7 -r 4f468d35fa29 src/prox_penalty.rs --- 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 { +pub struct InsertionConfig { /// Tolerance for point insertion. pub tolerance: Tolerance, @@ -68,9 +70,9 @@ } #[replace_float_literals(F::cast_from(literal))] -impl Default for FBGenericConfig { +impl Default for InsertionConfig { fn default() -> Self { - FBGenericConfig { + InsertionConfig { tolerance: Default::default(), insertion_cutoff_factor: 1.0, refinement: Default::default(), @@ -88,7 +90,7 @@ } } -impl FBGenericConfig { +impl InsertionConfig { /// Check if merging should be attempted this iteration pub fn merge_now(&self, state: &AlgIteratorIteration) -> 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 { - 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 +pub trait ProxPenalty where F: Float + ToNalgebraRealField, - Reg: RegTerm, + Reg: RegTerm, + Domain: Space + Clone, { - type ReturnMapping: RealMapping; + type ReturnMapping: Mapping; + + /// 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( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, τv: &mut PreadjointCodomain, - μ_base: &RNDM, - ν_delta: Option<&RNDM>, + μ_base: &DiscreteMeasure, + ν_delta: Option<&DiscreteMeasure>, τ: F, ε: F, - config: &FBGenericConfig, + config: &InsertionConfig, reg: &Reg, state: &AlgIteratorIteration, - stats: &mut IterInfo, - ) -> (Option, bool) + stats: &mut IterInfo, + ) -> DynResult<(Option, bool)> where I: AlgIterator; @@ -145,15 +157,15 @@ /// is set. fn merge_spikes( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, τv: &mut PreadjointCodomain, - μ_base: &RNDM, - ν_delta: Option<&RNDM>, + μ_base: &DiscreteMeasure, + ν_delta: Option<&DiscreteMeasure>, τ: F, ε: F, - config: &FBGenericConfig, + config: &InsertionConfig, reg: &Reg, - fitness: Option) -> F>, + fitness: Option) -> F>, ) -> usize; /// Merge spikes, if possible. @@ -162,13 +174,13 @@ #[inline] fn merge_spikes_no_fitness( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, τv: &mut PreadjointCodomain, - μ_base: &RNDM, - ν_delta: Option<&RNDM>, + μ_base: &DiscreteMeasure, + ν_delta: Option<&DiscreteMeasure>, τ: F, ε: F, - config: &FBGenericConfig, + config: &InsertionConfig, 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::ZERO)), + into_none(Some(|_: &DiscreteMeasure| 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 { + /// Returns $L$. + fn step_length_bound(&self, f: &Dat) -> DynResult; +} + +/// A variant of [`StepLengthBound`] for step length parameters for [`Pair`]s of variables. +pub trait StepLengthBoundPair { + 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 { + /// Returns $L$. + fn step_length_bound_pd(&self, f: &A) -> DynResult; +}