Lero Lero generator PowerUp

Depois do famoso lero-Lero Generator, grande amigo dos memorandos, e-mails para clientes e trabalhos de faculdade, eis mais uma arma acadêmica:

SCIgen - An Automatic CS Paper Generator

Aproveitem e leiam um paper que publiquei recentemente:

A Methodology for the Exploration of Smalltalk

heehehhehe muito bom! Não tinha visto ainda… :stuck_out_tongue:

Bom, o seu paper só tinha esse probleminha… acho que alguém (não Chomsky, que continua vivo e incomodando um monte de gente) não pôde investigar a configuração ortogonal nessa época.

Excelente !!! :lol:

Há muito que não ria tanto. O pior é que se eu espalhar um destes leros no meu trabalho, vai todo mundo me dar os parabéns …

HUhahahauahuahauh!!!

Towards the Refinement of the Partition Table

Uma vez eu tinha feito o seguinte:

  • Baixei os RFCs em formato texto. (Dá para obtê-los de www.rfc-editor.org)

  • Escrevi um programa que lia todos eles, e determinava algumas distribuições estatísticas do tipo “se a palavra X ocorre no texto, a palavra Y a precede com uma freqüência Z”.

  • Então, com esses dados, criava alguns textos aleatórios mas usando a mesma distribuição de freqüências.

  • Dava alguns textos bastante malucos também.

  • Mas esse gerador que o Shoes apresentou é bastante estruturado, dá para fingir bem. (se você rodar esse gerador algumas vezes, dá para perceber que a estrutura é fixa, tal como os papers que devem ser submetidos.)

Olá

[]s
Luca

Um exemplo da saída desse gerador que escrevi faz algum tempo (sorry, é em C++, e vi que ele não quebrava as linhas em sentenças direito. Mas veja o que é possível fazer apenas com estatística :wink: )

    The measures enhances rather than Network Graphics by 
    the response. 

    When aborting the last to it can be used to a which have 
    been discussed.. 

    Note that requiring other type code 

    For example, we send a Hello message assigned, none 

    Obsoletes: Joe NSW Protocol 26 C. 

    FIN-WAIT-1 STATE DIAGRAMS Here was put up parameters x0, 
    followed by Butler, should be found in response and the 
    number in response, and including entry, command to send 
    packet that at CCN that the old packets from NGP could 
    be composed of the contents and sent to half:.

    rrr T 
 
    NRTC-NET Northrop Research Network GEOF Geoff DARCOM-KA. 
 
    Console for ASCII type of bit-mapped graphics 
    functionality and ABORT command language designers to 
    its value for class 3 19 NBS MD or can then either 
    absolute and reissued as a postal and RFC 698,. 
 
    18, 54: a host names and discussion will communicate 
    more internet system were experienced user may be 
    incorporated into machine code 33 Oxford Street 
    Cambridge, if it encourages the graph is, i. 
    
    Ronald L, Message Formats ------------------------------
    ---------- ------------- 
    
    STATUS: address-list any-name path between the group or 
    algorithm, 8 3.. 
    
    McKenzie, 500-505, or the transit at the FDB. 
    
    That is simply duplicating each pseudo- typewriter 
    version number in the first file name server TELNET 
    connections which contains address field. 
    
    I do the byte Meaning: The following functions and may 
    be designed to a buffer? Would be regarded as the 
    control information with some number 0.. 
    Os Lábios da compressão cerrada, que adejava com a seu 
    ser ouvido: - Decidi fazer-vos mal. O chão; disse-lhe 
    que levaria a doçura: - O Felisberto, a Natividade 
    repreendeu a tempo, o patrão, sentada, mas deixou-me 
    outra a cúpula oval de levar em tal hipótese. Clínica e 
    a senhora que lá de seu agudo: - Esta esplêndida galeria 
    de todo o supunha Mr.. - Pois não se lhes não o ventre 
    para dizer às multidões! Fingiu que fazia com a fio a 
    acolheram Pereira de ter, uma das outras necessitadas.. 
    Além disso e da amiga, gestos eram toda a casa, apesar 
    da sacada, ficara de onde estivera na cabana o 
    esquecimento, e iluminando-se de Aurélia de benjoim; 
    Félix sorriu tristemente montados; pouco à vontade, 
    arreios, apoderando-se de história. - Por que um tanto 
    mais fino lavor o fato - tendo contribuído para receber 
    corpo, se cá está o jacaré bóia em que por esse mundo 
    dos pregadores há de noz... Emendava-lhe os guerreiros 
    que ainda agora irmos assim também de uma cabana do 
    outro e que se aproximava. A soldadesca pasma! -Morta 
    podem sair da cabeça no ouvido. Parava às horas e 
    culturais que mais formosa mulher, mas exceto onde me, 
    sanãs, constituíam a varanda, mas já era perto da mata e 
    falou da rua Direita, eram respeitáveis; já das nossas 
    frontes namoradas daquela miserável que faz ganhar 
    terreno amigo, -seu primo. 

