Begreper & referanser
Alle nøkkelbegrepene, formlene og referansene fra Søkeproblemer og uinformert søk, samlet på én side. Bruk denne som oppslag når du leser, øver flashcards eller tar quiz.
Begreper
Sentrale begreper fra kapittelet med korte definisjoner.
Mengden av alle tilstander miljøet kan være i, sammen med handlingene som fører mellom dem. Det kan tegnes som en graf med tilstander som noder og handlinger som kanter (state space).
Funksjonen som gir tilstanden handlingen fører til fra tilstanden . Den beskriver hva handlingene gjør, mens handlingsmengden bare sier hva som er lov (transition model).
Handlingskostnaden er prisen for ett steg, for eksempel minutter. Stikostnaden er summen av handlingskostnadene langs hele stien fra start til (action cost, path cost).
Et tre der roten er starttilstanden, hver kant er en handling og hver node svarer til en sti fra roten. Samme tilstand kan stå i mange noder hvis grafen har sykler eller flere veier til den (search tree).
Nodene som er generert, men ikke ekspandert ennå. De uinformerte søkene skiller seg bare i hvilken frontier-node de tar ut neste gang (frontier).
En tabell over tilstandene søket har nådd, med beste kjente stikostnad og forelder for hver. Et barn legges bare inn i frontier hvis tilstanden er ny, eller hvis den nye stien er strengt billigere (reached set).
Søk uten nådd-mengde: hver generert node legges i frontier, også om tilstanden er sett før. Det sparer minnet til nådd-mengden, men kan gjenta arbeid og gå i ring for alltid på en graf med sykel (tree-like search).
Søk med nådd-mengde eller utforsket-mengde, slik at en tilstand ikke utforskes på nytt uten grunn. Grafsøk er fullstendig i endelige tilstandsrom der trelikt søk kan gå i ring (graph search).
Antall barn en node har, . Sammen med dybden til grunneste mål og største dybde bestemmer den tid og minne for de uinformerte søkene (branching factor).
Sjekken av om en tilstand er et mål. BFS tester når noden genereres (tidlig), mens UCS, DFS, DLS og IDS tester når noden tas ut av frontier (sent); UCS trenger sen måltest for å være optimal (goal test).
Søk som ekspanderer grunneste node først, med frontier som FIFO-kø og måltest ved generering. Det er fullstendig, og optimalt når alle handlinger koster det samme (breadth-first search).
Søk som ekspanderer noden med lavest stikostnad , med måltest ved uttak og oppdatering av frontier når en billigere sti dukker opp. Det er fullstendig og optimalt når alle kostnader er minst (uniform-cost search).
Søk som ekspanderer dypeste node først, med frontier som stakk. Det bruker lite minne, , men er ikke optimalt, og som trelikt søk er det ikke fullstendig på grafer med sykler (depth-first search).
DFS med en grense der noder på dybde måltestes, men ikke ekspanderes. Søket gir en løsning, cutoff (grensen stoppet minst én gren) eller failure (ingen løsning i hele treet) (depth-limited search).
Gjentatt dybdebegrenset søk med til det finnes en løsning eller resultatet blir failure. Det er fullstendig og optimalt ved like kostnader, med minne (iterative deepening search).
To søk samtidig, ett forover fra start og ett bakover fra målet, som stopper når de møtes. Tid og minne blir i stedet for (bidirectional search).
En algoritme er fullstendig hvis den finner en løsning når det finnes en, og melder fra når det ikke finnes noen. Den er kostnadsoptimal hvis løsningen den finner, har lavest stikostnad av alle løsninger (completeness, cost optimality).
Formler
Hver formel: hva den heter, hvordan den ser ut, og hva symbolene betyr.
Stikostnad
Summen av handlingskostnadene langs stien fra start til . UCS sorterer frontier på ; en vanlig feil er å bruke kostnaden til siste kant i stedet for hele summen.
Noder generert av BFS
Tid og minne for BFS når grunneste mål ligger på dybde . Alle nodene ligger i minnet samtidig, så minnet sprekker før tiden; med måltest ved uttak blir det .
Kompleksitet for UCS
Tid og minne for UCS når hver handling koster minst . Uttrykket kan bli mye større enn , fordi UCS kan utforske mange billige kanter før en dyr kant mot målet; med like kostnader blir det .
Minne for DFS
Trelikt DFS lagrer bare stien fra roten og de ikke-ekspanderte søsknene langs den. Tiden er derimot , og kan være mye større enn eller uendelig.
Minne for IDS
IDS bruker minne som DFS, men bare ned til dybden for grunneste løsning. Tiden er som for BFS, og derfor er IDS standardvalget når tilstandsrommet er stort og kostnadene er like.
Noder generert av IDS
Nodene på dybde genereres på nytt i hver iterasjon med , altså ganger. Siden nederste nivå dominerer, er ekstraarbeidet lite når er stor; en vanlig feil er å tro at IDS bruker ganger så lang tid som BFS.
Toveis søk
To søk som møtes på midten, hvert til dybde , og er langt mindre enn . Det krever at handlingene kan reverseres og at målet er en konkret tilstand, og minnet er også , fordi det ene søket må huske frontier for å se at de møtes.
Kodesnutter
Kodesnutter fra kapittelet, vist literal.
BFS med tidlig eller sen måltest
from collections import deque tidlig_maltest = 1 # @param 0..1 # Urettet graf; naboene står i alfabetisk rekkefølgenaboer = {"S": "ABC", "A": "DS", "B": "ES", "C": "FS", "D": "AG", "E": "B", "F": "C", "G": "D"}frontier = deque(["S"])forelder = {"S": None} # nådd-mengdenutvidet, funnet = [], Nonewhile frontier and funnet is None: node = frontier.popleft() if not tidlig_maltest and node == "G": funnet = node break utvidet.append(node) for barn in naboer[node]: if barn not in forelder: forelder[barn] = node if tidlig_maltest and barn == "G": funnet = barn break frontier.append(barn)sti, node = [], funnetwhile node is not None: sti.insert(0, node) node = forelder[node]print(f"Ekspansjonsrekkefølge: {', '.join(utvidet)}")print(f"Funnet sti: {' → '.join(sti)}")print(f"Antall ekspansjoner: {len(utvidet)}")Prøv: sett tidlig_maltest til 0 og se at Antall ekspansjoner: øker fra 5 til 7, mens Funnet sti: er den samme.
UCS med en justerbar kant
import heapq kost_SB = 4 # @param 1..9 kanter = {("S", "A"): 2, ("S", "B"): kost_SB, ("A", "C"): 3, ("B", "C"): 1, ("C", "G"): 2, ("B", "G"): 6}naboer = {}for (u, v), c in kanter.items(): naboer.setdefault(u, []).append((v, c)) naboer.setdefault(v, []).append((u, c))frontier = [(0, "S")] # (g, node): lavest g først, likt g alfabetiskbeste = {"S": 0}forelder = {"S": None}utvidet = []while frontier: g, node = heapq.heappop(frontier) if g > beste[node]: continue # utdatert post, erstattet av en billigere sti if node == "G": break # måltest ved uttak utvidet.append(node) for barn, c in sorted(naboer[node]): if barn not in beste or g + c < beste[barn]: beste[barn], forelder[barn] = g + c, node heapq.heappush(frontier, (g + c, barn))sti, node = [], "G"while node is not None: sti.insert(0, node) node = forelder[node]print(f"Ekspansjonsrekkefølge: {', '.join(utvidet)}")print(f"Funnet sti: {' → '.join(sti)}")print(f"Kostnad: {beste['G']}")Prøv: sett kost_SB til 1 og se at Funnet sti: går via B og Kostnad: faller til 4, og sett den så til 9 og se at B ekspanderes sist på linja Ekspansjonsrekkefølge:.
Hva koster gjentakelsene i IDS?
b = 3 # @param 2..12d = 6 # @param 1..8 # Regnet med formlene, uten å kjøre søket (roten telles ikke som generert)bfs = sum(b ** i for i in range(1, d + 1))ids = sum((d + 1 - i) * b ** i for i in range(1, d + 1))ekstra = 100 * (ids - bfs) / bfs def tall(n): return f"{n:,}".replace(",", " ") print(f"Noder generert av BFS: {tall(bfs)}")print(f"Noder generert av IDS: {tall(ids)}")print(f"Ekstra arbeid for IDS: {ekstra:.1f} %")Prøv: øk b fra 3 til 10 og se at Ekstra arbeid for IDS: faller fra rundt 49 % til rundt 11 %, mens Noder generert av BFS: vokser kraftig.
Pseudokode
Pseudokode som forklarer fremgangsmåten steg for steg.
Best-først-søk (pseudokode)
best_forst(start, er_maal, naboer, prioritet): beste_g = {start: 0} # nådd-mengden: billigste kjente sti hit forelder = {start: ingen} kø = prioritetskø med posten (prioritet(start, 0), 0, start) så lenge kø ikke er tom: (_, g, x) = ta ut posten med lavest prioritet hvis g > beste_g[x]: hopp over posten # utdatert: x er nådd billigere siden hvis er_maal(x): # måltest ved uttak returner stien til x langs forelder, og g for (y, kost) i naboer(x): g_y = g + kost hvis y ikke er i beste_g eller g_y < beste_g[y]: # ny eller strengt billigere beste_g[y] = g_y forelder[y] = x legg (prioritet(y, g_y), g_y, y) i kø returner «ingen løsning»Samme løkke for alle søkene, bare prioriteten skiller dem. En billigere sti legger en ny post i køen i stedet for å lete opp den gamle, og den gamle hoppes over når den kommer ut.
Læringsmål
Hva du skal kunne etter å ha lest kapittelet.
- 01Formaliser en oppgave som søkeproblem med tilstandsrom, starttilstand, måltest, handlinger, overgangsmodell og handlingskostnad
- 02Spor BFS, UCS og DFS med minne på en graf og oppgi ekspansjonsrekkefølge, funnet sti og stikostnad
- 03Spor DLS og IDS og avgjør om søket gir en løsning, cutoff eller failure
- 04Forklar forskjellen på trelikt søk og grafsøk, og hvorfor BFS tester mål ved generering mens UCS tester ved uttak
- 05Sammenlign de uinformerte søkene i fullstendighet, optimalitet, tid og minne
- 06Regn ut hvor mange noder BFS og IDS genererer for gitte og