Escolar Documentos
Profissional Documentos
Cultura Documentos
Dado que em Prolog fcil criar estruturas (termos compostos) e fazer buscas sujeitas a certas restries, fcil resolver os tais desafios de lgica usando a linguagem. O tipo de desafio de lgica em questo similar aquele teste de Einstein que algumas correntes de email dizem que s meia-dzia de pessoas no mundo conseguem resolver (o que uma grande balela). Vrias informaes (mas no todas) so dadas sobre um conjunto de indivduos, e preciso deduzir as informaes que faltam para chegar na soluo. Resolver um problema desses em Prolog uma forma de explorar vrias caractersticas de linguagem e alguns padres de uso. A Coquetel publica uma linha de revistas de Desafios de Lgica desse tipo, usando uma tabela para ajudar a cruzar as informaes e resolver o problema. Esses problemas so um pouco diferentes porque algumas informaes no esto nas dicas, mas apenas nas listas de atributos nas tabelas, e porque s vezes preciso raciocinar por excluso (assumindo que no existem duas pessoas com o mesmo atributo). Para a soluo (em Prolog) de um puzzle simples no estilo do teste de Einstein, vejaesse post acol. Aqui vou mostrar a soluo para um problema de uma revista Desafios de Lgica (nmero 98). Sem colocar a tabela, aqui esto as informaes dadas (espero que a Coquetel no me processe): Desafio: Primeiro de Abril Quatro pessoas que gostam de pregar peas decidiram tornar o primeirode abril inesquecvel, ou seja, com muitas brincadeiras. Cada um pregou uma pea numa vtima diferente usando um objeto inofensivo. Nomes: Ana, Ester, Pablo, Rodolfo Sobrenomes: Fontes, Levis, Matoso, Salgado Brincadeiras: Almofada de barulho, Aranha falsa, Foto alterada, Mosca falsa Vtimas: Irmo, Me, Pai, Tia Dicas: 1. 2. 3. 4. 5. Ana deu risadas enquanto colocava uma aranha falsa na comida de sua vtima. A pessoa de sobrenome Salgado (que no Ana) pregou uma pea em seu irmo. A pessoa de sobrenome Matoso colocou uma almofada de barulho na cadeira de sua vtima. Rodolfo pregou uma pea em sua tia, mas no foi ele que usou a almofada de barulho. A brincadeira feita por Levis inclua uma mosca falsa. A vtima de Ester foi seu pai.
Para garantir que todas as possibilidades so examinadas e so testadas posteriormente, incluindo as partes de deduo por excluso, decidi usar o padro gerar e testar (generate-and-test) que comum em Prolog: gerar todas as possibilidades e ir restringindo (testando) at achar a soluo.
Gerao
Comeando com a gerao: o procedimento a seguir gera todas as configuraes possveis, se for usado backtracking. Para representar as informaes de uma pessoa, usei uma estrutura
Vtima).
/* p(Nome, Sobrenome, Brincadeira, Vitima) */ gera(p(N, S, B, V)) :member(N, [ana, ester, pablo, rodolfo]), member(S, [fontes, levis, matoso, salgado]), member(B, [almofada, aranha, foto, mosca]), member(V, [irmao, mae, pai, tia]).
O procedimento gera as possibilidades corretas usando o predicado pr-definido member, garantindo que o nome gerado ser um entre [ana, ester, pablo, rodolfo], e por a vai. Podemos testar a gerao fazendo uma consulta como
?- gera(P).
O prximo passo gerar no s um indivduo, mas uma soluo completa, que so quatro indivduos. Se simplesmente usarmos
?- gera(P1), gera(P2), gera(P3), gera(P4).
sero gerados muitos grupos com indivduos repetidos. Precisamos garantir a gerao de quatro indivduos diferentes em todos os atributos. No funciona se tentarmos usar P1 \= P2 e por a vai, porque o Prolog vai dizer que duas estruturas que diferem em apenas um dos termos so diferentes. Por exemplo,
?- p(ana, fontes, almofada, irmao) \= p(ana, fontes, almofada, mosca). true.
Precisamos diferenciar todos os atributos. Alm disso, preciso ter quatro indivduos diferentes dois a dois, pois se P1 diferente de P2 e P2 diferente de P3, possvel que P1 seja igual a P3, e por a vai. Assim, definimos
dif(p(N1, S1, B1, V1), p(N2, S2, B2, V2)) :N1 \= N2, S1 \= S2, B1 \= B2, V1 \= V2.
todas_dif(P1, P2, P3, P4) :dif(P1, P2), dif(P1, P3), dif(P1, P4), dif(P2, P3), dif(P2, P4), dif(P3, P4).
S veremos solues em que as quatro pessoas so diferentes em todos os atributos. Falta testar as possibilidades geradas com as dicas dadas no problema para encontrar a soluo.
Testes
A soluo consiste de quatro indivduos, todos diferentes (usando o critrio de diferena discutido), que se encaixem nas dicas dadas pelo problema. A ideia capturada no procedimento que resolve o problema:
solucao(S) :S = [P1, P2, P3, P4], gera(P1), gera(P2), gera(P3), gera(P4), todas_dif(P1, P2, P3, P4), member(p(ana, _, aranha, _), S), member(p(N, salgado, _, irmao), S), N \= ana, member(p(_, matoso, almofada, _), S), member(p(rodolfo, _, B, tia), S), B \= almofada, member(p(_, levis, mosca, _), S), member(p(ester, _, _, pai), S).
O primeiro objetivo da soluo apenas diz que S (a soluo) uma lista de tamanho 4, formada por P1, P2, P3 e P4. Na segunda e terceira linha do corpo da clusula, temos o padro de gerao discutido antes. Depois, cada linha um teste que representa uma dica do problema. O primeiro teste diz que Ana usou a Aranha como brincadeira, mas no conhecemos seu sobrenome nem qual foi sua vtima; esse indivduo faz parte da soluo (usando o predicado prdefinido member). A segunda diz que a pessoa de sobrenome Salgado pregou uma pea no irmo; no conhecemos o nome dessa pessoa, mas sabemos que no Ana, como expresso pela desigualdade seguinte. As outras linhas traduzem as outras dicas, sem maiores novidades. Carregando o cdigo inteiro em um sistema Prolog como o SWI-Prolog, e fazendo a consulta
?- solucao(S).
A resposta dever aparecer aps algum tempo. Dependendo do computador, isso pode demorar alguns minutos, o que ruim. Alm disso, so retornadas solues equivalentes, em que apenas a ordem dos indivduos muda. Isso tudo demonstra que o sistema Prolog est buscando em um espao de estados muito maior do que necessrio. Podemos fazer isso de maneira mais eficiente.
Depois s usar esse predicado na busca pela soluo. Alm disso, s precisamos de uma soluo, ento vamos incluir um corte no final para evitar clculos inteis. O resultado
solucao2(S) :S = [P1, P2, P3, P4], gera_ef(P1, P2, P3, P4), member(p(ana, _, aranha, _), S), member(p(N, salgado, _, irmao), S), N \= ana, member(p(_, matoso, almofada, _), S), member(p(rodolfo, _, B, tia), S), B \= almofada, member(p(_, levis, mosca, _), S), member(p(ester, _, _, pai), S), !.
Vai achar a soluo muito mais rpido. O cdigo completo pode ser visto aqui.
P.S.: Agora que o github abriu o cdigo para deteco de linguagens e syntax highlighting, queria ter tempo de
1/ * P (Nome, sobrenome, Brincadeira, Vitima) * / 2 3Gera ( p ( N , 4 5 6 7 8 9diferenas ( p ( N1 , 10 11 12todas_dif ( P1 , 13 P2 , P3 , P4 ) : P3 ), DIF ( P1 , P4 ), N1 \ = N2 , S1 , S1 B1 , \ = V1 ), B1 p ( N2 , \ = B2 , S2 , V1 B2 , \ = V2 )) V2 . : S , B , V )) : ster , pablo , rodolfo ]), salgado ]), mosca ]),
[ ana ,
levis ,
Matoso , foto ,
aranha , pai ,
mae ,
tia ]).
S2 ,
DIF ( P1 ,
P2 ),
DIF ( P1 ,
14 15
DIF ( P2 ,
P3 ),
DIF ( P2 ,
P4 ),
DIF ( P3 ,
P4 ).
Gera ( P1 ),
Gera ( P2 ), P2 , _ , P3 ,
aranha , _ ,
salgado , Matoso , _ ,
irmao ), _ ),
S ), S ), S ).
levis , _ ,
membro ( p ( ster ,
pai ),
P2 ,
P3 ,
P4 ) _ , _ , _ , _ , _ ,
: _ ), _ ), _ ), _ ), Gera ( P4 ),
_ , _ , _ ,
p ( rodolfo ,
Gera ( P1 ),
Gera ( P2 ), P2 , P3 ,
Gera ( P3 ), P4 ).
todas_dif ( P1 ,
: [ P1 , P2 , P2 , P3 , P4 ], P4 ), _ ), S ), S ), S ), B \ = almofada , N \ = ana ,
gera_ef ( P1 ,
P3 , _ ,
aranha , _ ,
salgado , Matoso , _ ,
irmao ), _ ),
S ), S ), S ),
levis , _ ,
membro ( p ( ster , !.
pai ),