cosyne/
permutation_prob_f.rs

1#[derive(Debug, Clone, Copy)]
2/// Enumerate the probability functions used for marking weights for permutation
3pub enum PermutationProbF {
4    /// Each weight has the same probability of being marked for permutation
5    Uniform(f64),
6    /// Each weight has a probability of being permuted relative to it's peers in sub-population
7    /// not quite the same as in paper
8    Relative,
9}
10
11impl PermutationProbF {
12    /// Return the probability that a weight is marked for permutation
13    /// given the sub-population fitnesses
14    pub(crate) fn get_probability(&self, subpopulation_fits: &Vec<f64>, weight_fit: f64) -> f64 {
15        match self {
16            PermutationProbF::Uniform(p) => *p,
17            PermutationProbF::Relative => {
18                let mut min_fit: f64 = subpopulation_fits[0];
19                let mut max_fit: f64 = subpopulation_fits[0];
20                for f in subpopulation_fits {
21                    if *f < min_fit {
22                        min_fit = *f;
23                    } else if *f > max_fit {
24                        max_fit = *f;
25                    }
26                }
27
28                1.0 - scale(min_fit, max_fit, 0.0, 1.0, weight_fit)
29            }
30        }
31    }
32}
33
34/// Scale a value from one range to another
35pub fn scale(from_min: f64, from_max: f64, to_min: f64, to_max: f64, value: f64) -> f64 {
36    to_min + ((value - from_min) * (to_max - to_min)) / (from_max - from_min)
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    use round::round;
43
44    #[test]
45    fn permutation_prob_f() {
46        let ppf = PermutationProbF::Uniform(1.0);
47        assert_eq!(ppf.get_probability(&vec![], 0.5), 1.0);
48
49        let ppf = PermutationProbF::Relative;
50        let spf: Vec<f64> = vec![0.1, 0.2, 0.5, -0.1, -0.2];
51        let weight_fit: f64 = spf[0];
52        let prob: f64 = ppf.get_probability(&spf, weight_fit);
53        assert_eq!(round(prob, 3), 0.571);
54    }
55}