Aidez-moi! J'ai plus de devoirs!

18

Mon professeur était plus que mécontent de mes devoirs martiens . J'ai suivi toutes les règles, mais elle dit que ce que je produisais était du charabia ... quand elle l'a regardé pour la première fois, elle était très méfiante. "Toutes les langues devraient suivre la loi de Zipf bla bla bla" ... Je ne savais même pas quelle était la loi de Zipf!

Il s'avère que la loi de Zipf stipule que si vous tracez le logarithme de la fréquence de chaque mot sur l'axe des y, et le logarithme de la "place" de chaque mot sur l'axe des x (le plus commun = 1, le deuxième le plus commun = 2, troisième plus commun = 3, et ainsi de suite), le tracé affichera une ligne avec une pente d'environ -1, donnant ou prenant environ 10%.

Par exemple, voici un complot pour Moby Dick:

entrez la description de l'image ici

L'axe des x est le n ème mot le plus courant, l'axe des y est le nombre d'occurrences du n ème mot le plus courant. La pente de la ligne est d'environ -1,07.

Maintenant, nous couvrons Venutian. Heureusement, les Vénutiens utilisent l'alphabet latin. Les règles sont les suivantes:

  • Chaque mot doit contenir au moins une voyelle (a, e, i, o, u)
  • Dans chaque mot, il peut y avoir jusqu'à trois voyelles d'affilée, mais pas plus de deux consonnes d'affilée (une consonne est une lettre qui n'est pas une voyelle).
  • Pas de mots de plus de 15 lettres
  • Facultatif: regrouper les mots en phrases de 3 à 30 mots, délimitées par des points

Parce que l'enseignant sent que j'ai triché sur mes devoirs martiens, j'ai été chargé d'écrire un essai d'au moins 30 000 mots (en vénitien). Elle va vérifier mon travail en utilisant la loi de Zipf, donc quand une ligne est ajustée (comme décrit ci-dessus), la pente doit être d'au plus -0,9 mais pas moins de -1,1, et elle veut un vocabulaire d'au moins 200 mots. Le même mot ne doit pas être répété plus de 5 fois de suite.

C'est CodeGolf, donc le code le plus court en octets l'emporte. Veuillez coller la sortie dans Pastebin ou un autre outil où je peux le télécharger en tant que fichier texte.

J. Antonio Perez
la source
Oui et si vous le souhaitez, vous pouvez simplement faire une phrase de 32767 mots. La restriction est que les fréquences des mots dans la phrase doivent respecter la loi de zipf
J. Antonio Perez
1
L'adjectif traditionnel pour "from Venus" est Veneral, mais pour une raison quelconque, sa popularité a diminué. Le vénusien est couramment utilisé en science-fiction.
Peter Taylor
Je suppose que construire une liste de mots après la distribution zipf et la mélanger aurait une forte probabilité de produire une séquence avec des paires de mots consécutifs également après la distribution zipf. De plus, avec suffisamment de mots différents dans la liste, la probabilité d'avoir le même mot répété plus de 5 fois de suite serait vraiment faible. Dans le cas où j'aurais essayé cette approche et réussi à produire un essai valide, serait-il accepté?
Leo
Votre conjecture est raisonnable, bien que la pente soit de -0,35
J. Antonio Perez
Cela ressemblerait toujours à une ligne droite; c'est juste que la pente serait trop grande
J. Antonio Perez

Réponses:

3

Mathematica, 102 octets

""<>RandomChoice[1/Range@215->Rest@Flatten@Outer[StringJoin,a={"v","a","e","i","o","u"},a,a,{" "}],8!]

Fonction sans nom ne prenant aucune entrée et renvoyant une chaîne composée de 40 320 mots vénusiens de trois lettres avec des espaces de fin.

Outer[StringJoin,a={"v","a","e","i","o","u"},a,a,{" "}]produit les 216 mots de trois lettres possibles en utilisant uniquement les lettres "vaeiou", chacune avec son propre espace de fin. Le premier de ces mots, "vvv", n'est pas valide vénusien, mais le Restjette.

Fait alors RandomChoice[1/Range@215->...,8!]8! = 40 320 choix aléatoires dans la liste résultante de 215 mots, avec des pondérations de fréquence déterminées par les inverses des 215 premiers entiers (1/Range@215 ). Enfin, <>""...concatène les chaînes dans la liste résultante.

La sortie est loin d'être déterministe; un essai a donné cet essai vénusien .

Mathematica, 129 octets

#2&@@@Sort[Join@@Table[{i,Rest@Flatten@Outer[StringJoin,a={"v","a","e","i","o","u"},a,a,{" "}]~Part~j},{j,215},{i,0,1,j/7!}]]<>""

Celui-ci est déterministe. L'ensemble de base de 215 mots est le même, mais maintenant chaque mot est répété un nombre exact de fois (le mot #j est répété environ 7! / J fois) pour forcer la loi de zipf à tenir. Ensuite, les mots sont entrelacés également pour éviter les répétitions. (Imaginez que chaque mot est disposé sur une règle, avec toutes les copies de ce mot également espacées; lorsque tous les mots sont lus dans l'ordre, aucun mot particulier ne se répétera beaucoup, peut-être pas du tout.) Le résultat est un mot de 30117 mots Essai vénusien .

Greg Martin
la source
Ne fait pas 8! un choix pseudo-aléatoire signifie que vous pourriez vous retrouver avec 6 répétitions consécutives du même mot?
Dennis
Oui, en théorie.
Greg Martin
@GregMartin En fait ... l'essai auquel vous avez lié n'est pas conforme; vvaapparaît six fois de suite. Je pense qu'il y a peut-être un problème plus important ... ne devrait pas remettre en question les réponses à chaque fois (Et sinon, comment tracez-vous la probabilité de travailler?)
H Walters
Ceci est une critique juste, et je suis intéressé de voir comment cela se passe.
Greg Martin
2

05AB1E ,34 33 32 octets

525DL/9*vNy<FD}})žMDâžNâJè3ô.rðý

525DL                            Yield [1, ..., 525]
     /                           Yield [525/1, ..., 525/525]
      9*                         Yield [4725/1, ..., 4725/525]. It's the number of occurences of each word. The sum of this array is greater than 30000
        v                        For each value (y = value, N = iteration counter starting from 0)
         N                       Push iteration counter
          y<FD}                  Push an array of "int(value)" times the iteration counter
               }                 End for
                )                Wrap everything in an array. At this point the array countains the sorted indices of all words that matches the frequency specs
                 žM              Push "aeiou"
                   Dâ            Cartesian product with itself (["aa", "ae", ...])
                     žN          Push the consonants
                       âJ        Cartesian product and join the values to make valid venutian words
                         è       Compute a big string with all words that correspond to the formerly computed indices
                          3ô     Since all words are concatenated, separate them into blocks of 3 letters
                            .r   Shuffle
                              ðý Join with whitespaces and implicitly display

Essayez-le en ligne!

Je pense que c'est encore assez golfable! Par exemple, les constantes numériques et vNy<FD}peuvent être jouables au golf.

Exemple de sortie

Comment ça marche?

Il génère toutes les combinaisons de mots suivant la règle "voyelle + voyelle + consonne", ce qui fait 525 mots valides uniques (plus de 200). Il associe ensuite à chacun d'eux une fréquence qui satisfait à la loi f(x) = 4725/xxest le rang du mot actuel, commençant à 1 et se terminant à 525. Ensuite, les fréquences sont normalisées et multipliées pour qu'il y ait au moins 30000 mots. Ce code produit toujours 32074 mots pour rendre les constantes impliquées jouables au golf (voir l'explication du code). Ainsi, chaque mot est répété le nombre de fois correspondant à la fréquence du même mot. Enfin, les mots sont mélangés. Cependant, cela ne garantit pas qu'un mot ne soit jamais répété cinq fois de suite. Par conséquent, les programmes génèrent plus que les 200 mots uniques nécessaires afin de diminuer la probabilité d'avoir un mot répété cinq fois de suite. Veuillez noter que ce code génère toujours la même séquence de mots. La seule chose qui diffère entre deux exécutions est le résultat de l'opération de brassage.

Comment évaluer la fréquence?

J'ai fait un simple code Python3 qui prend le texte dans le fichier nommé "sortie" (du point de vue de l'algorithme, cela a du sens!) Et des sorties vers "stats.csv".

