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

mgo.evolution.neat.NEATMutation.scala Maven / Gradle / Ivy

The newest version!
///*
// * Copyright (C) 17/09/2015 Guillaume Chérel
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
// * (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program.  If not, see .
// */
//package mgo.evolution.mutation
//
//import mgo.Population
//import mgo.evolution.breed.NEATBreedingContext
//import mgo.evolution.genome.{ NEATGenomesAlign, NEATGenome }
//import mgo.evolution.genome.NEATGenome._
//import math.{ max, min, abs }
//import scala.annotation.tailrec
//import scala.collection.immutable.IntMap
//
//import scala.util.Random
//
//import scalaz._
//import Scalaz._
//
//import scala.language.higherKinds
//
//trait NEATMutation <: Mutation with NEATGenome with NEATBreedingContext with NEATGenomesAlign {
//
//  def mutationAddNodeProb: Double
//  def mutationAddLinkProb: Double
//  def mutationWeightProb0: Double
//  def mutationWeightSigma: Double
//  def mutationWeightDriftTo0: Double
//  def mutationWeightHardMax: Double
//  def mutationWeightHardMin: Double
//  def mutationDisableProb: Double
//  def mutationEnableProb: Double
//  def useSpeciesHint: Boolean
//  def genDistDisjointCoeff: Double
//  def genDistExcessCoeff: Double
//  def genDistWeightDiffCoeff: Double
//
//  def pickNodesAddLink(genome: G)(implicit rng: Random): Option[(Int, Int)]
//  def pickNewHiddenNode(level: Double)(implicit rng: Random): HiddenNode
//
//  def initialWeight(implicit rng: Random): Double = rng.nextGaussian() * mutationWeightSigma
//
//  override def mutate(genome: G, population: Population[G, P, F], archive: A)(implicit rng: Random): BreedingContext[G] = {
//    val r = rng.nextDouble()
//    val mutated: BreedingContext[G] = if (genome.connectionGenes.nonEmpty && r < mutationAddNodeProb) {
//      mutateAddNode(genome)
//    } else if (r < mutationAddNodeProb + mutationAddLinkProb) {
//      mutateAddLink(genome)
//    } else {
//      // successively mutate weights and mutate enable bits on the genome
//      val result = {
//        mutateWeights(_: G)
//      }.andThen {
//        mutateEnabled(_: G)
//      }(genome)
//
//      result.point[BreedingContext]
//    }
//
//    /*now that the offspring g was mutated, set species*/
//    val result = (mutated: BreedingContext[G]) >>= { g: G =>
//      State[BreedingState, G]({
//        case (gin, gnn, roi, ios) =>
//          val (newg, newios) = setSpecies(g, ios)
//          ((gin, gnn, roi, newios), newg)
//      })
//    }
//
//    result
//  }
//
//  def mutateAddLink(genome: G)(implicit rng: Random): BreedingContext[G] = {
//    val pair = pickNodesAddLink(genome)
//
//    pair match {
//      case None => genome.point[BreedingContext]
//      case Some((u, v)) => State[BreedingState, G]({
//        case (gin, gnn, roi, ios) =>
//
//          //Look for a LinkInnovation between nodes u and v in the record
//          val sameInRoi: Option[LinkInnovation] = roi.collectFirst {
//            case LinkInnovation(number, `u`, `v`) => LinkInnovation(number, u, v)
//          }
//
//          val thisInnov =
//            sameInRoi match {
//              case None => LinkInnovation(gin + 1, u, v)
//              case Some(x) => x
//            }
//
//          val newroi =
//            sameInRoi match {
//              case None => roi :+ thisInnov
//              case Some(x) => roi
//            }
//
//          val newgene =
//            ConnectionGene(
//              inNode = u,
//              outNode = v,
//              weight = initialWeight,
//              enabled = true,
//              innovation = thisInnov.innovnum)
//
//          val newgenome =
//            Genome(
//              connectionGenes =
//                genome.connectionGenes :+ newgene,
//              nodes = genome.nodes,
//              species = genome.species,
//              lastNodeId = genome.lastNodeId)
//
//          ((gin + 1, gnn, newroi, ios), newgenome)
//      })
//    }
//  }
//
//  /** pick a connection gene, disable it and add 2 new connection genes */
//  def mutateAddNode(genome: G)(implicit rng: Random): BreedingContext[G] = State[BreedingState, G]({
//    case (gin, gnn, roi, ios) =>
//
//      val picked: Int = rng.nextInt(genome.connectionGenes.length)
//      val pickedcg = genome.connectionGenes(picked)
//
//      val newNode = pickNewHiddenNode((genome.nodes(pickedcg.inNode).level + genome.nodes(pickedcg.outNode).level) / 2.0)
//
//      //Look for a NodeInnovation between nodes u and v in the record
//      val sameInRoi: Option[NodeInnovation] = roi.collectFirst {
//        case NodeInnovation(a, b, c, `newNode`, pickedcg.inNode, pickedcg.outNode) => NodeInnovation(a, b, c, newNode, pickedcg.inNode, pickedcg.outNode)
//      }
//
//      val thisInnov =
//        sameInRoi match {
//          case None => NodeInnovation(gin + 1, gin + 2, gnn + 1, newNode, pickedcg.inNode, pickedcg.outNode)
//          case Some(x) => x
//        }
//
//      val newcg1: ConnectionGene =
//        ConnectionGene(
//          inNode = pickedcg.inNode,
//          outNode = thisInnov.newnodeId,
//          weight = 1,
//          enabled = true,
//          innovation = thisInnov.innovnum1)
//
//      val newcg2: ConnectionGene =
//        ConnectionGene(
//          inNode = thisInnov.newnodeId,
//          outNode = pickedcg.outNode,
//          weight = pickedcg.weight,
//          enabled = true,
//          innovation = thisInnov.innovnum2)
//
//      val newconnectiongenes = genome.connectionGenes.updated(
//        picked,
//        pickedcg.copy(enabled = false)
//      ) ++ Vector(newcg1, newcg2)
//
//      val newnodes = genome.nodes + (thisInnov.newnodeId -> newNode)
//
//      val newgenome = Genome(
//        connectionGenes = newconnectiongenes,
//        nodes = newnodes,
//        species = genome.species,
//        lastNodeId = thisInnov.newnodeId)
//
//      val newroi =
//        roi :+ thisInnov
//
//      ((gin + 2, gnn + 1, newroi, ios), newgenome)
//  })
//
//  def mutateWeights(genome: G)(implicit rng: Random): G =
//    genome.copy(
//      connectionGenes =
//        genome.connectionGenes.map { (cg: ConnectionGene) =>
//          cg.copy(weight = mutateWeight(cg.weight))
//        })
//
//  def mutateWeight(x: Double)(implicit rng: Random): Double = {
//    val newweight =
//      if (rng.nextDouble < mutationWeightProb0) 0
//      else x + rng.nextGaussian() * mutationWeightSigma - (x * mutationWeightDriftTo0)
//    max(min(mutationWeightHardMax, newweight), mutationWeightHardMin)
//  }
//
//  def mutateEnabled(g: G)(implicit rng: Random): G =
//    g.copy(
//      connectionGenes =
//        g.connectionGenes.map { mutateEnabled })
//
//  def mutateEnabled(cg: ConnectionGene)(implicit rng: Random): ConnectionGene = {
//    val newenabled =
//      if (cg.enabled) if (rng.nextDouble() < mutationDisableProb) !cg.enabled else cg.enabled
//      else if (rng.nextDouble() < mutationEnableProb) !cg.enabled else cg.enabled
//    cg.copy(enabled = newenabled)
//  }
//
//  /**
//   * Sets the innovation numbers of each new mutation in the offsprings such that
//   * * unique mutations are attributed a unique number greater than the archive's global innovation number,
//   * * mutations that are identical to one found it the archive's record of innovations are attributed its number
//   */
//  def setSpecies(
//    genome: G,
//    indexOfSpecies: IntMap[G]): (G, IntMap[G]) = {
//    // Find a genome in the index of species which is sufficiently similar to the current genome.
//    // The following code starts by checking if the offspring is compatible with the parent species (currently set in the species member of the offspring)
//    // There is a problem when used with the adaptive species compatibility threshold: the number of species doesn't decrease since most of the time,
//    // offsprings get attributed their parents species.
//    if (useSpeciesHint && genomesDistance(genome, indexOfSpecies(genome.species)) < speciesCompatibilityThreshold)
//      (genome, indexOfSpecies)
//    else
//      indexOfSpecies.find {
//        case (sindex, prototype) => genomesDistance(prototype, genome) < speciesCompatibilityThreshold
//      } match {
//        //If found, attribute the species to the current genome
//        case Some((species, _)) =>
//          (genome.copy(species = species), indexOfSpecies)
//        //Otherwise, create a new species with the current genome as the prototype
//        case None =>
//          val newspecies = indexOfSpecies.lastKey + 1
//          val newgenome = genome.copy(species = newspecies)
//          val newios = indexOfSpecies + ((newspecies, newgenome))
//          (newgenome, newios)
//
//      }
//  }
//
//  def genomesDistance(g1: G, g2: G): Double = {
//    val alignment = alignGenomes(g1.connectionGenes, g2.connectionGenes)
//    val (excess, disjoint, weightdiff, matchingGenes) = distanceFactors(alignment)
//    val longestGenomeSize: Double = max(g1.connectionGenes.length, g2.connectionGenes.length).toDouble
//    if (longestGenomeSize == 0) 0.0
//    else {
//      val structuralDistance = (genDistDisjointCoeff * excess / longestGenomeSize) +
//        (genDistExcessCoeff * disjoint / longestGenomeSize)
//      if (matchingGenes == 0)
//        structuralDistance
//      else
//        structuralDistance + (genDistWeightDiffCoeff * weightdiff / matchingGenes.toDouble)
//    }
//  }
//
//  import AlignmentInfo._
//  @tailrec final def distanceFactors(
//    alignment: List[(Option[ConnectionGene], Option[ConnectionGene], AlignmentInfo)],
//    acc: (Int, Int, Double, Int) = (0, 0, 0.0, 0)): (Int, Int, Double, Int) =
//    alignment match {
//      case List() => acc
//      case head :: tail =>
//        val (excess, disjoint, weightdiff, matchingGenes) = acc //distanceFactors(tail)
//        val newacc = head match {
//          case (Some(cg1), Some(cg2), Aligned) => (excess, disjoint, weightdiff + abs(cg1.weight - cg2.weight), matchingGenes + 1)
//          case (_, _, Disjoint) => (excess, disjoint + 1, weightdiff, matchingGenes)
//          case (_, _, Excess) => (excess + 1, disjoint, weightdiff, matchingGenes)
//          case _ => throw new RuntimeException(s"Improper alignment: $head") //this case should never happen
//        }
//        distanceFactors(tail, newacc)
//
//    }
//
//}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy