src/prox_penalty.rs

branch
dev
changeset 61
4f468d35fa29
parent 51
0693cc9ba9f0
child 62
32328a74c790
child 63
7a8a55fd41c0
--- 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>;
+}

mercurial