Skip to main content

rsgenetic/sim/select/
max_unstable.rs

1// file: max.rs
2//
3// Copyright 2015-2017 The RsGenetic Developers
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17use super::*;
18use pheno::{Fitness, Phenotype};
19use rayon::prelude::*;
20
21/// Selects best performing phenotypes from the population.
22#[derive(Clone, Copy, Debug)]
23pub struct UnstableMaximizeSelector {
24    count: usize,
25}
26
27impl UnstableMaximizeSelector {
28    /// Create and return a maximizing selector with unstable parallel sorting.
29    ///
30    /// Such a selector selects only the `count` best performing phenotypes
31    /// as parents.
32    ///
33    /// * `count`: must be larger than zero, a multiple of two and less than the population size.
34    pub fn new(count: usize) -> UnstableMaximizeSelector {
35        UnstableMaximizeSelector { count }
36    }
37}
38
39impl<T, F> Selector<T, F> for UnstableMaximizeSelector
40where
41    T: Phenotype<F>,
42    F: Fitness,
43    T: Send,
44    T: Sync,
45{
46    fn select<'a>(&self, population: &'a [T]) -> Result<Parents<&'a T>, String> {
47        if self.count == 0 || self.count % 2 != 0 || self.count * 2 >= population.len() {
48            return Err(format!(
49                "Invalid parameter `count`: {}. Should be larger than zero, a \
50                 multiple of two and less than half the population size.",
51                self.count
52            ));
53        }
54
55        let mut borrowed: Vec<&T> = population.iter().collect();
56        borrowed.par_sort_unstable_by(|x, y| y.fitness().cmp(&x.fitness()));
57        let mut index = 0;
58        let mut result: Parents<&T> = Vec::new();
59        while index < self.count {
60            result.push((borrowed[index], borrowed[index + 1]));
61            index += 2;
62        }
63        Ok(result)
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use pheno::*;
70    use sim::select::*;
71    use test::Test;
72
73    #[test]
74    fn test_count_zero() {
75        let selector = UnstableMaximizeSelector::new(0);
76        let population: Vec<Test> = (0..100).map(|i| Test { f: i }).collect();
77        assert!(selector.select(&population).is_err());
78    }
79
80    #[test]
81    fn test_count_odd() {
82        let selector = UnstableMaximizeSelector::new(5);
83        let population: Vec<Test> = (0..100).map(|i| Test { f: i }).collect();
84        assert!(selector.select(&population).is_err());
85    }
86
87    #[test]
88    fn test_count_too_large() {
89        let selector = UnstableMaximizeSelector::new(100);
90        let population: Vec<Test> = (0..100).map(|i| Test { f: i }).collect();
91        assert!(selector.select(&population).is_err());
92    }
93
94    #[test]
95    fn test_result_size() {
96        let selector = UnstableMaximizeSelector::new(20);
97        let population: Vec<Test> = (0..100).map(|i| Test { f: i }).collect();
98        assert_eq!(20, selector.select(&population).unwrap().len() * 2);
99    }
100
101    #[test]
102    fn test_result_ok() {
103        let selector = UnstableMaximizeSelector::new(20);
104        let population: Vec<Test> = (0..100).map(|i| Test { f: i }).collect();
105        // The greatest fitness should be 99.
106        assert_eq!(selector.select(&population).unwrap()[0].0.fitness().f, 99);
107    }
108
109    #[test]
110    fn test_contains_best() {
111        let selector = UnstableMaximizeSelector::new(2);
112        let population: Vec<Test> = (0..100).map(|i| Test { f: i }).collect();
113        let parents = selector.select(&population).unwrap()[0];
114        assert_eq!(
115            parents.0.fitness(),
116            population
117                .iter()
118                .max_by_key(|x| x.fitness())
119                .unwrap()
120                .fitness()
121        );
122    }
123}