首页 > 解决方案 > Javascript:在图形遗传算法中找不到错误

问题描述

我对 Javascript 很陌生,我一直在研究基于图形的遗传算法。但是,我认为在研究了一段时间后我得到了一些隧道视野,我似乎无法发现出了什么问题?我将Javascriptp5.js一起使用。问题描述如下。

前提

用基于概率的运动创建一堆红点。健康状况取决于他们吃了多少随机放置的绿点。进化吃更多。

错误

  1. 当我运行它时,一个绿点总是出现在左上角,即使它们应该是随机放置的。
  2. (已解决)繁殖功能似乎无法正常工作。它应该:
    • 为下一代创建一个数组(这有效)
    • 从交配池中随机抽取父母(可行)
    • 随机交叉他们的染色体阵列以形成一个新个体(不确定)
    • 为每个新个体应用突变机会(不确定)
    • 在新一代中存储后代(这个工作)
    • 用上一代最适合的成员替换随机后代(不确定)
    • 用新一代数组替换当前代数组(不确定)

代码

var settings = {
      populationSize : 25,
      geneLength : 8,
      mutationProbability : 0.01,
      forestSize : 1500,
      rows : 124,
      cols : 249,
      year : 250,
      end : 20,
    };
    
    function onCanvas(position){
      return position*4+2;
    }
    
    function randombetween(min, max){
      return Math.random()*max;
    }
    
    //set up sheep
    var population = new Population(settings.populationSize, settings.geneLength);
    
    function Sheep(g, dna){
      this.genLen = g;
      this.state = 0;
      this.fitness=0;
      this.xpos = Math.floor(Math.random()*settings.cols);
      this.ypos = Math.floor(Math.random()*settings.rows);
    
      this.chromosome = new Array(this.genLen);
      if (dna != null){
        this.chromosome = dna;
      } else{
        for(var x=0; x<this.genLen; x+=4){
          this.chromosome[x] = Math.random();
          this.chromosome[x+1] = randombetween(0, 1-this.chromosome[x]);
          this.chromosome[x+2] = randombetween(0, 1-this.chromosome[x]-this.chromosome[x+1]);
          this.chromosome[x+3] = 1-this.chromosome[x]-this.chromosome[x+1]-this.chromosome[x+2];
        }
      }
    }
    
    function Population(p, g){
      this.popSize = p;
      this.sheep = [];
      this.matingPool = [];
      this.maxFit;
      this.maxFitIndex;
    
      for (var x = 0; x < this.popSize; x++) {
        this.sheep[x] = new Sheep(g, null);
      }
    
      this.evaluate = function() {
        //find maximum fitness in generation
        this.maxFit = 0;
        this.maxFitIndex = 0;
        for (var x = 0; x < this.popSize; x++) {
          //this.sheep[x].calcFitness();
          if (this.sheep[x].fitness > this.maxFit){
            this.maxFitIndex = x;
            this.maxFit = this.sheep[x].fitness;
          }
        }
        //document.write("Maximum fitness: " + this.maxFit);
    
        //normalize fitness
        for (var i = 0; i < this.popSize; i++) {
          this.sheep[i].fitness /= this.maxFit;
        }
    
        //reset mating pool every generation
        this.matingPool = [];
    
        //higher fitness means more representation in the pool
        for (var i = 0; i < this.popSize; i++) {
          var n = this.sheep[i].fitness *10;
          for (var j = 0; j < n; j++) {
            this.matingPool.push(this.sheep[i]);
          }
        }
      }
    
      //create children sheep
      this.breed = function (){
        var newsheep = [];
    
        for (var i = 0; i < this.popSize; i++){
          //pick random parents from the mating pool
          let parentA = this.matingPool[Math.floor(Math.random()*this.matingPool.length)];
          let parentB = this.matingPool[Math.floor(Math.random()*this.matingPool.length)];
    
          //parent genes are randomly crossed
          var newchromosome = [];
          var midpoint = Math.floor(Math.random()*g);
          for (var j = 0; j < g; j++){
            if (j > midpoint){
              newchromosome[j] = parentA.chromosome[j];
            } else{
              newchromosome[j] = parentB.chromosome[j];
            }
          }
    
          //offspring may be mutated
          if(Math.random()<=settings.mutationProbability){
            newchromosome[Math.floor(Math.random()*g)]=Math.floor(Math.random()*10+1);
          }
          newsheep[i] = new Eater(g, newchromosome);
        }
    
        //elite offspring survive into next generation, replacing a random offspring
        var random = Math.floor(Math.random()*this.popSize);
    
        if(Math.random()<=settings.mutationProbability){
          this.sheep[this.maxFitIndex].chromosome[Math.floor(Math.random()*g)]=Math.floor(Math.random()*10+1);
        }
        for(var x = 0; x < g; x++){
          newsheep[random].chromosome[x] = this.sheep[this.maxFitIndex].chromosome[x];
        }
    
        //update array of sheep
        for(var x=0; x<this.popSize; x++){
          this.sheep[x] = newsheep[x];
        }
      }
    }
    
    //set up trees
    var forest = new Forest(settings.forestSize);
    
    function radialTreePopulation(x,y,r,count){
      let trees = [];
      for(let i = 0;i < count; i++){
        trees.push({
          posx : (x + Math.floor((Math.random()* r) * (Math.random() < 0.5 ? -1 : 1))),
          posy : (y + Math.floor((Math.random()* r) * (Math.random() < 0.5 ? -1 : 1)))
        });
      }
      return trees;
    }
    
    function Forest(f){
      this.forSize = f/ 75;
      this.trees = [];
    
      for (var x = 0; x < this.forSize ; x++) {
        this.trees.push(...radialTreePopulation(
          (Math.floor(Math.random()*(settings.cols-20)+10))| 0,
          (Math.floor(Math.random()*(settings.rows-20)+10))| 0,
          11,
          75)
        );
      }
    }
    
    //evaluate how to move
    function moveHungry(x, move){
      if(move<population.sheep[x].chromosome[0]){
        return 0;
      }
      else if(move-population.sheep[x].chromosome[0]<population.sheep[x].chromosome[1]){
        return 1;
      }
      else if(move-population.sheep[x].chromosome[0]-population.sheep[x].chromosome[1]<population.sheep[x].chromosome[2]){
        return 2;
      }
      else{
        return 3;
      }
    }
    
    function moveEaten(x,move){
      if(move<population.sheep[x].chromosome[4]){
        return 0;
      }
      else if(move-population.sheep[x].chromosome[4]<population.sheep[x].chromosome[5]){
        return 1;
      }
      else if(move-population.sheep[x].chromosome[4]-population.sheep[x].chromosome[5]<population.sheep[x].chromosome[6]){
        return 2;
      }
      else{
        return 3;
      }
    }
    
    //count generations and days
    var generation=0;
    var counter = 0;
    
    //create world
    function createWorld(){
      background("lightblue");
    
      fill(0,255,0);
      for(var x=0; x<settings.forestSize; x++){
        rect(onCanvas(forest.trees[x].posx), onCanvas(forest.trees[x].posy), 4, 4);
      }
    
      fill(255,0,0);
      for(var x=0; x<settings.populationSize; x++){
        population.sheep[x].state=0;
        rect(onCanvas(population.sheep[x].xpos), onCanvas(population.sheep[x].ypos), 4, 4);
      }
    
      //remove eaten trees
      for(var x=0; x<settings.populationSize; x++){
        for(var y=0; y<settings.forestSize; y++){
          if(population.sheep[x].xpos==forest.trees[y].posx && population.sheep[x].ypos==forest.trees[y].posy){
            forest.trees[y].posx=null;
            forest.trees[y].posy=null;
            population.sheep[x].state=1;
            population.sheep[x].fitness++;
          }
        }
      }
    
      //move sheep based on chromosome
      for(var x=0; x<settings.populationSize; x++){
        var move = Math.random();
        if(population.sheep[x].state==0){
          switch(moveHungry(x, move)){
            case 0: //up
              if(population.sheep[x].ypos>0)
                population.sheep[x].ypos-=1;
              break;
            case 1: //down
              if(population.sheep[x].ypos<settings.rows-1)
                population.sheep[x].ypos+=1;
              break;
            case 2: //right
              if(population.sheep[x].xpos<settings.cols-1)
                population.sheep[x].xpos+=1;
              break;
            case 3: //left
              if(population.sheep[x].xpos>0)
                population.sheep[x].xpos-=1;
          }
        }
        else {
          switch(moveEaten(x, move)){
            case 0: //up
              if(population.sheep[x].ypos>0)
                population.sheep[x].ypos-=1;
              break;
            case 1: //down
              if(population.sheep[x].ypos<settings.rows-1)
                population.sheep[x].ypos+=1;
              break;
            case 2: //right
              if(population.sheep[x].xpos<settings.cols-1)
                population.sheep[x].xpos+=1;
              break;
            case 3: //left
              if(population.sheep[x].xpos>0)
                population.sheep[x].xpos-=1;
          }
        }
      }
      counter++;
    }
    
    function reset(){
      counter=0;
      //regrow forest
      forest = new Forest(settings.forestSize);
      //reset locations and fitness values
      for(var x=0; x<settings.populationSize; x++){
        population.sheep[x].xpos = Math.floor(Math.random()*settings.cols);
        population.sheep[x].ypos = Math.floor(Math.random()*settings.rows);
        population.sheep[x].fitness=0;
      }
    }
    
    function setup() {
      createCanvas(1000, 500);
    }
    
    function draw() {
      createWorld();
      if(counter>=settings.year){
        population.evaluate();
        population.breed();
        reset();
        generation++;
        if(generation>=settings.end){
          noLoop();
        }
      }
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

标签: javascriptgenetic-algorithmp5.js

解决方案


推荐阅读