# CYK-algoritme

Het Cocke-Younger-Kasami (CYK)-algoritme (soms ook bekend als CKY) bepaalt of een string gegenereerd kan worden door een gegeven contextvrije grammatica en, als dit het geval is, levert het de manier waarop de string gegenereerd kan worden. Dit proces noemt men het parsen of ontleden van de string. Het algoritme is een voorbeeld van dynamisch programmeren.
De standaardversie van het CYK-algoritme herkent talen die gedefinieerd zijn door contextvrije grammatica's in Chomsky-normaalvorm. Aangezien elke contextvrije grammatica op eenvoudige wijze in deze normaalvorm om te zetten is, kan het CYK-algoritme gebruikt worden om alle contextvrije talen te herkennen. Het is eveneens mogelijk het CYK-algoritme uit te breiden zodat de gegeven contextvrije grammatica niet noodzakelijk in Chomsky-normaalvorm moet staan. Zo'n uitbreiding maakt het algoritme meer performant, maar ook moeilijker om de werking te begrijpen.
In het slechtste geval is de asymptotische tijdscomplexiteit van het CYK-algoritme Θ(n$^3$), waar n de lengte van de geparseerde string is. Dit maakt het een van de meest efficiënte algoritmes voor het herkennen van contextvrije talen qua tijdscomplexiteit. Er zijn echter wel andere algoritmes die nog beter presteren om bepaalde deelgroepen van de contextvrije talen te herkennen.
Het algoritme is vernoemd naar John Cocke, Daniel H. Younger en Tadao Kasami.

## Het algoritme

Het CYK-algoritme is een bottom up-algoritme en is van theoretisch belang, aangezien het gebruikt kan worden om een constructief bewijs te leveren dat het beslisbaar is of een string tot een contextvrije taal behoort.
Het algoritme werkt als volgt:

### Informeel

Simpeler uitgelegd: het algoritme beschouwt alle mogelijke onderdelen van de groep woorden en zet P[i,j,k] op true als de groep woorden beginnend vanaf letter i en van lengte j gegenereerd kan worden vanaf R$_k$. Zodra alle onderdelen van lengte 1 beschouwd zijn, worden alle onderdelen van lengte 2 beschouwd, enz. Voor onderdelen van lengte 2 en groter beschouwt het algoritme elke deelstring in 2 delen, en controleert zo of er een productie P → Q R is, zodat Q overeenkomt met het eerste deel en R met het tweede deel. Als dit positief is dan wordt besloten dat P er ook mee overeenkomt. Wanneer dit proces voltooid is, dan wordt de string herkend door de grammatica als de hele string overeenkomt met het startsymbool.

### Uitbreiding van het algoritme

Het is eenvoudig om het bovenstaande algoritme uit te breiden zodat het, naast bepalen of een string tot een taal behoort, een syntaxisboom van de string opstelt door knopen van de boom op te slaan in de array, in plaats van de booleans. Aangezien de grammatica's die herkend worden dubbelzinnig kunnen zijn, is het nodig om een lijst van die knopen bij te houden (behalve als je maar interesse hebt in 1 mogelijke boom). Het resultaat kan dan bestaan uit meerdere bomen. Een alternatieve mogelijkheid is een tweede tabel B[n,n,r] bij te houden met zogenaamde backpointers.
Het is eveneens mogelijk om het bovenstaande algoritme uit te breiden zodate het strings kan parseren door middel van gewogen en stochastische contextvrije grammatica's. In dat geval worden gewichten (of kansen) in de array P opgeslagen in plaats van booleans, zodat P[i,j,A] het minimum gewicht (of maximum kans) bevat waarmee de deelstring van i to j afgeleid kan worden uit A. Verdere uitbreidingen hierop laten toe om alle mogelijke parseringen van de string te vinden, gesorteerd van laagste naar hoogste gewicht (of hoogste naar laagste kans).

## Voorbeeld

Veronderstel de volgende productieregels van een bepaalde contextvrije grammatica:
| Productieregel | Beschrijving |
| E → OWS | Een Element bestaat uit een Opentag, een Woord en een Sluittag |
| O → KLG | Een Opentag bestaat uit een Kleiner-dan, een Letter en een Groter-dan |
| S → KDLG | Een Sluittag bestaat uit een Kleiner-dan, een Deelteken, een Letter en een Groter-dan |
| W → LLLLLLLLL | Een Woord bestaat uit 9 Letters |
| L → a | b | .. | z | Een Letter behoort tot het Nederlands alfabet |
| K → < | Een Kleiner-dan is het teken < |
| G → > | Een Groter-dan is het teken > |
| D → / | Een Deelteken is het teken / |
De volgende invoerstring <b>wikipedia</b> levert dan volgende tabel op:
E :
| O | O | O | W | W | W | W | W | W | W | W | W | S | S | S | S |
| K | L | G | L | L | L | L | L | L | L | L | L | K | D | L | G |
| < | b | > | w | i | k | i | p | e | d | i | a | < | / | b | > |
We kunnen dus besluiten dat de invoerstring tot de taal behoort.