Allgemeine Lösungsbeschreibung
Transcription
Allgemeine Lösungsbeschreibung
Belegarbeit Erstellung eines ProLog Programms Christian Fischer, Matthias Lenk, 44597 BNC 44683 BNC Aufgabenstellung: Erstellung eines POLOG Programms, mit dem alle nicht- repetitiven Wörter über dem Alphabet [a,b,c] der Länge m bestimmt werden. w = a …a ist nicht- repetitiv, wenn keine Teilsequenz xx = x …x x …x für n = 1, 2,…,m/2 1 m in w existiert. abcacbabcbac nicht- repetitiv 1 n 1 n abcbca repetitiv Mathematische Grundidee: Es werden Kombinationen der vorgegebenen Länge m über dem Alphabet [a,b,c] erstellt, indem aus einem Ausgangswort durch Anhängen von zwei „erlaubten“ Zeichen zwei neue Wörter gebildet werden. Dabei müssen nicht alle Kombinationen erstellt werden, sondern es genügt, wenn man ausgehend von [a,b], Wörter erstellt. Die fehlenden Wörter werden durch Permutation von [a,b,c] untereinander, erstellt. Ob ein Element vor oder hinter dem Wort angefügt wird, spielt keine Rolle, da die Wörter vorwärts als auch rückwärts gelesen werden können. Alle neu gebildeten Wörter werden auf Wiederholung der Länge 2 bis m//2 ab der ersten Stelle im Wort geprüft. Nach erfolgloser Prüfung (keine Übereinstimmung der Teilsequenzen), wird wieder jeweils ein „erlaubtes“ Zeichen angehängt. Ansonsten wird das Wort verworfen. Ist die gewünschte Stellenanzahl erreicht, liegt 1/6 der gesuchten Wörter vor. Die restlichen Wörter werden, wie bereits erwähnt, aus den geprüften erstellt, indem die darin enthaltenen Elemente [a,b,c] untereinander ersetzt werden. Es gibt 3! Permutationen, abzüglich der bereits existierenden, also fünf Umwandlungen, die für jedes Element eines Wortes durchgeführt werden müssen. 1. a -> a, b -> c, c -> b 2. b -> b, a -> c, c -> a 3. c -> c, a -> b, b -> a 4. a -> b, b -> c, c -> a 5. a -> c, c -> b, b -> a Funktionsweise des Algorithmus: Zur Speicherstruktur: Jedes Wort, bestehend aus [a, b, c], wird als Liste gespeichert. Die Wörter selbst werden wiederum in einer Liste abgelegt. Bsp.: [[a,b,c,a],[a,b,c,b],[a,c,b,a]] 1. Nach Programmstart wird automatisch die Funktion <start> aufgerufen, in der der Anwender die Stellenanzahl eingibt. Anschließend wird eine Ausgangsliste mit den beiden Ausgangswörtern [[a,b,a],[c,b,a]] erstellt und die Funktion <erstelle> aufgerufen. 2. Ausgehend von der Ausgangsliste werden die möglichen Wörter der Länge i (i=4,..,m) erstellt, indem das erste Element eines jeden Wortes gelesen und wiederum aus der Liste mit den Elementen [a,b,c] gelöscht wird. So verbleiben nur zwei Elemente aus dieser Liste, die jeweils an das Wort angehängt werden, wodurch zwei neue Wörter entstehen. Dadurch wird gleich beim Erstellen vermieden, dass unnötig viele Kombinationen erzeugt werden. Die neuen Wörter werden in einer separaten Liste gespeichert. 3. Nachdem jeweils zwei Wörter auf die genannte Weise erstellt wurden, werden diese der Funktion <pruefe> übergeben. Es werden immer zwei Teilsequenzen der Länge 2 bis, falls nötig, m//2, ab der ersten Position, aus dem Wort miteinander auf Gleichheit überprüft. Die Teilsequenzen werden mittels der Funktion <hole_elem> ermittelt. 4. Ist die Ausgangsliste aus 2. komplett durchlaufen und die Wortlänge m noch nicht erreicht, dient die separat erstellte Liste als neue Ausgangsliste… Ist die Stellenanzahl erreicht, (STELLEN<L) schlägt fehl, wird die Speicherstruktur vereinfacht, indem die Liste mit den Listen zu einer einzigen Liste abgeflacht wird, da für den folgenden Schritt die Elemente aus der Liste nur noch der Reihe nach ausgelesen werden müssen. 5. Weiter wird <subst> aufgerufen. Hier werden lediglich die restlichen Wörter durch Permutation von [a,b,c] erstellt. Dabei wird zunächst das erste Element aus der abgeflachten Liste entnommen (und aus dieser gelöscht) und dessen Position in der Liste [a,b,c] ermittelt. Mittels dieser Position wird nun je ein Element aus den Listen [b,a,c], [b,c,a], [a,c,b], [c,a,b], [c,b,a] selektiert. Die fünf Listen stellen die Permutationen von [a,b,c] dar. Diese fünf erhaltenen Elemente werden für jeden Durchlauf von <subst>, bis die angegebene Länge erreicht ist, zu fünf Wörtern zusammengefügt und anschließend ausgegeben. Dieser Schritt wird wiederholt, bis die abgeflachte Liste leer ist. – Ende 6. Programmneustart mittels <start.>. Erläuterungen zu den Funktionen start/0 erstelle/4 pruefe/5 hole_elem/4 subst/8 Ziel des Programms. Liest die Stellenanzahl von der Tastatur ein, prüft anschließend, ob er größer als drei und ein Integerwert ist. Erstellt neue Wörter durch das Anhängen von zwei Elementen aus [a,b,c] an bereits geprüfte Wörter. Überprüft, ob ein Wort zwei gleiche Teilsequenzen enthält. Erhöht, falls erforderlich, die Länge der Teilsequenzen. Stellt mittels Backtracking die Teilsequenzen aus einem Wort zusammen. [Erstellt die restlichen Wörter.] [Gibt alle Wörter aus.] Bemerkung: Um den Algorithmus weiter zu beschleunigen, kann man auf die Umwandlung der Listen zu Atomen verzichten. Die Umwandlung dient lediglich der besseren Lesbarkeit für den Nutzer. Es wurde eine zweite Version implementiert (repetitiv_short.pl), in der komplett auf die Erzeugung der restlichen Wörter, sowie auf die Umwandlung zu Atomen verzichtet wurde. Hier werden nur die nicht permutierten Listen ausgegeben. Eingebrachte Verbesserungen: 1. Beim Erstellen der Wörter wird darauf geachtet, dass keine zwei gleichen Elemente hintereinander angefügt werden. Das Element, das nicht verwendet werden darf, wird der Liste der möglichen Elemente gelöscht. 2. Beim Anfügen von Elementen werden die Elemente vor dem Wort angefügt. 3. Alle Wörter beginnen beim Erstellen mit [a,b], dadurch müssen nur 1/6 der Wörter auf diese Weise erstellt werden. 4. Als Datenstruktur werden Listen verwendet, mit denen effektiver als mit Strings umgegangen werden kann. 5. Die Wörter werden sofort nach dem Erstellen geprüft. 6. Es werden nur die Teilsequenzen aller möglichen Längen ab der ersten Position im Wort verglichen. 7. Die Permutation am Ende, um die restlichen Wörter zu Erstellen, wird per Selektion realisiert, ohne zu prüfen, um welches Element es sich konkret handelt. 8. In einer zweiten Programmversion (repetitiv_short.pl), wird auf das Erstellen und Konvertieren der restlichen Listen verzichten, was gerade bei einer höheren Stellenanzahl sinnvoll erscheint (s. Testläufe). Testläufe/ Vergleich: Testsystem: CPU: AMD Athlon XP (Barton) 2800+ Speicher FSB: 333 MHz (1024 MB) SWI- Prolog Version 5.4.7 Alte Programmversion Stellenanzahl 10 11 12 13 14 15 16 17 18 Zeit1 0,06 0,14 0,43 1,38 5,30 21,49 89,77 582,96 1912,06 Zeit2 0,05 0,13 0,44 1,43 5,32 21,58 90,85 583,71 1923,02 Zeit3 0,05 0,15 0,43 1,43 5,42 21,45 90,47 580,57 1905,61 Wörter 144 204 264 342 456 618 798 1044 1392 Zeit3 0,01 0,03 0,05 0,08 0,09 0,15 0,23 0,31 0,55 0,75 1,21 1,78 2,76 3,75 5,55 8,64 13,12 29,91 70,42 169,06 Wörter 144 204 264 342 456 618 798 1044 1392 Aktuelle Programmversion (repetitiv.pl) Stellenanzahl 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 28 30 32 Zeit1 0,01 0,01 0,05 0,06 0,09 0,12 0,21 0,33 0,56 0,72 1,18 1,81 2,78 3,99 5,61 8,80 12,87 33,61 70,64 189,25 Zeit2 0,02 0,01 0,04 0,06 0,10 0,13 0,20 0,30 0,53 0,80 1,15 1,75 2,85 3,82 5,52 8,53 13,03 29,85 70,68 169,19 Aktuelle Programmversion (repetitiv_short.pl) Stellenanzahl 28 30 32 33 Zeit1 25,25 61,05 149,73 235,55 Zeit2 25,45 61,25 150,08 233,24 *Alle Zeitangaben in Sekunden Zeit3 25,41 61,12 149,83 229,87 Verallgemeinerung Das verwendete Alphabet kann problemlos durch entsprechende Ergänzungen erweitert werden. Letztlich kann man sagen, dass sich die Programmiersprache Prolog gut für derartige kombinatorische Aufgabenstellungen eignet, insofern die Speicherstrukturen nicht zu komplex werden.