Till KTH:s startsida Till KTH:s startsida

Laboration 4

Laboration 4 - Från söt till sur

Det gäller att finna kortaste vägen från söt till sur genom att byta ut en bokstav i taget, till exempel så här:

söt->söm->döm->dum->dur->sur

Alla mellanliggande ord måste finnas i ordlistan word3.txt  från förra laborationen.

Ditt program ska finna en kortare väg till sur än den här föreslagna. Lösningsprincipen gås igenom nedan och den beskrivs ofta i läroböcker för det analoga problemet att finna kortaste väg i en graf.

Breddenförstsökning

Hur ska vi använda breddenförstsökning i det här problemet?

Problemträdets urmoder/stamfar söt har barnen nöt, sot, söm med flera,
barnbarnen döm, som, not osv. Enligt kedjan ovan är
sur barnbarnbarnbarnbarn till söt, men sur finns säkert redan tidigare i
problemträdet. För att finna den första förekomsten gör man en
breddenförstsökning enligt följande.
Lägg urmodern/stamfadern som första och enda post i en kö.
Gör sedan följande om och om igen:

  • Plocka ut den första ur kön,
  • skapa alla barn till den
  • och lägg in dom sist i kön.

Första förekomsten av det sökta ordet ger kortaste lösningen.
Man kan spara in både tid och utrymme om man undviker att skapa barn som är
kopior av tidigare släktingar (t ex nöts barn söt), så
kallade besöktabarn. Uppgiften är så komplicerad att det är lämpligt att
lösa den stegvis.

  1. Första versionen

    Låt filen bfs.py utgå från förra labben, som ju har
    två binärträd. Nu kallar vi dom svenska (ordlistan) och gamla (dumbarnen).
    Huvudprogrammet ska läsa in ordlistan, fråga efter startord och slutord,
    och göra anropet makechildren(startord).
    Denna funktion går systematiskt igenom alla sätt att byta ut en bokstav
    i startordet (aöt, böt, ..., söö), kollar att det nya ordet finns i
    ordlistan men inte finns i gamla och skriver i så fall ut det nya ordet på
    skärmen och lägger in det i gamla.
    Om du gjort rätt ska söt få 10 barn.
  2. Andra versionen

    För fortsatt genomgång av söts barnbarn osv behövs den köklass som du använde i kortkonstlabben. Importera den och skapa kön q. I stället för att skriva ut barnen på skärmen lägger makechildren in dom i kön. Huvudprogrammet lägger in startordet i kön och går sedan i en slinga

    while not q.isEmpty():
        nod = q.get()
        makechildren(nod)
    


    När makechildren() stöter på slutordet gör den utskriften
        print("Det finns en väg till", slutord)
    
    Provkör med lite olika start- och slutord, bland annat blå - röd, ful - fin och ute - hit.
  3. Tredje versionen

    Det tråkiga med programmet är att det bara talar om att det finns en lösning. För att programmet ska kunna skriva ut alla ord på vägen mellan söt och sur måste varje ord kunna peka på sin förälder. Det är alltså inte typen string man ska arbeta med utan en ParentNode som ser ut så här.

    class ParentNode:
        def __init__(self, word, parent = None):
            self.word = word
            self.parent = parent
    


    Huvudprogrammet skapar ett sådant objekt och lägger in startordet. Det som sätts in i kön och plockas ut ur kön är nu inte längre ord utanParentNode, och det betyder att du måste ändra i makechildren.

    När makechildren finner slutordet vill den skriva ut hela kedjan genom ett anrop writechain(child). Metoden writechain() ska skrivas rekursivt, så att man får ut kedjan med slutordet sist.

    Om kön töms utan att någon lösning påträffats bör programmet meddela att det är omöjligt. Och när en lösning skrivits ut bör programmet avbryta körningen. Ett sätt att göra det är sys.exit() om man importerar modulen sys.

Betyg

betyg E: Ditt program ska lösa uppgifterna ovan.
Vid redovisningen ska du också kunna

  • rita upp problemträdet,
  • förklara i detalj hur breddenförstsökningen fungerar,
  • förklara varför breddenförstsökning ger den kortaste lösningen,
  • visa hur utskriften av lösningen fungerar

