| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 11:09:28
|
Rimmon
HelloWorld
Membro desde: 21/10/2008 08:26:53
Mensagens: 12
Offline
|
Olá pessoal, eu tenho um código que eu fiz que gera palavras, e até frases porém como ele trabalha por análise combinatória existe o problema de ser extremamente sequencial, e conforme o tamanho da palvra vai aumentando, ou a quantidade de letras presente no alfabeto que ele irá trabalhar também aumenta eu tenho um problema de desempenho... Se alguém tiver alguma idéia de como eu posso fazer para melhorar esse código deixar ele mais rápido, ou paralelizar ele com threads para pelo menos melhorar o desempenho em processadores mais modernos, seria de grande ajuda.
o meu código é:
|
|
|
 |
|
|
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 11:19:04
|
ViniGodoy
Moderador
![[Avatar]](/images/avatar/1921493b5362e63fbe8983f4bd54157d.png)
Membro desde: 11/12/2006 08:22:01
Mensagens: 20578
Localização: Curitiba/PR
Offline
|
Ele precisa ser recursivo?
Pelo tipo do problema, acho potencialmente perigoso mante-lo assim, já que o número de combinações deve aumentar muito.
Você pode eliminar as palavras duplicadas se copia-las para um TreeSet antes de retornar o resultado final.
|
@ViniGodoy - Lattes
Tem dúvidas de Java? Poste no fórum! Não respondo dúvidas de java via MP!
Ponto V! - Desenvolvimento de Jogos Profissional - @Pontov - Facebook
Projeto Towel - Swing de uma forma inteligente (Novo lar do ObjectTableModel e do Auto-Filtro).
Ei... você está usando DefaultTableModel no seu projeto??
Não faça isso! Veja: http://www.guj.com.br/posts/list/15/199067.java#1001295 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 11:27:04
|
Rimmon
HelloWorld
Membro desde: 21/10/2008 08:26:53
Mensagens: 12
Offline
|
A principio não precisa ser recursivo, eu fiz dessa forma pois não encontrei outra forma que não limitasse o tamanho máximo das palavras geradas. O número de combinações depende somente do tamanho da plavra que for gerada, para palavras de 4 letras ele gera todas as palavras com 1 até 4. Mas acredito que o nivel de recursividade não se aprofunda tanto a ponto de causar um estouro de pilha pois ao gerar palavras ou frases de até 100 caracteres existirão apenas 100 niveis de recursividade, e isso acredito que é pouco pois em liguagens bem menos robustas do que o java, como o action script por exemplo, o nivel de recrsividade ronda em torno do valor 255.
Como que funciona esse TreeSet? Ele é algo que faz o gerenciamento de palavras repetidas sozinho ou seria um gerenciamento de forma parecida com vatores onde eu teria que criar um for percorrendo e verificando se existe ou não a palavra?
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 11:29:53
|
entanglement
GUJ Hacker
Membro desde: 26/09/2009 09:18:56
Mensagens: 5750
Offline
|
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2639.pdf
Procure (já que o paper acima é em C++, não Java) também por "lexicographically sorted permutations".
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 11:31:44
|
Rimmon
HelloWorld
Membro desde: 21/10/2008 08:26:53
Mensagens: 12
Offline
|
entanglement wrote:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2639.pdf
Procure (já que o paper acima é em C++, não Java) também por "lexicographically sorted permutations".
vou dar uma olhada no pdf, valeu pela indicação. E C++, Java no fundo se você entende a lógica não tem problema nenhum pois para portar para qualquer outra linguagem é simples questão de sintaxe.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 11:32:28
|
ViniGodoy
Moderador
![[Avatar]](/images/avatar/1921493b5362e63fbe8983f4bd54157d.png)
Membro desde: 11/12/2006 08:22:01
Mensagens: 20578
Localização: Curitiba/PR
Offline
|
Faz sozinho. Internamente o TreeSet usa uma árvore binária. Ele descarta automaticamente palavras duplicadas e as ordena, de acordo com o comparador fornecido (como o String já é comparable, será ordenada pela ordem alfabética).
Outra possibilidade, se vc não precisar usar ordenação, é o HashSet. É um pouco mais rápido, mas não garante nenhum tipo de ordem.
Esse código está mesmo lento? Talvez o ideal seja usar um profiler para identificar onde. Também experimente trocar o String pelo StringBuilder. A recursividade, por si só, não deveria deixar tão lento.
|
@ViniGodoy - Lattes
Tem dúvidas de Java? Poste no fórum! Não respondo dúvidas de java via MP!
Ponto V! - Desenvolvimento de Jogos Profissional - @Pontov - Facebook
Projeto Towel - Swing de uma forma inteligente (Novo lar do ObjectTableModel e do Auto-Filtro).
Ei... você está usando DefaultTableModel no seu projeto??
Não faça isso! Veja: http://www.guj.com.br/posts/list/15/199067.java#1001295 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 11:54:01
|
Rimmon
HelloWorld
Membro desde: 21/10/2008 08:26:53
Mensagens: 12
Offline
|
ViniGodoy wrote:Faz sozinho. Internamente o TreeSet usa uma árvore binária. Ele descarta automaticamente palavras duplicadas e as ordena, de acordo com o comparador fornecido (como o String já é comparable, será ordenada pela ordem alfabética).
Outra possibilidade, se vc não precisar usar ordenação, é o HashSet. É um pouco mais rápido, mas não garante nenhum tipo de ordem.
Esse código está mesmo lento? Talvez o ideal seja usar um profiler para identificar onde. Também experimente trocar o String pelo StringBuilder. A recursividade, por si só, não deveria deixar tão lento.
Obrigado pela dica do TreeSet, vou dar uma pesquisada sobre o mesmo para aplicar no meu código.
E eu tenho consiencia que meu código está lento por causa do tamanho das palavras que estou tentando gerar, e por causa também do alfabeto que estou utilizando, uma vez que para colar aqui colei um alfabeto reduzido para exemplificar apenas, no meu caso estou usando todos os caracteres minusculos, todos os maiusculos, numeros e caracteres especiais, incluindo nisso caracteres acentuados, então é um alfabeto bastante extenso, também estou colocando para gerar expressões de até 200 caracteres.
Então eu sei que pela forma que eu fiz ele inevitavemente ficará pesado pela quantidade de combinações, então pensei se alguém teria uma forma mais otimizada de fazer recursividade, ou se teria alguma idéia de quebrar isso em threads para que possa ser feito utilizando um quadricore com HT por exemplo.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 13:29:38
|
entanglement
GUJ Hacker
Membro desde: 26/09/2009 09:18:56
Mensagens: 5750
Offline
|
Você obviamente deve saber que o número de permutações com repetição aumenta exponencialmente, e o expoente é o comprimento da sequência, ou seja, para você listar as permutações com repetição de 52 símbolos (só as letras minúsculas e maiúsculas), de comprimento 4 (que é bem pequeno), você tem 52 ^ 4 = 7.311.616 possibilidades. Se você quer as permutações de 52 símbolos que tenham comprimento entre 1 e 4, você terá
52 + 52^2 + 52^3 + 52^4 = 7.454.980 possibilidades.
Ou seja, se você não limitar muito os parâmetros passados, você vai esgotar logo a memória da sua máquina, ou seu disco - não importa se você vai usar 100 CPUs para calcular as permutações.
Por que é que você precisa listar as permutações?
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 13:38:10
|
entanglement
GUJ Hacker
Membro desde: 26/09/2009 09:18:56
Mensagens: 5750
Offline
|
Uma dica bem boba: você sabe fazer conversão de bases? A idéia, para você gerar as permutações de comprimento 4 de um alfabeto de 52 símbolos, é contar de 0 até 52 ^ 4 - 1, e converter a contagem para "base 52". Vou dar um exemplo.
Digamos que você queira obter a permutação de número 4889287. Então você faria:
4889287 % 52 = 39
4889287 / 52 = 94024
94024 % 52 = 8
94024 / 52 = 1808
1808 % 52 = 40
1808 / 52 = 34
34 % 52 = 34
Ou seja, a sua permutação seria composta pelos símbolos de ordem: 34, 40, 8 e 9. (O primeiro símbolo teria ordem 0). Se o alfabeto fosse "abcdef...zABCDEF...Z" então teríamos a permutação "INij". (dê uma conferida, fiz de cabeça).
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 13:48:33
|
ViniGodoy
Moderador
![[Avatar]](/images/avatar/1921493b5362e63fbe8983f4bd54157d.png)
Membro desde: 11/12/2006 08:22:01
Mensagens: 20578
Localização: Curitiba/PR
Offline
|
aahahahahaha. Entaglement, essa foi exatamente a solução que eu pensei, quando li o tópico a primeira vez.
|
@ViniGodoy - Lattes
Tem dúvidas de Java? Poste no fórum! Não respondo dúvidas de java via MP!
Ponto V! - Desenvolvimento de Jogos Profissional - @Pontov - Facebook
Projeto Towel - Swing de uma forma inteligente (Novo lar do ObjectTableModel e do Auto-Filtro).
Ei... você está usando DefaultTableModel no seu projeto??
Não faça isso! Veja: http://www.guj.com.br/posts/list/15/199067.java#1001295 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 13:57:45
|
Bruno Laturner
GUJ Expert
![[Avatar]](/images/avatar/5800ccd9514fd789d08e5831951aa6bc.jpg)
Membro desde: 18/02/2008 16:17:53
Mensagens: 3002
Offline
|
entanglement wrote:Uma dica bem boba: você sabe fazer conversão de bases? A idéia, para você gerar as permutações de comprimento 4 de um alfabeto de 52 símbolos, é contar de 0 até 52 ^ 4 - 1, e converter a contagem para "base 52". Vou dar um exemplo.
Digamos que você queira obter a permutação de número 4889287. Então você faria:
4889287 % 52 = 39
4889287 / 52 = 94024
94024 % 52 = 8
94024 / 52 = 1808
1808 % 52 = 40
1808 / 52 = 34
34 % 52 = 34
Ou seja, a sua permutação seria composta pelos símbolos de ordem: 34, 40, 8 e 9. (O primeiro símbolo teria ordem 0). Se o alfabeto fosse "abcdef...zABCDEF...Z" então teríamos a permutação "INij". (dê uma conferida, fiz de cabeça).
Achei um show essa solução, muito bem pensada.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 14:48:22
|
entanglement
GUJ Hacker
Membro desde: 26/09/2009 09:18:56
Mensagens: 5750
Offline
|
Essa é uma variação de "gere as placas de carros em ordem". Nesse caso, a base é 10 para os dígitos e 26 para as letras. Você teria então
26 ^ 3 * 10 ^ 4 = 175.760.000
combinações. Digamos que você queira emplacar seu carro com a 100.000.000 combinação. Então:
100.000.000 % 10 = 0
10.000.000 % 10 = 0
1.000.000 % 10 = 0
100.000 % 10 = 0
10.000 % 26 = 16
384 % 26 = 20
14 % 26 = 14
Ou seja, a placa é NUP 0000.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 14:55:17
|
Rimmon
HelloWorld
Membro desde: 21/10/2008 08:26:53
Mensagens: 12
Offline
|
Realmente essa solução da conversão de base é uma solução bastante interessante, porém quand eu resolvo usar um alfabeto de 80 letras +/- e palavras de até 200 caracteres (1 a 200) eu não iria estourar o tamanho de variavel? uma vez que 80^200 irá me gerar um resultado monstruoso, algo em torno de: 414951556888099295851284078636912 seguidos de 349 zeros, não é possivel precisar o valor exato pois essa foia limitação que eu tive com a calculadora do windows. Pelo modo de que essa lista iria ser descomunalmente grande eu pensei em apenas listar elas.
Mesmo usando um alfabeto de 52 letras ao chamar uma lista com palavras de tamanho 100 já estoura ao tamanho máximo de um número, não?
Essa brincadeira foi um desafio que eu criei pra mim mesmo que era criar um algoritmo de permutação que permita todas as opções existentes para uma determinada quantidade de letras, da forma que ficasse o mais simples possivel e que ficasse com um desempenho bom. Para testes pequenos de permutação simples ele funcionou que é uma beleza, porém quando comecei a aumentar a brincadeira começou a me dar problemas, então resolvi vir perguntar se alguém tem alguma idéia pra melhorar a brincadeira.
[off: ViniGodoy você é o cara daquela engine de inteligencia artificial SOFIA?]
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 15:18:36
|
entanglement
GUJ Hacker
Membro desde: 26/09/2009 09:18:56
Mensagens: 5750
Offline
|
Ainda não entendi por que que você quer listar as opções (permutações).
Você não consegue listar mais de 10^15 permutações em tempo razoável para a sua espera, mesmo sem guardá-las, gravá-las em disco, etc. Imagine 80 ^ 200.
O que você pode fazer é achar uma permutação ao acaso e testá-la contra o que você quer, em vez de listá-las todas (o que você deve ter percebido que é inviável para grandes alfabetos e/ou tamanhos).
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/10/2009 15:23:09
|
entanglement
GUJ Hacker
Membro desde: 26/09/2009 09:18:56
Mensagens: 5750
Offline
|
Uma variação desse modo de fazer (conversão de bases) é semelhante ao odômetro (marcador de quilometragem) dos veículos antigos. Para facilitar, vou supor que o tamanho é fixo em N (tal como o odômetro).
Como é que o marcador funciona? Ele funciona assim: a rodinha de cada dígito gira de 0 até 9. Quando o dígito passar de 9 para zero, ele arrasta consigo a rodinha imediatamente à esquerda, para incrementar o dígito à sua esquerda.
00001
00002
...
00009
00010
Você pode começar com uma string inicializada com N caracteres correspondentes ao caracter inicial de seu alfabeto, e ir fazendo exatamente como é feito com o odômetro. Exemplo para o alfabeto "ABCDEF... .Z" e comprimento de 4 caracteres:
AAAA
AAAB
...
AAAZ
AABA
e assim por diante.
This message was edited 1 time. Last update was at 09/10/2009 15:23:34
|
|
|
 |
|
|