--- a/src/fb.rs Fri Aug 14 10:38:27 2026 -0500 +++ b/src/fb.rs Fri Oct 02 12:03:25 2026 -0500 @@ -79,17 +79,19 @@ use crate::domain::{AdmissibleDomain, FullSpace}; use crate::measures::merging::SpikeMerging; -use crate::measures::DiscreteMeasure; +use crate::measures::{DiscreteMeasure, Radon}; use crate::plot::Plotter; pub use crate::prox_penalty::{InsertionConfig, ProxPenalty, StepLengthBound}; use crate::regularisation::RegTerm; use crate::types::*; +use alg_tools::bounds::MinMaxMapping; use alg_tools::error::DynResult; use alg_tools::instance::Instance; use alg_tools::iterate::AlgIteratorFactory; use alg_tools::linops::Space; use alg_tools::mapping::DifferentiableMapping; use alg_tools::nalgebra_support::ToNalgebraRealField; +use alg_tools::norms::Norm; use colored::Colorize; use measures::DeltaMeasure; use numeric_literals::replace_float_literals; @@ -168,9 +170,9 @@ U: Space + Clone, F: Float + ToNalgebraRealField, I: AlgIteratorFactory<IterInfo<F>>, - DiscreteMeasure<U, F>: SpikeMerging<F>, + DiscreteMeasure<U, F>: SpikeMerging<F> + Norm<Radon, F>, Dat: DifferentiableMapping<DiscreteMeasure<U, F>, Codomain = F>, - Dat::DerivativeDomain: ClosedMul<F>, + Dat::DerivativeDomain: ClosedMul<F> + MinMaxMapping<U, F>, Reg: RegTerm<U, F>, P: ProxPenalty<U, Dat::DerivativeDomain, Reg, F> + StepLengthBound<F, Dat>, Plot: Plotter<P::ReturnMapping, Dat::DerivativeDomain, DiscreteMeasure<U, F>>, @@ -187,23 +189,26 @@ let mut μ = μ0.unwrap_or_else(|| DiscreteMeasure::new()); // Statistics - let full_stats = |μ: &DiscreteMeasure<U, F>, ε, stats| IterInfo { - value: f.apply(μ) + reg.apply(μ), - n_spikes: μ.len(), - ε, - //postprocessing: config.postprocessing.then(|| μ.clone()), - ..stats - }; + let full_stats = + |μ: &DiscreteMeasure<U, F>, τv: &mut Dat::DerivativeDomain, ε, stats| IterInfo { + value: f.apply(μ) + reg.apply(μ), + n_spikes: μ.len(), + μ_norm: μ.norm(Radon), + ε, + discrepancy: Some(reg.discrepancy(τv, τ, ε, μ, config)), + //postprocessing: config.postprocessing.then(|| μ.clone()), + ..stats + }; let mut stats = IterInfo::new(); + // Calculate smooth part of surrogate model. + let mut τv = f.differential(&μ) * τ; + // Run the algorithm - for state in iterator.iter_init(|| full_stats(&μ, ε, stats.clone())) { + for state in iterator.iter_init(|| full_stats(&μ, &mut τv, ε, stats.clone())) { let maybe_μ_base = config.if_merge_now_check(&state, || μ.clone()); let μ_base_len = μ.len(); - // Calculate smooth part of surrogate model. - let mut τv = f.differential(&μ) * τ; - // Do spike insertiona nd finite-dimensional weight optimisation prox_penalty.insert_and_reweigh(&mut μ, &mut τv, τ, ε, config, ®, &state, &mut stats)?; @@ -256,10 +261,18 @@ let iter = state.iteration(); stats.this_iters += 1; + // Calculate smooth part of surrogate model. + τv = f.differential(&μ) * τ; + // Give statistics if needed state.if_verbose(|| { plotter.plot_spikes(iter, None, Some(&τv), &μ); - full_stats(&μ, ε, std::mem::replace(&mut stats, IterInfo::new())) + full_stats( + &μ, + &mut τv, + ε, + std::mem::replace(&mut stats, IterInfo::new()), + ) }); // Update main tolerance for next iteration @@ -284,9 +297,9 @@ U: Space + Clone, F: Float + ToNalgebraRealField, I: AlgIteratorFactory<IterInfo<F>>, - DiscreteMeasure<U, F>: SpikeMerging<F>, + DiscreteMeasure<U, F>: SpikeMerging<F> + Norm<Radon, F>, Dat: DifferentiableMapping<DiscreteMeasure<U, F>, Codomain = F>, - Dat::DerivativeDomain: ClosedMul<F>, + Dat::DerivativeDomain: ClosedMul<F> + MinMaxMapping<U, F>, Reg: RegTerm<U, F>, P: ProxPenalty<U, Dat::DerivativeDomain, Reg, F> + StepLengthBound<F, Dat>, Plot: Plotter<P::ReturnMapping, Dat::DerivativeDomain, DiscreteMeasure<U, F>>, @@ -330,7 +343,7 @@ I: AlgIteratorFactory<IterInfo<F>>, DiscreteMeasure<U, F>: SpikeMerging<F>, Dat: DifferentiableMapping<DiscreteMeasure<U, F>, Codomain = F>, - Dat::DerivativeDomain: ClosedMul<F>, + Dat::DerivativeDomain: ClosedMul<F> + MinMaxMapping<U, F>, Reg: RegTerm<U, F>, P: ProxPenalty<U, Dat::DerivativeDomain, Reg, F> + StepLengthBound<F, Dat>, Plot: Plotter<P::ReturnMapping, Dat::DerivativeDomain, DiscreteMeasure<U, F>>, @@ -350,17 +363,21 @@ let mut warned_merging = false; // Statistics - let full_stats = |ν: &DiscreteMeasure<U, F>, ε, stats| IterInfo { + let full_stats = |ν: &DiscreteMeasure<U, F>, + maybe_τv: Option<&mut Dat::DerivativeDomain>, + ε, + stats| IterInfo { value: f.apply(ν) + reg.apply(ν), n_spikes: ν.len(), ε, + discrepancy: maybe_τv.map(|τv| reg.discrepancy(τv, τ, ε, ν, config)), // postprocessing: config.postprocessing.then(|| ν.clone()), ..stats }; let mut stats = IterInfo::new(); // Run the algorithm - for state in iterator.iter_init(|| full_stats(&μ, ε, stats.clone())) { + for state in iterator.iter_init(|| full_stats(&μ, None, ε, stats.clone())) { let μ_base_len = μ.len(); // Calculate smooth part of surrogate model. let mut τv = f.differential(&μ) * τ; @@ -410,7 +427,12 @@ // Give statistics if needed state.if_verbose(|| { plotter.plot_spikes(iter, None, Some(&τv), &μ_prev); - full_stats(&μ_prev, ε, std::mem::replace(&mut stats, IterInfo::new())) + full_stats( + &μ_prev, + Some(&mut τv), + ε, + std::mem::replace(&mut stats, IterInfo::new()), + ) }); // Update main tolerance for next iteration