
mgo.evolution.algorithm.NoisyOSE.scala Maven / Gradle / Ivy
package mgo.evolution.algorithm
import cats.implicits._
import mgo.evolution._
import mgo.evolution.algorithm.GenomeVectorDouble._
import mgo.evolution.algorithm.OSEOperation.ReachMap
import mgo.evolution.breeding._
import mgo.evolution.elitism._
import mgo.evolution.ranking._
import mgo.tools.execution._
import monocle.function
import scala.reflect.ClassTag
object NoisyOSE {
import CDGenome._
import NoisyIndividual._
type StateType[P] = (Archive[Individual[P]], OSEOperation.ReachMap)
type OSEState[P] = EvolutionState[StateType[P]]
def archiveLens[P] = EvolutionState.s[StateType[P]] composeLens function.fields.first
def reachMapLens[P] = EvolutionState.s[StateType[P]] composeLens function.fields.second
def initialGenomes(lambda: Int, continuous: Vector[C], discrete: Vector[D], reject: Option[Genome => Boolean], rng: scala.util.Random) =
CDGenome.initialGenomes(lambda, continuous, discrete, reject, rng)
def adaptiveBreeding[P: Manifest](
lambda: Int,
operatorExploration: Double,
cloneProbability: Double,
aggregation: Vector[P] => Vector[Double],
discrete: Vector[D],
origin: (Vector[Double], Vector[Int]) => Vector[Int],
limit: Vector[Double],
reject: Option[Genome => Boolean]) =
NoisyOSEOperations.adaptiveBreeding[OSEState[P], Individual[P], Genome, P](
vectorPhenotype[P].get,
aggregation,
Individual.genome.get,
continuousValues.get,
continuousOperator.get,
discreteValues.get,
discreteOperator.get,
discrete,
buildGenome,
logOfPopulationSize,
lambda,
reject,
operatorExploration,
cloneProbability,
origin,
limit,
archiveLens.get,
reachMapLens.get)
def expression[P: Manifest](fitness: (util.Random, Vector[Double], Vector[Int]) => P, continuous: Vector[C]): (util.Random, Genome) => Individual[P] =
NoisyIndividual.expression[P](fitness, continuous)
def elitism[P: Manifest](mu: Int, historySize: Int, aggregation: Vector[P] => Vector[Double], components: Vector[C], origin: (Vector[Double], Vector[Int]) => Vector[Int], limit: Vector[Double]): Elitism[OSEState[P], Individual[P]] = {
def individualValues(i: Individual[P]) = values(Individual.genome.get(i), components)
NoisyOSEOperations.elitism[OSEState[P], Individual[P], P](
vectorPhenotype[P].get,
aggregation,
individualValues,
origin,
limit,
historySize,
mergeHistories(individualValues, vectorPhenotype[P], Individual.historyAge[P], historySize),
mu,
archiveLens,
reachMapLens)
}
case class Result[P](continuous: Vector[Double], discrete: Vector[Int], fitness: Vector[Double], replications: Int, individual: Individual[P])
def result[P: Manifest](state: OSEState[P], population: Vector[Individual[P]], aggregation: Vector[P] => Vector[Double], continuous: Vector[C], limit: Vector[Double], keepAll: Boolean) = {
def goodIndividuals =
population.flatMap { i =>
val (c, d, f, r) = NoisyIndividual.aggregate[P](i, aggregation, continuous)
if (keepAll || OSEOperation.patternIsReached(f, limit)) Some(Result(c, d, f, r, i)) else None
}
state.s._1.toVector.map { i =>
val (c, d, f, r) = NoisyIndividual.aggregate(i, aggregation, continuous)
Result(c, d, f, r, i)
} ++ goodIndividuals
}
def result[P: Manifest](noisyOSE: NoisyOSE[P], state: OSEState[P], population: Vector[Individual[P]]): Vector[Result[P]] =
result[P](state, population, noisyOSE.aggregation, noisyOSE.continuous, noisyOSE.limit, keepAll = false)
def reject[P](pse: NoisyOSE[P]) = NSGA2.reject(pse.reject, pse.continuous)
implicit def isAlgorithm[P: Manifest]: Algorithm[NoisyOSE[P], Individual[P], Genome, OSEState[P]] = new Algorithm[NoisyOSE[P], Individual[P], Genome, OSEState[P]] {
def initialState(t: NoisyOSE[P], rng: scala.util.Random) = EvolutionState(s = (Array.empty, Array.empty))
def initialPopulation(t: NoisyOSE[P], rng: scala.util.Random) =
noisy.initialPopulation[Genome, Individual[P]](
NoisyOSE.initialGenomes(t.lambda, t.continuous, t.discrete, reject(t), rng),
NoisyOSE.expression[P](t.fitness, t.continuous),
rng)
def step(t: NoisyOSE[P]) =
noisy.step[OSEState[P], Individual[P], Genome](
NoisyOSE.adaptiveBreeding[P](
t.lambda,
t.operatorExploration,
t.cloneProbability,
t.aggregation,
t.discrete,
t.origin,
t.limit,
reject(t)),
NoisyOSE.expression(t.fitness, t.continuous),
NoisyOSE.elitism[P](
t.mu,
t.historySize,
t.aggregation,
t.continuous,
t.origin,
t.limit),
EvolutionState.generation,
EvolutionState.evaluated)
}
}
case class NoisyOSE[P](
mu: Int,
lambda: Int,
fitness: (util.Random, Vector[Double], Vector[Int]) => P,
limit: Vector[Double],
origin: (Vector[Double], Vector[Int]) => Vector[Int],
aggregation: Vector[P] => Vector[Double],
continuous: Vector[C] = Vector.empty,
discrete: Vector[D] = Vector.empty,
historySize: Int = 100,
cloneProbability: Double = 0.2,
operatorExploration: Double = 0.1,
reject: Option[(Vector[Double], Vector[Int]) => Boolean] = None)
object NoisyOSEOperations {
def aggregated[I, P](fitness: I => Vector[P], aggregation: Vector[P] => Vector[Double])(i: I): Vector[Double] =
aggregation(fitness(i)) ++ Vector(1.0 / fitness(i).size.toDouble)
def promisingReachMap[I](fitness: I => Vector[Double], limit: Vector[Double], origin: I => Vector[Int], population: Vector[I]): Set[Vector[Int]] = {
val promising = population.filter(i => OSEOperation.patternIsReached(fitness(i), limit))
promising.map(origin).toSet
}
def adaptiveBreeding[S, I, G, P](
history: I => Vector[P],
aggregation: Vector[P] => Vector[Double],
genome: I => G,
continuousValues: G => Vector[Double],
continuousOperator: G => Option[Int],
discreteValues: G => Vector[Int],
discreteOperator: G => Option[Int],
discrete: Vector[D],
buildGenome: (Vector[Double], Option[Int], Vector[Int], Option[Int]) => G,
tournamentRounds: Int => Int,
lambda: Int,
reject: Option[G => Boolean],
operatorExploration: Double,
cloneProbability: Double,
origin: (Vector[Double], Vector[Int]) => Vector[Int],
limit: Vector[Double],
archive: S => Archive[I],
reachMap: S => OSEOperation.ReachMap): Breeding[S, I, G] =
(s, population, rng) => {
def genomeOrigin(g: G) = origin(continuousValues(g), discreteValues(g))
val promisingReachMapValue =
promisingReachMap[I](
aggregated(history, aggregation),
limit,
i => genomeOrigin(genome(i)),
population)
val reached = reachMap(s).toSet
def filterAlreadyReachedAndNeighboursOfPromising(genomes: Vector[G]) =
OSEOperation.filterAlreadyReached[G](genomeOrigin, reached)(genomes).filter(g => !promisingReachMapValue.contains(genomeOrigin(g)))
val archivedPopulation = archive(s)
val ranks = ranking.paretoRankingMinAndCrowdingDiversity[I](population, aggregated(history, aggregation), rng)
val allRanks = ranks ++ Vector.fill(archivedPopulation.size)(worstParetoRanking)
val continuousOperatorStatistics = operatorProportions(genome andThen continuousOperator, population)
val discreteOperatorStatistics = operatorProportions(genome andThen discreteOperator, population)
def breeding: Breeding[S, I, G] =
(s, pop, g) => {
val breed = applyDynamicOperators[S, I, G](
tournament(allRanks, tournamentRounds),
genome andThen continuousValues,
genome andThen discreteValues,
continuousOperatorStatistics,
discreteOperatorStatistics,
discrete,
operatorExploration,
buildGenome)(s, pop, rng) //apply ()
filterAlreadyReachedAndNeighboursOfPromising(breed)
}
val offspring = breed(breeding, lambda, reject)(s, population ++ archivedPopulation, rng)
val sizedOffspringGenomes = randomTake[G](offspring, lambda, rng)
clonesReplace(cloneProbability, population, genome, tournament(ranks, tournamentRounds))(s, sizedOffspringGenomes, rng)
}
def elitism[S, I: ClassTag, P](
history: I => Vector[P],
aggregation: Vector[P] => Vector[Double],
values: I => (Vector[Double], Vector[Int]),
origin: (Vector[Double], Vector[Int]) => Vector[Int],
limit: Vector[Double],
historySize: Int,
mergeHistories: (Vector[I], Vector[I]) => Vector[I],
mu: Int,
archive: monocle.Lens[S, Archive[I]],
reachMap: monocle.Lens[S, ReachMap]): Elitism[S, I] =
(s, population, candidates, rng) => {
val merged = filterNaN(mergeHistories(population, candidates), aggregated(history, aggregation))
val reached = reachMap.get(s).toSet
def individualOrigin(i: I) = Function.tupled(origin)(values(i))
def newlyReaching = {
def keepNewlyReaching(i: I): Option[I] =
if (OSEOperation.patternIsReached(aggregated(history, aggregation)(i), limit))
(reached.contains(individualOrigin(i))) match {
case true => None
case false if history(i).size >= historySize => Some(i)
case _ => None
}
else None
merged.flatMap(i => keepNewlyReaching(i).toVector)
}
val reaching = newlyReaching
val s2 = reachMap.modify(_ ++ reaching.map(individualOrigin)).compose(archive.modify(_ ++ reaching))(s)
val filteredPopulation = OSEOperation.filterAlreadyReached[I](i => Function.tupled(origin)(values(i)), reachMap.get(s2).toSet)(merged)
NoisyNSGA2Operations.elitism[S, I, P](aggregated(history, aggregation), values, mergeHistories, mu)(s2, filteredPopulation, Vector.empty, rng)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy