LAB: Przeszukiwanie grafów i planowanie tras przejazdu

Celem ćwiczenia jest zapoznanie się z możliwościami wykorzystania technik sztucznej inteligencji do planowania tras przejazdu oraz poznanie technik poszukiwania ścieżek w grafach.

1 Wprowadzenie

Modelem przestrzeni poszukiwań dla planowania tras przejazdu jest graf.

Graf to twór matematyczny składający się ze zbioru wierzchołków V (ang. nodes, vertices) oraz zbioru krawędzi E (ang. links, edges).

Najprostsza definicja grafu mówi, że graf to para postaci G=(V,E), gdzie V jest zbiorem węzłów a E ⊆ V×V jest zbiorem łączących je krawędzi.

Model ten reprezentuje schematycznie mapę, gdzie w zależności od poziomu abstrakcji węzły mogą np. reprezentować miasta, a krawędzie - łączące je drogi, lub też węzły mogą reprezentować skrzyżowania ulic a krawędzie ulice (lub ich odcinki).

Zapoznaj się, lub raczej przypomnij sobie ;-) podstawowe wiadomości o grafach.

Pamiętaj, że krawędź grafu może być skierowana (modeluje przejazd tylko w jedną stronę; np. ulica jednokierunkowa) lub nieskierowanym (modeluje przejazd w obie strony; np. ulica dwukierunkowa).

Odpowiednio, graf może być grafem skierowanym, nieskierowanym lub mieszanym.

Ponadto, z każdą krawędzią może być związany koszt przejazdu (odległość, czas).

Jeżeli dwa węzły grafu połączone są więcej niż jedną krawędzią, krawędzie te muszą być etykietowane dla umożliwienia ich rozróżnienia.

2 Poszukiwanie ścieżek

Zadanie planowania tras przejazdu to zadanie polegające na wyznaczeniu drogi łączącej zadany punkt początkowy i pożądany punk docelowy.

Zwykle dążymy do wyznaczenia trasy najkrótszej, najszybszej lub o najniższym koszcie.

Modelem zadania planowania trasy jest poszukiwanie ścieżki w grafie.

Zadania planowania trasy definiowane jest jako:

P = (v_I, v_G, V, E)

gdzie v_I to zadany węzeł początkowy, v_G to zadany węzeł docelowy, a V oraz E definiują graf (przestrzeń poszukiwań).

Rozwiązaniem zadania planowania trasy jest ciąg krawędzi e_1, e_2,…,e_n, taki, że:

  • {e_1, e_2,…,e_n} ⊆ E,
  • e_1 zaczyna się węźle v_I,
  • krawędź e_i kończy się w węźle będącym początkiem krawędzi e_i+1,
  • krawędź e_n kończy się w węźle v_G.

Powyższy ciąg krawędzi tworzy ścieżkę stanowiącą plan przejazdu.

Zwykle wymaga się aby każdy węzeł leżący na ścieżce przejazdu odwiedzany był tylko raz (brak cykli).

Znanych jest wiele algorytmów przeszukiwania grafów, zarówno w obszarze teorii grafów, badań operacyjnych jak i sztucznej inteligencji.

Algorytmy z obszaru sztucznej inteligencji wyróżniają się tym, że:

  • często korzystają z heurystyk odległościowych (np. opartych na oszacowaniu odległości Euklidesowej i wg metryki ulicznej),
  • pozwalają na uwzględnianie dodatkowych ograniczeń, np. węzłów zabronionych,
  • pozwalają na przeszukiwanie przestrzeni o bardzo dużych rozmiarach,
  • pozwalają na przeszukiwanie przestrzeni zadanych niejawnie (nowe węzły lub stany pojawiają się w wyniku wywołania funkcji generującej).

Zapoznaj się z podstawowymi algorytmami:

