use crate::chromosone::Gene;
use super::{FitnessFunction, FitnessName};
pub struct ColorCount<const N: usize, const NSYMS: usize> {
pub chromosone_colors: Vec<usize>,
pub preferences: Vec<Vec<usize>>,
pub ncolors: usize,
pub color_names: &'static [&'static str],
pub weight: f64,
}
impl<const N: usize, const NSYMS: usize> ColorCount<N, NSYMS> {
pub fn new(
ncolors: usize,
chromosone_colors: Vec<usize>,
preferences: Vec<Vec<usize>>,
color_names: &'static [&'static str],
weight: f64,
) -> Self {
for prefs in preferences.iter() {
assert_eq!(ncolors, prefs.len());
}
ColorCount {
ncolors,
chromosone_colors,
preferences,
color_names,
weight,
}
}
}
impl<const N: usize, const NSYMS: usize> FitnessFunction<N, NSYMS> for ColorCount<N, NSYMS> {
fn nscores(&self) -> usize {
self.ncolors * NSYMS
}
fn weights(&self) -> Vec<f64> {
vec![self.weight; self.nscores()]
}
fn run(&self, chromosone: &[Gene; N]) -> Vec<f64> {
assert_eq!(self.chromosone_colors.len(), chromosone.len());
let mut scores = Vec::<f64>::with_capacity(self.nscores());
let mut counts: Vec<Vec<usize>> = vec![vec![0; self.ncolors]; NSYMS];
for (i, sym) in chromosone.iter().enumerate() {
let color = self.chromosone_colors[i];
counts[*sym as usize][color] += 1;
}
for m in 0..NSYMS {
for n in 0..self.ncolors {
scores.push(-(counts[m][n].abs_diff(self.preferences[m][n]) as f64))
}
}
scores
}
fn names(&self) -> Vec<FitnessName> {
let mut names = Vec::<FitnessName>::with_capacity(self.nscores());
for m in 0..NSYMS {
for n in 0..self.ncolors {
names.push(FitnessName {
prefix: format!("{} {}", self.color_names[n], self.preferences[m][n]),
gene: Some(m),
locus: None,
});
}
}
names
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_color_count() {
let cc = ColorCount::<5, 3>::new(
2,
vec![0, 1, 0, 1, 0],
vec![vec![1, 1], vec![0, 0], vec![2, 2]],
&["weekday", "weekend"],
1.0,
);
let scores = cc.run(&[0, 0, 0, 1, 1]);
assert_eq!(
scores,
vec![ -1.0, 0.0, -1.0, -1.0, -2.0, -2.0]
);
assert_eq!(cc.nscores(), scores.len());
}
}