1 /** 2 * Copyright: © 2012-2014 Anton Gushcha 3 * License: Subject to the terms of the MIT license, as written in the included LICENSE file. 4 * Authors: NCrashed <ncrashed@gmail.com>, 5 * LeMarwin <lemarwin42@gmail.com>, 6 * Nazgull09 <nazgull90@gmail.com> 7 */ 8 module devol.compiler; 9 10 import std.stdio; 11 import std.array; 12 import std.stream; 13 import std.conv; 14 import std.datetime; 15 import std.file; 16 import devol.singleton; 17 import core.time; 18 import core.thread; 19 20 import dyaml.all; 21 22 public 23 { 24 import devol.typemng; 25 import devol.operatormng; 26 import devol.population; 27 import devol.evolutor; 28 import devol.programtype; 29 } 30 31 interface SequentCompilation 32 { 33 final void initPop( PopAbstract pop, WorldAbstract world, ProgTypeAbstract progType ) 34 { 35 foreach( ind; pop ) 36 { 37 ind.invals = progType.initValues( world ); 38 ind.outvals = new Line[0]; 39 } 40 } 41 42 final void compilePop( PopAbstract pop, WorldAbstract world, ProgTypeAbstract progType, bool delegate() whenExit ) 43 { 44 foreach ( ind; pop ) 45 { 46 if(whenExit()) return; 47 48 foreach( line; ind.program ) 49 { 50 if(whenExit()) return; 51 line.compile(ind, world); 52 } 53 } 54 } 55 56 final void calcPopFitness( PopAbstract pop, WorldAbstract world, ProgTypeAbstract progType ) 57 { 58 uint i =0; 59 ulong summ = 0; 60 foreach( ind; pop ) 61 { 62 writeln("Individ №",i++); 63 ind.fitness = progType.getFitness(ind, world, 0); 64 summ += ind.fitness; 65 writeln("Fitness = ", ind.fitness ); 66 } 67 68 auto asumm = cast(double)summ/pop.length; 69 writeln("Average fitness = ", asumm); 70 } 71 } 72 73 interface GameCompilation 74 { 75 bool stopCond(ref int step, IndAbstract ind, WorldAbstract world); 76 void drawStep(IndAbstract ind, WorldAbstract world); 77 void drawFinal(PopAbstract pop, WorldAbstract world); 78 int roundsPerInd(); 79 80 final void initPop( PopAbstract pop, WorldAbstract world, ProgTypeAbstract progType ) 81 { 82 foreach( ind; pop ) 83 { 84 ind.invals = progType.initValues( world ); 85 ind.outvals = new Line[0]; 86 } 87 } 88 89 final void compilePop( PopAbstract pop, WorldAbstract world, ProgTypeAbstract progType 90 , bool delegate() whenExit, void delegate(double) updater , bool delegate() pauser) 91 { 92 bool continuation(double progress) 93 { 94 updater(progress); 95 if(whenExit()) return false; 96 while(pauser()) updater(progress); 97 return true; 98 } 99 100 if(!continuation(0.0)) return; 101 102 double popProgress = 0.0; 103 foreach (i, ind; pop ) 104 { 105 if(!continuation(popProgress)) return; 106 107 version(Verbose) std.stdio.writeln(ind.programString); 108 109 double indProgess = 0.0; 110 auto fitts = new double[roundsPerInd]; 111 foreach(j; 0..roundsPerInd) 112 { 113 version(Verbose)std.stdio.writeln("Round: ", j); 114 115 if(!continuation(popProgress + indProgess / cast(double) pop.length)) return; 116 117 version(Verbose)std.stdio.writeln("World initialization: "); 118 world.initialize(); 119 int step = 0; 120 121 version(Verbose) std.stdio.writeln("Individ initialization: "); 122 ind.initialize(world); 123 StopWatch sw; 124 while( !stopCond( step, ind, world ) ) 125 { 126 version(Verbose) std.stdio.writeln("Step ", step); 127 foreach( line; ind.program ) 128 { 129 version(Verbose) std.stdio.writeln("line : ", line.tostring); 130 if(whenExit()) return; 131 132 sw.start(); 133 line.compile(ind, world); 134 sw.stop(); 135 136 drawStep(ind, world); 137 } 138 139 step++; 140 } 141 version(Verbose) std.stdio.writeln("Saving fitness "); 142 fitts[j] = progType.getFitness(ind, world, 10e9*cast(double)sw.peek().hnsecs); 143 144 indProgess += 1 / cast(double) roundsPerInd; 145 } 146 147 double summ = 0; 148 foreach(val; fitts) 149 summ+=val; 150 ind.fitness = summ/fitts.length; 151 152 popProgress += 1 / cast(double)pop.length; 153 } 154 } 155 156 final void calcPopFitness( PopAbstract pop, WorldAbstract world, ProgTypeAbstract progType ) 157 { 158 uint i =0; 159 double summ = 0; 160 foreach( ind; pop ) 161 { 162 writeln("Individ №",i++); 163 summ += ind.fitness; 164 writeln("Fitness = ", ind.fitness ); 165 } 166 167 drawFinal(pop, world); 168 auto asumm = summ/ cast(double)pop.length; 169 writeln("Average fitness = ", asumm); 170 } 171 } 172 173 class Compiler( 174 CompStg = SequentCompilation, 175 EvolutorStg = Evolutor, 176 ProgType, 177 PopType, 178 WorldType) 179 if( __traits(compiles, "PopAbstract pop = new PopType()") ) 180 : Singleton!Compiler 181 { 182 public: 183 184 this(CompStg compStrategy) 185 { 186 compStg = compStrategy; 187 evolutor = new EvolutorStg(); 188 pops = []; 189 world = new WorldType(); 190 progtype = new ProgType(); 191 } 192 193 this(CompStg compStrategy, ProgType progtype) 194 { 195 compStg = compStrategy; 196 evolutor = new EvolutorStg(); 197 pops = []; 198 world = new WorldType(); 199 this.progtype = progtype; 200 } 201 202 this(CompStg compStrategy, ProgType progtype, WorldType world) 203 { 204 compStg = compStrategy; 205 evolutor = new EvolutorStg(); 206 pops = []; 207 this.world = world; 208 this.progtype = progtype; 209 } 210 211 this(CompStg compStrategy, ProgType progtype, WorldType world, EvolutorStg evolutor) 212 { 213 compStg = compStrategy; 214 this.evolutor = evolutor; 215 pops = []; 216 this.world = world; 217 this.progtype = progtype; 218 } 219 220 PopType addPop(PopType pop) 221 { 222 if (pop is null || !checkPop(pop)) return null; 223 224 pops ~= pop; 225 return pop; 226 } 227 228 void clean() 229 { 230 pops = []; 231 } 232 233 PopType getPop(size_t i) 234 { 235 return pops[i]; 236 } 237 238 PopType addPop(size_t size, string name="") 239 { 240 auto pop = new PopType(size); 241 242 if (name.empty) 243 pop.genName(); 244 else 245 pop.name = name; 246 247 248 foreach(ind; pop) 249 { 250 evolutor.generateInitProgram(ind, progtype); 251 } 252 253 debug writeln("Created population ", pop.name, " size of ", size); 254 255 pops ~= pop; 256 return pop; 257 } 258 259 void envolveGeneration(bool delegate() whenExit, string saveFolder, 260 void delegate(double) updater , bool delegate() pauser) 261 { 262 bool continuation(double progress) 263 { 264 updater(progress); 265 if(whenExit()) return false; 266 while(pauser()) updater(progress); 267 return true; 268 } 269 270 foreach(i, ref pop; pops ) 271 { 272 double progressPart = (i+1) / cast(double) pops.length; 273 274 writeln("Pop init"); 275 compStg.initPop( pop, world, progtype ); 276 if(!continuation(1.0 / 10.0 * progressPart)) return; 277 278 writeln("Pop compile"); 279 compStg.compilePop( pop, world, progtype, whenExit 280 , (val) 281 { 282 updater(1.0 / 10.0 * progressPart + 7.0 * val / 10.0 * progressPart ); 283 } 284 , pauser); 285 if(!continuation(8.0 / 10.0 * progressPart)) return; 286 287 writeln("GENERATION №", pop.generation, " results:"); 288 compStg.calcPopFitness( pop, world, progtype ); 289 if(!continuation(9.0 / 10.0 * progressPart)) return; 290 291 scope(exit) 292 { 293 if(!saveFolder.exists) 294 mkdirRecurse(saveFolder); 295 296 pop.saveBests(text(saveFolder, "/bests/")); 297 pop.saveAll(text(saveFolder, "/all/")); 298 299 Dumper(text(saveFolder, "/population_", pop.generation, ".yaml")).dump(pop.saveYaml); 300 } 301 302 pop = evolutor.formNextPopulation( pop, progtype ); 303 pop.generation = pop.generation + 1; 304 if(!continuation(progressPart)) return; 305 } 306 } 307 308 PopType loadPopulation(string filename) 309 { 310 auto node = Loader(filename).load(); 311 312 PopType pop = cast(PopType)PopType.loadYaml(node); 313 assert(pop !is null); 314 pops ~= pop; 315 316 return pop; 317 } 318 319 320 protected: 321 322 CompStg compStg; 323 PopType[] pops; 324 WorldAbstract world; 325 ProgTypeAbstract progtype; 326 EvolutorStg evolutor; 327 328 bool checkPop(PopAbstract pop) 329 { 330 foreach(p; pops) 331 { 332 if (p == pop) return false; 333 } 334 return true; 335 } 336 337 }