All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalagen.actor.Godfather.scala Maven / Gradle / Ivy

There is a newer version: 0.4.0
Show newest version
package scalagen.actor

import akka.actor._
import scalagen.genome.Genome
import scalagen.message._
import scala.collection.immutable.{HashSet, HashMap}
import scalagen.message.UpdatePopulation
import scalagen.message.Best
import scalagen.message.Eval
import scalagen.message.Kill
import akka.actor.Terminated
import scalagen.message.Evaluated
import scalagen.message.Phenotypes
import scalagen.message.Descendant

/**
 * The parent of all phenotypes.
 */
abstract class Godfather(val evaluator: ActorRef,
                         val deathItself: ActorRef,
                         val randomKiller: ActorRef,
                         val controller: ActorRef) extends Actor {
  var phenotypes = new HashMap[ActorRef, Evaluated]()
  var phenotypesToEvaluate = new HashSet[ActorRef]()
  var phenotypeId: Long = 0
  var procreatorId: Long = 0

  override def receive = {
    case GetPhenotypes =>
      sender ! Phenotypes(phenotypes.values.toList)
    case UpdatePopulation(couples, toBeKilled) =>
      updatePopulation(couples, toBeKilled)
    case evaluated@Evaluated(_, _) =>
      updateEvaluatedData(evaluated)
      if (shouldInformController) informController()
    case Descendant(genome) =>
      startNewPhenotype(genome)
    case Terminated(phenotype) =>
      randomKiller ! Death
  }

  def initialGenomes: Seq[Genome]

  def phenotypeFactory(genome: Genome): Phenotype = new Phenotype(genome)

  def procreatorFactory(male: ActorRef, female: ActorRef): Procreator

  def updatePopulation(couples: Seq[(ActorRef, ActorRef)], toBeKilled: Seq[ActorRef]) = {
    toBeKilled.foreach(killPhenotype(_))
    couples.foreach(procreate(_))
  }

  def procreate(parents: (ActorRef, ActorRef)): Unit = {
    val male = parents._1
    val female = parents._2
    context.actorOf(Props(procreatorFactory(male, female)), s"procreator$procreatorId")
    procreatorId += 1
  }

  def killPhenotype(phenotype: ActorRef): Unit = {
    phenotypes -= phenotype
    deathItself ! Kill(phenotype)
  }

  def updateEvaluatedData(evaluated: Evaluated): Unit = {
    phenotypesToEvaluate -= evaluated.phenotype
    phenotypes += ((evaluated.phenotype, evaluated))
  }

  override def preStart: Unit = {
    initialGenomes.map(startNewPhenotype _)
  }

  /**
   * Starts new actor representing phenotype.
   * Send request to evaluate it.
   */
  def startNewPhenotype(genome: Genome): Unit = {
    val newPhenotype = context.actorOf(Props(phenotypeFactory(genome)), s"phenotype$phenotypeId")
    phenotypeId += 1
    phenotypesToEvaluate += newPhenotype
    context.watch(newPhenotype)
    evaluator ! Eval(newPhenotype, genome)
  }

  def shouldInformController: Boolean = phenotypesToEvaluate.isEmpty

  def informController(): Unit = {
    controller ! Phenotypes(phenotypes.values.toSeq)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy