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.evolutor; 9 10 import std.random; 11 import std.stdio; 12 import std.array; 13 import std.math; 14 import std.conv; 15 import std.array; 16 import std.algorithm; 17 import devol.typemng; 18 import devol.operatormng; 19 import devol.std.random; 20 import devol.population; 21 22 /// Статистический тест случайного выбора элемента 23 enum RANDOM_ELEM_STAT_TEST = 0; 24 /// Статистический тест случайного выбора листа 25 enum RANDOM_LEAF_STAT_TEST = 0; 26 /// Тест замены случайного элемента 27 enum RANDOM_ELEM_REPLACE_TEST = 0; 28 /// Тест обмена случайными элементами 29 enum RANDOM_ELEM_SWAP_TEST = 0; 30 /// Тест мутации 31 enum MUTATION_TEST = 0; 32 /// Тест кроссинговера 33 enum CROSSINGOVER_TEST = 0; 34 35 public 36 { 37 import devol.std.typepod; 38 import devol.programtype; 39 } 40 41 class Evolutor 42 { 43 class GenExeption : Exception 44 { 45 ErrorType error; 46 Type t; 47 48 enum ErrorType 49 { 50 SEARCH_OPERATOR 51 } 52 53 this(string s, ErrorType errt, Type et) 54 { 55 super(s); 56 error = errt; 57 t = et; 58 } 59 } 60 61 static int MaxProgramDepth = 30; 62 63 static bool getChance(float val) 64 { 65 return uniform!"[]"(0.0,1.0) <= val; 66 } 67 68 void generateInitProgram(IndAbstract pInd, ProgTypeAbstract ptype) 69 { 70 Line[] buff = new Line[0]; 71 foreach(i; 0..uniform!("[]")(ptype.progMinSize,ptype.progMaxSize)) 72 { 73 buff ~= generateLine( pInd, ptype ); 74 } 75 pInd.program = buff; 76 } 77 78 /// Генерация линии 79 Line generateLine( IndAbstract pInd, ProgTypeAbstract ptype ) 80 { 81 auto line = new Line(); 82 auto opmng = OperatorMng.getSingleton(); 83 auto tmng = TypeMng.getSingleton(); 84 auto scopetype = cast(TypeScope)(tmng.getType("TypeScope")); 85 auto voidtype = cast(TypeVoid)(tmng.getType("TypeVoid")); 86 87 auto op = opmng.getRndOperator(); 88 if (op is null) return line; 89 90 line.operator = op; 91 92 uint i = 0; 93 foreach( j,arg; line ) 94 { 95 if (arg.type.name == voidtype.name && getChance(ptype.newScopeGenChance)) 96 { 97 auto ascope = scopetype.getNewArg(); 98 uint s = uniform!"[]"(ptype.scopeMinSize, ptype.scopeMaxSize); 99 scope(success) line[j] = ascope; 100 101 writeln("Generating scope"); 102 foreach(i; 0..s) 103 { 104 try 105 { 106 ascope.addElement( generateLine( pInd, ptype, voidtype ) ); 107 } catch( GenExeption e) 108 { 109 if (e.error == e.ErrorType.SEARCH_OPERATOR) 110 debug writeln("Note: cannot find operator for type ", e.t.name); 111 } 112 } 113 } else if (getChance(ptype.newOpGenChance) 114 || (op.style == ArgsStyle.CONTROL_STYLE && i != 0) ) 115 { 116 auto aline = new Line; 117 scope(success) line[j] = aline; 118 try 119 { 120 aline = generateLine( pInd, ptype, arg.type ); 121 } catch( GenExeption e) 122 { 123 if (e.error == e.ErrorType.SEARCH_OPERATOR) 124 debug writeln("Note: cannot find operator for type ", e.t.name); 125 126 } 127 } 128 129 i++; 130 } 131 132 return line; 133 } 134 135 /// Генерация типизированной линии 136 Line generateLine( IndAbstract pInd, ProgTypeAbstract ptype, 137 Type rtype, uint depth = 0) 138 { 139 auto line = new Line(); 140 auto opmng = OperatorMng.getSingleton(); 141 auto tmng = TypeMng.getSingleton(); 142 auto scopetype = cast(TypeScope)(tmng.getType("TypeScope")); 143 auto voidtype = cast(TypeVoid)(tmng.getType("TypeVoid")); 144 145 Operator op; 146 if ( cast(TypeLine)rtype is null && cast(TypeScope)rtype is null ) 147 { 148 op = opmng.getRndOperator(rtype); 149 if (op is null) 150 { 151 throw new Evolutor.GenExeption( 152 "Cannot choose operator for type " ~ rtype.name, 153 GenExeption.ErrorType.SEARCH_OPERATOR, 154 rtype 155 ); 156 } 157 } else 158 { 159 debug writeln("Type is container, generating any op."); 160 op = opmng.getRndOperator(); 161 if (op is null) 162 { 163 throw new Evolutor.GenExeption( 164 "Cannot choose operator for any type! May be there aren't any one?", 165 GenExeption.ErrorType.SEARCH_OPERATOR, 166 rtype 167 ); 168 } 169 } 170 171 line.operator = op; 172 173 if (depth >= MaxProgramDepth) return line; 174 175 uint i = 0; 176 foreach( i,arg; line ) 177 { 178 if (arg.type.name == voidtype.name && getChance(ptype.newScopeGenChance)) 179 { 180 auto ascope = scopetype.getNewArg(); 181 uint s = uniform!"[]"(ptype.scopeMinSize, ptype.scopeMaxSize); 182 183 foreach(j; 0..s) 184 { 185 ascope.addElement( generateLine( pInd, ptype, voidtype, depth+1 ) ); 186 } 187 line[i] = ascope; 188 } else if (getChance(ptype.newOpGenChance) 189 || (op.style == ArgsStyle.CONTROL_STYLE && i != 0) ) 190 { 191 auto aline = new Line; 192 aline = generateLine( pInd, ptype, arg.type, 193 depth+1 ); 194 line[i] = aline; 195 } 196 i++; 197 } 198 return line; 199 } 200 201 /// Получение случайного элемента дерева. Равномерное распределение. 202 /** 203 * Вероятности выбрать любой элемент дерева будет равные. Данный метод 204 * не подойдет, если нужно заменить элемента дерева. 205 * @param cont Узел дерева, в котором нужно выбрать. 206 * @see replaceRandomElementStd 207 */ 208 Argument getRandomElementStd(Container cont) 209 { 210 auto chances = new double[0]; 211 Argument ret = null; 212 213 do 214 { 215 ulong childs = cont.children; 216 217 chances ~= 1./childs; 218 foreach( arg; cont ) 219 { 220 chances ~= cast(double)arg.children/cast(double)childs; 221 } 222 223 randomRange!( 224 (int k) 225 { 226 if (k==0) 227 ret = cont; 228 else 229 if (cast(Container)(cont[k-1]) is null) 230 ret = cont[k-1]; 231 else 232 cont = cast(Container)(cont[k-1]); 233 } 234 )(chances); 235 236 chances.clear(); 237 } while(ret is null); 238 239 return ret; 240 } 241 242 /// Замена случайного элемента дерева. Равномерное распределение. 243 /** 244 * Вероятности заменить любой элемент дерева будет равные. 245 * @note Данный метод не подходит для замены самого первого переданного узла, его 246 * замену реализует пользователь этого метода отдельно. 247 * @param cont Узел дерева, в котором нужно заменить. 248 * @param generator Делегат-генератор, делегат, который создаст типизированный аргумент. 249 */ 250 void replaceRandomElementStd(Container cont, Argument delegate(Type) generator) 251 { 252 auto chances = new double[0]; 253 bool end = false; 254 Container prevCont = null; 255 uint prevContI = -1; 256 257 do 258 { 259 ulong childs = cont.children; 260 261 chances ~= 1./childs; 262 foreach( arg; cont ) 263 { 264 chances ~= cast(double)arg.children/cast(double)childs; 265 } 266 267 randomRange!( 268 (int k) 269 { 270 if (k==0) 271 { 272 if (prevCont !is null) 273 { 274 Type t; 275 if (cast(Line)(prevCont[prevContI]) !is null) 276 { 277 auto line = cast(Line)(prevCont[prevContI]); 278 t = line.operator.rtype; 279 } 280 else if (cast(ArgScope)(prevCont[prevContI]) !is null) 281 t = new TypeVoid; 282 prevCont[prevContI] = generator(t); 283 } 284 end = true; 285 } 286 else 287 if (cast(Container)(cont[k-1]) is null) 288 { 289 cont[k-1] = generator(cont[k-1].type); 290 end = true; 291 } 292 else 293 { 294 prevCont = cont; 295 prevContI = k-1; 296 cont = cast(Container)(cont[k-1]); 297 } 298 } 299 )(chances); 300 301 chances.clear(); 302 } while(!end); 303 } 304 305 /// Получение случайного листа по равномерному распределению 306 /** 307 * Вероятность выбрать любой лист дерева будет одинаковой. 308 */ 309 Argument getRandomLeafStd(Container cont) 310 { 311 bool normalize( ref double[] mass ) 312 { 313 if (mass.length == 0) return false; 314 315 double summ = 0; 316 foreach( val; mass) 317 summ += val; 318 319 if (summ == 0) 320 return false; 321 322 foreach( ref val; mass) 323 val /= summ; 324 return true; 325 } 326 327 auto chances = new double[0]; 328 Argument ret = null; 329 330 do 331 { 332 ulong leafs = cont.leafs; 333 334 foreach( arg; cont ) 335 { 336 chances ~= cast(double)arg.leafs/cast(double)leafs; 337 } 338 if (!normalize(chances)) 339 { 340 return null; 341 } 342 debug writeln("Распределение вероятностей по листам: ", chances); 343 344 randomRange!( 345 (int k) 346 { 347 if (cast(Container)(cont[k]) is null) 348 ret = cont[k]; 349 else 350 cont = cast(Container)(cont[k]); 351 } 352 )(chances); 353 354 chances.clear(); 355 } while(ret is null); 356 357 return ret; 358 } 359 360 /// Обмен элементами между деревьями 361 /** 362 * Выбирается поддерево из каждого контейнера и меняются местами. Выбор 363 * идет на основе равномерного распределения. 364 * @param cont1 Первый контейнер 365 * @param cont2 Второй контейнер 366 * @note Обмен корневыми элементами невозможен в рамках данного метода, 367 * его реализацей занимайтесь сами. 368 */ 369 bool swapRandomElements(Container cont1, Container cont2, ProgTypeAbstract ptype) 370 { 371 bool validType(Argument a, Argument b) 372 { 373 if (cast(ArgScope)a !is null && cast(ArgScope)b !is null) 374 return true; 375 else if (cast(Line)a !is null && cast(ArgScope)b !is null) 376 return (cast(Line)a).operator.rtype.name == "TypeVoid"; 377 else if (cast(Line)b !is null && cast(ArgScope)a !is null) 378 return (cast(Line)b).operator.rtype.name == "TypeVoid"; 379 else if (cast(Line)a !is null && cast(Line)b !is null) 380 return (cast(Line)a).operator.rtype == (cast(Line)b).operator.rtype; 381 else 382 return a.type == b.type; 383 384 } 385 386 struct SwapStruct 387 { 388 Container parentCont; 389 uint place; 390 } 391 /// Формирование массива возможных замен 392 SwapStruct[] checkExistens(Container checkCont, Argument swapArg) 393 { 394 auto ret = new SwapStruct[0]; 395 uint i = 0; 396 foreach(Argument arg; checkCont ) 397 { 398 if (cast(Container)(arg) !is null) 399 { 400 if ( (cast(Line)(arg) !is null && (cast(Line)arg).operator.rtype.name == swapArg.type.name) || 401 (cast(ArgScope)arg !is null && cast(ArgScope)swapArg !is null) ) 402 { 403 SwapStruct st; 404 st.parentCont = checkCont; 405 st.place = i; 406 ret ~= st; 407 } 408 ret ~= checkExistens( cast(Container)(arg), swapArg); 409 } 410 else 411 if ( arg.type.name == swapArg.type.name ) 412 { 413 SwapStruct st; 414 st.parentCont = checkCont; 415 st.place = i; 416 ret ~= st; 417 } 418 i++; 419 } 420 return ret; 421 } 422 423 /// Поиск второго подходящего поддерева и обмен. 424 bool innerSwap( Container parentCont, int place ) 425 { 426 auto candidates = checkExistens( cont2, parentCont[place] ); 427 if (candidates.length == 0) return false; 428 429 auto candidate = candidates[uniform(0,candidates.length)]; 430 auto temp = parentCont[place]; 431 parentCont[place] = candidate.parentCont[candidate.place]; 432 candidate.parentCont[candidate.place] = temp; 433 return true; 434 } 435 436 437 auto chances = new double[0]; 438 bool end = false; 439 Container cont = cont1; 440 Container prevCont = null; 441 uint prevContI = -1; 442 443 444 do 445 { 446 ulong childs = cont.children; 447 448 chances ~= 1./childs; 449 foreach( arg; cont ) 450 { 451 chances ~= cast(double)arg.children/cast(double)childs; 452 } 453 454 randomRange!( 455 (int k) 456 { 457 if (k==0) 458 { 459 debug writeln("Selected to stop. Finded 1st tree"); 460 if (prevCont !is null) 461 { 462 innerSwap(prevCont, prevContI); 463 } 464 end = true; 465 } 466 else 467 if (cast(Container)(cont[k-1]) is null) 468 { 469 debug writeln("Selected leaf. Finded 1st tree"); 470 innerSwap(cont, k-1); 471 472 end = true; 473 } 474 else 475 { 476 debug writeln("Going down"); 477 prevCont = cont; 478 prevContI = k-1; 479 cont = cast(Container)(cont[k-1]); 480 } 481 } 482 )(chances); 483 chances.clear(); 484 } while(!end); 485 486 return true; 487 } 488 489 /// Стандартная мутация 490 void mutationStd( IndAbstract pInd, ProgTypeAbstract ptype) 491 { 492 if (pInd.program.length == 0) return; 493 494 size_t k = uniform(0, pInd.program.length); 495 Line line = pInd.program[k]; 496 auto chances = new double[3]; 497 498 /// Сначала проверим на глобальную мутацию 499 chances[0] = ptype.mutationAddLineChance(); 500 chances[1] = ptype.mutationRemoveLineChance(); 501 chances[2] = 1 - chances[0] - chances[1]; 502 503 bool local = false; 504 randomRange!( 505 (int k) 506 { 507 if (k==0) // mutationAddLineChance 508 { 509 pInd.program = pInd.program ~ generateLine(pInd, ptype); 510 return; 511 } else if (k==1) // mutationRemoveLineChance 512 { 513 if( k != pInd.program.length -1) 514 pInd.program = pInd.program[0..k] ~ pInd.program[k+1..$]; 515 else 516 pInd.program = pInd.program[0..k]; 517 return; 518 } 519 local = true; 520 } 521 )(chances); 522 523 if (!local) return; 524 /// Локальная мутация 525 chances[0] = ptype.mutationChangeChance(); 526 chances[1] = ptype.mutationReplaceChance(); 527 chances[2] = ptype.mutationDeleteChance(); 528 529 debug writeln("Mutation chances: ", chances); 530 531 randomRange!( 532 (int t) 533 { 534 switch(t) 535 { 536 case 0: // mutationChangeChance 537 { 538 debug writeln("Change"); 539 if (line.length > 0 && line.leafs > 0) 540 { 541 auto arg = getRandomLeafStd(line); 542 if (arg !is null) 543 arg.randomChange(ptype.maxMutationChange); 544 } 545 break; 546 } 547 case 1: // mutationReplaceChance 548 { 549 debug writeln("Replace"); 550 if ( line.children > 1 ) 551 replaceRandomElementStd(line, 552 (Type t) 553 { 554 return cast(Argument)generateLine(pInd, ptype, t); 555 }); 556 557 break; 558 } 559 case 2: // mutationDeleteChance 560 { 561 debug writeln("Delete"); 562 replaceRandomElementStd(line, 563 (Type t) 564 { 565 Argument arg = t.getNewArg(); 566 arg.randomChange(ptype.maxMutationChange); 567 return arg; 568 }); 569 break; 570 } 571 default: 572 } 573 } 574 )(chances); 575 } 576 577 /// Стандартный кроссинговер 578 bool crossingoverStd(IndAbstract pIndA, IndAbstract pIndB, ProgTypeAbstract ptype) 579 { 580 if (pIndA.program.length == 0 || pIndB.program.length == 0) return false; 581 debug writeln("Starting crossingover"); 582 583 ulong length = pIndA.program.length; 584 if (pIndB.program.length < length) 585 length = pIndB.program.length; 586 debug writeln("Selected length:", length); 587 588 foreach(ulong i; 0..length/2+1) 589 { 590 debug writeln("Starting ",i," swapping"); 591 size_t kA = uniform(0,pIndA.program.length); 592 size_t kB = uniform(0,pIndB.program.length); 593 Line lineA = pIndA.program[kA]; 594 Line lineB = pIndB.program[kB]; 595 596 /// Перемена местами двух деревьев полностью 597 if ( uniform!"[]"(0,1) < 1./cast(double)(lineA.children+lineB.children)) 598 { 599 debug writeln("Swapping roots"); 600 swap(pIndA.program[kA], pIndB.program[kB]); 601 } else /// Обмен поддеревьями 602 { 603 debug writeln("Swapping subtrees"); 604 if (!swapRandomElements( lineA, lineB, ptype )) 605 return false; 606 607 } 608 } 609 return true; 610 } 611 612 /// Создание следующей популяции 613 /** 614 * Создание популяции на основе вычисленной приспособленности. 615 * @param pop Популяция, из которой будет браться материал для 616 * следующей популяции. 617 * @param ptype Тип программы, в котором записаны все настройки 618 * процесса эволюции. 619 * @return Новая популяция. 620 */ 621 PopType formNextPopulation(PopType)(PopType pop, ProgTypeAbstract ptype) 622 { 623 if (pop.length == 0) return pop; 624 625 //Вычисляем среднюю приспособленность 626 debug writeln("Вычисляем сумму приспособленность: "); 627 double averFitness = 0; 628 foreach( ind; pop) 629 averFitness += ind.fitness; 630 631 auto newPop = pop.dup; 632 newPop.clear(); 633 debug writeln( "averFitness = ", averFitness ); 634 635 // Копируем лучших индивидов 636 debug writeln("Копируем лучших индивидов"); 637 int k = cast(int)round((ptype.copyingPart()*pop.length)); 638 debug writeln("Будет выбрано ", k, " лучших муравьев"); 639 640 auto sortedInds = new pop.IndividType[0]; 641 foreach( ind; pop) 642 sortedInds ~= cast(pop.IndividType)ind; 643 644 sort!("a.fitness > b.fitness")(sortedInds); 645 foreach(i; 0..k) 646 { 647 debug writeln("Добавляем ", i, " из лучших"); 648 newPop.addIndivid(cast(newPop.IndividType)(sortedInds[i].dup)); 649 } 650 651 debug 652 { 653 write("Отсортированные индивиды по фитнес: ["); 654 foreach(ind; sortedInds) 655 write(ind.fitness,","); 656 writeln("]"); 657 writeln("Размер новой популяции ", newPop.length); 658 } 659 // Формируем шансы для операций 660 auto opChances = new double[2]; 661 opChances[0] = ptype.mutationChance(); 662 opChances[1] = ptype.crossingoverChance(); 663 debug writeln("Шансы на операции: ", opChances); 664 665 // Формируем шансы индивидов 666 auto indChances = new double[0]; 667 foreach( ind; pop ) 668 { 669 indChances ~= cast(double)(ind.fitness)/cast(double)(averFitness); 670 } 671 debug writeln("Шансы индивидов: ", indChances); 672 673 debug writeln("Начинаем формировать новую популяцию:"); 674 while( newPop.length < pop.length ) 675 { 676 int opSelected; 677 randomRange!((int m){opSelected = m;})(opChances); 678 679 if (opSelected == 0) // mutationChance 680 { 681 debug writeln("Выбрана мутация"); 682 randomRange!( 683 (int s) 684 { 685 debug writeln("Выбран индивид №", s); 686 auto ind = cast(pop.IndividType)pop[s].dup; 687 debug writeln("Был: ", ind.programString()); 688 mutationStd( ind, ptype); 689 debug writeln("Стал: ", ind.programString()); 690 newPop.addIndivid( ind ); 691 } 692 )(indChances); 693 } else // crossingoverChance 694 { 695 // Замечен странный баг с вложенными лямбдами, поэтому передаю занчения вверх 696 debug writeln("Выбран кроссинговер"); 697 int iInd1; 698 int iInd2; 699 randomRange!((int s1){iInd1 = s1;})(indChances); 700 randomRange!((int s2){iInd2 = s2;})(indChances); 701 auto pIndA = cast(pop.IndividType)pop[iInd1].dup; 702 auto pIndB = cast(pop.IndividType)pop[iInd2].dup; 703 704 debug writeln("Выбраны индивиды №", iInd1, " и №", iInd2); 705 debug writeln("Был: ", pIndA.programString()); 706 debug writeln("Был: ", pIndB.programString()); 707 crossingoverStd(pIndA, pIndB, ptype); 708 debug writeln("Стал: ", pIndA.programString()); 709 debug writeln("Стал: ", pIndB.programString()); 710 711 newPop.addIndivid( pIndA ); 712 if (newPop.length < pop.length) 713 newPop.addIndivid( pIndB ); 714 } 715 } 716 return newPop; 717 } 718 } 719 720 //====================================================================== 721 // Статистические тесты 722 //====================================================================== 723 static if (RANDOM_ELEM_STAT_TEST) 724 { 725 unittest 726 { 727 import std.process; 728 class VoidOp : Operator 729 { 730 this() 731 { 732 mRetType = new TypePod!int; 733 super("v","",ArgsStyle.CLASSIC_STYLE); 734 735 ArgInfo a1; 736 a1.type = mRetType; 737 a1.min = "-1000"; 738 a1.max = "+1000"; 739 740 args ~= a1; 741 args ~= a1; 742 args ~= a1; 743 } 744 745 Argument apply(IndAbstract ind, Line line, WorldAbstract world) 746 { 747 auto arg = mRetType.getNewArg(); 748 return arg; 749 } 750 751 } 752 753 auto tm = new TypeMng; 754 auto em = new Evolutor; 755 tm.registerType!(TypePod!int); 756 757 auto op = new VoidOp; 758 auto nline0 = new Line; 759 auto nline1 = new Line; 760 auto nline2 = new Line; 761 auto nline3 = new Line; 762 763 764 nline0.operator = op; 765 nline1.operator = op; 766 nline2.operator = op; 767 nline3.operator = op; 768 769 nline0[0] = nline1; 770 nline0[1] = op.mRetType.getNewArg("1","1",[]); 771 nline0[2] = op.mRetType.getNewArg("2","2",[]); 772 773 nline1[0] = op.mRetType.getNewArg("3","3",[]); 774 nline1[1] = nline2; 775 nline1[2] = nline3; 776 777 nline2[0] = op.mRetType.getNewArg("4","4",[]); 778 nline2[1] = op.mRetType.getNewArg("5","5",[]); 779 nline2[2] = op.mRetType.getNewArg("6","6",[]); 780 781 nline3[0] = op.mRetType.getNewArg("7","7",[]); 782 nline3[1] = op.mRetType.getNewArg("8","8",[]); 783 nline3[2] = op.mRetType.getNewArg("9","9",[]); 784 785 double[Argument] stat; 786 787 foreach(arg; nline0) 788 stat[arg] = 0; 789 foreach(arg; nline1) 790 stat[arg] = 0; 791 foreach(arg; nline2) 792 stat[arg] = 0; 793 foreach(arg; nline3) 794 stat[arg] = 0; 795 796 Argument a; 797 ProgTypeAbstract ptype; 798 ulong count = cast(ulong)1e6; 799 800 foreach(ulong i; 0..count) 801 { 802 version(linux) 803 system("clear"); 804 805 a = em.getRandomElementStd(nline0); 806 stat[a] += 1.; 807 808 foreach(key,val; stat) 809 { 810 writeln(key.tostring, " : ", val/i); 811 } 812 writeln( "Выполнено ", cast(double)i/count*100, "%"); 813 } 814 version(linux) 815 system("clear"); 816 writeln("Результаты теста: "); 817 foreach(key,val; stat) 818 { 819 writeln(key.tostring, " : ", val/count); 820 } 821 getchar(); 822 } 823 } 824 825 static if (RANDOM_ELEM_REPLACE_TEST) 826 { 827 unittest 828 { 829 import std.process; 830 import ant.progtype; 831 832 class VoidOp : Operator 833 { 834 this() 835 { 836 mRetType = new TypePod!int; 837 super("v","",ArgsStyle.CLASSIC_STYLE); 838 839 ArgInfo a1; 840 a1.type = mRetType; 841 a1.min = "-1000"; 842 a1.max = "+1000"; 843 844 args ~= a1; 845 args ~= a1; 846 args ~= a1; 847 } 848 849 Argument apply(IndAbstract ind, Line line, WorldAbstract world) 850 { 851 auto arg = mRetType.getNewArg(); 852 return arg; 853 } 854 855 } 856 857 auto tm = new TypeMng; 858 auto em = new Evolutor; 859 //tm.registerType!(TypePod!int); 860 861 AntProgType ptype = new AntProgType(); 862 Ant pInd = new Ant(); 863 864 auto op = new VoidOp; 865 auto nline0 = new Line; 866 auto nline1 = new Line; 867 auto nline2 = new Line; 868 auto nline3 = new Line; 869 870 871 nline0.operator = op; 872 nline1.operator = op; 873 nline2.operator = op; 874 nline3.operator = op; 875 876 nline0[0] = nline1; 877 nline0[1] = op.mRetType.getNewArg("1","1",[]); 878 nline0[2] = op.mRetType.getNewArg("2","2",[]); 879 880 nline1[0] = op.mRetType.getNewArg("3","3",[]); 881 nline1[1] = nline2; 882 nline1[2] = nline3; 883 884 nline2[0] = op.mRetType.getNewArg("4","4",[]); 885 nline2[1] = op.mRetType.getNewArg("5","5",[]); 886 nline2[2] = op.mRetType.getNewArg("6","6",[]); 887 888 nline3[0] = op.mRetType.getNewArg("7","7",[]); 889 nline3[1] = op.mRetType.getNewArg("8","8",[]); 890 nline3[2] = op.mRetType.getNewArg("9","9",[]); 891 892 //pInd.program[0] = nline0; 893 char ans; 894 895 do 896 { 897 version(linux) 898 system("clear"); 899 900 writeln("Было: "); 901 writeln(nline0.tostring); 902 em.replaceRandomElementStd(nline0, (Type t){return cast(Argument)em.generateLine(pInd, ptype, t);}); 903 //em.replaceRandomElementStd(nline0, (Type t){return new ArgVoid;}); 904 writeln("Стало: "); 905 writeln(nline0.tostring); 906 907 write("Для остновки введите 'n': "); 908 ans = readln()[0]; 909 } while(ans != 'n' && ans != 'N'); 910 911 } 912 } 913 914 static if (RANDOM_LEAF_STAT_TEST) 915 { 916 unittest 917 { 918 import std.process; 919 class VoidOp : Operator 920 { 921 this() 922 { 923 mRetType = new TypePod!int; 924 super("v","",ArgsStyle.CLASSIC_STYLE); 925 926 ArgInfo a1; 927 a1.type = mRetType; 928 a1.min = "-1000"; 929 a1.max = "+1000"; 930 931 args ~= a1; 932 args ~= a1; 933 args ~= a1; 934 } 935 936 Argument apply(IndAbstract ind, Line line, WorldAbstract world) 937 { 938 auto arg = mRetType.getNewArg(); 939 return arg; 940 } 941 942 } 943 944 auto tm = new TypeMng; 945 auto em = new Evolutor; 946 tm.registerType!(TypePod!int); 947 948 auto op = new VoidOp; 949 auto nline0 = new Line; 950 auto nline1 = new Line; 951 auto nline2 = new Line; 952 auto nline3 = new Line; 953 954 955 nline0.operator = op; 956 nline1.operator = op; 957 nline2.operator = op; 958 nline3.operator = op; 959 960 nline0[0] = nline1; 961 nline0[1] = op.mRetType.getNewArg("1","1",[]); 962 nline0[2] = op.mRetType.getNewArg("2","2",[]); 963 964 nline1[0] = op.mRetType.getNewArg("3","3",[]); 965 nline1[1] = nline2; 966 nline1[2] = nline3; 967 968 nline2[0] = op.mRetType.getNewArg("4","4",[]); 969 nline2[1] = op.mRetType.getNewArg("5","5",[]); 970 nline2[2] = op.mRetType.getNewArg("6","6",[]); 971 972 nline3[0] = op.mRetType.getNewArg("7","7",[]); 973 nline3[1] = op.mRetType.getNewArg("8","8",[]); 974 nline3[2] = op.mRetType.getNewArg("9","9",[]); 975 976 double[Argument] stat; 977 978 foreach(arg; nline0) 979 stat[arg] = 0; 980 foreach(arg; nline1) 981 stat[arg] = 0; 982 foreach(arg; nline2) 983 stat[arg] = 0; 984 foreach(arg; nline3) 985 stat[arg] = 0; 986 987 Argument a; 988 ProgTypeAbstract ptype; 989 ulong count = cast(ulong)1e6; 990 991 foreach(ulong i; 0..count) 992 { 993 version(linux) 994 system("clear"); 995 996 a = em.getRandomLeafStd(nline0); 997 stat[a] += 1.; 998 999 foreach(key,val; stat) 1000 { 1001 writeln(key.tostring, " : ", val/i); 1002 } 1003 writeln( "Выполнено ", cast(double)i/count*100, "%"); 1004 } 1005 version(linux) 1006 system("clear"); 1007 writeln("Результаты теста: "); 1008 foreach(key,val; stat) 1009 { 1010 writeln(key.tostring, " : ", val/count); 1011 } 1012 getchar(); 1013 } 1014 } 1015 1016 static if (RANDOM_ELEM_SWAP_TEST) 1017 { 1018 unittest 1019 { 1020 import std.process; 1021 import ant.progtype; 1022 1023 class VoidOp : Operator 1024 { 1025 this() 1026 { 1027 mRetType = new TypePod!int; 1028 super("v","",ArgsStyle.CLASSIC_STYLE); 1029 1030 ArgInfo a1; 1031 a1.type = mRetType; 1032 a1.min = "-1000"; 1033 a1.max = "+1000"; 1034 1035 args ~= a1; 1036 args ~= a1; 1037 args ~= a1; 1038 } 1039 1040 Argument apply(IndAbstract ind, Line line, WorldAbstract world) 1041 { 1042 auto arg = mRetType.getNewArg(); 1043 return arg; 1044 } 1045 1046 } 1047 1048 auto tm = new TypeMng; 1049 auto em = new Evolutor; 1050 //tm.registerType!(TypePod!int); 1051 1052 AntProgType ptype = new AntProgType(); 1053 Ant pInd = new Ant(); 1054 1055 auto op = new VoidOp; 1056 auto nline0 = new Line; 1057 auto nline1 = new Line; 1058 auto nline2 = new Line; 1059 auto nline3 = new Line; 1060 1061 1062 nline0.operator = op; 1063 nline1.operator = op; 1064 nline2.operator = op; 1065 nline3.operator = op; 1066 1067 nline0[0] = nline1; 1068 nline0[1] = op.mRetType.getNewArg("1","1",[]); 1069 nline0[2] = op.mRetType.getNewArg("2","2",[]); 1070 1071 nline1[0] = op.mRetType.getNewArg("3","3",[]); 1072 nline1[1] = nline2; 1073 nline1[2] = nline3; 1074 1075 nline2[0] = op.mRetType.getNewArg("4","4",[]); 1076 nline2[1] = op.mRetType.getNewArg("5","5",[]); 1077 nline2[2] = op.mRetType.getNewArg("6","6",[]); 1078 1079 nline3[0] = op.mRetType.getNewArg("7","7",[]); 1080 nline3[1] = op.mRetType.getNewArg("8","8",[]); 1081 nline3[2] = op.mRetType.getNewArg("9","9",[]); 1082 1083 pInd.program = pInd.program ~ nline0; 1084 char ans; 1085 1086 Line lineA = nline0; 1087 Line lineB = nline0.dup; 1088 1089 do 1090 { 1091 version(linux) 1092 system("clear"); 1093 1094 writeln("Было: "); 1095 writeln("Линия А: ", lineA.tostring); 1096 writeln("Линия B: ", lineB.tostring); 1097 1098 em.swapRandomElements( lineA, lineB, ptype ); 1099 //em.mutationStd(pInd, ptype); 1100 1101 writeln("Стало: "); 1102 writeln("Линия А: ", lineA.tostring); 1103 writeln("Линия B: ", lineB.tostring); 1104 1105 write("Для остновки введите 'n': "); 1106 ans = readln()[0]; 1107 } while(ans != 'n' && ans != 'N'); 1108 1109 } 1110 } 1111 1112 static if (MUTATION_TEST) 1113 { 1114 unittest 1115 { 1116 import std.process; 1117 import ant.progtype; 1118 1119 class VoidOp : Operator 1120 { 1121 this() 1122 { 1123 mRetType = new TypePod!int; 1124 super("v","",ArgsStyle.CLASSIC_STYLE); 1125 1126 ArgInfo a1; 1127 a1.type = mRetType; 1128 a1.min = "-1000"; 1129 a1.max = "+1000"; 1130 1131 args ~= a1; 1132 args ~= a1; 1133 args ~= a1; 1134 } 1135 1136 Argument apply(IndAbstract ind, Line line, WorldAbstract world) 1137 { 1138 auto arg = mRetType.getNewArg(); 1139 return arg; 1140 } 1141 1142 } 1143 1144 auto tm = new TypeMng; 1145 auto em = new Evolutor; 1146 //tm.registerType!(TypePod!int); 1147 1148 AntProgType ptype = new AntProgType(); 1149 Ant pInd = new Ant(); 1150 1151 auto op = new VoidOp; 1152 auto nline0 = new Line; 1153 auto nline1 = new Line; 1154 auto nline2 = new Line; 1155 auto nline3 = new Line; 1156 1157 1158 nline0.operator = op; 1159 nline1.operator = op; 1160 nline2.operator = op; 1161 nline3.operator = op; 1162 1163 nline0[0] = nline1; 1164 nline0[1] = op.mRetType.getNewArg("1","1",[]); 1165 nline0[2] = op.mRetType.getNewArg("2","2",[]); 1166 1167 nline1[0] = op.mRetType.getNewArg("3","3",[]); 1168 nline1[1] = nline2; 1169 nline1[2] = nline3; 1170 1171 nline2[0] = op.mRetType.getNewArg("4","4",[]); 1172 nline2[1] = op.mRetType.getNewArg("5","5",[]); 1173 nline2[2] = op.mRetType.getNewArg("6","6",[]); 1174 1175 nline3[0] = op.mRetType.getNewArg("7","7",[]); 1176 nline3[1] = op.mRetType.getNewArg("8","8",[]); 1177 nline3[2] = op.mRetType.getNewArg("9","9",[]); 1178 1179 pInd.program = pInd.program ~ nline0; 1180 char ans; 1181 1182 do 1183 { 1184 version(linux) 1185 system("clear"); 1186 1187 writeln("Было: "); 1188 writeln(nline0.tostring); 1189 em.mutationStd( pInd, ptype ); 1190 1191 writeln("Стало: "); 1192 writeln(nline0.tostring); 1193 1194 write("Для остновки введите 'n': "); 1195 ans = readln()[0]; 1196 } while(ans != 'n' && ans != 'N'); 1197 1198 } 1199 } 1200 1201 static if (CROSSINGOVER_TEST) 1202 { 1203 unittest 1204 { 1205 import std.process; 1206 import ant.progtype; 1207 1208 class VoidOp : Operator 1209 { 1210 this() 1211 { 1212 mRetType = new TypePod!int; 1213 super("v","",ArgsStyle.CLASSIC_STYLE); 1214 1215 ArgInfo a1; 1216 a1.type = mRetType; 1217 a1.min = "-1000"; 1218 a1.max = "+1000"; 1219 1220 args ~= a1; 1221 args ~= a1; 1222 args ~= a1; 1223 } 1224 1225 Argument apply(IndAbstract ind, Line line, WorldAbstract world) 1226 { 1227 auto arg = mRetType.getNewArg(); 1228 return arg; 1229 } 1230 1231 } 1232 1233 auto tm = new TypeMng; 1234 auto em = new Evolutor; 1235 //tm.registerType!(TypePod!int); 1236 1237 AntProgType ptype = new AntProgType(); 1238 Ant pIndA = new Ant(); 1239 Ant pIndB = new Ant(); 1240 1241 auto op = new VoidOp; 1242 auto nline0 = new Line; 1243 auto nline1 = new Line; 1244 auto nline2 = new Line; 1245 auto nline3 = new Line; 1246 1247 1248 nline0.operator = op; 1249 nline1.operator = op; 1250 nline2.operator = op; 1251 nline3.operator = op; 1252 1253 nline0[0] = nline1; 1254 nline0[1] = op.mRetType.getNewArg("1","1",[]); 1255 nline0[2] = op.mRetType.getNewArg("2","2",[]); 1256 1257 nline1[0] = op.mRetType.getNewArg("3","3",[]); 1258 nline1[1] = nline2; 1259 nline1[2] = nline3; 1260 1261 nline2[0] = op.mRetType.getNewArg("4","4",[]); 1262 nline2[1] = op.mRetType.getNewArg("5","5",[]); 1263 nline2[2] = op.mRetType.getNewArg("6","6",[]); 1264 1265 nline3[0] = op.mRetType.getNewArg("7","7",[]); 1266 nline3[1] = op.mRetType.getNewArg("8","8",[]); 1267 nline3[2] = op.mRetType.getNewArg("9","9",[]); 1268 1269 pIndA.program = pIndA.program ~ nline0.dup; 1270 pIndB.program = pIndB.program ~ nline1.dup; 1271 1272 char ans; 1273 1274 do 1275 { 1276 version(linux) 1277 system("clear"); 1278 1279 writeln("Было: "); 1280 writeln("Индивид А: ",pIndA.programString()); 1281 writeln("Индивид B: ",pIndB.programString()); 1282 1283 em.crossingoverStd( pIndA, pIndB, ptype ); 1284 1285 writeln("Стало: "); 1286 writeln("Индивид А: ",pIndA.programString()); 1287 writeln("Индивид B: ",pIndB.programString()); 1288 1289 write("Для остновки введите 'n': "); 1290 ans = readln()[0]; 1291 } while(ans != 'n' && ans != 'N'); 1292 1293 } 1294 }