use std::sync::Arc;
use genetic_algorithms::chromosomes::Range as RangeChromosome;
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::ga::{Ga, TerminationCause};
use genetic_algorithms::genotypes::Range as RangeGenotype;
use genetic_algorithms::initializers::range_random_initialization;
use genetic_algorithms::operations::{Crossover, Mutation, Selection, Survivor};
use genetic_algorithms::population::Population;
use genetic_algorithms::stats::GenerationStats;
use genetic_algorithms::traits::{
ChromosomeT, ConfigurationT, CrossoverConfig, MutationConfig, SelectionConfig, StoppingConfig,
};
use genetic_algorithms::LogObserver;
const PROCESSING_TIMES: [[u32; 5]; 15] = [
[5, 10, 6, 3, 7], [8, 3, 12, 5, 9], [4, 7, 3, 11, 6], [9, 5, 8, 4, 12], [3, 12, 7, 9, 5], [11, 4, 9, 6, 3], [6, 8, 5, 12, 10], [7, 6, 11, 3, 8], [12, 9, 4, 7, 5], [5, 11, 8, 10, 4], [8, 3, 6, 5, 11], [4, 10, 12, 8, 7], [10, 7, 3, 6, 9], [6, 5, 9, 12, 3], [3, 8, 10, 4, 6], ];
fn main() {
const N_JOBS: usize = 15;
const N_MACHINES: usize = 5;
const POP_SIZE: usize = 100;
const MAX_GENERATIONS: usize = 500;
let fitness_fn = |dna: &[RangeGenotype<i32>]| -> f64 {
let mut machine_finish = [0u32; N_MACHINES];
for gene in dna {
let job = gene.value as usize;
let (m, _) = machine_finish
.iter()
.enumerate()
.min_by_key(|(_, &t)| t)
.unwrap();
machine_finish[m] += PROCESSING_TIMES[job][m];
}
*machine_finish.iter().max().unwrap() as f64
};
let alleles = vec![RangeGenotype::new(0, vec![(0, N_JOBS as i32 - 1)], 0)];
let alleles_clone = alleles.clone();
let mut ga = Ga::new()
.with_genes_per_chromosome(N_JOBS)
.with_population_size(POP_SIZE)
.with_initialization_fn(move |genes_per_chromosome, _, _| {
range_random_initialization(genes_per_chromosome, Some(&alleles_clone), Some(false))
})
.with_fitness_fn(fitness_fn)
.with_selection_method(Selection::Tournament)
.with_crossover_method(Crossover::Order)
.with_mutation_method(Mutation::Insertion)
.with_survivor_method(Survivor::Fitness)
.with_problem_solving(ProblemSolving::Minimization)
.with_max_generations(MAX_GENERATIONS)
.with_observer(Arc::new(LogObserver))
.build()
.expect("Failed to build GA configuration");
println!("== Job Scheduling -- Permutation-Based Makespan Minimization ==");
println!(
"Jobs: {}, Machines: {}, Population: {}, Max generations: {}",
N_JOBS, N_MACHINES, POP_SIZE, MAX_GENERATIONS
);
println!("Operators: Selection=Tournament, Crossover=Order, Mutation=Insertion");
println!("-------------------------------------------------------");
let report_interval = 50;
let result = ga.run_with_callback(
Some(
|gen: &usize,
pop: &Population<RangeChromosome<i32>>,
_stats: &GenerationStats,
_cause: &TerminationCause|
-> std::ops::ControlFlow<()> {
println!(
"Generation {:4}: best makespan = {:.0}",
gen, pop.best_chromosome.fitness
);
std::ops::ControlFlow::Continue(())
},
),
report_interval,
);
match result {
Ok(population) => {
let dna = population.best_chromosome.dna();
let ordering = dna
.iter()
.map(|g| g.value.to_string())
.collect::<Vec<_>>()
.join(", ");
println!("-------------------------------------------------------");
println!(
"Best makespan: {:.0}",
population.best_chromosome.fitness
);
println!("Best ordering: [{}]", ordering);
}
Err(e) => {
eprintln!("GA failed: {:?}", e);
}
}
}