O mesmo programa, agora alimentado com o texto de alguns livros em português.

Suspeito que o povo da minha faculdade use algum sistema parecido para geração de artigos. Mero palpite, vou investigar :smiley:

Essa é de autoria própria :mrgreen:

Filosofia heheheh. @+ Quero ver alguém contra-argumentar uhauhahuauha!!

Thingol, vc usou o algoritmo da cadeia de Markov, ou algum outro esquema?

[quote=renato3110]Essa é de autoria própria :mrgreen:

Filosofia heheheh. @+ Quero ver alguém contra-argumentar uhauhahuauha!![/quote]
Alias quero ver alguém entender…

É isso mesmo.

Basicamente fiz o seguinte: (em C++ mesmo, mas usando STL):

  • Varri um arquivo texto, separando-o em palavras;

  • A freqüência de cada palavra é calculada;

  • Para cada palavra, calculamos também a freqüência da palavra imediatamente anterior.

  • Para cada palavra do texto, então, existe uma lista de palavras que podem sucedê-la, cujas freqüências são calculadas. Por exemplo, a palavra “should” foi sucedida, no texto, por “be”, “find” e outras palavras.

  • Para gerar o texto, fazemos o seguinte:

  • Escolhemos uma palavra, mas de acordo com a sua freqüência dentro do texto; (É por isso que a primeira palavra normalmente é “The”, se for em inglês, ou “os”, se for em português);

  • A próxima palavra deve ser escolhida na lista de palavras que podem sucedê-la, e de acordo com sua freqüência.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <hash_map>

//-- Leia um arquivo texto, e use critérios probabilísticos para gerar um outro texto.
//-- Neste caso iremos verificar para cada palavra qual a probabilidade de ela ser seguida por
//-- uma segunda palavra.
//-- As strings não serão repetidas, mas "internalizadas", ou seja, 
//-- apenas uma cópia física de cada string aparecerá na memória. Cada string será representada
//-- por um código. 

//-- 1) Ler cada palavra e inseri-la em um mapa A (palavra->codigo). Esse mapa será temporário
//-- porque iremos substituí-lo por um vetor B (código->palavra).
//-- 2) Reler o arquivo, usando o mapa A, palavra->código e procedendo como antes.
//-- 3) Duas strings são iguais se seus códigos forem iguais.

using namespace std;

//
//-- Required by hash_map
//
struct hasher
{
    enum { bucket_size = 4, min_buckets = 8 };
    /** A seguinte função retorna o hash da string. Adaptada da função de hash do MFC  */
    size_t operator() (const string& s1) const
    {
        size_t nHash = 0;
        for (string::const_iterator p = s1.begin(), p_end = s1.end(); p != p_end; ++p)
            nHash = (nHash<<5) + nHash + *p;

        return nHash;
    }
    /** A seguinte função retorna s1 < s2 */
    bool operator() (const string& s1, const string& s2) const
    {
        return stricmp (s1.c_str(), s2.c_str()) < 0;      
    }
};

typedef hash_map< string,long,hasher > MAP_S_L;
typedef MAP_S_L::iterator MAP_S_L_I;
typedef vector<string> V_S;
typedef vector<long> V_L;
typedef map<long,long> MAP_L_L;
typedef MAP_L_L::iterator MAP_L_L_I;
typedef vector<MAP_L_L> V_MAP_L_L;
typedef multimap<long, long> MMAP_L_L;
typedef MMAP_L_L::iterator MMAP_L_L_I;
typedef map<double,long> MAP_D_L;
typedef MAP_D_L::iterator MAP_D_L_I;
typedef vector<MAP_D_L> V_MAP_D_L;


    V_S b;
    V_L c; //-- Contagem das ocorrências das palavras, deve ter a mesma dimensão de b
    V_MAP_L_L d; //-- Contagem das ocorrências das palavras subseqüentes, deve ter a mesma dimensão de b
    MAP_D_L f;
    V_MAP_D_L g; //-- Freqüências das ocorrências das palavras subseqüentes, deve ter a mesma dimensão de b

bool ispunctchar (int ch)
{
    return ch == '.' || ch == ',' || ch == ':' || ch == ',' || ch == ';' || ch == '!' || ch == '?';
}

bool iswordchar (int ch)
{
    //-- Note que todos os caracteres acima de 128 serão considerados alfabéticos
    //-- para facilitar.
    return 'A' <= ch && ch <= 'Z' 
    || 'a' <= ch && ch <= 'z'
    || '0' <= ch && ch <= '9'
    || ch == '_' || ch == ''
    || ch == '-'
    || ch >= 128;
}

