/// <summary> /// Metoda, která vytvoří základní generaci CEST /// </summary> /// <param name="pocet">Počet CEST v počáteční i dalších generacích</param> public void VytvorZakladniGeneraci(int pocet) { for (int j = 0; j < pocet; j++) { // Vytvarim novy seznam mest, podle pozedavku. Tedy novou cestu, ktera bude obsahovat 35 mest List <Mesto> novaCesta = new List <Mesto>(); List <int> vyberMest = new List <int>(); // Pouze seznam abych vytvarel nova mesta a nebyli na ceste nektera mesta vicekrat for (int i = 0; i < 35; i++) { vyberMest.Add(i); } for (int i = 0; i < 35; i++) { // Vyberu ze zbyvajicich moznosti nejake ID a podle toho vytvorim dane mesto int pomocna = vyberMest[random.Next(vyberMest.Count)]; novaCesta.Add(new Mesto(mesta[pomocna].Id, mesta[pomocna].Nazev, SpocitejVzdalenosti(mesta[pomocna].Id))); // Smazu vybrane ID, protoze by se mi opakovali mesta vyberMest.RemoveAt(vyberMest.IndexOf(pomocna)); } // Přidám novou CESTU do generace a zvýším IDcesty posledniCesta = new Cesta(novaCesta, IdCesta); IdCesta++; Generace.Add(posledniCesta); } VykresliInfo(0, 1); }
/// <summary> /// Fitnes funkce pro genetický algoritmus. Ohodnotím potomky a poté roztočím váženou ruletu, která preferuje jedince s kratší vzdáleností. /// </summary> public void VypocitejKvalitu() { IdCesta = 0; double CelkovaVzdalenost = 0; // Instance randomu, pro náhodný výběr Random random = new Random(); List <Cesta> UpravenaGenerace = new List <Cesta>(); // Projdu všechny potomky a sečtu jejich vzdálenosti, abych měl celkovou vzdálenost všech potomků pro vytvoření poměru foreach (Cesta c in Generace) { CelkovaVzdalenost += (1 / c.Vzdalenost); } // Proměnná do která se postupně zvyšuje, tak aby bylo možné stanovit spodní hranici daného potomka na ruletě double Vzdalenost = 0; // Projdu všechny potomky a každému spočítám spodní a horní hranici. Tedy úsek, který zabírá z celkové vzdálenosti foreach (Cesta c in Generace) { // Násobek je pouze pro to, aby byla dosažena dostatečná velikost každého prvku if (Vzdalenost != 0) { c.MinRozsah = (int)Math.Floor((Vzdalenost / CelkovaVzdalenost) * 5000); } else { c.MinRozsah = 0; } // 1/vzdálenost, abych dosáhl toho, že nejlepší potomci (nejkratší vzdálenosti) zabírají více než ty s větší vzdáleností Vzdalenost += (1 / c.Vzdalenost); c.MaxRozsah = (int)Math.Floor((Vzdalenost / CelkovaVzdalenost) * 5000); } // Náhodně ,,trefuji,, rozsahy, dokud netrefím stejný počet potomků jako měla původní generace while (UpravenaGenerace.Count < PocetPotomku) { int hodnota = random.Next(5001); for (int i = 0; i < PocetPotomku; i++) { Cesta aktualniCesta = Generace[i]; if (hodnota > aktualniCesta.MinRozsah && hodnota < aktualniCesta.MaxRozsah) { UpravenaGenerace.Add(new Cesta(aktualniCesta.seznamMest, IdCesta)); IdCesta++; break; } } } // Předám referenci na novou kolekci původní kolekci Generace = UpravenaGenerace; // Zobrazím informace do konzole VykresliInfo(IdGenerace, 0); }
// Konstruktor ve kterém je vše potřebné zakomponováno, proto postačí vytvoření instance třídy public GenetickyAlgoritmus() { mapaVzdalenosti = new float[35, 35]; mesta = new List <Mesto>(); Generace = new List <Cesta>(); random = new Random(); // string[] nazvy = DefinujMapuVzdalenosti(); // Definuji si zakladni seznam mest, podle puvodniho poradi for (int i = 0; i < 35; i++) { mesta.Add(new Mesto(i, nazvy[i], SpocitejVzdalenosti(i))); } // Vytvoření základní generace, se kterou se dále prováději kroky mutace, křížení a ohodnocení VytvorZakladniGeneraci(PocetPotomku); // Pocet vytvorenych generaci VytvorNovouGeneraci(1000); Console.WriteLine(" ------------------------------ Nejlepsi nalezena cesta ------------------------------ "); int ind = 0; // Zobrazení nalezeného nejlepšího řešení foreach (Mesto m in nejlepsiCesta.seznamMest) { ind++; Console.Write("|" + m.Nazev + "\t\t" + m.Id + "|"); if (ind % 4 == 0) { Console.Write("\n"); } } Console.Write("\n Vzdalenost teto cesty je: {0} km", nejlepsiCesta.Vzdalenost); // Vypis vsech prvku v posledni generaci, pozdeji smazat. Pouze pro ucely testovani foreach (Cesta c in Generace) { Cesta puvodni = c; int pocetShody = 0; foreach (Cesta ces in Generace) { if (c.Vzdalenost == ces.Vzdalenost) { pocetShody++; } } Console.WriteLine("{0} {1}", pocetShody, puvodni.Vzdalenost); } }
/// <summary> /// Metoda, která vykreslí základní informace o právě probíhané události. /// </summary> /// <param name="generace">Číslo generace</param> /// <param name="vstup">0 - kvalita, 1 - nova generace, 2 - mutace</param> private void VykresliInfo(int generace, byte vstup) { int soucetIDmest = 0; // Smažu konzoli Console.Clear(); // Pouze podmínka, jaká hlavička se bude v konzoli vykreslovat, aby bylo vidět jaká operace probíhá if (vstup == 0) { Console.WriteLine("************************| Kvalita |*************************"); } else if (vstup == 1) { Console.WriteLine("************************| NovaGEN |*************************"); } else if (vstup == 2) { Console.WriteLine("************************| MUTACE |*************************"); } double cesta = 0; // Výpočet celkové vzdálenosti všech CEST v generaci foreach (Cesta c in Generace) { cesta += c.Vzdalenost; } // Seřazení kolekce Generace, vzestupně IEnumerable <Cesta> serazene = Generace.OrderBy(a => a.Vzdalenost); // Uložení nejvyšší vzdálenosti potomka - CESTY float TOP = serazene.Last().Vzdalenost; // Uložení nejnižší vzdálenosti potomka - CESTY float DOWN = serazene.First().Vzdalenost; // Vyčtení nejlepší CESTY Cesta novaNejvyssi = serazene.First(); if (nejlepsiCesta == null) { nejlepsiCesta = novaNejvyssi; } if (novaNejvyssi.Vzdalenost < nejlepsiCesta.Vzdalenost) { nejlepsiCesta = novaNejvyssi; } int pocetNejvyssich = 0; int pocetNejnizsich = 0; // Výpočet počtu nejlepších jedinců a současně nejhorších, pro kontrolu koncentrace nejlepších a nejhorších foreach (Cesta c in Generace) { if (c.Vzdalenost == TOP) { pocetNejvyssich++; } else if (c.Vzdalenost == DOWN) { pocetNejnizsich++; } } // Součet ID měst, pouze kontrola pro objevení duplicity města v kolekci foreach (Cesta c in Generace) { foreach (Mesto m in c.seznamMest) { soucetIDmest += m.Id; } } int hraniceSpodniHorni = Generace.Count / 5; double spodniSkupina = 0; double horniSkupina = 0; int inc = 0; // Nalezení CEST, které spadají do horních a spodních 20 % rozsahu aktuální generace foreach (Cesta c in serazene) { inc++; spodniSkupina += c.Vzdalenost; if (inc > hraniceSpodniHorni) { break; } } inc = 0; foreach (Cesta c in serazene) { inc++; if (inc > Generace.Count - hraniceSpodniHorni) { horniSkupina += c.Vzdalenost; } } // Výpočet průměru horní a spodních 20 % jedinců spodniSkupina = spodniSkupina / (double)hraniceSpodniHorni; spodniSkupina = Math.Floor(spodniSkupina); horniSkupina = horniSkupina / (double)hraniceSpodniHorni; horniSkupina = Math.Floor(horniSkupina); Console.WriteLine("------------------------| GENERACE {5} |------------------------\n" + " -- Celkova vzdalenost teto generace je:\t{0}\n" + " -- Nejvyssi vzdalenost je:\t\t\t{1}\n" + " -- A kolekce jich obsahuje:\t\t{2}\n" + " -- A jejich PRUMER je:\t\t\t{7}\n\n\n" + " -- Nejnizsi vzdalenost je:\t\t\t{3}\n" + " -- A kolekce jich obsahuje:\t\t{4}\n" + " -- A jejich PRUMER je:\t\t\t{8}\n" + " -- Soucet mest u potomku je:\t\t{6}\n" , cesta, serazene.Last().Vzdalenost, pocetNejvyssich, serazene.First().Vzdalenost, pocetNejnizsich , generace, soucetIDmest, horniSkupina, spodniSkupina); // Uspání vlákna pro čitelnost výpisu Thread.Sleep(50); }