diff -r 759634edb536 -r 8f1e57821d76 src/frank_wolfe.rs --- a/src/frank_wolfe.rs Tue Aug 04 20:11:10 2026 -0500 +++ b/src/frank_wolfe.rs Thu Aug 06 11:14:15 2026 -0500 @@ -20,7 +20,7 @@ use crate::dataterm::QuadraticDataTerm; use crate::forward_model::ForwardModel; use crate::measures::merging::{SpikeMerging, SpikeMergingMethod}; -use crate::measures::{DeltaMeasure, DiscreteMeasure, Radon, RNDM}; +use crate::measures::{DeltaMeasure, DiscreteMeasure, Radon}; use crate::plot::Plotter; use crate::regularisation::{NonnegRadonRegTerm, RadonRegTerm, RegTerm}; #[allow(unused_imports)] // Used in documentation @@ -29,18 +29,15 @@ }; use crate::tolerance::Tolerance; use crate::types::*; -use alg_tools::bisection_tree::P2Minimise; use alg_tools::bounds::MinMaxMapping; use alg_tools::error::DynResult; use alg_tools::euclidean::Euclidean; use alg_tools::instance::Instance; use alg_tools::iterate::{AlgIteratorFactory, AlgIteratorOptions, ValueIteratorFactory}; -use alg_tools::linops::Mapping; -use alg_tools::loc::Loc; +use alg_tools::linops::{Mapping, Space}; use alg_tools::nalgebra_support::ToNalgebraRealField; use alg_tools::norms::Norm; use alg_tools::norms::L2; -use alg_tools::sets::Cube; /// Settings for [`pointsource_fw_reg`]. #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] @@ -106,9 +103,9 @@ /// Trait for finite dimensional weight optimisation. pub trait WeightOptim< F: Float + ToNalgebraRealField, - A: ForwardModel, F>, + U: Space + Clone + PartialEq, + A: ForwardModel, F>, I: AlgIteratorFactory, - const N: usize, > { /// Return a pre-initialisation struct for [`Self::optimise_weights`]. @@ -135,7 +132,7 @@ /// Returns the number of iterations taken by the method configured in `inner`. fn optimise_weights<'a>( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, opA: &'a A, b: &A::Observable, findim_data: &FindimData, @@ -147,10 +144,10 @@ /// Trait for regularisation terms supported by [`pointsource_fw_reg`]. pub trait RegTermFW< F: Float + ToNalgebraRealField, - A: ForwardModel, F>, + U: Space + Clone + PartialEq, + A: ForwardModel, F>, I: AlgIteratorFactory, - const N: usize, ->: RegTerm, F> + WeightOptim + Mapping, Codomain = F> +>: RegTerm + WeightOptim + Mapping, Codomain = F> { /// With $g = A\_\*(Aμ-b)$, returns $(x, g(x))$ for $x$ a new point to be inserted /// into $μ$, as determined by the regulariser. @@ -162,26 +159,26 @@ g: &mut A::PreadjointCodomain, refinement_tolerance: F, max_steps: usize, - ) -> (Loc, F); + ) -> (U, F); /// Insert point `ξ` into `μ` for the relaxed algorithm from Bredies–Pikkarainen. fn relaxed_insert<'a>( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, g: &A::PreadjointCodomain, opA: &'a A, - ξ: Loc, + ξ: U, v_ξ: F, findim_data: &FindimData, ); } #[replace_float_literals(F::cast_from(literal))] -impl WeightOptim - for RadonRegTerm +impl WeightOptim for RadonRegTerm where + U: Space + Clone + PartialEq, I: AlgIteratorFactory, - A: FindimQuadraticModel, F>, + A: FindimQuadraticModel, { fn prepare_optimise_weights(&self, opA: &A, b: &A::Observable) -> DynResult> { Ok(FindimData { @@ -192,7 +189,7 @@ fn optimise_weights<'a>( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, opA: &'a A, b: &A::Observable, findim_data: &FindimData, @@ -221,23 +218,24 @@ } #[replace_float_literals(F::cast_from(literal))] -impl RegTermFW for RadonRegTerm +impl RegTermFW for RadonRegTerm where - Cube: P2Minimise, F>, + U: Space + Clone + PartialEq, + RadonRegTerm: RegTerm, I: AlgIteratorFactory, - A: FindimQuadraticModel, F>, - A::PreadjointCodomain: MinMaxMapping, F>, + A: FindimQuadraticModel, + A::PreadjointCodomain: MinMaxMapping, for<'a> &'a A::PreadjointCodomain: Instance, // FIXME: the following *should not* be needed, they are already implied - RNDM: Mapping, - DeltaMeasure, F>: Mapping, + DiscreteMeasure: Mapping, + DeltaMeasure: Copy + Mapping, { fn find_insertion( &self, g: &mut A::PreadjointCodomain, refinement_tolerance: F, max_steps: usize, - ) -> (Loc, F) { + ) -> (U, F) { let (ξmax, v_ξmax) = g.maximise(refinement_tolerance, max_steps); let (ξmin, v_ξmin) = g.minimise(refinement_tolerance, max_steps); if v_ξmin < 0.0 && -v_ξmin > v_ξmax { @@ -249,10 +247,10 @@ fn relaxed_insert<'a>( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, g: &A::PreadjointCodomain, opA: &'a A, - ξ: Loc, + ξ: U, v_ξ: F, findim_data: &FindimData, ) { @@ -285,11 +283,11 @@ } #[replace_float_literals(F::cast_from(literal))] -impl WeightOptim - for NonnegRadonRegTerm +impl WeightOptim for NonnegRadonRegTerm where + U: Space + Clone + PartialEq, I: AlgIteratorFactory, - A: FindimQuadraticModel, F>, + A: FindimQuadraticModel, { fn prepare_optimise_weights(&self, opA: &A, b: &A::Observable) -> DynResult> { Ok(FindimData { @@ -300,7 +298,7 @@ fn optimise_weights<'a>( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, opA: &'a A, b: &A::Observable, findim_data: &FindimData, @@ -329,33 +327,33 @@ } #[replace_float_literals(F::cast_from(literal))] -impl RegTermFW - for NonnegRadonRegTerm +impl RegTermFW for NonnegRadonRegTerm where - Cube: P2Minimise, F>, + U: Space + Clone + PartialEq, + NonnegRadonRegTerm: RegTerm, I: AlgIteratorFactory, - A: FindimQuadraticModel, F>, - A::PreadjointCodomain: MinMaxMapping, F>, + A: FindimQuadraticModel, + A::PreadjointCodomain: MinMaxMapping, for<'a> &'a A::PreadjointCodomain: Instance, // FIXME: the following *should not* be needed, they are already implied - RNDM: Mapping, - DeltaMeasure, F>: Mapping, + DiscreteMeasure: Mapping, + DeltaMeasure: Mapping, { fn find_insertion( &self, g: &mut A::PreadjointCodomain, refinement_tolerance: F, max_steps: usize, - ) -> (Loc, F) { + ) -> (U, F) { g.maximise(refinement_tolerance, max_steps) } fn relaxed_insert<'a>( &self, - μ: &mut RNDM, + μ: &mut DiscreteMeasure, g: &A::PreadjointCodomain, opA: &'a A, - ξ: Loc, + ξ: U, v_ξ: F, findim_data: &FindimData, ) { @@ -401,25 +399,25 @@ /// `iterator` is used to iterate the steps of the method, and `plotter` may be used to /// save intermediate iteration states as images. #[replace_float_literals(F::cast_from(literal))] -pub fn pointsource_fw_reg<'a, F, I, A, Reg, Plot, const N: usize>( - f: &'a QuadraticDataTerm, A>, +pub fn pointsource_fw_reg<'a, F, U, I, A, Reg, Plot>( + f: &'a QuadraticDataTerm, A>, reg: &Reg, - //domain : Cube, config: &FWConfig, iterator: I, mut plotter: Plot, - μ0: Option>, -) -> DynResult> + μ0: Option>, +) -> DynResult> where F: Float + ToNalgebraRealField, + U: Space + Clone + PartialEq, I: AlgIteratorFactory>, - A: ForwardModel, F>, - A::PreadjointCodomain: MinMaxMapping, F>, + A: ForwardModel, F>, + A::PreadjointCodomain: MinMaxMapping, &'a A::PreadjointCodomain: Instance, - Cube: P2Minimise, F>, - RNDM: SpikeMerging, - Reg: RegTermFW, N>, - Plot: Plotter>, + //Cube: P2Minimise, + DiscreteMeasure: SpikeMerging, + Reg: RegTermFW>, + Plot: Plotter>, { let opA = f.operator(); let b = f.data(); @@ -438,7 +436,7 @@ let mut residual = f.residual(&μ); // Statistics - let full_stats = |residual: &A::Observable, ν: &RNDM, ε, stats| IterInfo { + let full_stats = |residual: &A::Observable, ν: &DiscreteMeasure, ε, stats| IterInfo { value: residual.norm2_squared_div2() + reg.apply(ν), n_spikes: ν.len(), ε,