Skip to content
This repository was archived by the owner on Sep 22, 2024. It is now read-only.

Prototype improvements #59

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 36 additions & 35 deletions chp09_ga/NOC_9_01_GA_Shakespeare/DNA.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,49 +23,50 @@ function newChar() {
// Constructor (makes a random DNA)
function DNA(num) {
// The genetic sequence
this.genes = [];
this.genes = []; // TargetPhrase.length charaters
this.fitness = 0;
for (var i = 0; i < num; i++) {
this.genes[i] = newChar(); // Pick from range of chars
}
}

// Converts character array to a String
this.getPhrase = function() {
return this.genes.join("");
}

// Fitness function (returns floating point % of "correct" characters)
this.calcFitness = function(target) {
var score = 0;
for (var i = 0; i < this.genes.length; i++) {
if (this.genes[i] == target.charAt(i)) {
score++;
}
}
this.fitness = score / target.length;
}
// Fitness function (returns floating point % of "correct" characters)
DNA.prototype.calcFitness = function(target) {
var score = 0;
for (var i = 0; i < this.genes.length; i++) {
if (this.genes[i] == target.charAt(i)) {
score++;
}
}
this.fitness = score / target.length;
};

// Crossover
this.crossover = function(partner) {
// A new child
var child = new DNA(this.genes.length);

var midpoint = floor(random(this.genes.length)); // Pick a midpoint

// Half from one, half from the other
for (var i = 0; i < this.genes.length; i++) {
if (i > midpoint) child.genes[i] = this.genes[i];
else child.genes[i] = partner.genes[i];
}
return child;
// Crossover
DNA.prototype.crossover = function(partner) {
// A new child
var child = new DNA(this.genes.length);

var midpoint = floor(random(this.genes.length)); // Pick a midpoint

// Half from one, half from the other
for (var i = 0; i < this.genes.length; i++) {
if (i > midpoint) child.genes[i] = this.genes[i];
else child.genes[i] = partner.genes[i];
}
return child;
};

// Based on a mutation probability, picks a new random character
this.mutate = function(mutationRate) {
for (var i = 0; i < this.genes.length; i++) {
if (random(1) < mutationRate) {
this.genes[i] = newChar();
}
// Based on a mutation probability, picks a new random character
DNA.prototype.mutate = function(mutationRate) {
for (var i = 0; i < this.genes.length; i++) {
if (random(1) < mutationRate) {
this.genes[i] = newChar();
}
}
}
};

// Converts character array to a String
DNA.prototype.getPhrase = function() {
return this.genes.join("");
};
172 changes: 86 additions & 86 deletions chp09_ga/NOC_9_01_GA_Shakespeare/Population.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

function Population(p, m, num) {

this.population; // Array to hold the current population
this.matingPool; // ArrayList which we will use for our "mating pool"
this.population = []; // Array to hold the current population
this.matingPool = []; // ArrayList which we will use for our "mating pool"
this.generations = 0; // Number of generations
this.finished = false; // Are we finished evolving?
this.target = p; // Target phrase
Expand All @@ -19,109 +19,109 @@ function Population(p, m, num) {

this.best = "";

this.population = [];
for (var i = 0; i < num; i++) {
this.population[i] = new DNA(this.target.length);
}
this.matingPool = [];

// Fill our fitness array with a value for every member of the population
this.calcFitness = function() {
for (var i = 0; i < this.population.length; i++) {
this.population[i].calcFitness(target);
}
}
this.calcFitness();
}

// Generate a mating pool
this.naturalSelection = function() {
// Clear the ArrayList
this.matingPool = [];

var maxFitness = 0;
for (var i = 0; i < this.population.length; i++) {
if (this.population[i].fitness > maxFitness) {
maxFitness = this.population[i].fitness;
}
}

// Based on fitness, each member will get added to the mating pool a certain number of times
// a higher fitness = more entries to mating pool = more likely to be picked as a parent
// a lower fitness = fewer entries to mating pool = less likely to be picked as a parent
for (var i = 0; i < this.population.length; i++) {

var fitness = map(this.population[i].fitness,0,maxFitness,0,1);
var n = floor(fitness * 100); // Arbitrary multiplier, we can also use monte carlo method
for (var j = 0; j < n; j++) { // and pick two random numbers
this.matingPool.push(this.population[i]);
}
}
}

// Create a new generation
this.generate = function() {
// Refill the population with children from the mating pool
for (var i = 0; i < this.population.length; i++) {
var a = floor(random(this.matingPool.length));
var b = floor(random(this.matingPool.length));
var partnerA = this.matingPool[a];
var partnerB = this.matingPool[b];
var child = partnerA.crossover(partnerB);
child.mutate(this.mutationRate);
this.population[i] = child;
}
this.generations++;
// Fill our fitness array with a value for every member of the population
Population.prototype.calcFitness = function() {
for (let i = 0; i < this.population.length; i++) {
this.population[i].calcFitness(target);
}
};

// Generate a mating pool
Population.prototype.naturalSelection = function() {
// Clear the ArrayList
this.matingPool = [];

this.getBest = function() {
return this.best;
var maxFitness = 0;
for (var i = 0; i < this.population.length; i++) {
if (this.population[i].fitness > maxFitness) {
maxFitness = this.population[i].fitness;
}
}

// Compute the current "most fit" member of the population
this.evaluate = function() {
var worldrecord = 0.0;
var index = 0;
for (var i = 0; i < this.population.length; i++) {
if (this.population[i].fitness > worldrecord) {
index = i;
worldrecord = this.population[i].fitness;
}
// Based on fitness, each member will get added to the mating pool a certain number of times
// a higher fitness = more entries to mating pool = more likely to be picked as a parent
// a lower fitness = fewer entries to mating pool = less likely to be picked as a parent
for (let i = 0; i < this.population.length; i++) {

var fitness = map(this.population[i].fitness,0,maxFitness,0,1);
var n = floor(fitness * 100); // Arbitrary multiplier, we can also use monte carlo method
for (var j = 0; j < n; j++) { // and pick two random numbers
this.matingPool.push(this.population[i]);
}

this.best = this.population[index].getPhrase();
if (worldrecord === this.perfectScore) {
this.finished = true;
}
};

// Create a new generation
Population.prototype.generate = function() {
// Refill the population with children from the mating pool
for (var i = 0; i < this.population.length; i++) {
var a = floor(random(this.matingPool.length));
var b = floor(random(this.matingPool.length));
var partnerA = this.matingPool[a];
var partnerB = this.matingPool[b];
var child = partnerA.crossover(partnerB);
child.mutate(this.mutationRate);
this.population[i] = child;
}
this.generations++;
};


Population.prototype.getBest = function() {
return this.best;
};

// Compute the current "most fit" member of the population
Population.prototype.evaluate = function() {
var worldrecord = 0.0;
var index = 0;
for (var i = 0; i < this.population.length; i++) {
if (this.population[i].fitness > worldrecord) {
index = i;
worldrecord = this.population[i].fitness;
}
}

this.isFinished = function() {
return this.finished;
this.best = this.population[index].getPhrase();
if (worldrecord === this.perfectScore) {
this.finished = true;
}
};

this.getGenerations = function() {
return this.generations;
}
Population.prototype.isFinished = function() {
return this.finished;
};

// Compute average fitness for the population
this.getAverageFitness = function() {
var total = 0;
for (var i = 0; i < this.population.length; i++) {
total += this.population[i].fitness;
}
return total / (this.population.length);
}
Population.prototype.getGenerations = function() {
return this.generations;
};

this.allPhrases = function() {
var everything = "";

var displayLimit = min(this.population.length,50);


for (var i = 0; i < displayLimit; i++) {
everything += this.population[i].getPhrase() + "<br>";
}
return everything;
// Compute average fitness for the population
Population.prototype.getAverageFitness = function() {
var total = 0;
for (var i = 0; i < this.population.length; i++) {
total += this.population[i].fitness;
}
}

return total / (this.population.length);
};

Population.prototype.allPhrases = function() {
var everything = "";

var displayLimit = min(this.population.length,50);


for (var i = 0; i < displayLimit; i++) {
everything += this.population[i].getPhrase() + "<br>";
}
return everything;
};
2 changes: 1 addition & 1 deletion chp09_ga/NOC_9_01_GA_Shakespeare/sketch.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function displayInfo() {

stats.html(statstext);

allPhrases.html("All phrases:<br>" + population.allPhrases())
allPhrases.html("All phrases:<br>" + population.allPhrases());
}