Quantcast
Channel: Library Questions - Processing 2.x and 3.x Forum
Viewing all articles
Browse latest Browse all 2896

Why is my genetic algorithm not working?

$
0
0

I have been working on a genetic algorithm where the computer controls a ball with a string of balls attached to it, and the computer has to learn to jump over an obstacle. This is my code:

final float g = 1.5;
int allballs;
int hangingballs = 0;
int lifetime;
int lifecounter = 0;

boolean success = false;
class fragment {
  float x, y;
  float vx, vy;
  float getx;
  float gety;
  float ropelength;
  float failure;
  boolean ballishanging;

  fragment(float initialpositionx, float initialpositiony, float tempropelength) {
    x = initialpositionx;
    y = initialpositiony;
    ropelength = tempropelength;
  }
  void isballhanging() {
    if (dist(x, y, getx, gety)>ropelength) {
      hangingballs = hangingballs + 1;
      ballishanging = true;
    } else {
      ballishanging = false;
    }
  }
  void move(float attachtox, float attachtoy, float ballscarried, int arraynumber) {
    getx = attachtox;
    gety = attachtoy;
    vy = vy + g;
    if(ballishanging) {
    vy = vy + (((gety - y)/ropelength)*g)/(1+0.3*ballscarried);
    vx = vx + (((getx - x)/ropelength)*g)/(1+0.3*ballscarried);
    }
    vx = vx * 0.9;
    vy = vy * 0.9;
    //
    x = x + vx;
    y = y + vy;

    if (x>width-25) {
      x = width-25;
      if (vx>0) {
        vx = vx * -0.9;
      }
    }
    if (x<25) {
      x = 25;
      if (vx<0) {
        vx = vx * -0.9;
      }
    }
    if (y>height-25) {
      y = height-25;
      if (vy>0) {
        vy = vy * -0.9;
      }
    }
    if(y<25) {
      y = 25;
      if (vy<0) {
        vy = vy*-0.9;
      }
    }
    if(dist(x,y,obstacle.x,obstacle.y)<(25+obstacle.size/2)) {
      failure += arraynumber;
    }
    if(dist(x,y,obstacle.x,obstacle.x)<(obstacle.size/2+25)/2) {
      failure += arraynumber*2;
    }

    stroke(0);
    strokeWeight(3);
    line(x, y, attachtox, attachtoy);
    //actual ball
    noStroke();
    fill(0, 0, 255);
    ellipse(x, y, 50, 50);
  }
}

class DNA {
  PVector[] genes;

  DNA() {
    genes = new PVector[lifetime];
    for(int i = 0; i < genes.length; i++) {
      genes[i] = PVector.random2D().mult(g*2)  ;
    }
  }
}

class figure {
  DNA dna;
  PVector loc;
  PVector vel;
  PVector acc;
  int genecounter = 0;
  float failure;
  float performance;
  boolean collision = false;
  fragment[] fragments = new fragment[allballs];
  figure() {
    dna = new DNA();
    loc = new PVector(width/2,height-25);
    vel = new PVector(0,0);
    acc = new PVector(0,0);
    for (int i = 0; i < fragments.length; i++) {
      fragments[i] = new fragment(loc.x-(i+1)*50, loc.y, 50);
    }
  }

  void drawfigure() {
    hangingballs = 0;
    for (int i = 0; i<fragments.length; i++) {
      fragments[i].isballhanging();
    }
    acc.mult(0);
    acc.add(dna.genes[genecounter]);
    vel.add(acc);
    loc.add(vel);
    genecounter += 1;
    if ((loc.x>width-25) || (loc.x<25) || (loc.y>height-25) || (loc.y<0)) {
      collision = true;
    }
    for (int i = 0; i<fragments.length; i++) {
      if (i==0) {
        fragments[i].move(loc.x, loc.y, hangingballs, i+1);
        if (hangingballs>0) {
          hangingballs -= 1;
        }
      }
      else {
        fragments[i].move(fragments[i-1].x, fragments[i-1].y, hangingballs, i+1);
        if (hangingballs>0) {
          hangingballs = hangingballs -1;
        }
      }
    }
    if(dist(loc.x,loc.y,obstacle.x,obstacle.y)<(25+obstacle.size/2)) {
      failure = failure + 1;
    }
    if(dist(loc.x,loc.y,obstacle.x,obstacle.x)<(obstacle.size/2+25)/2) {
      failure = failure + 1;
    }
    if (loc.x>width-25) {
      loc.x = width-25;
      failure = failure * 2;
      if (vel.x>0) {
        vel.x = vel.x * -0.9;
      }
    }
    if (loc.x<25) {
      loc.x = 25;
      failure = failure * 2;
      if (vel.x<0) {
        vel.x = vel.x * -0.9;
      }
    }
    if (loc.y>height-25) {
      loc.y = height-25;
      failure = failure * 2;
      if (vel.y>0) {
        vel.y = vel.y * -0.9;
      }
    }
    if(loc.y<25) {
      loc.y = 25;
      failure = failure * 2;
      if (vel.y<0) {
        vel.y = vel.y*-0.9;
      }
    }
    noStroke();
    fill(255, 0, 0);
    ellipse(loc.x, loc.y, 50, 50);
  }
  void evaluateperformance() {
    for(int i = 0; i<fragments.length; i++) {
      failure = failure + fragments[i].failure;
    }
    performance = lifetime*allballs-failure;
    if(failure == 0) {
      success = true;
      for(int i = 0; i<dna.genes.length; i++) {
      successfulfigure.dna.genes[i] = dna.genes[i];
      }
    }
  }
  figure crossover(figure partner) {
    figure child = new figure();
    int midpoint = int(random(dna.genes.length));
    for(int i = 0; i<dna.genes.length; i++) {
      if(i>midpoint) {
        child.dna.genes[i] = dna.genes[i];
      } else {
        child.dna.genes[i] = partner.dna.genes[i];
      }
    }
    return child;
  }
}


