--- a/src/measures/merging.rs Thu Jan 23 23:35:28 2025 +0100 +++ b/src/measures/merging.rs Thu Jan 23 23:34:05 2025 +0100 @@ -19,63 +19,24 @@ /// Spike merging heuristic selection #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] #[allow(dead_code)] -pub enum SpikeMergingMethod<F> { - /// Try to merge spikes within a given radius of each other, averaging the location - HeuristicRadius(F), - /// Try to merge spikes within a given radius of each other, attempting original locations - HeuristicRadiusNoInterp(F), - /// No merging - None, +pub struct SpikeMergingMethod<F> { + // Merging radius + pub(crate) radius : F, + // Enabled + pub(crate) enabled : bool, + // Interpolate merged points + pub(crate) interp : bool, } -// impl<F : Float> SpikeMergingMethod<F> { -// /// This is for [`clap`] to display command line help. -// pub fn value_parser() -> PossibleValuesParser { -// PossibleValuesParser::new([ -// PossibleValue::new("none").help("No merging"), -// PossibleValue::new("<radius>").help("Heuristic merging within indicated radius") -// ]) -// } -// } - -impl<F : ClapFloat> std::fmt::Display for SpikeMergingMethod<F> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - Self::None => write!(f, "none"), - Self::HeuristicRadius(r) => write!(f, "i:{}", r), - Self::HeuristicRadiusNoInterp(r) => write!(f, "n:{}", r), - } - } -} - -impl<F : ClapFloat> std::str::FromStr for SpikeMergingMethod<F> { - type Err = F::Err; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - if s == "none" { - Ok(Self::None) - } else { - let mut subs = s.split(':'); - match subs.next() { - None => Ok(Self::HeuristicRadius(F::from_str(s)?)), - Some(t) if t == "n" => match subs.next() { - None => Err(core::num::dec2flt::pfe_invalid()), - Some(v) => Ok(Self::HeuristicRadiusNoInterp(F::from_str(v)?)) - }, - Some(t) if t == "i" => match subs.next() { - None => Err(core::num::dec2flt::pfe_invalid()), - Some(v) => Ok(Self::HeuristicRadius(F::from_str(v)?)) - }, - Some(v) => Ok(Self::HeuristicRadius(F::from_str(v)?)) - } - } - } -} #[replace_float_literals(F::cast_from(literal))] impl<F : Float> Default for SpikeMergingMethod<F> { fn default() -> Self { - SpikeMergingMethod::HeuristicRadius(0.02) + SpikeMergingMethod{ + radius : 0.01, + enabled : false, + interp : true, + } } } @@ -90,16 +51,16 @@ /// an arbitrary value. This method will return that value for the *last* accepted merge, or /// [`None`] if no merge was accepted. /// - /// This method is stable with respect to spike locations: on merge, the weight of existing - /// spikes is set to zero, and a new one inserted at the end of the spike vector. + /// This method is stable with respect to spike locations: on merge, the weights of existing + /// removed spikes is set to zero, new ones inserted at the end of the spike vector. + /// They merge may also be performed by increasing the weights of the existing spikes, + /// without inserting new spikes. fn merge_spikes<G>(&mut self, method : SpikeMergingMethod<F>, accept : G) -> usize where G : FnMut(&'_ Self) -> bool { - match method { - SpikeMergingMethod::HeuristicRadius(ρ) => - self.do_merge_spikes_radius(ρ, true, accept), - SpikeMergingMethod::HeuristicRadiusNoInterp(ρ) => - self.do_merge_spikes_radius(ρ, false, accept), - SpikeMergingMethod::None => 0, + if method.enabled { + self.do_merge_spikes_radius(method.radius, method.interp, accept) + } else { + 0 } }