use crate::{Chromosome, EngineRuntime, Generation, ThreadSync};
use crate::{GenerationView, builder::GeneticEngineBuilder};
use crate::{
Handler,
events::{
EngineStart, EngineStop, EpochComplete, EpochStart, EventStream, Improvement, Subscription,
},
};
use crate::{context::EvolutionContext, events::Event};
use crate::{events::GenerationSnapshot, pipeline::Pipeline};
use radiate_core::{Engine, EngineState};
use radiate_core::{EngineStream, error::Result};
pub struct GeneticEngine<C, T>
where
C: Chromosome,
T: Clone + Send + Sync + 'static,
{
context: EvolutionContext<C, T>,
pipeline: Pipeline<C>,
stream: EventStream,
}
impl<C, T> GeneticEngine<C, T>
where
C: Chromosome + Clone,
T: Clone + Send + Sync + 'static,
{
pub(crate) fn new(
context: EvolutionContext<C, T>,
pipeline: Pipeline<C>,
stream: EventStream,
) -> Self {
GeneticEngine {
context,
pipeline,
stream,
}
}
pub fn builder() -> GeneticEngineBuilder<C, T> {
GeneticEngineBuilder::default()
}
pub fn control(&mut self) -> ThreadSync {
self.context.get_or_create_sync()
}
pub fn iter(self) -> EngineRuntime<Self>
where
C: 'static,
{
EngineRuntime::new(self)
}
pub fn subscribe<E: Event>(&self, handler: impl Handler<E>) -> Subscription {
self.stream.subscribe(handler)
}
}
impl<C, T> Engine for GeneticEngine<C, T>
where
C: Chromosome + Clone + 'static,
T: Clone + Send + Sync + 'static,
{
type Epoch = Generation<C, T>;
type Ctx = EvolutionContext<C, T>;
fn context(&self) -> &Self::Ctx {
&self.context
}
fn epoch(&self) -> Self::Epoch {
Generation::from(&self.context)
}
fn state(&self) -> EngineState {
self.context.state
}
fn start(&mut self) {
self.context.set_running();
self.stream.publish(EngineStart);
}
fn stop(&mut self) {
self.context.set_stopped();
self.stream.publish(EngineStop::from(&self.context));
}
#[inline]
fn step(&mut self) -> Result<()> {
match self.state() {
EngineState::PreStart => self.start(),
EngineState::Stopped => return Ok(()),
_ => {
if self.context.stop_requested() {
self.stop();
return Ok(());
}
if self.context.pause_requested() {
self.context.set_paused();
self.context.wait();
if self.context.stop_requested() {
self.stop();
return Ok(());
}
self.context.set_running();
}
}
}
self.stream.publish(EpochStart::from(&self.context));
self.pipeline.run(&mut self.context)?;
if self.context.try_advance_one()? {
self.stream
.lazy_publish(|| Improvement::from(&self.context))?;
}
self.stream.publish(EpochComplete::from(&self.context));
self.stream
.lazy_publish(|| GenerationSnapshot::from(&self.context))?;
Ok(())
}
}
impl<C, T> EngineStream for GeneticEngine<C, T>
where
C: Chromosome + Clone + 'static,
T: Clone + Send + Sync,
{
type View<'a>
= GenerationView<'a, C, T>
where
Self: 'a;
fn run<F>(self, limit: F) -> Result<Self::Epoch>
where
F: Fn(Self::View<'_>) -> bool + 'static,
{
self.iter().until(limit).last()
}
}