Tema
/
Algoritmai ir duomenų struktūros GO
Pamoka 15 / 15 Svoriniai grafai ~60 min
Teorija

A*: pastatytas ir pralaimėjęs

Dijkstra plečiasi į visas puses vienodai. Ieškant kelio iš Šeškinės į Naujininkus, ji su tokiu pat uolumu tiria Fabijoniškes — nes nežino, kur yra tikslas.

A* prideda vieną dalyką: įvertį, kiek dar liko. Vietoj d mazgai rikiuojami pagal d + h(v), kur h(v) yra spėjimas apie likusią kainą.

Jei h niekada nepervertina likusios kainos, atsakymas lieka teisingas — tokia h vadinama leistina (admissible). Ir tada paieška krypsta į tikslą, o šoninės šakos atkrenta anksčiau.

Skamba kaip nemokamas pagerinimas. transit jį pastatė.

Jis teisingas

TestAStarMatchesDijkstra   A* matches Dijkstra's optimum on all 120 queries

Visos 120 užklausų, tas pats optimalus atsakymas. Realizacija gera, euristika leistina, algoritmas veikia kaip parašyta vadovėlyje.

Ir jis pralaimi

                                          mūsų matavimas   prieš ranka rašytą krūvą
Dijkstra, ranka rašyta krūva                     53.4 ms   1.0
A*, container/heap + euristika                   77.2 ms   1.45x lėčiau

BenchmarkRouter duoda 1.75 karto. transit README teigia 1.05–1.09 karto lėčiau; mūsų mašinoje pralaimėjimas didesnis, ne mažesnis.

Mes jį pastatėme, ir jis pralaimėjo.

Kodėl — ir tai svarbiausia šio žingsnio dalis

A* nukerta šakas proporcingai tam, ką jo euristika mato. Tad kiek ji mato?

TestHeuristicTightness   over 187 queries — h(origin) as a fraction of true optimal cost:
                           mean 4.1%, min 0.5%, max 22.1%

4.1 %. Euristika mato dvidešimt penktąją dalį tos kainos, kurią turėtų apriboti. Blogiausiu atveju — 0.5 %.

Priežastis pamatuota atskirai:

TestHeuristicBlindToWaiting   over 186 journeys: mean elapsed time 99.7 min,
                              mean generalised cost 145.0 equivalent-min,
                              mean transfers 3.57
                              generalised cost exceeds elapsed time by 45%

Euristika yra geometrinė: atstumas iki tikslo, padalytas iš didžiausio stebėto greičio. Geometrija gali modeliuoti važiavimą. Ji negali modeliuoti laukimo kito reiso ir persėdimo bausmės — o tai yra 45 % kainos.

Kelionės kaina viešuoju transportu priklauso ne nuo to, KUR tu esi, o nuo to, KADA. Euristika mato tik „kur".

Ir rezultatas matomas mazgų skaičiuje:

TestAStarSpread
  short_hop            dijkstra settled  1974 | A* settled  1760 | reduction 10.8%
  cross_city           dijkstra settled 15154 | A* settled 12829 | reduction 15.3%
  late_night           dijkstra settled  9923 | A* settled  9923 | reduction  0.0%
  exhaustive_no_route  dijkstra settled   147 | A* settled   147 | reduction  0.0%

Dviem užklausoms iš keturių — lygiai nulis. O ten, kur nukerta 10–15 %, sutaupytas darbas nepadengia to, ko euristikos skaičiavimas kainuoja kiekviename mazge.

Kainos svoriai nėra išgalvoti

Verta sustoti: gal A* pralaimi todėl, kad kainos modelis dirbtinai sudėtingas — įpainiotas tik tam, kad geometrija atrodytų bejėgė?

Ne. Svoriai paimti iš transporto planavimo literatūros:

  • laukimo svoris 2.0 — Wardman apžvalgos pateikia laukimo ir važiavimo santykį 2:1; Metropolitan Transportation Commission (Travel Model One) ir San Francisco County TA (CHAMP 5.0) abu naudoja lygiai 2.0;
  • persėdimo bausmė 5 min — literatūra siūlo 5–15; MTC ima 5/10/30 minutes už pirmą, antrą ir trečią persėdimą, SFCTA — vienodai 6. Paimta žemutinė riba.

Ir modelis pamatuotas prieš gryną laiką:

TestGeneralisedCostPrefersFewerTransfers
  over 200 queries: 10 chose a later arrival, 149 used fewer transfers

149 maršrutai iš 200 gavo mažiau persėdimų, ir tik 10 atvyko vėliau. Tai modelio pataisa, ne gudrybė, kad krūva atrodytų reikalinga.

Ir vis dėlto keliuose A* laimi

Čia lengva padaryti neteisingą išvadą: „A* neveikia". Neteisinga.

Automobilių maršrutų paieškoje A* ir jo įpėdiniai — contraction hierarchies — yra standartas. Ten euristika veikia puikiai, nes kelionės automobiliu kaina tikrai yra beveik atstumas: nėra tvarkaraščio, nėra laukimo, greitis svyruoja siaurose ribose.

Viešojo transporto maršrutų paieška nuėjo kitu keliu — į CSA ir RAPTOR algoritmus, kurie euristikų neturi visai.

Tas pats trumpiausio kelio uždavinys. Priešingi laimėtojai.

Bast ir kt. („Route Planning in Transportation Networks", MSR-TR-2014-4) šitą skirtumą aptaria kaip pagrindinį; Geisberger, contraction hierarchies autorius, dokumentuoja, kad metodas „completely fails for timetable networks".

Algoritmą renkasi ne uždavinys, o uždavinio STRUKTŪRA.

Kodėl A* nėra tavo bibliotekoje

Pabandyk parašyti h(v) savo tinklui: kiek dienų liko nuo knygos v iki tikslo?

Negali. Knygos neturi koordinačių. Nėra nieko, ką būtų galima išmatuoti neatlikus pačios paieškos, o įvertis, kurį reikia apskaičiuoti paiešką atlikus, nėra įvertis.

A* reikalauja žinių apie uždavinį, kurių tavo grafas neturi. Todėl šioje pamokoje jo ir nestatai — ne dėl to, kad jis sunkus, o dėl to, kad jam nėra iš ko atsispirti.

Tai irgi atsakymas, ir sąžiningas.