O tipo de problemas com "presença na festa" pode ser solucionado no Prolog? Por exemplo:
Burdock Muldoon e Carlotta Pinkstone disseram que viriam se Albus Dumbledore viesse. Albus Dumbledore e Daisy Dodderidge disseram que viriam se Carlotta Pinkstone viesse. Albus Dumbledore, Burdock Muldoon e Carlotta Pinkstone disseram que viriam se Elfrida Clagg viesse. Carlotta Pinkstone e Daisy Dodderidge disseram que viriam se Falco Aesalon viesse. Burdock Muldoon, Elfrida Clagg e Falco Aesalon disseram que viriam se Carlotta Pinkstone e Daisy Dodderidge viessem. Daisy Dodderidge disse que viria se Albus Dumbledore e Burdock Muldoon viessem. A quem precisa ser persuadido a participar da festa para garantir que todos os seus convidados participem?
Eu tentei expressar isso no GNU Prolog:
attend(BM) :- attend(AD).
attend(CP) :- attend(AD).
attend(AD) :- attend(CP).
attend(DD) :- attend(CP).
attend(AD) :- attend(EC).
attend(BM) :- attend(EC).
attend(CP) :- attend(EC).
attend(CP) :- attend(FA).
attend(DD) :- attend(FA).
attend(BM) :- attend(CP),attend(DD).
attend(EC) :- attend(CP),attend(DD).
attend(FA) :- attend(CP),attend(DD).
attend(DD) :- attend(AD),attend(BM).
attend(FA). /* try different seed invitees in order to see if all would attend*/
/* input:
write('invited:'),nl,
attend(X),write(X),nl,
fail.*/
Estou com estouro de pilha (sem trocadilhos) e não tenho conhecimento de avaliação de prólogo, é por isso que estou perguntando.
De um modo geral, esse problema pode ser convertido na fórmula de satisfação CNF booleana (com 6 variáveis booleanas). Portanto, a perspectiva do prólogo tem algum mérito?
fonte
attend(BM) :- attend(AD).
é exatamente o mesmo queattend(X) :- attend(Y).
Respostas:
Para resolver um problema com o Prolog, como em qualquer linguagem de programação, seja ela declarativa ou imperativa, é necessário pensar na representação da solução e da entrada.
Como essa é uma questão de programação, teria sido popular no StackOverflow.com, onde os programadores resolvem problemas de programação. Aqui eu tentaria ser mais científico.
são mais difíceis de tratar.
Com o Prolog, a primeira abordagem simples é evitar uma reversão completa do relacionamento e, em vez disso, ser direcionada à meta.
Assuma uma ordem na lista de convidados e use uma regra
Esta regra é fácil de implementar.
Uma abordagem bastante ingênua
Para facilitar a leitura,
follows
seja a relação dada como entrada ebrings
seja o seu inverso.Então a entrada é dada por
E
brings
pode ser definido da seguinte maneira:brings/3(X,L,S)
Se definirmos
Temos as seguintes soluções exclusivas:
Esta não é a lista completa, pois sob a ordem alfabética da cláusula
não está funcionando.
Uma solução bastante envolvida para o quebra-cabeça original
Para resolver o problema completamente, você deve realmente deixar o sistema tentar provar a presença de convidados posteriores sem introduzir loops infinitos na árvore de pesquisa. Existem várias maneiras de atingir esse objetivo. Cada um tem suas vantagens e desvantagens.
Uma maneira é redefinir da
brings/2
seguinte maneira:O último argumento em
brings/4
é necessário para evitar um loop infinitotry_bring
.Isso fornece as seguintes respostas: Albus, Carlotta, Elfrida e Falco. No entanto, essa solução não é a mais eficiente, uma vez que o retorno é introduzido, onde às vezes pode ser evitado.
Uma solução geral
Agora, se, por exemplo, o conjunto de dados # 2 for fornecido como
Nós obtemos a resposta L = [[ad, bm, dd, ec]]. O que significa que todos os convidados, exceto Carlotte e Falco, devem ser convidados.
As respostas que essa solução me deu correspondem às soluções fornecidas no artigo da Wicked Witch, com exceção do conjunto de dados # 6, onde mais soluções foram produzidas. Esta parece ser a solução correta.
Finalmente, devo mencionar a biblioteca de Prolog CLP (FD) que é particularmente adequada para esse tipo de problemas.
fonte
Como observado por svick, o primeiro problema com o código no OP é que nomes começando com letras maiúsculas são variáveis no Prolog. Portanto,
admit(CP) :- admit(AD)
é equivalente aattend(X) :- attend(Y)
, o que resulta no Prolog entrando imediatamente em um loop infinito, tentando demonstrar queattend
é válido por algum termo, encontrando algum termo para o qualattend
é válido.No entanto, se você quisesse que cada conjunto de iniciais fosse um termo distinto concreto, ainda ocorreria um estouro de pilha porque você tem ciclos, por exemplo
Portanto, para descobrir se há
attend(cp)
retenções, o Prolog tentará determinar se háattend(ad)
retenções, o que será feito verificando seattend(cp)
retenções e assim por diante até o estouro da pilha.Não acredito que o baunilha Prolog faça qualquer tentativa de determinar se existe esse ciclo e examine outras maneiras de fazer uma delas
attend(cp)
ouattend(ad)
verdadeira, em vez de ficar preso em um loop infinito.Pode ou não haver versões do Prolog compatíveis com esse recurso. Eu estou mais familiarizado com Mercury e acho que a "apresentação mínima do modelo" de Mercury é exatamente o que você precisa para este caso. Na verdade, nunca o usei, mas meu entendimento é que mais ou menos permite que um termo que se implique seja considerado verdadeiro se houver alguma outra maneira de provar isso, ou falso caso contrário, sem ser pego em um loop infinito. Consulte a seção relevante dos documentos Mercury e, se você estiver interessado, um documento descrevendo a implementação.
O Mercury é uma linguagem de programação lógica de pureza forçada, com sintaxe semelhante ao Prolog, mas sistemas fortes de tipo e modo, e é compilada em vez de interpretada.
Acabei de repensar a introdução do artigo (que não leio há algum tempo), e ele menciona que o tabling foi implementado em várias versões do Prologs, para que você possa ir mais longe pesquisando no Google. em Prolog.
fonte
Encontrei o seguinte artigo sobre resolução de SAT usando o prólogo:
Uma implementação do solucionador pode ser encontrada aqui .
Veja esta resposta do stackoverflow para obter detalhes sobre o código e como usá-lo.
fonte
Deixando de lado a questão minúscula / maiúscula, há um ciclo nas cláusulas:
Portanto, quando você chama um intérprete de cima para baixo, ele faz um loop. Você pode ter mais sorte com a Programação de conjunto de respostas (ASP), que funciona de baixo para cima. Aqui está uma codificação via biblioteca ( minimal / asp ):
Aqui está um exemplo de execução:
fonte