¡Ayuda! ¡Tengo más tarea!

18

Mi maestra estaba más que descontenta con mi tarea marciana . Seguí todas las reglas, pero ella dice que lo que saqué fue un galimatías ... cuando lo miró por primera vez, sospechaba mucho. "Todos los idiomas deben seguir la ley de Zipf, bla, bla, bla" ... ¡Ni siquiera sabía cuál era la ley de Zipf!

Resulta que la ley de Zipf establece que si trazas el logaritmo de la frecuencia de cada palabra en el eje y, y el logaritmo del "lugar" de cada palabra en el eje x (más común = 1, segundo más común = 2, tercero más común = 3, y así sucesivamente), entonces la gráfica mostrará una línea con una pendiente de aproximadamente -1, más o menos 10%.

Por ejemplo, aquí hay una trama para Moby Dick:

ingrese la descripción de la imagen aquí

El eje x es el n º palabra más común, el eje y es el número de ocurrencias de la n º palabra más común. La pendiente de la línea es de aproximadamente -1.07.

Ahora estamos cubriendo a Venutian. Afortunadamente, los venutianos usan el alfabeto latino. Las reglas son las siguientes:

  • Cada palabra debe contener al menos una vocal (a, e, i, o, u)
  • En cada palabra puede haber hasta tres vocales seguidas, pero no más de dos consonantes seguidas (una consonante es cualquier letra que no sea vocal).
  • No hay palabras de más de 15 letras
  • Opcional: agrupe palabras en oraciones de 3 a 30 palabras, delimitadas por puntos

Debido a que el maestro siente que hice trampa en mi tarea marciana, me han asignado que escriba un ensayo de al menos 30,000 palabras (en venutiano). Verificará mi trabajo utilizando la ley de Zipf, por lo que cuando se ajusta una línea (como se describió anteriormente) la pendiente debe ser como máximo -0.9 pero no inferior a -1.1, y quiere un vocabulario de al menos 200 palabras. La misma palabra no debe repetirse más de 5 veces seguidas.

Este es CodeGolf, por lo que gana el código más corto en bytes. Pegue el resultado en Pastebin u otra herramienta donde pueda descargarlo como un archivo de texto.

J. Antonio Perez
fuente
Sí, y si quieres puedes hacer una oración de 32767 palabras. La restricción es que las frecuencias de las palabras en la oración deben seguir la ley de zipf
J. Antonio Perez
1
El adjetivo tradicional para "de Venus" es Veneral, pero por alguna razón ha disminuido en popularidad. Venusian se usa comúnmente en la ciencia ficción.
Peter Taylor
Estoy conjeturando que construir una lista de palabras después de la distribución zipf y barajarla tendría una alta probabilidad de producir una secuencia con pares de palabras consecutivas que también sigan la distribución zipf. Además, con suficientes palabras diferentes en la lista, la probabilidad de que la misma palabra se repita más de 5 veces seguidas sería realmente pequeña. En caso de que probé este enfoque y logré producir un ensayo válido, ¿sería aceptado?
Leo
Su conjetura es razonable, aunque la pendiente sería -0.35
J. Antonio Perez
Todavía se vería como una línea recta; es solo que la pendiente sería demasiado grande
J. Antonio Perez

Respuestas:

3

Mathematica, 102 bytes

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

Función sin nombre que no toma ninguna entrada y devuelve una cadena que consta de 40,320 palabras venusianas de tres letras con espacios finales.

Outer[StringJoin,a={"v","a","e","i","o","u"},a,a,{" "}]produce las 216 palabras de tres letras posibles utilizando solo las letras "vaeiou", cada una con su propio espacio final. La primera de estas palabras, "vvv", no es válida venusiana, pero Restla descarta.

¡Entonces RandomChoice[1/Range@215->...,8!]hace 8! = 40,320 elecciones aleatorias de la lista de 215 palabras resultante, con ponderaciones de frecuencia determinadas por los recíprocos de los primeros 215 enteros ( 1/Range@215). Finalmente, <>""...concatena las cadenas en la lista resultante.

La salida está lejos de ser determinista; una carrera produjo este ensayo venusiano .

Mathematica, 129 bytes

#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!}]]<>""

