Repository navigation
Knowledge and Logic
A representação de conhecimento em sistemas de inteligência artificial simbólica é fundamentada, principalmente na lógica de predicados. Especificamente, em fatos e regras definidos por meio de uma linguagem de programação baseada em, ou que implemente, essa lógica. Prolog é uma linguagem declarativa fundamentada na utilização de um formato específico de construção de cláusulas da lógica de predicados. Essas cláusulas, denominadas cláusulas de Horn, e conceitos da lógica de predicados são apresentados a seguir.
Considere o seguinte argumento descrito em lógica de predicados.
premissa
conclusão
Assumindo, por exemplo, que o predicado relacional
É possível utilizar o método de prova por contradição para tentar verificar a validade do argumento. Para isso, bloqueia-se a conclusão e supõe-se que ela é falsa.
1 premissa
conclusão
2 suposição
Na suposição tem-se a negação do quantificador universal.
Utilizando a regra
RU:
é possível concluir
1 premissa
conclusão
2 suposição
3 RU em 2
Com a reescrita da sentença 2 na 3 é possível instanciar o quantificador existencial utilizando a regra
DE:
onde
1 premissa
conclusão
2 suposição
3 RU em 2
4 DE em 3
Em 4 tem-se a negação do quantificador existencial.
Utilizando a regra
RE:
é possível concluir RE em 4 e instanciando o quantificador existencial da premissa 1 em DE, tem-se o seguinte resultado.
1 premissa
conclusão
2 suposição
3 RU em 2
4 DE em 3
5 RE em 4
6 DE em 1
Nesse ponto é possível identificar que é possível chegar a uma contradição ao instanciar o quantificador universal de 5 em 6 em
DU:
onde
Com a contradição, é possível concluir que a suposição inicial é falsa por RAA (reductio ad absurdum, ou, redução ao absurdo).
Resultando em
SN:
remove-se a dupla negação (resultando em
1 premissa
conclusão
2 suposição
3 RU em 2
4 DE em 3
5 RE em 4
6 DE em 1
7 DU em 6
8 DU em 5
9 RAA em 2, cont. 7 e 8
10 SN em 9
O método de prova por contradição e a utilização de argumentos da lógica de predicados são a base conceitual necessária para compreender a linguagem de programação Prolog. A seguir, são apresentadas as cláusulas de Horn. Elas são a fundamentação da linguagem e da gramática utilizada para definir argumentos da lógica de predicados em Prolog.
Uma fórmula atômica, ou átomo, tem formato
Um literal é um átomo ou a negação de um átomo, denominados, respectivamente, literal positivo e literal negativo.
Por exemplo,
Uma cláusula é uma disjunção de literais no formato
Uma cláusula de Horn é uma cláusula com no máximo um literal positivo, podendo ser subclassificada em:
- cláusula definitiva, uma cláusula de Horn com exatamente um literal positivo;
- cláusula unitária, uma cláusula definitiva sem literais negativos; e
- cláusula objetivo, uma cláusula de Horn sem literais positivos.
Cláusulas definitivas podem ser interpretadas como regras de inferência.
Por exemplo, considere a seguinte cláusula
Utilizando a seguinte equivalência semântica entre a disjunção e a implicação
Prolog usa as três cláusulas de Horn apresentadas como elementos de linguagem para construção de programas.
Utilizando o operador :- (dois pontos traço) para representar a operação de implicação , (vírgula) para a conjunção
-
regras: cláusulas definitivas no formato
H :- G1, ..., Gn., ondeGilê-se objetivo; -
fatos: cláusulas unitárias no formato
H.; e -
consultas: cláusulas objetivo no formato
?- G1, ..., Gn..
Sobre a sintaxe da linguagem cabe reforçar que todos o elementos terminam com . (ponto) e que nas consultas o operador de implicação :- é substituído por ?-.
Uma questão importante relacionada a utilização de cláusulas de Horn é que o processo de dedução ou prova de programas é significativamente simplificado por causa da sua sintaxe simples. Embora essa simplificação reduza o poder de expressão da lógica de predicados, é conhecido que com a utilização cláusulas de Horn é possível construir programas com a mesma representatividade computacional da máquina de Turing. Ou seja, a utilização de cláusulas de Horn permite escrever programas para tudo que é conhecido como computável.
Considere o seguinte programa composto por três fatos.
love(romeo, juliet).
love(paris, juliet).
love(juliet, juliet).Esse programa representa um dos possíveis universos de discurso do argumento apresentado no início da Seção Predicate Logic.
Temos na premissa que juliet.
Com o programa definido, é possível criar cláusulas de consulta.
?- love(romeo, juliet).
true.
NOTA - É possível experimentar programação em Prolog na plataforma on-line SWISH.
Nesse exemplo, o objetivo da consulta love(romeo, juliet) tem como resultado o valor verdade true.
Isso quer dizer que o Prolog encontrou uma forma de demonstrar que o objetivo é verdadeiro com base no programa escrito.
Considere agora as seguintes consultas.
?- love(romeo, paris).
false.
?- love(juliet, romeo).
false.
No primeiro caso, love(romeo, paris), o Prolog não encontrou uma forma de provar o objetivo e, por isso, o considerou falso (false).
É importante destacar que a linguagem considera que o universo de discurso é fechado e, portanto, tudo aquilo que ela não consegue provar é considerado por ela falso.
Veja que isso também é reforçado pela segunda consulta do exemplo.
O programa também conclui que love(juliet, romeo) é falso, pois não há como concluir isso com base no programa apresentado.
Uma consulta em Prolog pode ser mais generalista através da utilização de variáveis.
Por exemplo, é possível com objetivo love(rome, X) buscar por uma solução para X que torne o objetivo verdadeiro.
?- love(romeo, X).
X = juliet.
Nesse caso, tem-se como resposta uma solução para a variável X.
De forma ainda mais geral, é possível criar a consulta love(X, Y), onde o Prolog tentará encontrar termos que possam substituir as variáveis X e Y a fim de tornar a consulta verdadeira.
?- love(X, Y).
X = romeo,
Y = juliet ;
X = paris,
Y = juliet ;
X = Y, Y = juliet.
Onde o símbolo , representa a conjunção ; representa a disjunção
Em Prolog, as respostas a uma cláusula consulta podem ser dos seguintes tipo.
- Uma avaliação da cláusula objetivo:
trueoufalse; ou - Uma solução: podendo ser única ou um conjunto de soluções.
No exemplo a seguir, inspirado no livro do Harry J. Gensler, tem-se um conjunto de fatos sobre uma festa em que o dinheiro de Herman foi roubado.
- Alice doesn’t love money.
- Bob loves money.
- Carol knew where the money was.
- David works for Herman.
- All who stole money love money.
- All who stole money knew where the money was.
- All who work for Herman hate Herman.
- All who hate Herman stole money.
Podemos traduzi-los para lógica de predicados a fim de verificar se é possível identificar culpados e inocentes.
did_not_stole(X, money) :- does_not_love(X, money).
does_not_love(alice, money).
hate(X, herman) :- works(X, herman).
knew_where_was(carol, money).
knew_where_was(X, money) :- stole(X, money).
love(bob, money).
love(X, money) :- stole(X, money).
stole(X, money) :- hate(X, herman).
works(david, herman).Nessa tradução, um dos fatos originais é que Alice não gosta de dinheiro.
Como a falha em provar resulta em false.
Deve-se reescrever um novo predicado, no caso does_not_love(alice, money).
Como a regra love(X, money) :- stole(X, money) é importante para inocentar Alice, devemos reescreve-la considerando o novo predicado does_not_love(X, Y).
Como a tabela verdade de did_not_stole(X, money) :- does_not_love(X, money).
Dessa forma, é possível realizar uma consulta para, com base no fatos, provar a culpabilidade e a inocência.
term@ai$ swipl -q party.pl
?- stole(X, money).
X = david.
?- did_not_stole(X, money).
X = alice.Com base nos fatos, não é possível concluir sobre a culpa ou inocência de Bob, Carol ou Herman.
NOTA - O programa utilizado nesse exemplo está disponível no arquivo
party.plno repositório. Uma versão estendida está disponível no arquivoparty-plus.pl.
O cálculo do fatorial de
Nessa cláusula definitiva é primeiro verificado pela avaliação do primeiro literal se
O programa a seguir implementa essas cláusulas utilizando > para o predicado is para o predicado - para o predicado * para o predicado
factorial(0, 1).
factorial(N, R) :- >(N, 0),
is(N1, -(N, 1)),
factorial(N1, R1),
is(R, *(N, R1)).Com base no programa pode-se verificar o resultado das seguintes consultas.
term@ai$ swipl -q factorial.pl
?- factorial(0, R).
R = 1 .
?- factorial(5, R).
R = 120 .NOTA - O programa utilizado nesse exemplo está disponível no arquivo
factorial.plno repositório. Também é possível encontrar exemplos para o teste de primalidade no arquivoprime.ple cálculo de raiz exata no arquivoroot.pl.
adjacent(a1, a2). adjacent(a1, b1).
adjacent(a2, a1). adjacent(a2, a3). adjacent(a2, b2).
adjacent(a3, a2). adjacent(a3, a4). adjacent(a3, b3).
adjacent(a4, a3). adjacent(a4, a5). adjacent(a4, b4).
adjacent(a5, a4). adjacent(a5, b5).
[...]
path(X, Y) :- path(X, Y, P), print(P).
path(X, Y, P) :- path(X, Y, F, [X]), append([X], F, P), !.
path(X, Y, P, V) :- adjacent(X, Y),
append([Y], [], P);
adjacent(X, Z),
not(member(Z, V)),
append([Z], V, W),
path(Z, Y, F, W),
append([Z], F, P).
path(X, Y) :- path(X, Y, P), % Includes the P variable.
print(P). % Prints the path P.path(X, Y, P) :- path(X, Y, F, [X]), % Includes X in the memory.
append([X], F, P). % Appends X to the path P.path(X, Y, P, V) :- adjacent(X, Y), % Verify if X and Y are adjacent.
append([Y], [], P); % Appends Y to the path P.
adjacent(X, Z), % Gets a Z adjacent to X.
not(member(Z, V)), % Verify if Z is not visited.
append([Z], V, W), % Appends Z to the memory.
path(Z, Y, F, W), % Finds a path from Z to Y.
append([Z], F, P). % Appends Z to the path.term@ai$ swipl -q robot.pl
?- path(a1, e5).
[a1,a2,a3,a4,a5,b5,c5,d5,e5]
true.[1] Harry Gensler. Introduction to Logic.
[2] Peter Flach. Simply Logical.
[3] Markus Triska. The Power of Prolog.