2009-12-26 12 views
5

Durante las vacaciones, a mi familia le encanta jugar Boggle. El problema es que soy terrible en Boggle. Así que hice lo que cualquier buen programador haría: escribió un programa para tocar para mí.Erlang: ¿Qué hay de malo en esta implementación?

En el núcleo del algoritmo es un simple prefix trie, donde cada nodo es un dict de referencias a las siguientes letras.

Este es el trie:add aplicación:

add([], Trie) -> 
    dict:store(stop, true, Trie); 

add([Ch|Rest], Trie) -> 
    % setdefault(Key, Default, Dict) -> 
    %  case dict:find(Key, Dict) of 
    %   { ok, Val } -> { Dict, Val } 
    %   error -> { dict:new(), Default } 
    %  end. 
    { NewTrie, SubTrie } = setdefault(Ch, dict:new(), Trie), 
    NewSubTrie = add(Rest, SubTrie), 
    dict:store(Ch, NewSubTrie, NewTrie).

Y se puede ver el resto, junto con un ejemplo de cómo se utiliza (en el fondo), aquí:

http://gist.github.com/263513

Ahora que este es mi primer programa serio en Erlang, sé que probablemente hay un montón de cosas mal con eso ... Pero mi immediat La preocupación es que usa 800 megabytes de RAM.

Entonces, ¿qué estoy haciendo más mal? ¿Y cómo podría hacerlo un poco menos mal?

+0

Ha. Lo hice en PHP hace unos años. – gahooa

+0

¿Cuán grande es tu lista de palabras de entrada? – Zed

+0

Mi lista de palabras es de 200,000 palabras (o 2.5 megas). –

Respuesta

4

Se podría implementar esta funcionalidad simplemente almacenar las palabras en una tabla de ETS:

% create table; add words 
> ets:new(words, [named_table, set]). 
> ets:insert(words, [{"zed"}]). 
> ets:insert(words, [{"zebra"}]).  

% check if word exists 
> ets:lookup(words, "zed").   
[{"zed"}] 

% check if "ze" has a continuation among the words 
78> ets:match(words, {"ze" ++ '$1'}). 
[["d"],["bra"]] 

Si trie es una necesidad, pero se puede vivir con un enfoque no-funcional, entonces usted puede intentar digraph s, como Paul ya sugirió.

Si desea permanecer funcional, puede guardar algunos bytes de memoria mediante el uso de estructuras con menos memoria, por ejemplo proplist s, o registros, como -record(node, {a,b,....,x,y,z}).

+0

Ah, genial, gracias por los consejos. –

+0

Muy bien, así que he estado jugando con ets, pero he estado teniendo problemas con "mala discusión". Tal vez conoces una solución simple? La pregunta está aquí: http://stackoverflow.com/questions/1964990/erlang-ets-reset-ets-table-after-getting-a-bad-argument –

+0

Muy bien, también he jugado con la implementación del proplist ... Y ha afectado un problema que hace que el shell se cuelgue. Lo he preguntado aquí: http://stackoverflow.com/questions/1982257/erlang-erl-shell-hangs-after-building-a-large-data-structure (ps: gracias por toda su ayuda, es muy apreciado) –

1

No sé tu algoritmo, pero si estás almacenando esa cantidad de datos, tal vez deberías considerar el uso de la biblioteca de digrafos incorporada de Erlang para representar tu trie, en lugar de tantos dicts. http://www.erlang.org/doc/man/digraph.html

+0

Cool - Lo investigaré. Gracias. –

4

No recuerdo cuánta memoria toma un dict, pero estimémoslo. Tienes 2.5e6 caracteres y 2e5 palabras. Si tu trie no compartía nada, eso tomaría 2.7e6 asociaciones en los dicts (una para cada personaje y cada símbolo de 'stop'). Una simple representación dict puramente funcional sería de 4 palabras por asociación, podría ser menos, pero estoy tratando de obtener un límite superior. En una máquina de 64 bits, eso tomaría 8 * 4 * 2.7 millones de bytes, o 86 megabytes. Eso es solo una décima parte de tus 800M, entonces algo seguramente está mal aquí.

Actualización:dict.erl representa los dictados con una tabla hash; esto implica mucha sobrecarga cuando tienes muchos dicts muy pequeños, como lo haces. Intentaría cambiar tu código para usar el módulo proplists, que debería coincidir con mis cálculos anteriores.

+3

Para comprobar la cantidad de memoria que toma una construcción dict(), llame a: 'erts_debug: flat_size (dict: new())'. Devuelve 46 palabras, que son 184 bytes en un sistema de 32 bits, o 368 bytes en uno de 64 bits. – Zed

+0

Gracias por la sugerencia ... Aunque me he encontrado con un problema extraño en el que se cuelga el caparazón cuando creo mi trie basado en proplist, que he preguntado aquí: http://stackoverflow.com/questions/1982257/ erlang-erl-shell-cuelga-después-construyendo-una-gran-estructura-de-datos - ¿podría, por casualidad, ofrecer alguna información allí? –

1

Si todas las palabras están en inglés, y el caso no importa, todos los caracteres pueden codificarse con números del 1 al 26 (y de hecho, en Erlang son son números del 97 al 122), reservando 0 para parar. Para que pueda usar el array module también.

2

Una forma alternativa de resolver el problema es ir a través de la lista de palabras y ver si la palabra se puede construir a partir de los dados. De esta forma, necesitará muy poca memoria RAM, y podría ser más divertido codificar.(optimización y concurrencia)

+0

Esa es una idea interesante, gracias. –

2

Mire en DAWG s. Son mucho más compactos que los intentos.

Cuestiones relacionadas