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_core::{beltoptions::Beltspeed, prelude::*, visualize::Visualize};
|
||||||
use factorio_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock};
|
use factorio_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock};
|
||||||
use factorio_pathfinding::Pathfinder;
|
use factorio_pathfinding::Pathfinder;
|
||||||
use rand::{Rng, seq::IndexedRandom};
|
use rand::{Rng, SeedableRng, seq::IndexedRandom};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::assembly::assembly_line_2_input;
|
use crate::assembly::assembly_line_2_input;
|
||||||
|
|
@ -38,11 +38,11 @@ pub struct FactoryConnection {
|
||||||
pub to: usize,
|
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,
|
layouter: &L,
|
||||||
pathfinder: &P,
|
pathfinder: &P,
|
||||||
factory_graph: FactoryGraph,
|
factory_graph: FactoryGraph,
|
||||||
rng: &mut impl Rng,
|
rng: &mut R,
|
||||||
) -> Blueprint {
|
) -> Blueprint {
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
let mut blueprints = 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"] }
|
miette = { version = "7.2.0", features = ["fancy"] }
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
tracing = "0.1.41"
|
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 tracing::{Level, field::Empty, info, span, trace, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -16,30 +17,39 @@ pub struct GeneticAlgorithm {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layouter for GeneticAlgorithm {
|
impl Layouter for GeneticAlgorithm {
|
||||||
fn layout<R: rand::Rng, P: factorio_pathfinding::Pathfinder>(
|
fn layout<R, P>(
|
||||||
&self,
|
&self,
|
||||||
input: &crate::LayoutInput,
|
input: &crate::LayoutInput,
|
||||||
pathfinder: &P,
|
pathfinder: &P,
|
||||||
rng: &mut R,
|
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);
|
assert!(self.population_new + self.population_keep <= self.population_size);
|
||||||
let _complete_span = span!(Level::TRACE, "genetic_algorithm_v1").entered();
|
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();
|
let _initial_generation_span = span!(Level::TRACE, "initial generation").entered();
|
||||||
for i in 0..self.population_size {
|
population = (0..self.population_size, &mut rngs)
|
||||||
let _layout_span = span!(Level::TRACE, "layout", i).entered();
|
.into_par_iter()
|
||||||
loop {
|
.map(|(i, rng)| {
|
||||||
if let Some(l) = self.valid_layout.layout(input, pathfinder, rng) {
|
let _layout_span = span!(Level::TRACE, "layout", i).entered();
|
||||||
let score = score(input, &l);
|
loop {
|
||||||
population.push((l, score));
|
if let Some(l) = self.valid_layout.layout(input, pathfinder, rng) {
|
||||||
break;
|
let score = score(input, &l);
|
||||||
|
break (l, score);
|
||||||
|
}
|
||||||
|
warn!("Unable to generate valid layout");
|
||||||
}
|
}
|
||||||
warn!("Unable to generate valid layout");
|
})
|
||||||
}
|
.collect();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
population.sort_by_key(|(_, s)| *s);
|
population.sort_by_key(|(_, s)| *s);
|
||||||
|
|
||||||
|
|
@ -49,51 +59,55 @@ impl Layouter for GeneticAlgorithm {
|
||||||
let generation_span =
|
let generation_span =
|
||||||
span!(Level::TRACE, "generation", generation = g, score = Empty).entered();
|
span!(Level::TRACE, "generation", generation = g, score = Empty).entered();
|
||||||
|
|
||||||
{
|
let (keep, modify) = population.split_at_mut(self.population_keep);
|
||||||
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, "layout", i).entered();
|
|
||||||
loop {
|
|
||||||
let parent = &population[i % self.population_keep].0;
|
|
||||||
if let Some(blocks) = mutate(input, parent, rng) {
|
|
||||||
let (connections, map) =
|
|
||||||
path_input_from_blocks_positions(input, parent.size, &blocks);
|
|
||||||
|
|
||||||
if let Some(paths) =
|
(
|
||||||
pathfinder.find_paths(factorio_pathfinding::PathInput {
|
(0..self.population_size - self.population_keep),
|
||||||
connections: &connections,
|
&mut rngs,
|
||||||
map,
|
modify,
|
||||||
})
|
)
|
||||||
{
|
.into_par_iter()
|
||||||
let r = LayoutResult {
|
.for_each(|(i, rng, m)| {
|
||||||
positions: blocks,
|
if i < self.population_new {
|
||||||
path_result: paths,
|
{
|
||||||
size: parent.size,
|
let _layout_span = span!(Level::TRACE, "new layout", i).entered();
|
||||||
};
|
loop {
|
||||||
let score = score(input, &r);
|
if let Some(l) = self.valid_layout.layout(input, pathfinder, rng) {
|
||||||
population.push((r, score));
|
let score = score(input, &l);
|
||||||
break;
|
let _ = std::mem::replace(m, (l, score));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
warn!("Unable to generate valid layout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trace!("unsuccesfull mutation");
|
} else {
|
||||||
}
|
let _layout_span = span!(Level::TRACE, "layout", i).entered();
|
||||||
}
|
loop {
|
||||||
}
|
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);
|
||||||
|
|
||||||
{
|
if let Some(paths) =
|
||||||
let _new_span = span!(Level::TRACE, "new").entered();
|
pathfinder.find_paths(factorio_pathfinding::PathInput {
|
||||||
for i in 0..self.population_new {
|
connections: &connections,
|
||||||
let _layout_span = span!(Level::TRACE, "layout", i).entered();
|
map,
|
||||||
loop {
|
})
|
||||||
if let Some(l) = self.valid_layout.layout(input, pathfinder, rng) {
|
{
|
||||||
let score = score(input, &l);
|
let r = LayoutResult {
|
||||||
population[self.population_size - self.population_new + i] = (l, score);
|
positions: blocks,
|
||||||
break;
|
path_result: paths,
|
||||||
|
size: parent.size,
|
||||||
|
};
|
||||||
|
let score = score(input, &r);
|
||||||
|
let _ = std::mem::replace(m, (r, score));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("unsuccesfull mutation");
|
||||||
}
|
}
|
||||||
warn!("Unable to generate valid layout");
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
population.sort_by_key(|(_, s)| *s);
|
population.sort_by_key(|(_, s)| *s);
|
||||||
if population[0].1 < best_result.1 {
|
if population[0].1 < best_result.1 {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use factorio_core::{
|
||||||
visualize::{self, Visualization, Visualize},
|
visualize::{self, Visualization, Visualize},
|
||||||
};
|
};
|
||||||
use factorio_pathfinding::Pathfinder;
|
use factorio_pathfinding::Pathfinder;
|
||||||
use rand::Rng;
|
use rand::{Rng, SeedableRng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod genetic_algorithm_v1;
|
pub mod genetic_algorithm_v1;
|
||||||
|
|
@ -51,7 +51,7 @@ pub struct LayoutResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Layouter {
|
pub trait Layouter {
|
||||||
fn layout<R: Rng, P: Pathfinder>(
|
fn layout<R: Rng + SeedableRng + Send + Sync, P: Pathfinder + Sync>(
|
||||||
&self,
|
&self,
|
||||||
input: &LayoutInput,
|
input: &LayoutInput,
|
||||||
pathfinder: &P,
|
pathfinder: &P,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue