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 }