Plan dopuszczalny to plan stanowiący rozwiązanie (ścieżka łącząca węzeł początkowy i docelowy) i ew. spełniający zadane ograniczenia (np. długości, omijania wybranych węzłów zabronionych, przechodzenia przez zadane węzły wymagające odwiedzenia, etc. Plan ten nie musi być 'najlepszy'.

Plan optymalny to plan najlepszy w sensie wybranego kryterium, np.

  • plan zawierający najmniejszą liczbę węzłów,
  • plan realizujący najkrótszą trasę,
  • plan o najtańszej trasie przejazdu,
  • plan pozwalający na najszybszy przejazd.

3 Wyszukiwanie najkrótszej ścieżki

  1. Zapoznaj się z narzędziem http://home.agh.edu.pl/~kk/psi/pathfinder
    • Przeczytaj instrukcje wyświetlane w lewym górnym rogu.
    • Wypróbuj działanie dostępnych algorytmów przeszukiwania dla domyślnego problemu bez ograniczeń (bez ścian):
      • Zaobserwuj obszar analizowany przez poszczególne algorytmy działające dla domyślnych ustawień.
      • Zanotuj statystyki: długość znalezionej ścieżki, czas potrzebny do jej znalezienia, liczbę przeprowadzonych operacji.
      • Warto zauważyć, że koszt przejścia do węzła powyżej, poniżej, na lewo i na prawo jest równy 1. Natomiast koszt przejścia do węzła po przekątnej wynosi 1.4.
  2. Dla algorytmów heurystycznych zdefiniuj heurystykę wpisując w pole My heuristic wartość „dx”.
    • Ponownie zaobserwuj działanie algorytmów i zanotuj statystyki. Czy dodanie heurystyki poprawia działanie algorytmu?
  3. Jakie są najpopularniejsze heurystyki dla wyszukiwania na płaszczyźnie?
    • Przeczytaj artykuł i wprowadź opisane w nim heurystyki obserwując zmiany działania algorytmu (aby wykonać operację pierwiastkowania wpisz Math.sqrt(x)).

Zadania

Przed wykonaniem zadań należy odświeżyć stronę aby przywrócić jej stan początkowy.

Zadanie 1

  1. Po wygenerowaniu siatki, naciśnij przycisk Build test, plansza powinna wyglądać następująco:
  2. Używając algorytmu wyszukaj najkrótszą ścieżkę, niezależnie od jego rodzaju powinna ona przebiegać następująco:
  3. Zmodyfikuj heurystykę algorytmu Best-First Search i A* w taki sposób aby znaleziona ścieżka przebiegała nad dłuższą krawędzią - tak jak na poniższym rysunku:

Zadanie 2

  1. Zamodeluj planszę jak na rysunku poniżej
  2. Spróbuj wymyślić heurystykę która pozwoli na jak najszybsze znalezienie ścieżki:
    • Przetestuj różne warianty np. „dy”, „dx”, „5*dx”
    • Zanotuj najlepszy rezultat.
    • Dlaczego algorytm tak wolno porusza się wewnątrz labiryntu?
    • W celu lepszego zrozumienia zachowania algorytmu włącz pokazywanie wartości (kliknij „Show values”):
      1. f - oszacowania długości trasy.
      2. g - długości dotychczasowej ścieżki.
      3. h - oszacowania od punktu docelowego (heurystyki).
  3. Uruchom wyszukiwanie dwukierunkowe w we wszystkich algorytmach (zaznacz opcje „Bi-directional”).
  4. Przetestuj różne heurystyki.
  5. Czy Twoja najlepsza heurystyka w wyszukiwaniu jednokierunkowym jest w którymś przypadku lepsza?
  6. Dla tego konkretnego przypadku zaproponuj najszybszy sposób wyznaczania najkrótszej ścieżki pomiędzy punktami końcowymi z wykorzystaniem przeszukiwania jednokierunkowego.
    Spróbuj osiągnąć czas poniżej 50ms i poniżej 200 operacji :!: Jak tego dokonać :?:

4 Problem n-puzzli

Puzzle 3x3 z niezapomnianej gry The Neverhood Chronicles Opisane w poprzednich sekcjach algorytmy nie są ograniczone jedynie do dziedziny planowania tras przejazdu. W ogólnym przypadku pozwalają na znajdywania najkrótszych ścieżek w dowolnych¹ grafach, które dzięki abstrakcyjnej strukturze mogą modelować wiele problemów, będących obiektami zainteresowania sztucznej inteligencji. Sztandarowym przykładem może być tutaj problem n-puzzli, czyli popularna zagadka-układanka, w której należy odtworzyć zadany wzorzec poprzez przesuwanie puzzli zamkniętych w kwadratowej ramce. Jeżeli ktoś nigdy nie grał, to może spróbować na tej stronie lub w przypadku braku wtyczki Flash tutaj.

Z punktu widzenia informatyki rozwiązaniem problemu n-puzzli jest skończony ciąg ruchów [m_1, m_2, …, m_k], których wykonanie w danej kolejności pozwoliłoby na przejście z zadanego stanu początkowego S do stanu końcowego G.

¹oczywiście, istnieją pewne ograniczenia, np. nie może istnieć w grafie cykl o ujemnej sumie wag należących do niego krawędzi. W takim wypadku dla pewnych wierzchołków najkrótsza ścieżka nie istnieje. W problemie znajdywania najkrótszej trasy na mapie sytuacja taka w oczywisty sposób nie występuje.

Reprezentacja grafowa

Problem n-puzzli w prosty sposób daje się przedstawić w postaci problemu znajdowania najkrótszej ścieżki w nieskierowanym grafie:

  1. Za wierzchołki grafu należy przyjąć wszystkie możliwe kombinacje puzzli na planszy.
  2. Między wierzchołkami grafu v_1 i v_2 istnieje krawędź wtedy i tylko wtedy, gdy istnieje pojedynczy ruch, który pozwala na przejście między tymi stanami.

Przy takim kodowaniu problemu, do jego rozwiązania może zostać użyty dowolny z algorytmów zaprezentowanych w poprzednich zadaniach.

Zadania

  1. Oszacuj liczbę wierzchołków w grafie reprezentującym puzzle 5×5. Następnie odpowiedz na poniższe pytania:
    1. Czy taki graf zmieści się w pamięci współczesnego komputera (załóż, że jeden wierzchołek zajmuje w pamięci 32 bity, zignoruj krawędzie)?
    2. Czy graf musi być w całości wygenerowany przed przystąpieniem do szukania rozwiązania?
  2. Zapoznaj się z narzędziem http://home.agh.edu.pl/~kk/psi/npuzzles:
    1. Przeczytaj opis problemu i instrukcję obsługi.
    2. Użyj narzędzia w trybie „single-step” na domyślnych stanach początkowych i końcowych.
      • Wypróbuj różne algorytmy i heurystyki, zapisz liczbę odwiedzonych przez nie wierzchołków.
      • Czym różni się heurystyka „Tiles Out-of-place” od heurystyki „Manhattan Distance”? Możesz spróbować zaobserwować różnice na inaczej zdefiniowanych stanach początkowych/końcowych.
    3. Powtórz eksperyment po zamienieniu 1 z 2 w domyślnym stanie początkowym. Następnie odpowiedz na następujące pytania:
      • Czy algorytm jest w stanie znaleźć rozwiązanie?
      • Jaka jest przyczyna zaobserwowanego stanu rzeczy?

5 Świat klocków

Przykładowy problem ze świata bloków. Kolejnym problemem, który może zostać zamodelowany przy użyciu grafu jest, tzw. świat klocków. Problem jest pozornie mało ambitny: polega na znalezieniu odpowiedniej sekwencji ruchów, pozwalających na przestawienie klocków ze stanu początkowego do zadanego stanu końcowego. W świecie klocków istnieje określona liczba klocków (tradycyjnie każdy klocek wyróżnia narysowana na nim literka) oraz kilka kolumn, w których te klocki mogą leżeć. Każdy klocek leży na dnie jednej z kolumn lub umieszczony jest na innym klocku. Przykładowe stany początkowy i końcowy pokazane są na obrazu powyżej. Jedyną możliwą akcją w świecie klocka jest podniesienie klocka, który jest na szczycie kolumny i położenie go na szczycie kolumnie.

Kodowanie problemu w postaci nieskierowanego grafu działa podobnie jak w n-puzzlach: każdy wierzchołek to możliwe ustawienie klocków; każda krawędź między wierzchołkami v_1 i v_2 odpowiada dozwolonemu przełożeniu klocka, które stan v_1 przekształca w stan v_2 (i vice versa).

Heurystyka

Chociaż świat klocków wydaje się być dziecinny, nie funkcjonują w nim standardowe heurystyki napotkane w poprzednich sekcjach, podczas, gdy jego najtrudniejsze wersje są NP-zupełne. Przykładowa heurystyka dla problemu klocków może zostać zdefiniowana w dwóch następujących regułach:

  1. Jeżeli klocek leży nie w tej kolumnie, w której powinien (w stanie docelowym), należy dodać 1 do wartości heurystyki — intuicyjnie: z pewnością konieczne będzie chociaż jedno przełożenie tego klocka
  2. Jeżeli klocek leży w dobrej kolumnie, ale struktura klocków pod nim nie zgadza się ze stanem docelowym, należy dodać 2 do heurystyki — intuicyjnie: z pewnością trzeba będzie ten klocek przełożyć na inną kolumnę, by potem go przełożyć z powrotem na dobrą kolumnę.

Te dwie reguły są sprawdzane i wykonywane dla każdego klocka osobno.

Zadania

  1. Uruchom rozpakowany applet (narzędzie jest proste, w razie czego tu jest instrukcja obsługi)
    1. Aby uruchomić wpisz w konsoli javaws search.jnlp
    2. Jeżeli program nie chce się uruchomić ze względu na poziom bezpieczeństwa, dodaj aispace do listy wyjątków: uruchom w konsoli ControlPanel → zakładka Security → Edit Site List… → Dodaj wpis http://www.aispace.org/ → zatwierdź
  2. Otwórz w narzędziu załączony graf blocks.xml.
  3. Dokończ budowę grafu:
    1. Dodaj wierzchołki dla pozostałych stanów świata klocków:
      • Podpowiedź: Etykieta węzła opisuje stan 3-kolumnowego, 2-klockowego świata, np. „|ab| | |” oznacza, że w pierwszej kolumnie klocek „a” leży na klocku „b”, a pozostałe kolumny są puste.
    2. W każdym wierzchołku wpisz ręcznie wartość heurystyki wyliczonej według dwóch reguł podanych powyżej (dla stanu początkowego została już policzona).
    3. Dodaj krawędzie między odpowiednimi stanami.
      • Podpowiedź: Graf dla świata klocków powinien być nieskierowany. Krawędź nieskierowaną można symulować dwiema krawędziami skierowanymi.
    4. Uruchom na gotowym grafie algorytm przeszukiwania i zapisz wyniki.

6 Dla zainteresowanych

Podczas tego laboratorium dotknęliśmy bardzo ważnej i wszechobecnej (przemysł, robotyka, gry komputerowe, etc.) dziedziny AI, jaką jest planowanie. Zasadniczo planowanie polega na znalezieniu ciągu akcji (zwanego planem), który po zastosowaniu na stanie początkowym S, doprowadzi do osiągnięcia stanu docelowego G. Każda akcja posiada warunki, w których może zostać wykonana oraz skutki jej zastosowania. Planowanie jest trudne, o ile nie założy się odpowiednich ograniczeń na akcje, jego złożoność jest klasyPSPACE-zupełnej. Trzeba ponadto zauważyć, że w realnych nie zabawkowych problemach występują dodatkowe czynniki zwiększające trudność problemu:

  • niepełna wiedza o aktualnym stanie (np. brak odpowiednich sensorów w robocie)
  • niepewność wynikająca z zawodności akcji (niektóre akcje mogą się zwyczajnie nie powieść)
  • wykonywanie akcji zajmuje czas — plan powinien brać pod uwagę temporalny wymiar problemu
  • mogą wydarzać się zdarzenia niezależne od agenta — np. wypadek drogowy na drodze autonomicznego samochodu.

Świat bloków jest jednym z najbardziej popularnych problemów/zabawek w świecie planowania.

STRIPS

Jednym z najbardziej znanych programów planujących jest powstały na Stanfordzie w latach 70 program STRIPS. Używana w nim reprezentacja wiedzy jest do dzisiaj podstawą większości narzędzi planujących. Przykładowa struktura problemu może być zdefiniowana następująca:

  • na stan składa się z listy zachodzących w nim faktów
  • akcja jest zdefiniowana jako czwórka:
    1. nazwa akcji plus jej argumenty
    2. warunki: lista faktów, które muszą zachodzić, aby akcja była wykonalna
    3. fakty dodawane: lista faktów, które stają się prawdziwe po wykonaniu akcji
    4. fakty usuwane: lista faktów, które przestają być prawdziwe po wykonaniu akcji

Mając taką reprezentację wiedzy, klasyczny program planujący działa według bardzo prostego wzorca (dla zadanego stanu końcowego G i początkowego S):

  1. Sprawdź, czy aktualny stan jest stanem końcowym. Jeżeli tak, wypisz znaleziony plan.
  2. Znajdź fakt F, który jest prawdziwy w stanie końcowym, ale nie jest prawdziwy aktualnym stanie.
  3. Znajdź akcję A, którą na liście faktów dodawanych F.
  4. Uruchom rekurencyjnie rutynę planującą, aby znaleźć plan doprowadzający do stanu, który spełnia warunki wykonania akcji A.
  5. Wykonaj akcję A i zaktualizuj aktualny stan do stanu S'.
  6. Uruchom rutynę planującą zaczynając od nowego stanu S'.

Efektem powyższej procedury będzie „odwrócony plan”, aby miał sens, należy go wypisać idąc od końca. Drugi haczyk polega na unikaniu zapętlenia w planowaniu - jeżeli chcemy osiągnąć warunki wykonania akcji A (punt 4.) należy wyłączyć ją z procesu planowania.

Poniższy kod jest jego prostą implementacją STRIPS w języku Prolog:

| STRIPS regression planner
% Strips as a regression planner.
% Top-level interface.
strips(InitState, GoalList, Plan) :-
	strips1(InitState, GoalList, [], [], _, RevPlan),
	reverse(RevPlan, Plan).
 
% Base case: All goals satisfied in State.
strips1(State, GoalList, Plan, _, State, Plan) :-
 subset(GoalList, State).
 
% Plan
strips1(State, GoalList, Plan, BadActions, NewState, NewPlan) :-
	member(Goal, GoalList),
	not(member(Goal, State)),    % Find unsatisfied goal.
	write('\nAttempting goal:  '),write(Goal),nl,
	adds(Ac, Goal),              % Find action that achieves it.
	write(' Choosing Action:  '),write(Ac),
	not(member(Ac, BadActions)), % Do not repeat actions (dangerous).
	write(' -- not a bad action.'),nl,
	preclist(Ac, PrecList),      % Find preconds and achieve them.       
	strips1(State, PrecList, Plan, [Ac|BadActions], TmpState1, TmpPlan1),
	apply_rule(Ac, TmpState1, TmpState2),  % Recurse w/new state and goals.
	strips1(TmpState2,GoalList,[Ac|TmpPlan1],BadActions,NewState,NewPlan).
 
% Apply Rule
apply_rule(Ac, State, NewState) :-
	write('\nSimulating '),write(Ac),nl,
	write('From: '), write(State), write('\n----> '),
	dellist(Ac, DelList),                     % find deleted props
	subtract(State, DelList, TmpState),       % remove deleted props
	addlist(Ac, AddList),                     % find added props
	union(AddList, TmpState, NewState),       % add props to old state
	write(NewState).
 
% Utilities
preclist(Action, Plist) :- strips_rule(Action, Plist, _, _).
prec(Action, Cond) :- preclist(Action, Plist), member(Cond, Plist).
addlist(Action, Alist) :- strips_rule(Action, _, Alist, _).
adds(Action, Cond) :- addlist(Action, Alist), member(Cond, Alist).
dellist(Action, Dlist) :- strips_rule(Action, _, _, Dlist).
dels(Action, Cond) :- dellist(Action, Dlist), member(Cond, Dlist).
 
% Pretty-print Init, Goal, and Plan.
plan(InitState, Goal) :-
	strips(InitState,Goal,Plan),
	write('\n\nInit: '), write(InitState),nl,
	write('Goal: '),write(Goal),nl,
	write('Plan:\n'),
        writeplan(Plan),nl.
 
% Pretty-print the plan.
writeplan([]).
writeplan([A|B]):-
  write('       '),write(A),nl,
  writeplan(B).

Zadania

  1. Należy pobrać kod programu planującego i uzupełnić go o informacje potrzebne do rozwiązania problemu bloków (sekcje %TODO:). Objaśnienia:
    1. dla wygody planowania możemy pominąć numery kolumn, a stan może być reprezentowane przez pięć typów faktów (przykładowe stany można zobaczyć w sekcji EXAMPLES OF USAGE):
      1. ontable/1 — dany klocek leży na stole, np. ontable(a)
      2. on/2 — dany klocek leży na drugim klocku, np. on(a,b)
      3. clear/1 — na danym klocku nic nie leży, np. clear(a)
      4. holding/1 — dany klocek został właśnie podniesiony, np. holding(a)
      5. handempty/0 — żaden klocek nie jest aktualnie podniesiony, czyli: handempty
    2. potrzebne są cztery rodzaje akcji (jedna z nich już jest zaimplementowana)
      1. połóż klocek X na klocku Y: wykonalna, o ile klocek X jest aktualnie trzymany, a Y jest czysty. Po wykonaniu akcji klocek X leży na klocku Y i jest czysty, klocek Y przestaje być czysty i żaden klocek nie jest aktualnie podniesiony.
      2. zdejmij klocek X z klocka Y: wykonalna, o ile klocek X jest czysty i aktualnie leży na klocku Y. Po wykonaniu akcji klocek X przestaje być czysty, przestaje leżeć na klocku Y i zostaje podniesiony. Klocek Y natomiast staje się czysty.
      3. połóż klocek X na stole: analogicznie do akcji pierwszej z taką różnicą, że nie ma wymagań i zmian względem Y
      4. zdejmij klocek X ze stołu: analogicznie do akcji drugiej
  2. Proszę uruchomić planowanie dla trzech załączonych przykładów oraz dla jednej zamodelowanego samodzielnie.
  3. Proszę usunąć z części warunkowej akcji wszystkie warunki o postaci clear/1 i ponownie uruchomić planowanie dla czterech przypadków.
    1. jaką wartość mają tak wygenerowane plany?
    2. przeczytać pobieżnie stronę wikipedii na temat relaksacji.
pl/dydaktyka/ai/2017/labs/lab_search.txt · ostatnio zmienione: 2017/07/17 08:08 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0