# HG changeset patch # User Tuomo Valkonen # Date 1785105051 18000 # Node ID 2a122736e91c270eb4786a97fe19c9b88176ff16 # Parent be105c046777f3340bd01b3b8a51c286e7517c3d Add maximum iteration setting for scaling heuristic diff -r be105c046777 -r 2a122736e91c src/fb.rs --- a/src/fb.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/fb.rs Sun Jul 26 17:30:51 2026 -0500 @@ -188,7 +188,7 @@ // Run the algorithm for state in iterator.iter_init(|| full_stats(&μ, ε, stats.clone())) { - let maybe_μ_base = config.merge_now(&state).then(|| μ.clone()); + let maybe_μ_base = config.if_merge_now(&state, |_| μ.clone()); let μ_base_len = μ.len(); // Calculate smooth part of surrogate model. @@ -201,16 +201,18 @@ // Prune and possibly merge spikes if let Some(μ_base) = maybe_μ_base { - stats.merged += prox_penalty.merge_spikes( - &mut μ, - &mut τv, - &μ_base, - τ, - ε, - config, - ®, - Some(|μ̃: &RNDM| f.apply(μ̃)), - ); + config.if_merge_now(&state, |ins| { + stats.merged += prox_penalty.merge_spikes( + &mut μ, + &mut τv, + &μ_base, + τ, + ε, + ins, + ®, + Some(|μ̃: &RNDM| f.apply(μ̃)), + ) + }); } stats.pruned += prune_with_stats(&mut μ); @@ -309,10 +311,12 @@ stats.inserted += μ.len() - μ_base_len; // (Do not) merge spikes. - if config.merge_now(&state) && !warned_merging { - let err = format!("Merging not supported for μFISTA"); - println!("{}", err.red()); - warned_merging = true; + if !warned_merging { + config.if_merge_now(&state, |_| { + let err = format!("Merging not supported for μFISTA"); + println!("{}", err.red()); + warned_merging = true; + }); } // Do extra weight optimisation step heuristic diff -r be105c046777 -r 2a122736e91c src/forward_pdps.rs --- a/src/forward_pdps.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/forward_pdps.rs Sun Jul 26 17:30:51 2026 -0500 @@ -240,8 +240,7 @@ // Merge spikes. // This crucially expects the merge routine to be stable with respect to spike locations, // and not to performing any pruning. That is be to done below simultaneously for γ. - let ins = &config.insertion; - if ins.merge_now(&state) { + config.insertion.if_merge_now(&state, |ins| { stats.merged += prox_penalty.merge_spikes( &mut μ, &mut τv, @@ -252,7 +251,7 @@ ®, Some(|μ̃: &RNDM| f.apply(Pair(μ̃, &z))), ); - } + }); // Prune spikes with zero weight. stats.pruned += prune_with_stats(&mut μ); diff -r be105c046777 -r 2a122736e91c src/lib.rs --- a/src/lib.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/lib.rs Sun Jul 26 17:30:51 2026 -0500 @@ -235,10 +235,14 @@ pub fitness_merging: Option, #[arg(long)] - /// Scaling heuristic factor + /// Scaling heuristic factor. Enables the heuristic if set. pub scaling_heuristic: Option, #[arg(long)] + /// Maximum scaling iteration for scaling heuristic. + pub max_scaling_iter: Option, + + #[arg(long)] /// Extra finite dimensional steps to take pub extra_weight_optimisation_steps: Option, diff -r be105c046777 -r 2a122736e91c src/pdps.rs --- a/src/pdps.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/pdps.rs Sun Jul 26 17:30:51 2026 -0500 @@ -209,10 +209,10 @@ prox_penalty.insert_and_reweigh(&mut μ, &mut τv, τ, ε, config, ®, &state, &mut stats)?; // Prune and possibly merge spikes - if config.merge_now(&state) { + config.if_merge_now(&state, |ins| { stats.merged += - prox_penalty.merge_spikes_no_fitness(&mut μ, &mut τv, &μ_base, τ, ε, config, ®); - } + prox_penalty.merge_spikes_no_fitness(&mut μ, &mut τv, &μ_base, τ, ε, ins, ®); + }); stats.inserted += μ.len() - μ_base.len(); stats.pruned += prune_with_stats(&mut μ); diff -r be105c046777 -r 2a122736e91c src/prox_penalty.rs --- a/src/prox_penalty.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/prox_penalty.rs Sun Jul 26 17:30:51 2026 -0500 @@ -68,6 +68,9 @@ /// Additional weight optimisation steps pub extra_weight_optimisation_steps: usize, + + /// Maximum iteration for scaling hack, zero if no maximum. + pub max_scaling_iter: usize, } #[replace_float_literals(F::cast_from(literal))] @@ -87,19 +90,41 @@ merge_every: 10, merge_tolerance_mult: 2.0, extra_weight_optimisation_steps: 0, + max_scaling_iter: 0, } } } 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 + pub fn if_merge_now( + &self, + state: &AlgIteratorIteration, + mut f: impl FnMut(&Self) -> A, + ) -> Option { + if (self.merging.enabled || self.merging.scaling.is_some()) + && state.iteration() % self.merge_every == 0 + { + if self.max_scaling_iter != 0 && state.iteration() > self.max_scaling_iter { + if !self.merging.enabled { + None + } else { + Some(f(&InsertionConfig { + merging: SpikeMergingMethod { scaling: None, ..self.merging }, + ..*self + })) + } + } else { + Some(f(self)) + } + } else { + None + } } /// Returns the final merging method pub fn final_merging_method(&self) -> SpikeMergingMethod { - SpikeMergingMethod { enabled: self.final_merging, ..self.merging } + SpikeMergingMethod { enabled: self.final_merging, scaling: None, ..self.merging } } } diff -r be105c046777 -r 2a122736e91c src/run.rs --- a/src/run.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/run.rs Sun Jul 26 17:30:51 2026 -0500 @@ -120,6 +120,7 @@ .map_or(g.bootstrap_insertions, |n| Some((n[0], n[1]))), merge_every: cli.merge_every.unwrap_or(g.merge_every), merging: override_merging(g.merging), + max_scaling_iter: cli.max_scaling_iter.unwrap_or(g.max_scaling_iter), final_merging: cli.final_merging.unwrap_or(g.final_merging), fitness_merging: cli.fitness_merging.unwrap_or(g.fitness_merging), inner: override_inner(g.inner), diff -r be105c046777 -r 2a122736e91c src/sliding_fb.rs --- a/src/sliding_fb.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/sliding_fb.rs Sun Jul 26 17:30:51 2026 -0500 @@ -1092,14 +1092,14 @@ // Merge spikes. // This crucially expects the merge routine to be stable with respect to spike locations, // and not to performing any pruning. That is be to done below simultaneously for γ. - if config.insertion.merge_now(&state) { + config.insertion.if_merge_now(&state, |ins| { let m = prox_penalty.merge_spikes( &mut μ, &mut τv̆, &μ̆, τ, ε, - &config.insertion, + ins, ®, Some(|μ̃: &RNDM| f.apply(μ̃)), ); @@ -1107,7 +1107,7 @@ stats.merged += m; //v = f.differential(&μ); //} - } + }); γ.prune_compat(&mut μ, &mut stats); diff -r be105c046777 -r 2a122736e91c src/sliding_pdps.rs --- a/src/sliding_pdps.rs Wed Jul 22 16:48:22 2026 -0500 +++ b/src/sliding_pdps.rs Sun Jul 26 17:30:51 2026 -0500 @@ -303,21 +303,21 @@ // Merge spikes. // This crucially expects the merge routine to be stable with respect to spike locations, // and not to performing any pruning. That is be to done below simultaneously for γ. - if config.insertion.merge_now(&state) { + config.insertion.if_merge_now(&state, |ins| { let m = prox_penalty.merge_spikes( &mut μ, &mut τv̆, &μ̆, τ, ε, - &config.insertion, + ins, ®, Some(|μ̃: &RNDM| f.apply(Pair(μ̃, &z))), ); if m > 0 { stats.merged += m; } - } + }); γ.prune_compat(&mut μ, &mut stats);