Este es determinista. El conjunto base de 215 palabras es el mismo, pero ahora cada palabra se repite un número exacto de veces (la palabra #j se repite aproximadamente 7! / J veces) para obligar a la ley de zipf a cumplir. Luego, las palabras se entrelazan por igual para evitar repeticiones. (Imagine que cada palabra se presenta en una regla, con todas las copias de esa palabra igualmente espaciadas; cuando todas las palabras se leen en orden, ninguna palabra en particular se repetirá mucho, tal vez en absoluto). El resultado es un palabra de 30,117 palabras. Ensayo venusiano .

Greg Martin
fuente
No hace 8! elección pseudoaleatoria significa que podría terminar con 6 repeticiones consecutivas de la misma palabra?
Dennis
Si, en teoria.
Greg Martin
@GregMartin En realidad ... el ensayo al que se vinculó no cumple; vvaaparece seis veces consecutivas. Sin embargo, creo que posiblemente haya un problema mayor ... ¿No debería desafiar las respuestas a trabajar siempre? (Y si no, ¿cómo trazas la línea de la probabilidad de que trabajen?)
H Walters
Esta es una crítica justa, y estoy interesado en ver cómo se desarrolla.
Greg Martin
2

05AB1E ,34 33 32 bytes

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

Pruébalo en línea!

¡Creo que todavía es bastante golfable! Por ejemplo, las constantes numéricas y vNy<FD}podrían ser golfables.

Ejemplo de salida

¿Como funciona?

Genera todas las combinaciones de palabras siguiendo la regla "vocal + vocal + consonante", que hace 525 palabras válidas únicas (más de 200). Luego asocia a cada uno de ellos una frecuencia que satisface la ley f(x) = 4725/xdondexes el rango de la palabra actual, que comienza en 1 y termina en 525. Luego, las frecuencias se normalizan y multiplican para que haya al menos 30000 palabras. Este código siempre produce 32074 palabras para hacer que las constantes involucradas se puedan jugar (ver la explicación del código). Entonces cada palabra se repite la cantidad de veces correspondiente a la frecuencia de la misma palabra. Finalmente se barajan las palabras. Sin embargo, no garantiza que una palabra nunca se repita cinco veces seguidas. Por lo tanto, los programas generan más de las 200 palabras únicas necesarias para disminuir la probabilidad de que una palabra se repita cinco veces seguidas. Tenga en cuenta que este código siempre genera la misma secuencia de palabras. Lo único que difiere entre dos ejecuciones es el resultado de la operación de barajar.

¿Cómo evaluar la frecuencia?

Hice un código simple de Python3 que toma el texto en el archivo llamado "output" (desde el punto de vista del algoritmo, ¡tiene sentido!) Y lo envía a "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")

Lo que siempre produce la siguiente distribución para mi código: Ley de frecuencia

Entonces la pendiente es -1.0138. Este valor ahora es menos cercano a -1 que la pendiente del código anterior, pero aún satisface las restricciones de pendiente.

Osable
fuente
Gracias por el guión para evaluar la frecuencia, tenga en cuenta que tiene un `extra al final. Además, ¿por qué usa punto y coma como separadores? csv generalmente significa valores separados por comas;)
Leo
1
Sí tienes razón jaja! Me confundí con Markdown por un segundo. Primero utilicé el código en línea, luego me di cuenta de que era más apropiado usar un bloque de código, pero olvidé eliminar el extra `. Utilizo puntos y comas como separadores de CSV porque soy francés y algunos softwares o empresas están acostumbrados a poner valores decimales con comas en lugar de puntos como lo hacemos con los valores decimales escritos a mano. Aunque siempre uso el punto para separar la parte entera de la parte fraccionaria, uso el punto y coma sin pensarlo más. Pero bueno, SSV también es genial;)
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)

Desenrollado:

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)

El for wbucle genera 243 palabras distintas. let ++x;incrementos inicialmente desarmados x (por reglas de expresión aritmética durante esa primera ejecución,x se trata como 0 y, por lo tanto, su incremento lo establece en 1). La siguiente línea genera palabras sucesivas a una frecuencia de 5575 / x para aproximar la frecuencia zipf.

El siguiente paso es permutar esto de manera determinista para ajustarse al requisito de repetición; a pesar de --random-sourceser un nombre de bandera terriblemente grande, usarlo con shuf supera el conteo de caracteres de rodar un selector mul-mod. yes aees en realidad el dispositivo "aleatorio" fijo más corto que encontré que cumple.

Esto genera este ensayo de 33729 palabras [pastebin] .

Bash / Core Utils, 96 84 bytes (no competitivos)

Para un enfoque no determinista, simplemente corte las banderas 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

Análisis

La pendiente zipf está ajustada para ser recta. Usando Excel para trazar en escalas logarítmicas:

El maestro debe notar una pendiente zipf de = -1.000764.

H Walters
fuente