Je dáno m měst. Některá města jsou propojena silnicemi, délka silnic je známa. Úkolem obchodního cestujícího je navštívit všechna města (právě jednou, aspoň jednou, uvažujte oba případy). Nalezněte takovou túru (permutaci měst), aby délka ujeté cesty byla co nejmenší.
Navrhněte a implementujte algoritmus řešící problém obchodního cestujícího (TSP). Funkčnost algoritmu ověřte na sadě dodaných testovacích příkladů.Poznámka
K řešení jsem zvolil metodu simulovaného ochlazování, která
řeší problém pro navštívení všech měst právě jednou, druhá varianta není
uvažována
Metoda simulovaného ochlazování je jednou ze základních iterativních metod pro řešení NPO problémů. Její podstata spočívá v postupném "snižování teploty", přičemž teplota ovlivňuje pravděpodobnost přijmutí nového stavu zhoršujícího optimalizační kritérium současného řešení. Tedy pokud je teplota vysoká, pravděpodobnost akceptace stavu, který má horší optimalizační kritérium než současný stav je vyšší, než pokud je teplota nízká. Základní schéma algoritmu simulovaného ochlazování je následující:
//hlavní cyklus
state = initial_state; //pocatecni stav
t = t0; //pocatecni teplota
do {
do {
state = try(state, t);
} while (! equilibrium(state, t, ...) );
t = cool(t);
} while (! frozen(t, ...) );
//nalezení dalšího stavu
try(state, t) {
new = random_neighbourhood(state);
delta = cost(new) - cost(old);
//zlepseni ci pripustne zhorseni
if ( (delta < 0) || (random() < exp(-delta/t)) )
return new;
return state;
}
Ze schématu je jasné, že metoda je rozsáhle parametrizovaná, a to jak použitými algoritmy, tak počátečními podmínkami. V následujících odstavcích naleznete mojí implementaci pro řešení TSP.
Metoda simulovaného ochlazování vychází z předpokladu, že počáteční stav je řešením daného problému, a proto není sestavení počátečního řešení zcela triviální - je to problém nalezení libovolné Hamiltonovské kružnice (kružnice procházející všemi městy právě jednou) v zadaném grafu. Výsledné řešení je také na volbě počátečního stavu závislé, ale špatná volba počáteční řešení lze "dohnat" zvýšením počáteční teploty, což nám umožní dostat s z lokálního minima, které počáteční řešení může představovat. Proto bylo mou snahou nalézt libovolné počáteční řešení, nikoliv jeho optimalizace.
Algoritmus pro nalezení Hamiltonovské kružnice je všem (alespoň těm kteří řeší tuto úlohu) relativně známý, proto jen stručně (mou konkrétní implementaci naleznete v přiloženém zdrojáku). Základem algoritmu jsou následující funkce:
Tyto funkce jsou používány ve třech fázích algoritmu:
Daný popis by měl stačit k pochopení principu algoritmu. Je z něj též patrná případná "parametrizace" algoritmu - volba počátečního měst a algoritmus výběru měst pro prodložení a modifikaci. Já jsem volil cestu nejjednodušší - počátečním městem je město 0 a algoritmus výběru je jednoduchý cyklus procházející postupně všechna města (0..count-1)
Již z popisu algoritmu simulovaného ochlazování je zřejmé, že i zde je výrazná možnost "parametrizace" řešení, a to jak volbou parametrů, tak samotnou implementací metod. Proto se postupně zaměřím na všechny části algoritmu
Volba nového stavu (random_neigbourhood)
Nový je z existujícího stavu tvořen tzv. dvojzáměnou
(překřížením), kdy jsou náhodně vybrána města i a j, u kterých
existují spojení i->j a i+1->j+1 a platí i<j-1.
Pokud je taková dvojice nalezena, provedene se překřížení, tedy spojení i->i+1
nahradí i->j, poté je cesta vedena proti původnímu směru do města i+1,
kde je přidána cesta i+1->j+1, čímž zaniká cesta j->j+1. Pro
pochopení ještě schéma obou cest
stará cesta: a ->...-> i ->
i+1 ->...-> j -> j+1 ->...-> a
nová cesta: a ->...-> i
-> j ->...-> i+1 -> j+1 ->...-> a
Rovnováha vniřního cyklu (equilibrium)
rovnováhy je dosaženo, pokud počet iterací uvnitř cyklu překročí zadanou
mez
return iterCount > maxIter;
Rozvrh ochlazování (cool)
teplota je snižována exponenciálně násobením koeficientem alfa
return t * alfa;
Bod zamrznutí (frozen)
teplota klesne pod zadanou hranici
return t < tMin;
Ze zadaného popisu vyplývá, že jsem zvolil nejjednodušší implementaci algoritmu simulovaného ochlazování, ale i ta má možnost nastavení čtyřech parametrů, což je pro testování více než dostatečné. Vstupní parametry mého algoritmu tedy jsou:
Výstupem je délka výsledné cesty a počet iterací potředný k dosažení výsledku.
Implementaci algoritmu naleznete ve zdrojáku. Je umožněno i opakované spouštění s různým nastavení parametrů a výstupem do "tabulky" - výstupního souboru.
| Název instance | Počet měst | Délka poč. řešení | t0 | alfa | tMin | maxIter | délka řešení | počet iterací |
| A | 2187 | 21253 | 3 | 0.8 | 0.5 | 100 | 20531 | 909 |
| B | 625 | 3886 | 5 | 0.96 | 0.001 | 500 | 2010 | 104709 |
| D | 200 | 600 | 3 | 0.97 | 0.001 | 200 | 581 | 52863 |
| E | 256 | 325 | 3 | 0.96 | 0.001 | 200 | 286 | 39597 |
| J | 2048 | 21416 | 3 | 0.96 | 0.001 | 200 | 21091 | 39597 |
| Testik | 81 | 616 | 5 | 0.96 | 0.001 | 1000 | 131 | 209209 |
| C, F, G, H, I, K | Nenalezena Hamiltonovská kružnice |
|||||||
První část testu zachycuje závislost kvality řešení na počtu iterací (při
snižování bodu mrazu, ale i mírné změně ostatních parametrů). Část druhá se
naopak snaží zachytit závislost kvality řešení na nastavení parametrů při
"konstantním" počtu iterací. Výsledky shrnuje následující tabulka, délka
řešení představuje průměr z 5-ti pokusů.
Instance Testik byla zvolena pro její malou velikost a tím vyšší rychlost řešení,
která umožnila provést více testů.
| t0 | alfa | tMin | maxIter | počet iterací | délka řešení |
| 5 | 0.98 | 1.0 | 100 | 8080 | 211 |
| 5 | 0.98 | 0.5 | 100 | 11514 | 182 |
| 5 | 0.98 | 0.1 | 100 | 19594 | 159 |
| 5 | 0.98 | 0.05 | 100 | 23028 | 153 |
| 5 | 0.98 | 0.01 | 100 | 31108 | 146 |
| 5 | 0.98 | 0.001 | 100 | 42622 | 146 |
| 5 | 0.98 | 0.0001 | 100 | 54136 | 143 |
| 5 | 0.99 | 0.01 | 100 | 62519 | 143 |
| 5 | 0.99 | 0.001 | 100 | 85648 | 140 |
| 5 | 0.96 | 0.001 | 1000 | 209209 | 135 |
| 1000 | 0.97 | 0.01 | 100 | 38172 | 156 |
| 100 | 0.975 | 0.01 | 100 | 36764 | 158 |
| 10 | 0.98 | 0.01 | 100 | 34542 | 150 |
| 5 | 0.982 | 0.01 | 100 | 34542 | 150 |
| 1 | 0.986 | 0.01 | 100 | 33027 | 147 |
| 0.5 | 0.989 | 0.01 | 100 | 35754 | 147 |
| 0.1 | 0.993 | 0.01 | 100 | 33128 | 147 |
| 0.05 | 0.995 | 0.01 | 100 | 32522 | 146 |
První část potvrzuje relativně velkou (a samozřejmě očekávanou) závislost kvality řešení na počtu iterací. Je jasné, že při přibližování se optimálnímu řešení se rozdíly ve kvalitě snižují, ale snižuje se též rozptyl hodnot jednotlivých měření - zvyšuje se zaručení přesnosti řešení.
Druhá část prokazuje, že počáteční teplota by neměla být volena příliš
vysoká - umožňuje to vzdálit se optimálnímu řešení výrazným zhoršením, které
pak již není možno při nižších teplotách překonat zpět. Mnohem výhodnější se
ukazuje volba v podstatě konstantní teploty - stačí relativně nízká počáteční
hodnota a její jen mírné snižování.
Je zřejmé, že na kvalitě řešení se nejvýrazněji projevuje celkový počet
iterací (ne však lineárně, jak již bylo uvedeno), pokud ovšem neuvažujeme extremní
nastavení parametrů metody.
Je však nutno upozornit, že tento závěr je velmi závislý na konkrétní instanci a
též na počátečním řešení.
Obecně by se dalo shrnout, že mnohem výhodnější než zvyšování počtu iterací se jeví vícenásobné spuštění řešení a posléze výběr nejlepšího řešení. Ani vysoký počet iterací totiž kvalitní řešení nemusí zajistit.
Jako zajímavou pro testování jsem uznal i instanci A, která svojí velkou velikostí neumožňuje zvyšovat počet iterací - pro velký počet je řešení velmi časově náročné. Následující tabulka shrnuje výsledky mých měření
| t0 | alfa | tMin | maxIter | počet iterací | délka řešení |
| 3 | 0.5 | 2.0 | 100 | 101 | 20761 |
| 3 | 0.8 | 2.0 | 100 | 202 | 20678 |
| 3 | 0.8 | 1.6 | 100 | 303 | 20660 |
| 3 | 0.8 | 1.3 | 100 | 404 | 20666 |
| 3 | 0.8 | 1.0 | 100 | 505 | 20577 |
| 3 | 0.8 | 0.5 | 100 | 909 | 20531 |
| 10 | 0.2 | 0.05 | 100 | 404 | 20604 |
| 10 | 0.2 | 0.01 | 100 | 505 | 20564 |
| 3 | 0.9 | 1.8 | 100 | 505 | 20584 |
Z výsledků je patrné, že pro tuto instanci se při nízkém počtu iterací jako
nejvýhodnější jeví rychlé ochlazení počáteční relativně vysoké teploty.
Závislost kvality na počtu iterací se samozřejmě projevuje také.
Je ale nutné upozornit, že testy nebyly prováděny opakovaně a proto je možný
znatelný projev náhodnosti v jednotlivých výsledcích.
Má implementace simulovaného ochlazování řeší problém obchodního cestujícího s navštívením všech měst právě jednou. Výsledky jsou samozřejmě závislé na zadaných vstupních parametrech, výsledky testů naleznete v předchozí části.
Zdrojový soubor (v C++) naleznete zde.