private void removeStaleSpecies() { //REMOVE STALE SPECIES List <newSpecies> survived = new List <newSpecies>(); for (int i = 0; i < Pool.species.Count; i++) { newSpecies species = Pool.species[i]; species.genomes.Sort(); //(species.genomes, function(a, b) return (a.fitness > b.fitness) end); species.genomes.Reverse(); //A.FITNESS > B.FITNESS if (species.genomes[0].fitness > species.topFitness) { species.topFitness = species.genomes[0].fitness; species.staleness = 0; } else { species.staleness = species.staleness + 1; } if (species.staleness < StaleSpecies || species.topFitness >= Pool.maxFitness) { survived.Add(species); } } //TRANSFER TO POOL NetMain.setConsoleInvoke("Generation complete:\t" + (Pool.species.Count - survived.Count) + " species removed\t" + survived.Count + " survived"); Pool.species = survived; }
private void cullSpecies(bool cutToOne) { //CULL SPECIES (AUSSORTIEREN) int removed = 0; for (int i = 0; i < Pool.species.Count; i++) { newSpecies species = Pool.species[i]; species.genomes.Sort(); //table.sort(species.genomes, function(a, b) return (a.fitness > b.fitness) end) species.genomes.Reverse(); //A.FITNESS > B.FITNESS double remaining = Math.Ceiling((double)species.genomes.Count / 2); //HALF GENOME SIZE if (cutToOne) { remaining = 1; //SIZE ONE } while (species.genomes.Count > remaining) { species.genomes.Remove(species.genomes[species.genomes.Count - 1]); //DELETE LAST ITEM removed++; } } //CONSOLE FEEDBACK NetMain.setConsoleInvoke("Cull species:\t" + removed + " genomes removed from " + Pool.species.Count + " species (cut to one = " + cutToOne + ")"); }
private bool fitnessAlreadyMeasured() { //FITNESS ALREADY MEASURED newSpecies species = Pool.species[Pool.currentSpecies]; newGenome genome = species.genomes[Pool.currentGenome]; return(genome.fitness != 0); }
private void initializeRun() { //INITIALIZE RUN Score = 0; clearJoypad(); newSpecies species = Pool.species[Pool.currentSpecies]; newGenome genome = species.genomes[Pool.currentGenome]; generateNetwork network = new generateNetwork(genome); evaluateCurrent(); }
private double totalAverageFitness() { //TOTAL AVERAGE FITNESS double total = 0; for (int i = 0; i < Pool.species.Count; i++) { newSpecies species = Pool.species[i]; total = total + species.averageFitness; } return(total); }
private void calculateAverageFitness(newSpecies species) { //CALCULATE AVERAGE FITNESS double total = 0; for (int i = 0; i < species.genomes.Count; i++) { newGenome genome = species.genomes[i]; total = total + genome.globalRank; } //SET SPECIES FITNESS species.averageFitness = total / species.genomes.Count; }
private void newGeneration() { //NEW GENERATION cullSpecies(false); //CULL THE BOTTOM HALF OF EACH SPECIES rankGlobally(); removeStaleSpecies(); rankGlobally(); for (int i = 0; i < Pool.species.Count; i++) { newSpecies species = Pool.species[i]; calculateAverageFitness(species); } //REMOVE WEAK SPECIES removeWeakSpecies(); double sum = totalAverageFitness(); List <newGenome> children = new List <newGenome>(); for (int i = 0; i < Pool.species.Count; i++) { newSpecies species = Pool.species[i]; double breed = Math.Floor(species.averageFitness / sum * Population) - 1; for (double d = 0; d < breed; d++) //DOUBLE LOOP { children.Add(breedChild(species)); } } cullSpecies(true); //CULL ALL BUT THE TOP MEMBER OF EACH SPECIES while (children.Count + Pool.species.Count < Population) { newSpecies species = Pool.species[Random(0, Pool.species.Count - 1)]; children.Add(breedChild(species)); } for (int i = 0; i < children.Count; i++) { newGenome child = children[i]; addToSpecies(child); } //RAISE POOL GENERATION Pool.generation = Pool.generation + 1; //GENERATE BACKUP FILE //writeFile("backup."..pool.generation.. "."..forms.gettext(saveLoadFile)) }
private void evaluateCurrent() { //ABBRUCH if (!NetMain.Cam.Visible) { return; } //EVALUATE CURRENT newSpecies species = Pool.species[Pool.currentSpecies]; newGenome genome = species.genomes[Pool.currentGenome]; List <double> inputs = Mod_Convert.ArrayToList <double>(NetMain.Cam.getDoubleArray()); //READ INPUTS FROM CAM Controller = genome.network.evaluateNetwork(inputs); //GET OUTPUTS }
private void removeWeakSpecies() { //REMOVE WEAK SPECIES List <newSpecies> survived = new List <newSpecies>(); double sum = totalAverageFitness(); for (int i = 0; i < Pool.species.Count; i++) { newSpecies species = Pool.species[i]; double breed = Math.Floor(species.averageFitness / sum * Population); if (breed >= 1) { survived.Add(species); } } //TRANSFER TO POOL NetMain.setConsoleInvoke("Weak species:\t" + (Pool.species.Count - survived.Count) + " removed\t" + survived.Count + " survived"); Pool.species = survived; }
private newGenome breedChild(newSpecies species) { //BREED CHILD newGenome child; if (Random() < CrossoverChance) { newGenome g1 = species.genomes[Random(0, species.genomes.Count - 1)]; newGenome g2 = species.genomes[Random(0, species.genomes.Count - 1)]; child = crossover(g1, g2); } else { newGenome g = species.genomes[Random(0, species.genomes.Count - 1)]; child = g.copyGenome(); } //MUTATE CHILD mutate(child); return(child); }
private void rankGlobally() { List <newGenome> global = new List <newGenome>(); for (int j = 0; j < Pool.species.Count; j++) { newSpecies species = Pool.species[j]; for (int i = 0; i < species.genomes.Count; i++) { global.Add(species.genomes[i]); } } //SORT BY FITNESS global.Sort(); //function(a, b) return (a.fitness < b.fitness) end) //SET GLOBAL RANK for (int i = 0; i < global.Count; i++) { global[i].globalRank = i; } }
private void addToSpecies(newGenome child) { //ADD TO SPECIES bool foundSpecies = false; //LOOP AND SEARCH POOL SPECIES for (int i = 0; i < Pool.species.Count; i++) { newSpecies species = Pool.species[i]; if (!foundSpecies && sameSpecies(child, species.genomes[0])) { species.genomes.Add(child); foundSpecies = true; } } //SPECIES NOT FOUND if (!foundSpecies) { newSpecies childSpecies = new newSpecies(); childSpecies.genomes.Add(child); Pool.species.Add(childSpecies); } }
public void Plot(Graphics g) { Pool = Main.Mario.Pool; //ABBRUCH if (Pool == null) { return; } //RECALCULATE NEUROEVOLUTION RecalculateNeuroevolution(Pool); //GET SPCIES LIST List <newSpecies> spciesList = Pool.species; for (int i = 0; i < spciesList.Count; i++) { float width = PanelLeft[2] + getScoreWidth(spciesList[i].topFitness); float average = PanelLeft[2] + getScoreWidth(spciesList[i].averageFitness); float height = PanelTop[0] + i * PenPositive.Width; //DRAW NUMBER g.DrawString((i + 1) + ".", Mod_Convert.FontSize(Fonts.MainFont, PenText.Width), PenText.Brush, new PointF(PanelLeft[1], height - PenPositive.Width / 2)); //DRAW SCORE if (Mod_Check.isEven(i)) { g.DrawLine(PenNegative, new PointF(PanelLeft[2], height), new PointF(width, height)); } else { g.DrawLine(PenPositive, new PointF(PanelLeft[2], height), new PointF(width, height)); } //DRAW STALE for (int l = 0; l < Pool.species[i].staleness; l++) { g.FillEllipse(new SolidBrush(Colors.MainLight), PanelLeft[2] + 1f + l * PenPositive.Width, height, PenPositive.Width / 2, PenPositive.Width / 2); } //DRAW AVERAGE g.DrawLine(new Pen(Colors.MainDominant, 1), new PointF(average, height), new PointF(average, height + PenPositive.Width / 2)); } //INFORMATIONS newSpecies currSpecies = Pool.species[Pool.currentSpecies]; //GET CURRENT SPECIES newGenome currGenome = currSpecies.genomes[Pool.currentGenome]; //GET CURRENT GENOME float left = PanelLeft[0]; Font infoFont = Mod_Convert.FontSize(Fonts.MainFont, 9); g.DrawString("Generation:", infoFont, PenNegative.Brush, new PointF(left, PanelTop[1])); g.DrawString(Pool.generation.ToString(), infoFont, PenText.Brush, new PointF(left, PanelTop[2])); left += PanelLeft[0] * 2.5f; g.DrawString("Species:", infoFont, PenNegative.Brush, new PointF(left, PanelTop[1])); g.DrawString((Pool.currentSpecies + 1) + "/" + Pool.species.Count, infoFont, PenText.Brush, new PointF(left, PanelTop[2])); left += PanelLeft[0] * 2.5f; g.DrawString("Genome:", infoFont, PenNegative.Brush, new PointF(left, PanelTop[1])); g.DrawString((Pool.currentGenome + 1) + "/" + currSpecies.genomes.Count, infoFont, PenText.Brush, new PointF(left, PanelTop[2])); left += PanelLeft[0] * 2.5f; g.DrawString("Stale:", infoFont, PenNegative.Brush, new PointF(left, PanelTop[1])); g.DrawString(currSpecies.staleness + "/" + (NetMario.StaleSpecies - 1), infoFont, PenText.Brush, new PointF(left, PanelTop[2])); left += PanelLeft[0] * 2.5f; g.DrawString("Fitness:", infoFont, PenNegative.Brush, new PointF(left, PanelTop[1])); g.DrawString(currGenome.fitness + " (" + Pool.maxFitness + ", " + currSpecies.averageFitness + ")", infoFont, PenText.Brush, new PointF(left, PanelTop[2])); left += PanelLeft[0] * 2.5f; g.DrawString("Measure:", infoFont, PenNegative.Brush, new PointF(left, PanelTop[1])); g.DrawString(Pool.measured + " %", infoFont, PenText.Brush, new PointF(left, PanelTop[2])); }
public void Load() { //LOAD string[] path = Mod_File.FileOpenDialog(false, FILTER.TXT); //ABBRUCH if (path == null) { return; } //START LOADING UniLoad.loadingStart(); //READ TXT FILE string[] file = Mod_TXT.readTXT(path[0]); int x = 0; //GET DURATION Duration = TimeSpan.FromMilliseconds(Mod_Convert.StringToDouble(file[x++])); //GET OUTPUT KEYS OutputKeys = file[x++].Split(' '); //INITIALIZE POOL Initialize(OutputKeys, true); Pool.generation = Mod_Convert.StringToInteger(file[x++]); Pool.maxFitness = Mod_Convert.StringToDouble(file[x++]); int numSpecies = Mod_Convert.StringToInteger(file[x++]); for (int j = 0; j < numSpecies; j++) //SPECIES { newSpecies species = new newSpecies(); Pool.species.Add(species); species.topFitness = Mod_Convert.StringToDouble(file[x++]); species.staleness = Mod_Convert.StringToInteger(file[x++]); int numGenomes = Mod_Convert.StringToInteger(file[x++]); for (int i = 0; i < numGenomes; i++) //GENOME { newGenome genome = new newGenome(); species.genomes.Add(genome); genome.fitness = Mod_Convert.StringToDouble(file[x++]); genome.maxneuron = Mod_Convert.StringToInteger(file[x++]); string line = file[x++]; while (line != "done") { genome.mutationRates[line] = Mod_Convert.StringToDouble(file[x++]); line = file[x++]; } int numGenes = Mod_Convert.StringToInteger(file[x++]); for (int k = 0; k < numGenes; k++) //GENE { newGene gene = new newGene(); genome.genes.Add(gene); string[] split = file[x++].Split(' '); gene.into = Mod_Convert.StringToInteger(split[0]); gene.output = Mod_Convert.StringToInteger(split[1]); gene.weight = Mod_Convert.StringToDouble(split[2]); gene.innovation = Mod_Convert.StringToInteger(split[3]); gene.enabled = Mod_Convert.ObjectToBool(split[4]); } } } //FITNESS ALREADY MEASURED while (fitnessAlreadyMeasured()) { nextGenome(); } initializeRun(); //UPDATE LEARN PANEL NetMain.RoundFinished(0); //END LOADING UniLoad.loadingEnd(); }
public void LearningRun() { //LEARNING RUN if (!Learning) { Status = "stopped"; return; } //GET SCORE Score = NetMain.Cam.Score; //SCORE = TIME -> T-REX RUNNING //RESET GAME if (Reset) { NetMain.Cam.eventResetGame(); Wait = true; Status = "reset"; } if (Wait) { if (NetMain.Cam.Alive) { Reset = Wait = false; StartRun = DateTime.Now; } else { return; } } Status = "alive"; //GET CURRENT SPECIES & GENOME newSpecies species = Pool.species[Pool.currentSpecies]; newGenome genome = species.genomes[Pool.currentGenome]; //CONVERT INPUTS TO OUTPUTS evaluateCurrent(); //EXECUTE OUTPUTS foreach (string key in Controller.Keys.ToList()) { if (Controller[key]) { NetMain.Cam.eventGlobalSendKeys(Array.IndexOf(Controller.Keys.ToArray(), key)); //SENDKEYS } else { NetMain.Cam.eventGlobalSendKeys(int.MinValue); } } //CHECK IS ALIVE if (!NetMain.Cam.Alive && !Reset) { double fitness = Score; if (Score > 500) //INPUT BONUS SCORE { fitness = fitness + 200; } if (fitness == 0) { fitness = -1; } genome.fitness = fitness; //MAKE BACKUP IF HIGHSCORE REACHED if (fitness > Pool.maxFitness) { Pool.maxFitness = fitness; Console.WriteLine("Max Fitness: " + Math.Floor(Pool.maxFitness)); Console.WriteLine("backup." + Pool.generation + "."); } Pool.currentSpecies = 0; //ZERO START Pool.currentGenome = 0; //ZERO START while (fitnessAlreadyMeasured()) { Status = "next genome"; nextGenome(); } Status = "dead"; //FEEDBACK int currSpecies = Pool.currentSpecies + 1; int currGenome = Pool.currentGenome + 1; //LEARN PANEL CALLBACK FUNCTION NetMain.RoundFinished(Score); //INITIALIZE RUN initializeRun(); double measured = 0; double total = 0; foreach (newSpecies spec in Pool.species) { foreach (newGenome gen in spec.genomes) { total = total + 1; if (gen.fitness != 0) { measured = measured + 1; } Status = "measure"; } } //CONSOLE FEEDBACK Pool.measured = Math.Floor(measured / total * 100); DurationRun = StartRun - DateTime.Now; NetMain.setConsoleInvoke("Round finished!\tDuration: " + DurationRun.ToString(@"mm\:ss") + "\tGeneration: " + Pool.generation + "\tSpecies: " + currSpecies + "\tStale: " + Pool.species[Pool.currentSpecies].staleness + "\tGenome: " + currGenome + "\tFitness: " + fitness + "\tMeasured: " + Pool.measured + "%"); //RESET GAME Reset = true; } }