Add rayon to genetic_algorithm_v1
This commit is contained in:
parent
81edc8e67a
commit
3b8865c169
4 changed files with 72 additions and 57 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue