In 1996 voerde Alan Sokal1 — hoogleraar in de natuurkunde aan de universiteit van New York — het volgende ietwat onethische experiment uit. Hij stuurde een nepartikel, doorspekt met onzinnige redeneringen en pseudowetenschappelijk jargon, naar het Amerikaanse tijdschrift Social Text dat wordt uitgegeven door Duke University. Met dit experiment wilde Sokal te weten komen of een goed gemaakt, maar compleet onzinnig artikel zou kunnen gepubliceerd worden in een postmodern tijdschrift, als het maar goed zou klinken en de redactieleden om de oren zou slaan met ideologische maar holle concepten. Het artikel werd inderdaad gepubliceerd en veroorzaakte heel wat verontwaardiging in de internationale academische wereld.

Deze Sokal-affaire2 doet de vraag rijzen of het mogelijk is om een computer willekeurige nonsensicale taal te laten genereren, die op het eerste gezicht toch welluidend is. Natuurlijke taal is immers zeer gestructureerd en totaal niet willekeurig opgebouwd: niet elke reeks letters vormt een woord, en niet elke reeks woorden vormt een betekenisvolle en grammaticaal correcte zin. Toch klinken bepaalde aspecten van willekeurig gegenereerde zinnen vertrouwd in de oren, als ze maar voldoende gestructureerd zijn opgebouwd. Daarbij komt nog dat elke auteur een eigen patroon heeft om woorden te kiezen. Door de volgorde van naburige woorden in een tekst te behouden maar voor de rest de tekst willekeurig op te bouwen, is het mogelijk om willekeurige tekst te genereren die er verrassend goed uitziet en die grotendeels de stijl (maar niet de betekenis) van de originele tekst behoudt.

Opgave

  1. Schrijf een functie woordenlijst waarmee een lijst van woorden kan uitgelezen worden uit een tekstbestand. De locatie van het tekstbestand moet als argument aan de functie doorgegeven worden. De functie moet als resultaat een lijst van de woorden teruggeven, in de volgorde waarin ze in het tekstbestand voorkomen. Een woord wordt in het tekstbestand gevormd door de langst mogelijke reeks karakters waarin geen witruimtekarakters (spaties, tabs, carriage returns en newlines) voorkomen. De woorden worden in het tekstbestand dus van elkaar gescheiden door één of meer opeenvolgende witruimtekarakters. Leestekens die eventueel aan een woord zouden vasthangen, maken dus deel uit van dat woord.

  2. Schrijf een functie vervolgwoorden met twee parameters: een parameter woorden waaraan een lijst van woorden moet doorgegeven worden, en een parameter k waaraan een natuurlijk getal ($$k \geq 1$$) moet doorgegeven worden. De functie moet als resultaat een dictionary teruggeven, waarvan de sleutels gevormd worden door alle tuples van $$k$$ woorden die opeenvolgend in de opgegeven woordenlijst voorkomen, en waarna minstens nog één woord staat. De dictionary beeldt elk van deze $$k$$-tuples af op de lijst van woorden die in de gegeven woordenlijst voorkomen na deze opeenvolging van $$k$$ woorden, en dit in de volgorde waarin deze woorden voorkomen in de gegeven woordenlijst. Als in de dictionary bijvoorbeeld een sleutel ('aa', 'bb', 'cc') voorkomt met bijhorende waarde ['dd', 'ee', 'dd', 'ff'], dan betekent dit dat in de gegeven woordenlijst de woorden aa, bb en cc vier keer na elkaar voorkomen, en dat deze voorkomens respectievelijk gevolgd worden door de woorden dd, ee, dd en ff. Merk dus op dat hetzelfde woord meerdere keren kan volgen op hetzelfde $$k$$-tuple, waardoor het ook meerdere keren voorkomt in de lijst waarop dit $$k$$-tuple wordt afgebeeld door de dictionary.

  3. Schrijf een functie nonsens die een willekeurig gegenereerde tekst als resultaat teruggeeft. Deze functie heeft de volgende drie parameters: een parameter start waaraan een tuple van woorden moet doorgegeven worden, een parameter vervolg waaraan een dictionary moet doorgegeven worden die opgebouwd is zoals de dictionaries die door de functie vervolgwoorden teruggegeven worden, en een parameter minimumlengte waaraan een natuurlijk getal moet doorgegeven worden. De willekeurige tekst moet door de functie op de volgende manier gegenereerd worden:

    1. De woorden van het tuple start vormen de eerste woorden van de tekst, en worden daarbij telkens van elkaar gescheiden door één enkele spatie.

    2. Gebruik de dictionary vervolg om het volgende woord van de tekst te bepalen, door een willekeurig woord te kiezen uit de lijst die door de dictionary wordt afgebeeld op het tuple start. Dit nieuwe woord wordt achteraan de tekst toegevoegd, voorafgegaan door één enkele spatie.

    3. Bereken een nieuwe waarde voor het tuple start, door het eerste woord weg te laten uit de oude waarde van het tuple start, en achteraan het tuple het nieuwe woord toe te voegen dat werd gevonden in stap b.

    4. Blijf deze procedure herhalen vanaf stap b, totdat

      • tuple start geen sleutel is van de dictionary vervolg, of

      • de gegeneerde tekst bestaat uit minstens minimumlengte woorden en het laatste woord eindigt op een punt (.), een vraagteken (?) of een uitroepteken (!), of

      • de gegenereerde tekst bestaat uit minstens twee keer zoveel woorden als aangegeven door de parameter minimumlengte.

Voorbeeld

Onderstaand voorbeeld veronderstelt dat het tekstbestand shelovesyou.txt3 met de tekst van het nummer She Loves You van de Beatles zich in de huidige map bevindt. Klik hier om de tekst van dit nummer te bekijken. Merk op dat de uitvoer van het voorbeeld gedeeltelijk werd weggelaten om plaats te besparen, en dat de uitvoer van de functie nonsens over verschillende regels werd uitgeschreven om de tekst niet onnodig breed te maken.

>>> woorden = woordenlijst('shelovesyou.txt')
>>> woorden
['She', 'loves', 'you,', 'yeh,', 'yeh,', ..., 'yeh;', 'yeh,', 'yeh,', 'yeeeh!']

>>> k = 3
>>> start = tuple(woorden[:k])
>>> start
('She', 'loves', 'you,')
>>> vervolg = vervolgwoorden(woorden, k)
>>> vervolg
{
  ('yeh,', 'yeh.', 'She'): ['loves', 'loves'], 
  ('should', 'be', 'glad.'): ['Ooh!', 'Ooh!', 'And', 'Ooh!', 'And', 'And'], 
  ('you', 'shouuuld', 'be'): ['glad.'], 
  ("It's", 'you', "she's"): ['thinking'], 
  ..., 
  ('like', 'that,', 'you'): ['know', 'know', 'know', 'know']
}

>>> nonsens(start, vervolg, 25)
She loves you, yeh, yeh, yeh, yeeeh! You think you lost your
love, when I saw her yesterday. It's you she's thinking of,
and she told me what to say.

>>> nonsens(start, vervolg, 25)
She loves you, yeh, yeh, yeh. She loves you, yeh, yeh, yeh.
She loves you, yeh, yeh, yeh. She loves you, yeh, yeh, yeh!
She loves you, yeh, yeh, yeh.

>>> nonsens(start, vervolg, 25)
She loves you, yeh, yeh, yeh. She loves you, yeh, yeh, yeh!
And with a love like that, you know you should be glad. And
now it's up to you, I think it's only fair, if I should hurt
you too, apologize to her, because she loves you, and you

>>> nonsens(start, vervolg, 25)
She loves you, yeh, yeh, yeh! And with a love like that, you
know you shouuuld be glad. Yeh, yeh, yeh; yeh, yeh, yeh;
yeh, yeh, yeh; yeh, yeh, yeh; yeh, yeh, yeh; yeh, yeh, yeh;
yeh, yeh, yeh; yeh, yeh, yeh; yeh, yeh, yeh; yeh, yeh, yeh;
yeh, yeh,

De volgende tekstbestanden kunnen gebruikt worden om je oplossing verder uit te testen. De eerste daarvan wordt ook door ons gebruikt om je oplossing automatisch te testen.

Wetenschappelijke achtergrond

Het thema van deze opgave is eerder een spielerei om je vertrouwd te maken met het inlezen van informatie uit bestanden en het leren werken met dictionaries in Python. Toch is het interessant om weten dat gelijkaardige concepten gebruikt worden bij belangrijke wetenschappelijke problemen die gebruikmaken van Markov ketens8 om probabilistische processen te modelleren. Bij de studie van genoomsequenties is er bijvoorbeeld heel wat bewijsmateriaal dat aangeeft dat DNA sequenties hogere-orde structuren bevatten (Karlin et al., 1998). Dit betekent dat het niet voldoende is om de frequenties van de nucleotiden A, C, G en T te beschrijven in een genoom, maar ook de correlaties tussen langere reeksen nucleotiden. Het gebruik van codons (tripletten van nucleotiden) om de aminozuren waaruit eiwitten zijn opgebouwd te coderen, geeft bijvoorbeeld reeds aan dat er belangrijke drie-letter correlaties te vinden zijn in een genoomsequentie. Voor wat natuurlijke taal betreft, zal deze opgave je hopelijk reeds intuitief hebben doen aanvoelen dat drie-woord correlaties kunnen helpen om karakteristieke eigenschappen van de taal weer te geven.

Karlin S, Campbell AM, Mrázek J (1998). Comparative DNA analysis across diverse genomes. Annu Rev Genet 32, 185-225. 9