fuzzcheck/sensors_and_pools/
maximise_observation_pool.rs

1use std::fmt::{Debug, Display};
2use std::path::PathBuf;
3
4use crate::traits::{CorpusDelta, Pool, SaveToStatsFolder, Stats};
5use crate::{CSVField, CompatibleWithObservations, PoolStorageIndex, ToCSV};
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash)]
8struct Unit;
9
10struct Input {
11    input_id: PoolStorageIndex,
12    complexity: f64,
13}
14
15/// A pool that finds a single test case maximising a value given by a sensor.
16pub struct MaximiseObservationPool<T> {
17    name: String,
18    current_best: Option<(T, Input)>,
19}
20#[derive(Clone)]
21pub struct MaximiseObservationPoolStats<T> {
22    name: String,
23    best: T,
24}
25impl<T> Display for MaximiseObservationPoolStats<T>
26where
27    T: Debug,
28{
29    #[coverage(off)]
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        write!(f, "{}({:?})", self.name, self.best)
32    }
33}
34impl<T> ToCSV for MaximiseObservationPoolStats<T>
35where
36    T: Debug,
37{
38    #[coverage(off)]
39    fn csv_headers(&self) -> Vec<CSVField> {
40        vec![CSVField::String(self.name.clone())]
41    }
42    #[coverage(off)]
43    fn to_csv_record(&self) -> Vec<CSVField> {
44        vec![CSVField::String(format!("{:?}", self.best))]
45    }
46}
47impl<T> Stats for MaximiseObservationPoolStats<T> where T: Debug + Default + 'static {}
48
49impl<T> MaximiseObservationPool<T> {
50    #[coverage(off)]
51    pub fn new(name: &str) -> Self {
52        Self {
53            name: name.to_string(),
54            current_best: None,
55        }
56    }
57}
58impl<T> Pool for MaximiseObservationPool<T>
59where
60    T: Clone + Debug + Default + 'static,
61{
62    type Stats = MaximiseObservationPoolStats<T>;
63
64    #[coverage(off)]
65    fn stats(&self) -> Self::Stats {
66        MaximiseObservationPoolStats {
67            name: self.name.clone(),
68            best: self
69                .current_best
70                .as_ref()
71                .map(
72                    #[coverage(off)]
73                    |z| z.0.clone(),
74                )
75                .unwrap_or_default(),
76        }
77    }
78    #[coverage(off)]
79    fn get_random_index(&mut self) -> Option<PoolStorageIndex> {
80        if let Some(best) = &self.current_best {
81            Some(best.1.input_id)
82        } else {
83            None
84        }
85    }
86}
87impl<T> SaveToStatsFolder for MaximiseObservationPool<T> {
88    #[coverage(off)]
89    fn save_to_stats_folder(&self) -> Vec<(PathBuf, Vec<u8>)> {
90        vec![]
91    }
92}
93
94impl<T> CompatibleWithObservations<T> for MaximiseObservationPool<T>
95where
96    T: Clone + Debug + Default + PartialOrd + 'static,
97{
98    #[coverage(off)]
99    fn process(&mut self, input_id: PoolStorageIndex, observations: &T, complexity: f64) -> Vec<CorpusDelta> {
100        let observations = observations.clone();
101        let is_interesting = if let Some((counter, cur_input)) = &self.current_best {
102            observations > *counter || (observations == *counter && cur_input.complexity > complexity)
103        } else {
104            true
105        };
106        if !is_interesting {
107            return vec![];
108        }
109        let delta = CorpusDelta {
110            path: PathBuf::new().join(&self.name),
111            add: true,
112            remove: if let Some(best) = &self.current_best {
113                vec![best.1.input_id]
114            } else {
115                vec![]
116            },
117        };
118        let new = Input { input_id, complexity };
119        self.current_best = Some((observations, new));
120        vec![delta]
121    }
122}