use std::ops::Not;
use rand::Rng;
use ops::traits::MutateOperator;
#[derive(Debug, Serialize, Deserialize)]
pub struct FlipBit {
pb: u32,
}
impl FlipBit {
pub fn with_pb(pb: f32) -> Self
{
assert!(
pb >= 0.0 && pb <= 1.0,
"Probability must be a value between 0.0 and 1.0"
);
let pb = (1.0 / pb) as u32;
Self { pb }
}
}
impl<C> MutateOperator<Vec<C>> for FlipBit
where
C: Clone + Not<Output = C>,
{
fn mutate<R: Rng>(&self, g: &Vec<C>, rng: &mut R) -> Vec<C>
{
g.iter()
.cloned()
.map(|x| if rng.gen_weighted_bool(self.pb)
{
!x
}
else
{
x
})
.collect()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[should_panic]
fn test_panics_on_lt_0()
{
FlipBit::with_pb(-0.001);
}
#[test]
#[should_panic]
fn test_panics_on_gt_1()
{
FlipBit::with_pb(1.001);
}
#[test]
fn test_mutates_correctly()
{
use rand::{StdRng, SeedableRng};
let mut genome =
vec![true, false, true, false, true, true, false, false];
let pb = 0.05;
let seed: &[_] = &[0, 0, 0, 0];
let mut rng: StdRng = SeedableRng::from_seed(seed);
let mut sampled = vec![];
for _ in 0..genome.len()
{
sampled.push(rng.gen_weighted_bool((1.0 / pb) as u32));
}
rng.reseed(seed);
let original = genome.clone();
let mutated = FlipBit::with_pb(pb).mutate(&mut genome, &mut rng);
for i in 0..genome.len()
{
if sampled[i]
{
assert_eq!(!original[i], mutated[i]);
}
else
{
assert_eq!(original[i], mutated[i]);
}
}
}
}