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.population; 9 10 import std.stdio; 11 12 import std.random; 13 import std..string; 14 import std.array; 15 import std.algorithm; 16 import std.conv; 17 import std.file; 18 import std.path; 19 import devol.serializable; 20 import dyaml.all; 21 22 public 23 { 24 import devol.individ; 25 } 26 27 interface PopAbstract : ISerializable 28 { 29 void genName(size_t size); 30 @property string name(); 31 @property void name(string val); 32 @property size_t generation(); 33 @property void generation(size_t val); 34 @property size_t length(); 35 IndAbstract opIndex( size_t i ); 36 IndAbstract[] opSlice( size_t a, size_t b ); 37 size_t opDollar(); 38 int opApply(int delegate(IndAbstract) dg); 39 int opApply(int delegate(size_t, IndAbstract) dg); 40 Node saveYaml(); 41 } 42 43 static string getDefChars() 44 { 45 string ret = "qwertyuiopasdfghjklzxcvbnm"; 46 return ret ~ toUpper(ret); 47 } 48 49 alias Population!(getDefChars, Individ) StdPop; 50 51 class Population(alias nameChecker, IndType) 52 if ( is(typeof(nameChecker()) == string) ) 53 : PopAbstract 54 { 55 enum DefNameLength = 10; 56 enum DefNameChars = getDefChars(); 57 58 alias Population!(nameChecker, IndType) thistype; 59 alias IndType IndividType; 60 61 @property size_t generation() 62 { 63 return iGeneration; 64 } 65 66 @property void generation(size_t val) 67 { 68 //if (val < iGeneration) return; 69 iGeneration = val; 70 } 71 72 this() 73 { 74 inds = new IndType[0]; 75 } 76 77 this(size_t size) 78 { 79 inds = new IndType[size]; 80 foreach( ref ind; inds) 81 { 82 ind = new IndType; 83 } 84 } 85 86 void genName(size_t size = DefNameLength) 87 { 88 auto buff = new char[size]; 89 string chars = nameChecker(); 90 foreach(ref c; buff) 91 { 92 c = chars[uniform(0,chars.length)]; 93 } 94 mName = buff.idup; 95 } 96 97 @property string name() 98 { 99 return mName; 100 } 101 102 @property void name(string val) 103 { 104 string chars = nameChecker(); 105 foreach(i,c; val) 106 { 107 if ( chars.find(c).empty ) 108 { 109 val = val[0..i] ~ chars[uniform(0,chars.length)] ~ val[i+1..$]; 110 } 111 } 112 mName = val; 113 } 114 115 @property size_t length() 116 { 117 return inds.length; 118 } 119 120 IndType opIndex( size_t i ) 121 { 122 return cast(IndType)inds[i]; 123 } 124 125 IndAbstract[] opSlice( size_t a, size_t b ) 126 { 127 return cast(IndAbstract[])(inds[a..b]); 128 } 129 130 size_t opDollar() 131 { 132 return inds.length; 133 } 134 135 int opApply(int delegate(IndAbstract) dg) 136 { 137 int result = 0; 138 139 foreach(i, ref ind; inds) 140 { 141 IndAbstract inda = (ind); 142 result = dg(inda); 143 if (result) break; 144 } 145 return result; 146 } 147 148 int opApply(int delegate(size_t, IndAbstract) dg) 149 { 150 int result = 0; 151 152 foreach(i, ref ind; inds) 153 { 154 IndAbstract inda = (ind); 155 result = dg(i, inda); 156 if (result) break; 157 } 158 return result; 159 } 160 161 auto opBinary(string m)(IndType val) 162 if (m == "~") 163 { 164 inds ~= val; 165 return this; 166 } 167 168 void addIndivid(IndType val) 169 { 170 if (val is null) return; 171 inds ~= val; 172 } 173 174 void saveBests(string filename) 175 { 176 if (inds.length == 0) return; 177 178 auto sortedInds = inds.sort!"a.fitness > b.fitness"; 179 180 Individ best; 181 int k = 0; 182 183 std.stdio.File* f; 184 try 185 { 186 mkdirRecurse(filename); 187 188 f = new std.stdio.File(filename~mName~"_g"~to!string(iGeneration), "w"); 189 190 do 191 { 192 best = sortedInds[k++]; 193 f.writeln("Individ №", k,":"); 194 f.writeln(best.programString()); 195 f.writeln("=================================="); 196 } while( k < sortedInds.length && sortedInds[k].fitness >= best.fitness); 197 } catch(Exception e) 198 { 199 writeln("FAILED TO CREATE FILE TO WRITE RESULTED INDIVIDS!!"); 200 } 201 } 202 203 void saveAll(string filename) 204 { 205 std.stdio.File* f; 206 try 207 { 208 mkdirRecurse(filename); 209 210 f = new std.stdio.File(filename~mName~"_g"~to!string(iGeneration), "w"); 211 212 foreach(i,ind;inds) 213 { 214 f.writeln("Individ №", i,":"); 215 f.writeln(ind.programString()); 216 f.writeln("=================================="); 217 } 218 } catch(Exception e) 219 { 220 writeln("FAILED TO CREATE FILE TO WRITE RESULTED INDIVIDS!!"); 221 } 222 } 223 224 @property auto dup() 225 { 226 auto ret = new Population!(nameChecker, IndType); 227 ret.iGeneration = iGeneration; 228 foreach(ind;inds) 229 ret.inds ~= ind.dup; 230 ret.mName = mName; 231 return ret; 232 } 233 234 void clear() 235 { 236 inds.clear(); 237 } 238 239 void saveBinary(OutputStream stream) 240 { 241 stream.write(mName); 242 stream.write(iGeneration); 243 244 stream.write(cast(ulong)inds.length); 245 foreach(ind; inds) 246 { 247 ind.saveBinary(stream); 248 } 249 } 250 251 Node saveYaml() 252 { 253 auto builder = appender!(Node[]); 254 foreach(ind; inds) 255 { 256 builder.put(ind.saveYaml); 257 } 258 259 return Node([ 260 "name": Node(mName), 261 "generation": Node(iGeneration), 262 "individs": Node(builder.data) 263 ]); 264 } 265 266 static thistype loadBinary(InputStream stream) 267 { 268 auto pop = new thistype(); 269 char[] popName; 270 stream.read(popName); 271 pop.mName = popName.idup; 272 273 stream.read(pop.iGeneration); 274 275 ulong indsLength; 276 stream.read(indsLength); 277 auto builder = appender!(IndType[]); 278 foreach(i; 0..cast(size_t)indsLength) 279 { 280 auto ind = IndType.loadBinary(stream); 281 282 if(ind is null) 283 { 284 throw new Exception("Loaded ind is null!"); 285 } 286 287 builder.put(new IndType(ind)); 288 } 289 pop.inds = builder.data; 290 291 return pop; 292 } 293 294 static thistype loadYaml(Node node) 295 { 296 auto ret = new thistype(); 297 298 ret.mName = node["name"].as!string; 299 ret.iGeneration = node["generation"].as!size_t; 300 301 auto builder = appender!(IndType[]); 302 foreach(Node subnode; node["individs"]) 303 { 304 builder.put(IndType.loadYaml(subnode)); 305 } 306 307 ret.inds = builder.data; 308 309 return ret; 310 } 311 312 protected 313 { 314 size_t iGeneration; 315 IndType[] inds; 316 string mName = ""; 317 } 318 }