use genetic_algorithm::strategy::permutate::prelude::*;
type WeightLimit = u16;
type Weight = u16;
type Value = u16;
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
struct Item(pub Weight, pub Value);
#[derive(Clone, Debug)]
struct KnapsackFitness<'a> {
pub items: &'a Vec<Item>,
pub weight_limit: WeightLimit,
}
impl KnapsackFitness<'_> {
const EXCESS_WEIGHT_PENALTY: FitnessValue = 1000;
}
impl Fitness for KnapsackFitness<'_> {
type Genotype = BinaryGenotype;
fn calculate_for_chromosome(
&mut self,
chromosome: &FitnessChromosome<Self>,
_genotype: &FitnessGenotype<Self>,
) -> Option<FitnessValue> {
let item_indices: Vec<usize> = chromosome
.genes
.iter()
.enumerate()
.filter_map(|(i, v)| if *v { Some(i) } else { None })
.collect();
let weight: u16 = item_indices.iter().map(|i| self.items[*i].0).sum();
let value: u16 = item_indices.iter().map(|i| self.items[*i].1).sum();
let mut score = value as FitnessValue;
if weight > self.weight_limit {
score -= (weight - self.weight_limit) as FitnessValue * Self::EXCESS_WEIGHT_PENALTY;
}
Some(score)
}
}
fn main() {
env_logger::init();
let items: Vec<Item> = vec![
Item(23, 505),
Item(26, 352),
Item(20, 458),
Item(18, 220),
Item(32, 354),
Item(27, 414),
Item(29, 498),
Item(26, 545),
Item(30, 473),
Item(27, 543),
];
let weight_limit = 67;
let fitness = KnapsackFitness {
items: &items,
weight_limit,
};
let genotype = BinaryGenotype::builder()
.with_genes_size(items.len())
.build()
.unwrap();
println!("{}", genotype);
let mut permutate = Permutate::builder()
.with_genotype(genotype)
.with_fitness(fitness)
.with_reporter(PermutateReporterSimple::new(100))
.build()
.unwrap();
permutate.call();
if let Some(best_genes) = permutate.best_genes() {
let selected_items =
best_genes
.iter()
.enumerate()
.filter_map(|(i, v)| if *v { Some(&items[i]) } else { None });
println!("selected items: {:?}", selected_items.collect::<Vec<_>>());
}
}