Add rayon to genetic_algorithm_v1

This commit is contained in:
hal8174 2025-02-18 22:02:31 +01:00
parent 81edc8e67a
commit 3b8865c169
4 changed files with 72 additions and 57 deletions

View file

@ -4,7 +4,7 @@ use factorio_blueprint::abstraction::{Blueprint, Entity};
use factorio_core::{beltoptions::Beltspeed, prelude::*, visualize::Visualize};
use factorio_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock};
use factorio_pathfinding::Pathfinder;
use rand::{Rng, seq::IndexedRandom};
use rand::{Rng, SeedableRng, seq::IndexedRandom};
use serde::{Deserialize, Serialize};
use crate::assembly::assembly_line_2_input;
@ -38,11 +38,11 @@ pub struct FactoryConnection {
pub to: usize,
}
pub fn generate_factory<L: Layouter, P: Pathfinder>(
pub fn generate_factory<L: Layouter, P: Pathfinder + Sync, R: Rng + SeedableRng + Send + Sync>(
layouter: &L,
pathfinder: &P,
factory_graph: FactoryGraph,
rng: &mut impl Rng,
rng: &mut R,
) -> Blueprint {
let mut blocks = Vec::new();
let mut blueprints = Vec::new();

View file

@ -14,3 +14,4 @@ clap = { version = "4.4.8", features = ["derive"] }
miette = { version = "7.2.0", features = ["fancy"] }
serde_yaml = "0.9.34"
tracing = "0.1.41"
rayon = "1.10.0"

View file

@ -1,3 +1,4 @@
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use tracing::{Level, field::Empty, info, span, trace, warn};
use crate::{
@ -16,30 +17,39 @@ pub struct GeneticAlgorithm {
}
impl Layouter for GeneticAlgorithm {
fn layout<R: rand::Rng, P: factorio_pathfinding::Pathfinder>(
fn layout<R, P>(
&self,
input: &crate::LayoutInput,
pathfinder: &P,
rng: &mut R,
) -> Option<crate::LayoutResult> {
) -> Option<crate::LayoutResult>
where
R: rand::Rng + rand::SeedableRng + Send + Sync,
P: factorio_pathfinding::Pathfinder + Sync,
{
assert!(self.population_new + self.population_keep <= self.population_size);
let _complete_span = span!(Level::TRACE, "genetic_algorithm_v1").entered();
let mut population = Vec::new();
let mut population: Vec<(LayoutResult, usize)>;
let mut rngs: Vec<_> = (0..self.population_size)
.map(|_| R::from_rng(rng))
.collect();
{
let _initial_generation_span = span!(Level::TRACE, "initial generation").entered();
for i in 0..self.population_size {
population = (0..self.population_size, &mut rngs)
.into_par_iter()
.map(|(i, rng)| {
let _layout_span = span!(Level::TRACE, "layout", i).entered();
loop {
if let Some(l) = self.valid_layout.layout(input, pathfinder, rng) {
let score = score(input, &l);
population.push((l, score));
break;
break (l, score);
}
warn!("Unable to generate valid layout");
}
}
})
.collect();
}
population.sort_by_key(|(_, s)| *s);
@ -49,12 +59,31 @@ impl Layouter for GeneticAlgorithm {
let generation_span =
span!(Level::TRACE, "generation", generation = g, score = Empty).entered();
let (keep, modify) = population.split_at_mut(self.population_keep);
(
(0..self.population_size - self.population_keep),
&mut rngs,
modify,
)
.into_par_iter()
.for_each(|(i, rng, m)| {
if i < self.population_new {
{
let _mutate_span = span!(Level::TRACE, "mutate").entered();
for i in 0..(self.population_size - self.population_keep - self.population_new) {
let _layout_span = span!(Level::TRACE, "new layout", i).entered();
loop {
if let Some(l) = self.valid_layout.layout(input, pathfinder, rng) {
let score = score(input, &l);
let _ = std::mem::replace(m, (l, score));
break;
}
warn!("Unable to generate valid layout");
}
}
} else {
let _layout_span = span!(Level::TRACE, "layout", i).entered();
loop {
let parent = &population[i % self.population_keep].0;
let parent = &keep[i % keep.len()].0;
if let Some(blocks) = mutate(input, parent, rng) {
let (connections, map) =
path_input_from_blocks_positions(input, parent.size, &blocks);
@ -71,29 +100,14 @@ impl Layouter for GeneticAlgorithm {
size: parent.size,
};
let score = score(input, &r);
population.push((r, score));
let _ = std::mem::replace(m, (r, score));
break;
}
}
trace!("unsuccesfull mutation");
}
}
}
{
let _new_span = span!(Level::TRACE, "new").entered();
for i in 0..self.population_new {
let _layout_span = span!(Level::TRACE, "layout", i).entered();
loop {
if let Some(l) = self.valid_layout.layout(input, pathfinder, rng) {
let score = score(input, &l);
population[self.population_size - self.population_new + i] = (l, score);
break;
}
warn!("Unable to generate valid layout");
}
}
}
});
population.sort_by_key(|(_, s)| *s);
if population[0].1 < best_result.1 {

View file

@ -5,7 +5,7 @@ use factorio_core::{
visualize::{self, Visualization, Visualize},
};
use factorio_pathfinding::Pathfinder;
use rand::Rng;
use rand::{Rng, SeedableRng};
use serde::{Deserialize, Serialize};
pub mod genetic_algorithm_v1;
@ -51,7 +51,7 @@ pub struct LayoutResult {
}
pub trait Layouter {
fn layout<R: Rng, P: Pathfinder>(
fn layout<R: Rng + SeedableRng + Send + Sync, P: Pathfinder + Sync>(
&self,
input: &LayoutInput,
pathfinder: &P,