from collections import Counter
from math import log10

with open("output", "r") as f:
    with open("stats.csv", "w") as stats:
        words = f.read().split()
        freqs = Counter(words)
        freqs = sorted([(i,freqs[i]) for i in freqs],key=lambda x:-x[1])

        print(len(words), "words")
        stats.write("logX;logF\n")
        for i, (key, f) in enumerate(freqs):
            stats.write(str(log10(i+1))+";"+str(log10(f))+"\n")

Ce qui donne toujours la distribution suivante pour mon code: Loi de fréquence

La pente est donc de -1,0138. Cette valeur est désormais moins proche de -1 que la pente du code précédent, mais elle satisfait toujours les contraintes de pente.

Osable
la source
Merci pour le script pour évaluer la fréquence, notez que vous avez un extra `à la fin. Aussi, pourquoi utilisez-vous des points-virgules comme séparateurs? csv signifie généralement des valeurs séparées par des virgules;)
Leo
1
Oui tu as raison haha! Je me suis confondu avec le démarque pendant une seconde. J'ai d'abord utilisé le code en ligne, puis j'ai réalisé qu'il était plus approprié d'utiliser un bloc de code mais j'ai oublié de supprimer le supplément `. J'utilise des points-virgules comme séparateurs csv parce que je suis français et certains logiciels ou entreprises ont l'habitude de mettre des valeurs décimales avec des comas au lieu de points comme nous le faisons avec des valeurs décimales manuscrites. Bien que j'utilise toujours le point pour séparer la partie entière de la partie fractionnaire, j'utilise le point-virgule sans réfléchir davantage. Mais bon, ssv est super aussi;)
Osable
0

Bash / Core utils 122 110 bytes

for w in {b,c,d}{a,e,i}{f,g,h}{o,u,a}{j,k,l};{ let ++x;yes $w|head -$[5575/x];}|shuf --random-source=<(yes ae)

Déroulé:

for w in {b,c,d}{a,e,i}{f,g,h}{o,u,a}{j,k,l};{
    let ++x
    yes $w|head -$[5575/x]
}|shuf --random-source=<(yes ae)

La for wboucle génère 243 mots distincts. let ++x;incréments initialement non définis x (par les règles d'expression arithmétique lors de cette première exécution, xest traité comme 0 et donc son incrément le met à 1). La ligne suivante génère ainsi les mots suivants à la fréquence 5575 / x pour approcher la fréquence zipf.

L'étape suivante consiste à permuter de manière déterministe pour répondre à l'exigence de répétition; bien qu'il --random-sources'agisse d'un nom de drapeau terriblement grand, son utilisation avec shuf bat le nombre de caractères de la main roulant un sélecteur mul-mod. yes aeest en fait le dispositif "aléatoire" fixe le plus court que j'ai trouvé conforme.

Cela génère cet essai de 33729 mots [pastebin] .

Bash / Core Utils, 96 84 octets (non concurrents)

Pour une approche non déterministe, il suffit de couper les drapeaux shuf:

for w in {b,c,d}{a,e,i}{f,g,h}{o,u,a}{j,k,l};{ let ++x;yes $w|head -$[5575/x];}|shuf

Une analyse

La pente du zipf est réglée pour être droite. Utilisation d'Excel pour tracer sur des échelles logarithmiques:

L'enseignant doit remarquer une pente zipf = -1,000764.

H Walters
la source