class Population {
  float mutationrate;
  figure[] populus;
  ArrayList<figure> matingpool = new ArrayList<figure>();
  int size;
  Population(float tempmutationrate, int tempsize) {
    mutationrate = tempmutationrate;
    size = tempsize;
    populus = new figure[size];
    for(int i = 0; i < populus.length; i++) {
      populus[i] = new figure();
    }
  }
  void formmatingpool() {
    matingpool.clear();
    for(int i = 0; i < populus.length; i++) {
      populus[i].evaluateperformance();
      if(success) {
        successfulfigure.dna.genes = populus[i].dna.genes;
      }
      for(int j = 0; j<int(populus[i].performance); j++) {
        matingpool.add(populus[i]);
      }
    }
     println(matingpool.size());
  }
  figure selection() {
    int a = int(random(matingpool.size()));
    int b = int(random(matingpool.size()));
    figure parent1 = matingpool.get(a);
    figure parent2 = matingpool.get(b);
    figure child = parent1.crossover(parent2);
    for(int i = 0; i<child.dna.genes.length; i++) {
      if(random(1)<mutationrate) {
        child.dna.genes[i] = PVector.random2D().mult(g*2);
      }
    }
    return child;
  }
  void reproduce() {
    for(int i = 0; i<populus.length; i++) {
      populus[i] = selection();
    }
  }
  void live() {
    for(int i = 0; i<populus.length; i++) {
      populus[i].drawfigure();
    }
  }
}

class Obstacle {
  float x, y, size, xspeed;
  Obstacle() {
    size = 150;
    x = width+size/2;
    y = height-size/2;
    xspeed = 30/allballs;
  }
  void move() {
    x = x - xspeed;
    fill(0,255,0);
    ellipse(x,y,size,size);
  }
}
Population population;
Obstacle obstacle;
figure successfulfigure;
void setup() {
  size(800, 800, P2D);
  frameRate(60);
  allballs = 6;
  float mutationrate = 0.01;
  int populationsize = 150;
  obstacle = new Obstacle();
  lifetime = int((width+obstacle.size)/obstacle.xspeed);
  population = new Population(mutationrate, populationsize);
  successfulfigure = new figure();
}

void draw() {
  background(255);
  obstacle.move();
  if(!success) {
  if(lifecounter<lifetime) {
    population.live();
    lifecounter++;
  } else {
    obstacle.x = width + obstacle.size/2;
    lifecounter = 0;
    population.formmatingpool();
    population.reproduce();
  }
  } else {
    if(lifecounter<lifetime) {
    successfulfigure.drawfigure();
    lifecounter++;
  } else {
      obstacle.x = width + obstacle.size/2;
      lifecounter = 0;
      successfulfigure.genecounter = 0;
    }
  }
}

As you can see, the performance of each figure is inversely proportional to its failure, and its failure is calculated by how many frames every ball in the figure has overlapped with the obstacle (gaining more failure if it's overlapped greatly). The further down each ball is, the more its failure affects the entire figure's failure, because the further down the string a ball is, the harder it is to control and so the computer has to be rewarded.

I have also added a function that, if a ball has 0 failure (has never overlapped), removes the population and only displays the successful ball (mind that it is only going to display it successfully on the first go since I have not smoothened out the function so make sure you catch it).

The thing is, the supposedly 'successful' figure is not successful at all!!!

I have spent DAYS trying to understand why and I'm sure that it's something absolutely STUPID but for the life of me I CAN'T FIGURE IT OUT.

PLEASE, run my code, have a look at it and try to see what's wrong. Is the problem with how I evaluate each figure's performance? Is it with the functions that find the successful figure??

THANK YOU ALL IN ADVANCE.


Viewing all articles
Browse latest Browse all 2896

Trending Articles