1use rand::SeedableRng;
9use rayon::prelude::*;
10use serde::{Deserialize, Serialize};
11use std::sync::Arc;
12
13use crate::error::{EvoResult, EvolutionError, OperatorResult};
14use crate::fitness::traits::{Fitness, FitnessValue};
15use crate::genome::bounds::MultiBounds;
16use crate::genome::traits::EvolutionaryGenome;
17use crate::operators::traits::{CrossoverOperator, MutationOperator, SelectionOperator};
18use crate::population::individual::Individual;
19use crate::population::population::Population;
20
21#[derive(Clone, Debug, Serialize, Deserialize)]
23pub enum MigrationTopology {
24 Ring,
26 FullyConnected,
28 Random,
30 Star { hub_index: usize },
32}
33
34impl Default for MigrationTopology {
35 fn default() -> Self {
36 Self::Ring
37 }
38}
39
40impl MigrationTopology {
41 pub fn targets(&self, source: usize, num_islands: usize) -> Vec<usize> {
43 match self {
44 Self::Ring => vec![(source + 1) % num_islands],
45 Self::FullyConnected => (0..num_islands).filter(|&i| i != source).collect(),
46 Self::Random => (0..num_islands).filter(|&i| i != source).collect(),
47 Self::Star { hub_index } => {
48 if source == *hub_index {
49 (0..num_islands).filter(|&i| i != source).collect()
50 } else {
51 vec![*hub_index]
52 }
53 }
54 }
55 }
56}
57
58#[derive(Clone, Debug, Serialize, Deserialize)]
60pub enum MigrationPolicy {
61 Best(usize),
63 Random(usize),
65 BestReplaceWorst(usize),
67}
68
69impl Default for MigrationPolicy {
70 fn default() -> Self {
71 Self::Best(1)
72 }
73}
74
75#[derive(Clone, Debug)]
77pub struct IslandModelConfig {
78 pub num_islands: usize,
80 pub island_population_size: usize,
82 pub migration_interval: usize,
84 pub topology: MigrationTopology,
86 pub policy: MigrationPolicy,
88 pub bounds: MultiBounds,
90 pub elitism: usize,
92}
93
94impl Default for IslandModelConfig {
95 fn default() -> Self {
96 Self {
97 num_islands: 4,
98 island_population_size: 50,
99 migration_interval: 10,
100 topology: MigrationTopology::Ring,
101 policy: MigrationPolicy::Best(1),
102 bounds: MultiBounds::symmetric(5.0, 10),
103 elitism: 1,
104 }
105 }
106}
107
108pub struct Island<G, F = f64>
110where
111 G: EvolutionaryGenome,
112 F: FitnessValue,
113{
114 pub index: usize,
116 pub population: Population<G, F>,
118 pub best: Option<Individual<G, F>>,
120 pub generation: usize,
122 pub evaluations: usize,
124}
125
126impl<G, F> Island<G, F>
127where
128 G: EvolutionaryGenome,
129 F: FitnessValue,
130{
131 pub fn new<R: rand::Rng>(index: usize, size: usize, bounds: &MultiBounds, rng: &mut R) -> Self {
133 Self {
134 index,
135 population: Population::random(size, bounds, rng),
136 best: None,
137 generation: 0,
138 evaluations: 0,
139 }
140 }
141
142 pub fn with_population(index: usize, population: Population<G, F>) -> Self {
144 Self {
145 index,
146 population,
147 best: None,
148 generation: 0,
149 evaluations: 0,
150 }
151 }
152
153 pub fn evolve_one_generation<Fit, Sel, Cross, Mut, R>(
155 &mut self,
156 fitness: &Fit,
157 selection: &Sel,
158 crossover: &Cross,
159 mutation: &Mut,
160 elitism: usize,
161 rng: &mut R,
162 ) -> EvoResult<()>
163 where
164 Fit: Fitness<Genome = G, Value = F>,
165 Sel: SelectionOperator<G>,
166 Cross: CrossoverOperator<G>,
167 Mut: MutationOperator<G>,
168 R: rand::Rng,
169 {
170 self.population.evaluate(fitness);
172 self.evaluations += self.population.len();
173
174 if let Some(current_best) = self.population.best() {
176 match &self.best {
177 None => self.best = Some(current_best.clone()),
178 Some(best) if current_best.is_better_than(best) => {
179 self.best = Some(current_best.clone());
180 }
181 _ => {}
182 }
183 }
184
185 self.population.sort_by_fitness();
187 let elites: Vec<_> = self.population.iter().take(elitism).cloned().collect();
188
189 let selection_pool: Vec<(G, f64)> = self
191 .population
192 .iter()
193 .filter_map(|ind| {
194 ind.fitness
195 .as_ref()
196 .map(|f| (ind.genome.clone(), f.to_f64()))
197 })
198 .collect();
199
200 if selection_pool.len() < 2 {
201 return Err(EvolutionError::EmptyPopulation);
202 }
203
204 let mut offspring = Vec::with_capacity(self.population.len());
206
207 while offspring.len() < self.population.len() - elitism {
208 let idx1 = selection.select(&selection_pool, rng);
210 let idx2 = selection.select(&selection_pool, rng);
211 let parent1 = &selection_pool[idx1].0;
212 let parent2 = &selection_pool[idx2].0;
213
214 let (mut child1, mut child2) = match crossover.crossover(parent1, parent2, rng) {
216 OperatorResult::Success((c1, c2)) | OperatorResult::Repaired((c1, c2), _) => {
217 (c1, c2)
218 }
219 OperatorResult::Failed(_) => (parent1.clone(), parent2.clone()),
220 };
221
222 mutation.mutate(&mut child1, rng);
224 mutation.mutate(&mut child2, rng);
225
226 offspring.push(Individual::new(child1));
227 if offspring.len() < self.population.len() - elitism {
228 offspring.push(Individual::new(child2));
229 }
230 }
231
232 let mut new_population = Population::new();
234 for elite in elites {
235 new_population.push(elite);
236 }
237 for child in offspring {
238 new_population.push(child);
239 }
240 self.population = new_population;
241
242 self.generation += 1;
243 Ok(())
244 }
245
246 pub fn get_emigrants<R: rand::Rng>(
248 &self,
249 policy: &MigrationPolicy,
250 rng: &mut R,
251 ) -> Vec<Individual<G, F>> {
252 match policy {
253 MigrationPolicy::Best(k) => {
254 let mut sorted: Vec<_> = self.population.iter().cloned().collect();
255 sorted.sort_by(|a, b| match (a.fitness.as_ref(), b.fitness.as_ref()) {
256 (Some(fa), Some(fb)) => fb.partial_cmp(fa).unwrap_or(std::cmp::Ordering::Equal),
257 (Some(_), None) => std::cmp::Ordering::Less,
258 (None, Some(_)) => std::cmp::Ordering::Greater,
259 (None, None) => std::cmp::Ordering::Equal,
260 });
261 sorted.into_iter().take(*k).collect()
262 }
263 MigrationPolicy::Random(k) => {
264 use rand::seq::SliceRandom;
265 let mut individuals: Vec<_> = self.population.iter().cloned().collect();
266 individuals.shuffle(rng);
267 individuals.into_iter().take(*k).collect()
268 }
269 MigrationPolicy::BestReplaceWorst(k) => {
270 let mut sorted: Vec<_> = self.population.iter().cloned().collect();
271 sorted.sort_by(|a, b| match (a.fitness.as_ref(), b.fitness.as_ref()) {
272 (Some(fa), Some(fb)) => fb.partial_cmp(fa).unwrap_or(std::cmp::Ordering::Equal),
273 (Some(_), None) => std::cmp::Ordering::Less,
274 (None, Some(_)) => std::cmp::Ordering::Greater,
275 (None, None) => std::cmp::Ordering::Equal,
276 });
277 sorted.into_iter().take(*k).collect()
278 }
279 }
280 }
281
282 pub fn accept_immigrants<R: rand::Rng>(
284 &mut self,
285 immigrants: Vec<Individual<G, F>>,
286 policy: &MigrationPolicy,
287 rng: &mut R,
288 ) {
289 match policy {
290 MigrationPolicy::Best(_) | MigrationPolicy::Random(_) => {
291 for immigrant in immigrants {
293 let idx = rng.gen_range(0..self.population.len());
294 self.population[idx] = immigrant;
295 }
296 }
297 MigrationPolicy::BestReplaceWorst(k) => {
298 self.population.sort_by_fitness();
300 let pop_len = self.population.len();
301 for (i, immigrant) in immigrants.into_iter().enumerate() {
302 if i < *k && pop_len > i {
303 self.population[pop_len - 1 - i] = immigrant;
304 }
305 }
306 }
307 }
308 }
309}
310
311pub struct IslandModel<G, Fit, Sel, Cross, Mut, F = f64>
313where
314 G: EvolutionaryGenome,
315 F: FitnessValue,
316{
317 pub config: IslandModelConfig,
319 pub islands: Vec<Island<G, F>>,
321 pub fitness: Arc<Fit>,
323 pub selection: Sel,
325 pub crossover: Cross,
327 pub mutation: Mut,
329 pub global_best: Option<Individual<G, F>>,
331 pub generation: usize,
333 pub total_evaluations: usize,
335}
336
337impl<G, Fit, Sel, Cross, Mut, F> IslandModel<G, Fit, Sel, Cross, Mut, F>
338where
339 G: EvolutionaryGenome,
340 F: FitnessValue,
341 Fit: Fitness<Genome = G, Value = F> + Send + Sync,
342 Sel: SelectionOperator<G> + Clone + Send + Sync,
343 Cross: CrossoverOperator<G> + Clone + Send + Sync,
344 Mut: MutationOperator<G> + Clone + Send + Sync,
345{
346 pub fn new<R: rand::Rng>(
348 config: IslandModelConfig,
349 fitness: Fit,
350 selection: Sel,
351 crossover: Cross,
352 mutation: Mut,
353 rng: &mut R,
354 ) -> Self {
355 let islands: Vec<_> = (0..config.num_islands)
356 .map(|i| {
357 let mut island_rng = rand::rngs::StdRng::from_seed(rng.gen());
358 Island::new(
359 i,
360 config.island_population_size,
361 &config.bounds,
362 &mut island_rng,
363 )
364 })
365 .collect();
366
367 Self {
368 config,
369 islands,
370 fitness: Arc::new(fitness),
371 selection,
372 crossover,
373 mutation,
374 global_best: None,
375 generation: 0,
376 total_evaluations: 0,
377 }
378 }
379
380 pub fn run<R: rand::Rng>(
382 &mut self,
383 max_generations: usize,
384 rng: &mut R,
385 ) -> EvoResult<&Individual<G, F>> {
386 for _ in 0..max_generations {
387 self.step(rng)?;
388 }
389
390 self.global_best
391 .as_ref()
392 .ok_or(EvolutionError::EmptyPopulation)
393 }
394
395 pub fn step<R: rand::Rng>(&mut self, rng: &mut R) -> EvoResult<()> {
397 let elitism = self.config.elitism;
399 let fitness = Arc::clone(&self.fitness);
400 let selection = self.selection.clone();
401 let crossover = self.crossover.clone();
402 let mutation = self.mutation.clone();
403
404 self.islands.par_iter_mut().for_each(|island| {
406 let mut island_rng = rand::rngs::StdRng::from_entropy();
407 let _ = island.evolve_one_generation(
408 fitness.as_ref(),
409 &selection,
410 &crossover,
411 &mutation,
412 elitism,
413 &mut island_rng,
414 );
415 });
416
417 for island in &self.islands {
419 if let Some(island_best) = &island.best {
420 match &self.global_best {
421 None => self.global_best = Some(island_best.clone()),
422 Some(global) if island_best.is_better_than(global) => {
423 self.global_best = Some(island_best.clone());
424 }
425 _ => {}
426 }
427 }
428 }
429
430 self.generation += 1;
431 self.total_evaluations = self.islands.iter().map(|i| i.evaluations).sum();
432
433 if self
435 .generation
436 .is_multiple_of(self.config.migration_interval)
437 {
438 self.migrate(rng);
439 }
440
441 Ok(())
442 }
443
444 fn migrate<R: rand::Rng>(&mut self, rng: &mut R) {
446 let num_islands = self.islands.len();
447 let policy = &self.config.policy;
448 let topology = &self.config.topology;
449
450 let emigrants: Vec<Vec<Individual<G, F>>> = self
452 .islands
453 .iter()
454 .map(|island| island.get_emigrants(policy, &mut rand::rngs::StdRng::from_entropy()))
455 .collect();
456
457 for (source, source_emigrants) in emigrants.into_iter().enumerate() {
459 let targets = topology.targets(source, num_islands);
460
461 if targets.is_empty() {
462 continue;
463 }
464
465 match topology {
466 MigrationTopology::Random => {
467 let target = targets[rng.gen_range(0..targets.len())];
469 self.islands[target].accept_immigrants(source_emigrants, policy, rng);
470 }
471 _ => {
472 if let Some(&target) = targets.first() {
474 self.islands[target].accept_immigrants(
475 source_emigrants.clone(),
476 policy,
477 rng,
478 );
479 }
480 }
481 }
482 }
483 }
484
485 pub fn combined_population(&self) -> Population<G, F> {
487 let mut combined = Population::new();
488 for island in &self.islands {
489 for individual in island.population.iter() {
490 combined.push(individual.clone());
491 }
492 }
493 combined
494 }
495
496 pub fn island_statistics(&self) -> Vec<IslandStats<F>> {
498 self.islands
499 .iter()
500 .map(|island| {
501 let (sum, best) = island
502 .population
503 .iter()
504 .filter_map(|i| i.fitness.clone())
505 .fold((0.0, None::<F>), |(sum, best), f| {
506 let new_best = match best {
507 None => Some(f.clone()),
508 Some(b) if f.is_better_than(&b) => Some(f.clone()),
509 b => b,
510 };
511 (sum + f.to_f64(), new_best)
512 });
513
514 let count = island
515 .population
516 .iter()
517 .filter(|i| i.fitness.is_some())
518 .count();
519
520 IslandStats {
521 index: island.index,
522 generation: island.generation,
523 evaluations: island.evaluations,
524 population_size: island.population.len(),
525 mean_fitness: if count > 0 { sum / count as f64 } else { 0.0 },
526 best_fitness: best,
527 }
528 })
529 .collect()
530 }
531}
532
533#[derive(Clone, Debug)]
535pub struct IslandStats<F: FitnessValue> {
536 pub index: usize,
538 pub generation: usize,
540 pub evaluations: usize,
542 pub population_size: usize,
544 pub mean_fitness: f64,
546 pub best_fitness: Option<F>,
548}
549
550pub struct IslandModelBuilder<G, Fit, Sel, Cross, Mut, F = f64>
552where
553 G: EvolutionaryGenome,
554 F: FitnessValue,
555{
556 config: IslandModelConfig,
557 fitness: Option<Fit>,
558 selection: Option<Sel>,
559 crossover: Option<Cross>,
560 mutation: Option<Mut>,
561 _phantom: std::marker::PhantomData<(G, F)>,
562}
563
564impl<G, Fit, Sel, Cross, Mut, F> IslandModelBuilder<G, Fit, Sel, Cross, Mut, F>
565where
566 G: EvolutionaryGenome,
567 F: FitnessValue,
568 Fit: Fitness<Genome = G, Value = F> + Send + Sync,
569 Sel: SelectionOperator<G> + Clone + Send + Sync,
570 Cross: CrossoverOperator<G> + Clone + Send + Sync,
571 Mut: MutationOperator<G> + Clone + Send + Sync,
572{
573 pub fn new() -> Self {
575 Self {
576 config: IslandModelConfig::default(),
577 fitness: None,
578 selection: None,
579 crossover: None,
580 mutation: None,
581 _phantom: std::marker::PhantomData,
582 }
583 }
584
585 pub fn num_islands(mut self, n: usize) -> Self {
587 self.config.num_islands = n;
588 self
589 }
590
591 pub fn island_population_size(mut self, size: usize) -> Self {
593 self.config.island_population_size = size;
594 self
595 }
596
597 pub fn migration_interval(mut self, interval: usize) -> Self {
599 self.config.migration_interval = interval;
600 self
601 }
602
603 pub fn topology(mut self, topology: MigrationTopology) -> Self {
605 self.config.topology = topology;
606 self
607 }
608
609 pub fn migration_policy(mut self, policy: MigrationPolicy) -> Self {
611 self.config.policy = policy;
612 self
613 }
614
615 pub fn bounds(mut self, bounds: MultiBounds) -> Self {
617 self.config.bounds = bounds;
618 self
619 }
620
621 pub fn elitism(mut self, n: usize) -> Self {
623 self.config.elitism = n;
624 self
625 }
626
627 pub fn fitness(mut self, fitness: Fit) -> Self {
629 self.fitness = Some(fitness);
630 self
631 }
632
633 pub fn selection(mut self, selection: Sel) -> Self {
635 self.selection = Some(selection);
636 self
637 }
638
639 pub fn crossover(mut self, crossover: Cross) -> Self {
641 self.crossover = Some(crossover);
642 self
643 }
644
645 pub fn mutation(mut self, mutation: Mut) -> Self {
647 self.mutation = Some(mutation);
648 self
649 }
650
651 pub fn build<R: rand::Rng>(
653 self,
654 rng: &mut R,
655 ) -> EvoResult<IslandModel<G, Fit, Sel, Cross, Mut, F>> {
656 let fitness = self.fitness.ok_or(EvolutionError::Configuration(
657 "Fitness function is required".to_string(),
658 ))?;
659 let selection = self.selection.ok_or(EvolutionError::Configuration(
660 "Selection operator is required".to_string(),
661 ))?;
662 let crossover = self.crossover.ok_or(EvolutionError::Configuration(
663 "Crossover operator is required".to_string(),
664 ))?;
665 let mutation = self.mutation.ok_or(EvolutionError::Configuration(
666 "Mutation operator is required".to_string(),
667 ))?;
668
669 Ok(IslandModel::new(
670 self.config,
671 fitness,
672 selection,
673 crossover,
674 mutation,
675 rng,
676 ))
677 }
678}
679
680impl<G, Fit, Sel, Cross, Mut, F> Default for IslandModelBuilder<G, Fit, Sel, Cross, Mut, F>
681where
682 G: EvolutionaryGenome,
683 F: FitnessValue,
684 Fit: Fitness<Genome = G, Value = F> + Send + Sync,
685 Sel: SelectionOperator<G> + Clone + Send + Sync,
686 Cross: CrossoverOperator<G> + Clone + Send + Sync,
687 Mut: MutationOperator<G> + Clone + Send + Sync,
688{
689 fn default() -> Self {
690 Self::new()
691 }
692}
693
694#[cfg(test)]
695mod tests {
696 use super::*;
697 use crate::fitness::benchmarks::Sphere;
698 use crate::genome::real_vector::RealVector;
699 use crate::operators::crossover::BlxAlphaCrossover;
700 use crate::operators::mutation::GaussianMutation;
701 use crate::operators::selection::TournamentSelection;
702 use rand::SeedableRng;
703
704 #[test]
705 fn test_migration_topology_ring() {
706 let topology = MigrationTopology::Ring;
707 assert_eq!(topology.targets(0, 4), vec![1]);
708 assert_eq!(topology.targets(1, 4), vec![2]);
709 assert_eq!(topology.targets(3, 4), vec![0]);
710 }
711
712 #[test]
713 fn test_migration_topology_fully_connected() {
714 let topology = MigrationTopology::FullyConnected;
715 let targets = topology.targets(0, 4);
716 assert_eq!(targets.len(), 3);
717 assert!(!targets.contains(&0));
718 }
719
720 #[test]
721 fn test_migration_topology_star() {
722 let topology = MigrationTopology::Star { hub_index: 0 };
723 assert_eq!(topology.targets(1, 4), vec![0]);
725 assert_eq!(topology.targets(2, 4), vec![0]);
726 let hub_targets = topology.targets(0, 4);
728 assert_eq!(hub_targets.len(), 3);
729 }
730
731 #[test]
732 fn test_island_creation() {
733 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
734 let bounds = MultiBounds::symmetric(5.0, 5);
735 let island: Island<RealVector> = Island::new(0, 10, &bounds, &mut rng);
736
737 assert_eq!(island.index, 0);
738 assert_eq!(island.population.len(), 10);
739 assert_eq!(island.generation, 0);
740 }
741
742 #[test]
743 fn test_island_model_builder() {
744 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
745 let bounds = MultiBounds::symmetric(5.0, 5);
746
747 let result = IslandModelBuilder::<RealVector, _, _, _, _>::new()
748 .num_islands(4)
749 .island_population_size(20)
750 .migration_interval(5)
751 .topology(MigrationTopology::Ring)
752 .migration_policy(MigrationPolicy::Best(2))
753 .bounds(bounds)
754 .elitism(1)
755 .fitness(Sphere::new(5))
756 .selection(TournamentSelection::new(3))
757 .crossover(BlxAlphaCrossover::new(0.5))
758 .mutation(GaussianMutation::new(0.1))
759 .build(&mut rng);
760
761 assert!(result.is_ok());
762 let model = result.unwrap();
763 assert_eq!(model.islands.len(), 4);
764 }
765
766 #[test]
767 fn test_island_model_evolution() {
768 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
769 let bounds = MultiBounds::symmetric(5.0, 5);
770
771 let mut model = IslandModelBuilder::<RealVector, _, _, _, _>::new()
772 .num_islands(2)
773 .island_population_size(20)
774 .migration_interval(5)
775 .topology(MigrationTopology::Ring)
776 .migration_policy(MigrationPolicy::Best(1))
777 .bounds(bounds)
778 .elitism(1)
779 .fitness(Sphere::new(5))
780 .selection(TournamentSelection::new(2))
781 .crossover(BlxAlphaCrossover::new(0.5))
782 .mutation(GaussianMutation::new(0.1))
783 .build(&mut rng)
784 .unwrap();
785
786 let result = model.run(10, &mut rng);
788 assert!(result.is_ok());
789
790 assert_eq!(model.generation, 10);
791 assert!(model.global_best.is_some());
792 }
793
794 #[test]
795 fn test_island_statistics() {
796 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
797 let bounds = MultiBounds::symmetric(5.0, 5);
798
799 let mut model = IslandModelBuilder::<RealVector, _, _, _, _>::new()
800 .num_islands(3)
801 .island_population_size(10)
802 .migration_interval(10)
803 .bounds(bounds)
804 .fitness(Sphere::new(5))
805 .selection(TournamentSelection::new(2))
806 .crossover(BlxAlphaCrossover::new(0.5))
807 .mutation(GaussianMutation::new(0.1))
808 .build(&mut rng)
809 .unwrap();
810
811 model.run(5, &mut rng).unwrap();
812
813 let stats = model.island_statistics();
814 assert_eq!(stats.len(), 3);
815 for stat in &stats {
816 assert_eq!(stat.generation, 5);
817 assert_eq!(stat.population_size, 10);
818 }
819 }
820}