import ai_ga.*; // A simple program that finds collections of numbers that add up to a given value // Aaron Steed 2008 //Heavily modified by Chris Calef, 2009 PFont font; ArtAppreciation myArt; int initialTarget = 0;//No longer relevant. String solution = ""; String target = "target: " + initialTarget; int mySize; int myFirstValue; int posX; int posY; int sizeX; int sizeY; int shapeIndex; int colorR; int colorG; int colorB; int colorA; int numParameters = 9; int numShapes = 1; int numShapeTypes = 2; int numCompetitors = 16; int currentCompetitor=0; int[] goal_chromosome = {0,55,45,50,50,100,100,100,100};// 0,57,71,50,50,100,100,100,100, 0,7,36,50,50,100,100,100,100, 0,93,36,50,50,100,100,100,100}; int[] clicks = new int[numCompetitors]; //int[] goal_chromosome = new int[36]; int currentScoreCounter=16; PrintWriter output; boolean propagating = false; boolean logging = true; boolean verboseLogging = true; void setup(){ size(800, 600); // initialise the GA with a number to pack other numbers into if (logging) output = createWriter("output.txt"); myArt = new ArtAppreciation(initialTarget); for (int i=0;i= myArt.errorThreshold) myArt.found = true; for(int i = 0; i < numShapes; i++) { int startParam = i * numParameters; if (temp.dna[startParam+0]<=50) shapeIndex = 0; else shapeIndex = 1; posX = temp.dna[startParam+1] * 7; posY = temp.dna[startParam+2] * 7; sizeX = temp.dna[startParam+3] * 2; sizeY = temp.dna[startParam+4] * 2; colorR = (int)(temp.dna[startParam+5] * 2.5); colorG = (int)(temp.dna[startParam+6] * 2.5); colorB = (int)(temp.dna[startParam+7] * 2.5); colorA = 125 + (int)(temp.dna[startParam+8] * 1.25); /* //(Uncomment this block to see the target chromosome.) shapeIndex=0; posX = 55 * 7;//400 posY = 45 * 7;//100 sizeX = 50 * 2;//100 sizeY = 50 * 2;//100 colorR = int(100 * 2.55); colorG = int(100 * 2.55); colorB = int(100 * 2.55); colorA = int(100 * 2.55); */ fill(colorR,colorG,colorB,colorA); if (shapeIndex==0) { ellipse(posX, posY, sizeX, sizeY); } else if (shapeIndex==1) { rect(posX, posY, sizeX, sizeY); } } fill(150); text("Generation: " + myArt.generation, 30, 40); //if (currentCompetitor>0) //{ //Chromosome temp2 = (Chromosome)myArt.genePool.get(currentCompetitor-1); //text("score:" + temp.score, 30, 60); loopAgain(); } void loopAgain() { currentCompetitor++; if (currentCompetitor==numCompetitors) { currentCompetitor = 0; myArt.propagate(); } } //void mousePressed() //{ // currentCompetitor++; // if (currentCompetitor==numCompetitors) // { // output.println(" "); // currentCompetitor = 0; // currentScoreCounter = numCompetitors - 1; // //myArt.sortGenePool(); // myArt.propagate(); // for (int i=0;i-1) //{ // float finalScore = 1.0 / (clicks[currentScoreCounter]+1); //currentScoreCounter--; // return finalScore; //}// else return 1.0; } //NOW, if we're just grabbing randomly, why make it so complicated? //We don't need to remove genes from the intermediate set, which wouldn't //work anyway because there are not necessarily the same number as there are in the main pool. Chromosome selection(ArrayList anyGenePool) { int geneIndex = (int)(Math.random() * anyGenePool.size()); //output.println("selecting " + geneIndex); Chromosome o = (Chromosome)anyGenePool.get(geneIndex); Chromosome c = o.copy();//HERE: CRITICAL. Have to return a COPY, not a REFERENCE, because otherwise we //end up with a bunch of pointers to the same object, and every time we mutate it all references get the same mutation. return c; } void mutateAll() { for(int i = 0; i < poolSize; i++) { Chromosome o = (Chromosome)genePool.get(i); String myLine = "Mutating " + i + " before: "; for (int j=0; j < dnaLength; j++) { myLine += o.dna[j] + " "; } if ((logging)&&(verboseLogging)) output.println(myLine); myLine = "after: "; for (int j=0; j < dnaLength; j++) { float myRandom = (float)Math.random(); if ( myRandom <= mutationRate) { if ( myRandom <= (mutationRate * totalMutateChance)) {//One quarter of the time, do a total mutate. o.dna[j] = (int)((float)Math.random() * (float)valueLength); } else {//otherwise, do an incremental mutate. float delta = (((float)Math.random() * mutationScale * valueLength) - ((mutationScale * valueLength) / 2.0)); o.dna[j] += delta; if (o.dna[j]<0.0) o.dna[j]=0; if (o.dna[j]>valueLength) o.dna[j]=valueLength; } } myLine += o.dna[j] + " "; } if ((logging)&&(verboseLogging)) output.println(myLine); } } void propagate() { propagating = true; generation++; ///The new way to do it: have your set of chromosomes, and then make another set of intermediates //between each generation. Stock the intermediates with copies of the last generation, weighted to //favor the winners. Do this by averaging all the scores, and then finding score-ofer-average for //each chromosome. When score-over-average is more than one, add one intermediate per multiple of //score-over-average. If less than one, flip a random() and if it's higher than the percentage, add one. if (logging) output.println("////////////////////////// Propagating! ////////////////////////////////////////////////////////////////"); //First, just print everything out, so we know what we're starting with. if (logging) { for(int i = 0; i < poolSize; i++) { int total = 0; int max_total = dnaLength * valueLength;//(100 times number of dna fields) String[] lines = new String[1]; Chromosome o = (Chromosome)genePool.get(i); for (int j = 0; j < dnaLength; j++) { if(o.dna[j] <= valueLength){ total += abs(goal_chromosome[j] - o.dna[j]); if (j==0) { lines[0] = abs(goal_chromosome[j] - o.dna[j]) + "\t"; } else { lines[0] += abs(goal_chromosome[j] - o.dna[j]) + "\t"; } } } lines[0] += "Total: " + total; float finalScore = (1.0 / (float)max_total) * (float)(total); lines[0] += " Score: " + (1.0 / finalScore); //lines[0] += " Score: " + o.score; output.println(lines[0]); } } if (logging) output.println(" "); //Find the average score. (Modified fitness to return positive numbers as good.) float avgScore = 0; for(int i = 0; i < poolSize; i++) { Chromosome o = (Chromosome)genePool.get(i); avgScore += o.score; } avgScore /= poolSize; float [] SOAs = new float[poolSize]; //Now find score_over_average for everybody. for (int i = 0; i < poolSize; i++) { Chromosome o = (Chromosome)genePool.get(i); SOAs[i] = o.score / avgScore; } //Now, make the set of intermediates and fill it up. ArrayList intermediateGenePool = new ArrayList(); for (int i = 0; i < poolSize; i++) { Chromosome o = (Chromosome)genePool.get(i); String myLine = "intermediates from " + i + " with SOA " + SOAs[i] + " and score " + o.score + ": "; float SOA_temp = SOAs[i]; while (SOA_temp>=1.0) { intermediateGenePool.add(o); myLine += SOA_temp + " -> 1, "; SOA_temp -= 1.0; } if (Math.random() 1."; } if ((logging)&&(verboseLogging)) output.println(myLine); } //Sanity checks... if (intermediateGenePool.size()==0) { if (logging) output.println("Something is wrong, we didn't even get one intermediate, bailing out!"); return; } else if (intermediateGenePool.size()==1) { if (logging) output.println("Had only one intermediate, had to duplicate the best one."); Chromosome o = (Chromosome)genePool.get(0);//Sorting puts them in descending order by score, and now high score Chromosome c = o.copy(); intermediateGenePool.add(c);//is best, so first one is always the best one. } else { if (logging) output.println("Intermediate set: " + intermediateGenePool.size() + " Average score: " + avgScore); } //Now, fill up the competitor gene pool from mating and mutating the intermediates. newGenePool.clear(); for(int i = poolSize; i > 0; i -= 2) { Chromosome p1 = selection(intermediateGenePool); Chromosome p2 = selection(intermediateGenePool); while (p2==p1) { p2 = selection(intermediateGenePool); }//make sure we get two different ones to mate. p1.splice(p2); //p1.mutate();//calling my own mutate function which does incremental rather than total mutations. //p2.mutate(); newGenePool.add(p1); newGenePool.add(p2); } genePool.clear(); //genePool.addAll(newGenePool);//HERE: I think this and add(o) above are just copying pointers, NOT making independent duplicates. genePool = (ArrayList)newGenePool.clone(); poolSize = genePool.size(); //Print them out now, pre-mutation, then print again after to see if that's working. if ((logging)&&(verboseLogging)) { output.println("Pre Mutation: "); for(int i = 0; i < poolSize; i++){ int total = 0; int max_total = dnaLength * valueLength;//(100 times number of dna fields) String[] lines = new String[1]; Chromosome o = (Chromosome)genePool.get(i); for (int j = 0; j < dnaLength; j++) { if(o.dna[j] <= valueLength){ total += abs(goal_chromosome[j] - o.dna[j]); if (j==0) { lines[0] = abs(goal_chromosome[j] - o.dna[j]) + "\t"; } else { lines[0] += abs(goal_chromosome[j] - o.dna[j]) + "\t"; } } } lines[0] += "Total: " + total; float finalScore = (1.0 / (float)max_total) * (float)(total); lines[0] += " Score: " + (1.0 / finalScore); output.println(lines[0]); } } mutateAll(); if ((logging)&&(verboseLogging)) { output.println("Post Mutation: "); for(int i = 0; i < poolSize; i++){ int total = 0; int max_total = dnaLength * valueLength;//(100 times number of dna fields) String[] lines = new String[1]; Chromosome o = (Chromosome)genePool.get(i); for (int j = 0; j < dnaLength; j++) { if(o.dna[j] <= valueLength){ total += abs(goal_chromosome[j] - o.dna[j]); if (j==0) { lines[0] = abs(goal_chromosome[j] - o.dna[j]) + "\t"; } else { lines[0] += abs(goal_chromosome[j] - o.dna[j]) + "\t"; } } } lines[0] += "Total: " + total; float finalScore = (1.0 / (float)max_total) * (float)(total); lines[0] += " Score: " + (1.0 / finalScore); //lines[0] += " Score: " + o.score; //output.println(lines[0]); } } propagating = false; } } //TEMP: design our target pattern /* if (i==0) { shapeIndex=0; posX = 57 * 7;//400 posY = 14 * 7;//100 sizeX = 50 * 2;//100 sizeY = 50 * 2;//100 colorR = int(100 * 2.55); colorG = int(100 * 2.55); colorB = int(100 * 2.55); colorA = int(100 * 2.55); } else if (i==1) { shapeIndex=0; posX = 57 * 7;//400 posY = 71 * 7;//500 sizeX = 50 * 2;//100 sizeY = 50 * 2;//100 colorR = int(100 * 2.55); colorG = int(100 * 2.55); colorB = int(100 * 2.55); colorA = int(100 * 2.55); } else if (i==2) { shapeIndex=1; posX = 7 * 7;//50 posY = 36 * 7;//250 sizeX = 50 * 2;//100 sizeY = 50 * 2;//100 colorR = int(100 * 2.55); colorG = int(100 * 2.55); colorB = int(100 * 2.55); colorA = int(100 * 2.55); } else if (i==3) { shapeIndex=1; posX = 93 * 7;//650 posY = 36 * 7;//250 sizeX = 50 * 2;//100 sizeY = 50 * 2;//100 colorR = int(100 * 2.55); colorG = int(100 * 2.55); colorB = int(100 * 2.55); colorA = int(100 * 2.55); }*/