src/measures/merging.rs

branch
dev
changeset 39
6316d68b58af
parent 34
efa60bc4f743
child 51
0693cc9ba9f0
equal deleted inserted replaced
37:c5d8bd1a7728 39:6316d68b58af
17 use super::discrete::*; 17 use super::discrete::*;
18 18
19 /// Spike merging heuristic selection 19 /// Spike merging heuristic selection
20 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] 20 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)]
21 #[allow(dead_code)] 21 #[allow(dead_code)]
22 pub enum SpikeMergingMethod<F> { 22 pub struct SpikeMergingMethod<F> {
23 /// Try to merge spikes within a given radius of each other, averaging the location 23 // Merging radius
24 HeuristicRadius(F), 24 pub(crate) radius : F,
25 /// Try to merge spikes within a given radius of each other, attempting original locations 25 // Enabled
26 HeuristicRadiusNoInterp(F), 26 pub(crate) enabled : bool,
27 /// No merging 27 // Interpolate merged points
28 None, 28 pub(crate) interp : bool,
29 } 29 }
30 30
31 // impl<F : Float> SpikeMergingMethod<F> {
32 // /// This is for [`clap`] to display command line help.
33 // pub fn value_parser() -> PossibleValuesParser {
34 // PossibleValuesParser::new([
35 // PossibleValue::new("none").help("No merging"),
36 // PossibleValue::new("<radius>").help("Heuristic merging within indicated radius")
37 // ])
38 // }
39 // }
40
41 impl<F : ClapFloat> std::fmt::Display for SpikeMergingMethod<F> {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
43 match self {
44 Self::None => write!(f, "none"),
45 Self::HeuristicRadius(r) => write!(f, "i:{}", r),
46 Self::HeuristicRadiusNoInterp(r) => write!(f, "n:{}", r),
47 }
48 }
49 }
50
51 impl<F : ClapFloat> std::str::FromStr for SpikeMergingMethod<F> {
52 type Err = F::Err;
53
54 fn from_str(s: &str) -> Result<Self, Self::Err> {
55 if s == "none" {
56 Ok(Self::None)
57 } else {
58 let mut subs = s.split(':');
59 match subs.next() {
60 None => Ok(Self::HeuristicRadius(F::from_str(s)?)),
61 Some(t) if t == "n" => match subs.next() {
62 None => Err(core::num::dec2flt::pfe_invalid()),
63 Some(v) => Ok(Self::HeuristicRadiusNoInterp(F::from_str(v)?))
64 },
65 Some(t) if t == "i" => match subs.next() {
66 None => Err(core::num::dec2flt::pfe_invalid()),
67 Some(v) => Ok(Self::HeuristicRadius(F::from_str(v)?))
68 },
69 Some(v) => Ok(Self::HeuristicRadius(F::from_str(v)?))
70 }
71 }
72 }
73 }
74 31
75 #[replace_float_literals(F::cast_from(literal))] 32 #[replace_float_literals(F::cast_from(literal))]
76 impl<F : Float> Default for SpikeMergingMethod<F> { 33 impl<F : Float> Default for SpikeMergingMethod<F> {
77 fn default() -> Self { 34 fn default() -> Self {
78 SpikeMergingMethod::HeuristicRadius(0.02) 35 SpikeMergingMethod{
36 radius : 0.01,
37 enabled : false,
38 interp : true,
39 }
79 } 40 }
80 } 41 }
81 42
82 /// Trait for dimension-dependent implementation of heuristic peak merging strategies. 43 /// Trait for dimension-dependent implementation of heuristic peak merging strategies.
83 pub trait SpikeMerging<F> { 44 pub trait SpikeMerging<F> {
88 /// new candidate measure (it will generally be internally mutated `self`, although this is 49 /// new candidate measure (it will generally be internally mutated `self`, although this is
89 /// not guaranteed), and return [`None`] if the merge is accepted, and otherwise a [`Some`] of 50 /// not guaranteed), and return [`None`] if the merge is accepted, and otherwise a [`Some`] of
90 /// an arbitrary value. This method will return that value for the *last* accepted merge, or 51 /// an arbitrary value. This method will return that value for the *last* accepted merge, or
91 /// [`None`] if no merge was accepted. 52 /// [`None`] if no merge was accepted.
92 /// 53 ///
93 /// This method is stable with respect to spike locations: on merge, the weight of existing 54 /// This method is stable with respect to spike locations: on merge, the weights of existing
94 /// spikes is set to zero, and a new one inserted at the end of the spike vector. 55 /// removed spikes is set to zero, new ones inserted at the end of the spike vector.
56 /// They merge may also be performed by increasing the weights of the existing spikes,
57 /// without inserting new spikes.
95 fn merge_spikes<G>(&mut self, method : SpikeMergingMethod<F>, accept : G) -> usize 58 fn merge_spikes<G>(&mut self, method : SpikeMergingMethod<F>, accept : G) -> usize
96 where G : FnMut(&'_ Self) -> bool { 59 where G : FnMut(&'_ Self) -> bool {
97 match method { 60 if method.enabled {
98 SpikeMergingMethod::HeuristicRadius(ρ) => 61 self.do_merge_spikes_radius(method.radius, method.interp, accept)
99 self.do_merge_spikes_radius(ρ, true, accept), 62 } else {
100 SpikeMergingMethod::HeuristicRadiusNoInterp(ρ) => 63 0
101 self.do_merge_spikes_radius(ρ, false, accept),
102 SpikeMergingMethod::None => 0,
103 } 64 }
104 } 65 }
105 66
106 /// Attempt to merge spikes based on a value and a fitness function. 67 /// Attempt to merge spikes based on a value and a fitness function.
107 /// 68 ///

mercurial