int getword (FILE *v, char word[])
{
    int ch;
    //-- Devemos pular os caracteres não-alfabéticos [^A-Za-z0-9_']
    char *p = word;
    
    while ((ch = getc (v)) != EOF && !iswordchar (ch))
    {
        if (ispunctchar (ch))
        {
            *p++ = ch;
            *p = '[code]
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <hash_map>

//-- Leia um arquivo texto, e use critérios probabilísticos para gerar um outro texto.
//-- Neste caso iremos verificar para cada palavra qual a probabilidade de ela ser seguida por
//-- uma segunda palavra.
//-- As strings não serão repetidas, mas "internalizadas", ou seja, 
//-- apenas uma cópia física de cada string aparecerá na memória. Cada string será representada
//-- por um código. 

//-- 1) Ler cada palavra e inseri-la em um mapa A (palavra->codigo). Esse mapa será temporário
//-- porque iremos substituí-lo por um vetor B (código->palavra).
//-- 2) Reler o arquivo, usando o mapa A, palavra->código e procedendo como antes.
//-- 3) Duas strings são iguais se seus códigos forem iguais.

using namespace std;

//
//-- Required by hash_map
//
struct hasher
{
    enum { bucket_size = 4, min_buckets = 8 };
    /** A seguinte função retorna o hash da string. Adaptada da função de hash do MFC  */
    size_t operator() (const string& s1) const
    {
        size_t nHash = 0;
        for (string::const_iterator p = s1.begin(), p_end = s1.end(); p != p_end; ++p)
            nHash = (nHash<<5) + nHash + *p;

        return nHash;
    }
    /** A seguinte função retorna s1 < s2 */
    bool operator() (const string& s1, const string& s2) const
    {
        return stricmp (s1.c_str(), s2.c_str()) < 0;      
    }
};

typedef hash_map< string,long,hasher > MAP_S_L;
typedef MAP_S_L::iterator MAP_S_L_I;
typedef vector<string> V_S;
typedef vector<long> V_L;
typedef map<long,long> MAP_L_L;
typedef MAP_L_L::iterator MAP_L_L_I;
typedef vector<MAP_L_L> V_MAP_L_L;
typedef multimap<long, long> MMAP_L_L;
typedef MMAP_L_L::iterator MMAP_L_L_I;
typedef map<double,long> MAP_D_L;
typedef MAP_D_L::iterator MAP_D_L_I;
typedef vector<MAP_D_L> V_MAP_D_L;


    V_S b;
    V_L c; //-- Contagem das ocorrências das palavras, deve ter a mesma dimensão de b
    V_MAP_L_L d; //-- Contagem das ocorrências das palavras subseqüentes, deve ter a mesma dimensão de b
    MAP_D_L f;
    V_MAP_D_L g; //-- Freqüências das ocorrências das palavras subseqüentes, deve ter a mesma dimensão de b

bool ispunctchar (int ch)
{
    return ch == '.' || ch == ',' || ch == ':' || ch == ',' || ch == ';' || ch == '!' || ch == '?';
}

bool iswordchar (int ch)
{
    //-- Note que todos os caracteres acima de 128 serão considerados alfabéticos
    //-- para facilitar.
    return 'A' <= ch && ch <= 'Z' 
    || 'a' <= ch && ch <= 'z'
    || '0' <= ch && ch <= '9'
    || ch == '_' || ch == '\''
    || ch == '-'
    || ch >= 128;
}

int getword (FILE *v, char word[])
{
    int ch;
    //-- Devemos pular os caracteres não-alfabéticos [^A-Za-z0-9_']
    char *p = word;
    
    while ((ch = getc (v)) != EOF && !iswordchar (ch))
    {
        if (ispunctchar (ch))
        {
            *p++ = ch;
            *p = '\0';
            return ch;
            break;
        }
    }
    if (iswordchar (ch))
        ungetc (ch, v);
    while ((ch = getc (v)) != EOF && iswordchar (ch))
    {
        *p++ = ch;
    }
    if (ch != EOF) ungetc (ch, v);
    *p = '\0';
    return ch; //-- EOF se acabarem as palavras...
}

int main (int argc, char *argv[])
{
    char word[1024];
    FILE *v, *w;
    
    {
        MAP_S_L a;
        long code = 0;
        long ncodes;
        long code1, code2;
        
        fprintf (stderr, "Lendo o arquivo %s\n", argv[1]);
        v = fopen (argv[1], "rt");
        code2 = 0;
        while (getword (v, word) != EOF)
        {
            //-- Se a palavra não existia antes em A, incrementamos code
            if (a.insert(make_pair<string,long>(word, code)).second)
            {
                code++;
                c.resize (c.size() + 1); d.resize(d.size() + 1);
                if (code % 1000 == 0)
                    fprintf (stderr, "\r%d códigos", code);
            }
            code1 = code2; code2 = a[word]; 
            //-- Contando as palavras
            //-- Note que como as palavras agora são códigos, podemos usar um vetor simples
            //-- para contar as ocorrências, e um vetor de mapas para contar as ocorrências
            //-- da string subseqüentes
            c [code1]++;
            d [code1][code2]++;
        }
        ncodes = a.size();
        fclose (v);
        
        fprintf (stderr, "\rLidos %d códigos\n", ncodes);
        fprintf (stderr, "Invertendo a lista\n");
        b.resize (ncodes);
        for (MAP_S_L_I p = a.begin(), p_end = a.end(); p != p_end; ++p)
        {
            //-- p->second contém o código, p->first contém a string
            b[p->second] = p->first;
        }
        
        //-- c contém as freqüências, mas precisamos ordenar por freqüências relativas
        long nTotalWords = 0;
        fprintf (stderr, "Determinando as freqüências relativas\n");
        {
            MMAP_L_L e;
            
            fprintf (stderr, "Passo 1\n");
            for (long i = 0; i < c.size(); ++i)
            {
                nTotalWords += c[i];
                e.insert (make_pair<long,long>(c[i], i));
            }
            fprintf (stderr, "Passo 2\n");
            long nAccWords = 0;
            for (MMAP_L_L_I p = e.begin(), p_end = e.end(); p != p_end; ++p)
            {
                nAccWords += p->first;
                f[(double)nAccWords / nTotalWords] = p->second;
            }
        }
        
        
        //-- Agora para cada palavra subseqüente precisamos determinar a sua freqüência...
        fprintf (stderr, "Determinando as freqüências relativas das palavras subseqüentes.\n", ncodes);
        for (long i = 0; i < d.size(); ++i)
        {
            if (i % 200 == 0)
                fprintf (stderr, "\r%d palavras...", i);
            long nTotalWords = 0;
            MMAP_L_L h;
            for (MAP_L_L_I p = d[i].begin(), p_end = d[i].end(); p != p_end; ++p)
            {
                nTotalWords += p->second;
                h.insert (make_pair<long,long>(p->second, p->first));
            }
            MAP_D_L k;
            long nAccWords = 0;
            for (MMAP_L_L_I p = h.begin(), p_end = h.end(); p != p_end; ++p)
            {
                nAccWords += p->first;
                k[(double)nAccWords/nTotalWords] = p->second;
            }
            g.push_back (k);
        }
        fprintf (stderr, "\r%d palavras processadas.\n", d.size());   
    }

    fprintf (stderr, "Gerando as palavras...\n");
    w = fopen (argv[2], "wt");
    
    long thisword = 0;
    srand (time (NULL));
    for (long i = 0; i < 100000; ++i)
    {
        const char *palavra = b[thisword].c_str();
        if (!ispunctchar (palavra[0]))
            fprintf (w, " ");
        fprintf (w, "%s", palavra);
        double r = (double)rand() / RAND_MAX;
        MAP_D_L_I p = g[thisword].upper_bound(r);
        if (p != g[thisword].end())
        {
            thisword = p->second;
        }
        else
        {
            printf ("!");
            thisword = f.upper_bound(r)->second;
        }
    }
    
    fclose (w);
}


[/code]';
            return ch;
            break;
        }
    }
    if (iswordchar (ch))
        ungetc (ch, v);
    while ((ch = getc (v)) != EOF && iswordchar (ch))
    {
        *p++ = ch;
    }
    if (ch != EOF) ungetc (ch, v);
    *p = '[code]
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <hash_map>

//-- Leia um arquivo texto, e use critérios probabilísticos para gerar um outro texto.
//-- Neste caso iremos verificar para cada palavra qual a probabilidade de ela ser seguida por
//-- uma segunda palavra.
//-- As strings não serão repetidas, mas "internalizadas", ou seja, 
//-- apenas uma cópia física de cada string aparecerá na memória. Cada string será representada
//-- por um código. 

//-- 1) Ler cada palavra e inseri-la em um mapa A (palavra->codigo). Esse mapa será temporário
//-- porque iremos substituí-lo por um vetor B (código->palavra).
//-- 2) Reler o arquivo, usando o mapa A, palavra->código e procedendo como antes.
//-- 3) Duas strings são iguais se seus códigos forem iguais.

using namespace std;

//
//-- Required by hash_map
//
struct hasher
{
    enum { bucket_size = 4, min_buckets = 8 };
    /** A seguinte função retorna o hash da string. Adaptada da função de hash do MFC  */
    size_t operator() (const string& s1) const
    {
        size_t nHash = 0;
        for (string::const_iterator p = s1.begin(), p_end = s1.end(); p != p_end; ++p)
            nHash = (nHash<<5) + nHash + *p;

        return nHash;
    }
    /** A seguinte função retorna s1 < s2 */
    bool operator() (const string& s1, const string& s2) const
    {
        return stricmp (s1.c_str(), s2.c_str()) < 0;      
    }
};

typedef hash_map< string,long,hasher > MAP_S_L;
typedef MAP_S_L::iterator MAP_S_L_I;
typedef vector<string> V_S;
typedef vector<long> V_L;
typedef map<long,long> MAP_L_L;
typedef MAP_L_L::iterator MAP_L_L_I;
typedef vector<MAP_L_L> V_MAP_L_L;
typedef multimap<long, long> MMAP_L_L;
typedef MMAP_L_L::iterator MMAP_L_L_I;
typedef map<double,long> MAP_D_L;
typedef MAP_D_L::iterator MAP_D_L_I;
typedef vector<MAP_D_L> V_MAP_D_L;


    V_S b;
    V_L c; //-- Contagem das ocorrências das palavras, deve ter a mesma dimensão de b
    V_MAP_L_L d; //-- Contagem das ocorrências das palavras subseqüentes, deve ter a mesma dimensão de b
    MAP_D_L f;
    V_MAP_D_L g; //-- Freqüências das ocorrências das palavras subseqüentes, deve ter a mesma dimensão de b

bool ispunctchar (int ch)
{
    return ch == '.' || ch == ',' || ch == ':' || ch == ',' || ch == ';' || ch == '!' || ch == '?';
}

bool iswordchar (int ch)
{
    //-- Note que todos os caracteres acima de 128 serão considerados alfabéticos
    //-- para facilitar.
    return 'A' <= ch && ch <= 'Z' 
    || 'a' <= ch && ch <= 'z'
    || '0' <= ch && ch <= '9'
    || ch == '_' || ch == '\''
    || ch == '-'
    || ch >= 128;
}

int getword (FILE *v, char word[])
{
    int ch;
    //-- Devemos pular os caracteres não-alfabéticos [^A-Za-z0-9_']
    char *p = word;
    
    while ((ch = getc (v)) != EOF && !iswordchar (ch))
    {
        if (ispunctchar (ch))
        {
            *p++ = ch;
            *p = '\0';
            return ch;
            break;
        }
    }
    if (iswordchar (ch))
        ungetc (ch, v);
    while ((ch = getc (v)) != EOF && iswordchar (ch))
    {
        *p++ = ch;
    }
    if (ch != EOF) ungetc (ch, v);
    *p = '\0';
    return ch; //-- EOF se acabarem as palavras...
}

int main (int argc, char *argv[])
{
    char word[1024];
    FILE *v, *w;
    
    {
        MAP_S_L a;
        long code = 0;
        long ncodes;
        long code1, code2;
        
        fprintf (stderr, "Lendo o arquivo %s\n", argv[1]);
        v = fopen (argv[1], "rt");
        code2 = 0;
        while (getword (v, word) != EOF)
        {
            //-- Se a palavra não existia antes em A, incrementamos code
            if (a.insert(make_pair<string,long>(word, code)).second)
            {
                code++;
                c.resize (c.size() + 1); d.resize(d.size() + 1);
                if (code % 1000 == 0)
                    fprintf (stderr, "\r%d códigos", code);
            }
            code1 = code2; code2 = a[word]; 
            //-- Contando as palavras
            //-- Note que como as palavras agora são códigos, podemos usar um vetor simples
            //-- para contar as ocorrências, e um vetor de mapas para contar as ocorrências
            //-- da string subseqüentes
            c [code1]++;
            d [code1][code2]++;
        }
        ncodes = a.size();
        fclose (v);
        
        fprintf (stderr, "\rLidos %d códigos\n", ncodes);
        fprintf (stderr, "Invertendo a lista\n");
        b.resize (ncodes);
        for (MAP_S_L_I p = a.begin(), p_end = a.end(); p != p_end; ++p)
        {
            //-- p->second contém o código, p->first contém a string
            b[p->second] = p->first;
        }
        
        //-- c contém as freqüências, mas precisamos ordenar por freqüências relativas
        long nTotalWords = 0;
        fprintf (stderr, "Determinando as freqüências relativas\n");
        {
            MMAP_L_L e;
            
            fprintf (stderr, "Passo 1\n");
            for (long i = 0; i < c.size(); ++i)
            {
                nTotalWords += c[i];
                e.insert (make_pair<long,long>(c[i], i));
            }
            fprintf (stderr, "Passo 2\n");
            long nAccWords = 0;
            for (MMAP_L_L_I p = e.begin(), p_end = e.end(); p != p_end; ++p)
            {
                nAccWords += p->first;
                f[(double)nAccWords / nTotalWords] = p->second;
            }
        }
        
        
        //-- Agora para cada palavra subseqüente precisamos determinar a sua freqüência...
        fprintf (stderr, "Determinando as freqüências relativas das palavras subseqüentes.\n", ncodes);
        for (long i = 0; i < d.size(); ++i)
        {
            if (i % 200 == 0)
                fprintf (stderr, "\r%d palavras...", i);
            long nTotalWords = 0;
            MMAP_L_L h;
            for (MAP_L_L_I p = d[i].begin(), p_end = d[i].end(); p != p_end; ++p)
            {
                nTotalWords += p->second;
                h.insert (make_pair<long,long>(p->second, p->first));
            }
            MAP_D_L k;
            long nAccWords = 0;
            for (MMAP_L_L_I p = h.begin(), p_end = h.end(); p != p_end; ++p)
            {
                nAccWords += p->first;
                k[(double)nAccWords/nTotalWords] = p->second;
            }
            g.push_back (k);
        }
        fprintf (stderr, "\r%d palavras processadas.\n", d.size());   
    }

    fprintf (stderr, "Gerando as palavras...\n");
    w = fopen (argv[2], "wt");
    
    long thisword = 0;
    srand (time (NULL));
    for (long i = 0; i < 100000; ++i)
    {
        const char *palavra = b[thisword].c_str();
        if (!ispunctchar (palavra[0]))
            fprintf (w, " ");
        fprintf (w, "%s", palavra);
        double r = (double)rand() / RAND_MAX;
        MAP_D_L_I p = g[thisword].upper_bound(r);
        if (p != g[thisword].end())
        {
            thisword = p->second;
        }
        else
        {
            printf ("!");
            thisword = f.upper_bound(r)->second;
        }
    }
    
    fclose (w);
}


[/code]';
    return ch; //-- EOF se acabarem as palavras...
}