betyg C:

  • Kraven för E uppfyllda
  • Perfekt program
  • Labben inlämnad via KTH Social i tid och redovisad i tid (se datum under Laborationer).
    Du ska också:

betyg A:

  • Kraven för C uppfyllda
  • Följande två extrauppgifter:
    • Längst från söt: Undersök vilka trebokstavsord som har längst väg till söt (längsta kortaste vägen, inte längsta omvägen).
    • Du måste då skriva en rekursiv countchain(child) som returnerar kedjans längd. Ledning: Om startord och slutord byter roller ändrar det inte kedjans längd.
    • Längst från varandra: Vilka två ord är längst från varandra? Ledning: Iterera över föregående uppgift.

Denna labb ska du redovisa tillsammans med labb 2 och labb 3.

Alexander Baltatzis skapade sidan 23 januari 2015

kommenterade 2 februari 2015

Betyg C:
   

  • kunna jämföra algoritmerna och förklara skillnaden i resultat

Vilka algoritmer ska jämföras? Eftersom djupet-först är överstruken.

kommenterade 12 februari 2015

Betyg A:

Ska man verkligen göra en djupetförst-sökning och skapa hela problemträdet under söt? Tycker dels ledningen indikerar att man ska hålla på med breddenförst (och hitta den längsta optimala vägen, inte längsta tänkbara), och när jag skrivit en funktion för att skapa hela trädet genom djupetförst så skjuter processtiden i höjden...

Testade med lite förkortade ordlistor:

15 ord = 0.0068904801113127455 
30 ord = 0.014822127640980896
40 ord = 0.7422847787468032
45 ord = 34.117401355361025
50 ord = 234.55052904959507

Om man kör på word3.txt, som har 750 ord, vet jag inte hur lång tid det kommer ta. Om man sen i andra A-uppgiften ska skapa ett problemträd för varje ord i word3.txt...

Är det jag som har gjort ett ineffektivt program, eller är det inte tänkt att man ska göra djupetförst?

En användare har tagit bort sin kommentar
kommenterade 12 februari 2015

Jag är ingen expert/ansvarig för kursen, men fick en notis eftersom jag kommenterat tidigare.

Utgående från att man ska hitta den längsta optimala vägen lyckas jag köra word3.txt och hitta ordet som står längst ifrån t.ex. "söt" på under sekunden.

Tror du får fila lite på din kod, det finns ett "antagande" du måste göra för att snabba upp programmet.

kommenterade 12 februari 2015

Jo, längsta optimala vägen är snabb, och det var så jag först tolkade uppgiften. Men när jag frågade Alexander sa han uttryckligen att man ska skriva ut hela trädet och hitta det ord som har längst tänkbara väg, och att det får ta lång tid. Men nu när jag gjort det programmet verkar det ta orimligt lång tid.

Lärare kommenterade 13 februari 2015

Kan du komma förbi på labbtiden idag så kan vi titta på koden.

Lärare kommenterade 13 februari 2015

Problemformuleringen är inte helt bra. Jag ska se över den.

kommenterade 23 februari 2015

Då hela koden finns färdig i boken ska man bara kopiera den, men att man förstår den så pass bra att man ska kunna jämföra de olika metoderna man använt sig av (sin egna version och bokens), eftersom att dessa noder är helt anpassade efter grafer och inte lika enkla som  i träden i grunduppgiften?

Lärare kommenterade 23 februari 2015

Ja

Lärare kommenterade 26 februari 2015

@Rebecca det räcker med bokens sätt att generera "barn"-orden i en datastruktur och göra jämförelser. Det är berömvärt om du även implementerar bokens bfs-algoritm (på sidan efter) men klasserna i boken saknar några get/set-metoder som måste implementeras och färgattributet måste vitfärgas initialt. Man behöver slutligen en loop för att skriva ut vägen, ungefär så här (OBS otestat):

  g = buildGraph('word3.txt')
  g_bfs = bfs(g, g.getVertex('söt'))
  v = g.getVertex('sur')
  while v != None:
      print(v.id)
      v = v.getPredicate()

Jag tar med mig godis till de som implementerar bokens bfs-algoritm.

kommenterade 2 mars 2015

getPredicate() ska vara getPred() bara.