1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| import com.typesafe.scalalogging.LazyLogging import org.slf4j.Logger
import scala.annotation.tailrec import scala.collection.immutable.Stream.consWrapper import scala.language._ import scala.util.Random
object GeneticLayout extends App with LazyLogging { val target = "101010" val genePool = Array[Char]('1','0')
implicit val _: Logger = logger.underlying
def fitness(src: String, tgt: String): Double = src.zip(tgt).count { case (s, t) => s == t } def conflictClear(agents: Seq[String]): Seq[String] = agents
val testBench = new GeneticExploration[Char, String](0.5, 0.01, 10, genePool, cs => new String(cs.toArray), conflictClear, fitness) val (p, g) = testBench.evolution(testBench.newPool(10, target.length), target) }
class GeneticExploration[Gene, Specimen](val cross: Double, val mutation: Double, val population: Int, genePool: Array[Gene], specimenBuilder: Iterable[Gene] => Specimen, conflictClear: Seq[Specimen] => Seq[Specimen], fitnessF: (Specimen, Specimen) => Double)(implicit ev$1: Specimen => Iterable[Gene], logger: Logger) { type Pool = Seq[Specimen] type MatePool = Seq[(Specimen, Double)]
def randomGenes: Stream[Gene] = genePool(Random.nextInt(genePool.length)) #:: randomGenes def newSpecimen(len: Int): Specimen = specimenBuilder(randomGenes.take(len)) def newPool(size: Int, len: Int): Pool = (1 to size).map(_ => newSpecimen(len))
def matePool(pool: Pool, tgt: Specimen): MatePool = { val fitnesses: Seq[Double] = pool.map(fitnessF(_, tgt)) pool.zip(renormalize(fitnesses)) }
def renormalize(vector: Iterable[Double]): Iterable[Double] = { val sum = vector.sum vector.map(_ / sum) }
@tailrec final def monteCarloSelection(matePool: MatePool): Specimen = { val (specimen, fitness) = matePool(Random.nextInt(matePool.length)) if (fitness > Random.nextFloat()) specimen else monteCarloSelection(matePool) }
def popReproduction(matePool: MatePool): Pool = (1 to population) .par .map(_ => crossover(monteCarloSelection(matePool), monteCarloSelection(matePool))) .map(mutate) ./:(Seq[Specimen]())(conflictDetection) .seq
def crossover(a: Specimen, b: Specimen): Specimen = specimenBuilder(a.zip(b).map(gene => if (Random.nextFloat > cross) gene._1 else gene._2)) def mutate(s: Specimen): Specimen = specimenBuilder(s.map(gene => if (mutation > Random.nextFloat) randomGenes.head else gene))
def conflictDetection(z: Pool, b: Specimen): Pool = { @tailrec def _conflictRif(e: Specimen): Specimen = if (!z.contains(e)) e else { val x = mutate(e) if (z.contains(x)) _conflictRif(e) else x } conflictClear(z :+ _conflictRif(b)) }
@tailrec final def evolution(pool: Pool, target: Specimen, generation: Int = 0): (Pool, Int) = { val newGeneration = popReproduction(matePool(pool, target))
logger.debug(s"第${Console.RED}[{}]${Console.RESET}代 向 第${Console.RED}[{}]${Console.RESET}代进化: ", generation, generation + 1) logger.debug("") pool.zip(newGeneration).collect{ case (s, t) => if (t.equals(target)) logger.debug(s"${s.mkString} -> ${Console.BLACK_B}${Console.GREEN}$t${Console.RESET}") else logger.debug(s"${s.mkString} -> ${t.mkString}") } if (newGeneration.contains(target)) (newGeneration, generation) else evolution(newGeneration, target, generation + 1) } }
|