int main (int argc, char *argv[])
{
    char word[1024];
    FILE *v, *w;
    
    {
        MAP_S_L a;
        long code = 0;
        long ncodes;
        long code1, code2;
        
        fprintf (stderr, "Lendo o arquivo %s\n", argv[1]);
        v = fopen (argv[1], "rt");
        code2 = 0;
        while (getword (v, word) != EOF)
        {
            //-- Se a palavra não existia antes em A, incrementamos code
            if (a.insert(make_pair<string,long>(word, code)).second)
            {
                code++;
                c.resize (c.size() + 1); d.resize(d.size() + 1);
                if (code % 1000 == 0)
                    fprintf (stderr, "\r%d códigos", code);
            }
            code1 = code2; code2 = a[word]; 
            //-- Contando as palavras
            //-- Note que como as palavras agora são códigos, podemos usar um vetor simples
            //-- para contar as ocorrências, e um vetor de mapas para contar as ocorrências
            //-- da string subseqüentes
            c [code1]++;
            d [code1][code2]++;
        }
        ncodes = a.size();
        fclose (v);
        
        fprintf (stderr, "\rLidos %d códigos\n", ncodes);
        fprintf (stderr, "Invertendo a lista\n");
        b.resize (ncodes);
        for (MAP_S_L_I p = a.begin(), p_end = a.end(); p != p_end; ++p)
        {
            //-- p->second contém o código, p->first contém a string
            b[p->second] = p->first;
        }
        
        //-- c contém as freqüências, mas precisamos ordenar por freqüências relativas
        long nTotalWords = 0;
        fprintf (stderr, "Determinando as freqüências relativas\n");
        {
            MMAP_L_L e;
            
            fprintf (stderr, "Passo 1\n");
            for (long i = 0; i < c.size(); ++i)
            {
                nTotalWords += c[i];
                e.insert (make_pair<long,long>(c[i], i));
            }
            fprintf (stderr, "Passo 2\n");
            long nAccWords = 0;
            for (MMAP_L_L_I p = e.begin(), p_end = e.end(); p != p_end; ++p)
            {
                nAccWords += p->first;
                f[(double)nAccWords / nTotalWords] = p->second;
            }
        }
        
        
        //-- Agora para cada palavra subseqüente precisamos determinar a sua freqüência...
        fprintf (stderr, "Determinando as freqüências relativas das palavras subseqüentes.\n", ncodes);
        for (long i = 0; i < d.size(); ++i)
        {
            if (i % 200 == 0)
                fprintf (stderr, "\r%d palavras...", i);
            long nTotalWords = 0;
            MMAP_L_L h;
            for (MAP_L_L_I p = d[i].begin(), p_end = d[i].end(); p != p_end; ++p)
            {
                nTotalWords += p->second;
                h.insert (make_pair<long,long>(p->second, p->first));
            }
            MAP_D_L k;
            long nAccWords = 0;
            for (MMAP_L_L_I p = h.begin(), p_end = h.end(); p != p_end; ++p)
            {
                nAccWords += p->first;
                k[(double)nAccWords/nTotalWords] = p->second;
            }
            g.push_back (k);
        }
        fprintf (stderr, "\r%d palavras processadas.\n", d.size());   
    }

    fprintf (stderr, "Gerando as palavras...\n");
    w = fopen (argv[2], "wt");
    
    long thisword = 0;
    srand (time (NULL));
    for (long i = 0; i < 100000; ++i)
    {
        const char *palavra = b[thisword].c_str();
        if (!ispunctchar (palavra[0]))
            fprintf (w, " ");
        fprintf (w, "%s", palavra);
        double r = (double)rand() / RAND_MAX;
        MAP_D_L_I p = g[thisword].upper_bound(r);
        if (p != g[thisword].end())
        {
            thisword = p->second;
        }
        else
        {
            printf ("!");
            thisword = f.upper_bound(r)->second;
        }
    }
    
    fclose (w);
}