Publicado por: STRØNGM@N | 11 março, 2008

Prolog – Um pouco de techniques!!!

Bem, irei postar algo voltado ao techniques agora, uma linguagem de programação voltada para a IA.

PROLOG é uma linguagem de programação baseada na lógica simbólica, servindo como ferramenta para o desenvolvimento de aplicações na área da Inteligência Artificial.
A linguagem PROLOG é utilizada em problemas que envolvam objetos e relações entre eles. É de fácil dedução que PROLOG vem de PROgramação em LÓGica. Em lógica define-se um Teorema e para verificar a sua validade, procura-se regras e fatos. Comparativamente à lógica, em PROLOG exprime-se fatos e relações entre fatos, para inferir soluções para os problemas.

Explicando alguns conceitos:

Um fato expressa uma verdade sobre uma relação. Um fato é uma relação entre objetos da forma:
relação(objeto1, … ,objeton) em que ‘objeto1, … , objeton’, são os argumentos. O nome da relação é chamado predicado. Uma relação é um conjunto de n-tuplos de objetos. Uma regra expressa uma relação entre fatos. As regras são usadas quando se deseja dizer que um fato depende de uma conjunção de outros fatos, que têm a forma: cabeça :- corpo. em que o conector ‘:-‘ significa “se”. O conjunto de regras e de fatos designa-se por base de dados, ou base de conhecimento. Os objetos manipulados em PROLOG são chamados termos, que podem ser átomos ou estruturas. Os átomos poderão ser uma de duas coisas: constantes ou variáveis. As constantes podem ser: identificadores, que começam por letras minúsculas; Strings entre apóstrofos; ou números inteiros. Ao contrário de outras linguagens, uma variável em PROLOG, não representa uma posição de memória, mas sim uma associação a um objeto. Começam por letra maiúscula ou por “_”, epresentando um objeto que não é possível de nomear. As estruturas são representadas por: símbolo_funcional(argumentos) em que o ‘simbolo_funcional’ é um identificador, e os argumentos são uma lista de termos, que pode ser vazia. Após concluída a base de conhecimento do programa em PROLOG, esta poderá ser consultada.

Uma consulta é uma interrogação ao sistema, da forma: ?-predicado(argumentos).
A resposta dada a uma consulta, depende da forma como é feita a pergunta. Se esta for fechada, ou seja, se não contiver variáveis nos argumentos dos predicados, a resposta do sistema será da forma yes/no. Se a pergunta for aberta, ou seja, se contiver variáveis nos argumentos dos predicados, serão listados todos os valores, que unificam com as variáveis, formando um fato verdadeiro. A primeira resposta do sistema, corresponde à primeira unificação das variáveis, que forma um fato verdadeiro. Para pedir ao sistema que mostre outras respostas possíveis, utiliza-se o simbolo ‘;’ que significa “ou”. O símbolo ‘;’ pede ao PROLOG que procure na base de conhecimento, a partir da última solução retornada, a próxima unificação que satisfaça a consulta (processo designado de “back-tracking”). Quando não houver mais unificações verdadeiras para mostrar, responde no.
A unificação corresponde a uma substituição que instância um termo, ou seja, é uma operação que atribui um valor a um termo. Para a pesquisa de uma resposta a uma consulta,
o interpretador de PROLOG, utiliza uma árvore de prova, que “é uma entidade perfeitamente definida que constitui, por si só, uma prova, intuitivamente evidente, que um átomo é consequência lógica de um programa”. O interpretador de PROLOG percorre a árvore de prova com avanços e retrocessos (“back-tracking”), “cada avanço está associado a uma transformação (alvo e instanciação) e cada retrocesso está associado à anulação dessa transformação”. Será apresentado um exemplo de uma árvore de prova, quando for abordado o tema das listas em PROLOG.<>Um dos primeiros exemplos e dos mais interessantes, para quem se inicia na Programação em Lógica é fazer a sua árvore genealógica.

% A base de conhecimento
pai(antonio,jose).
pai(antonio,costa).
pai(jose,carlos).
mae(maria,jose).
mae(maria,costa).
mae(carla,carlos).
casado(antonio,maria).
casado(jose,carla).
homem(antonio).
homem(jose).
homem(costa).
homem(carlos).
mulher(maria).
mulher(carla).
% Fim da base de conhecimento
O fato ‘pai(antonio,josé).’, lê-se: o indivíduo antonio é pai do indivíduo josé. Para manipular a base de conhecimento anterior, pode escrever-se, entre outros, os seguintes predicados (regras):
progenitor(P,F) :- pai(P,F).
progenitor(P,F) :- mae(P,F).
avo(A,N) :-
progenitor(A,F),
progenitor(F,N).
bisavo(BV,BN) :-
avo(BV,N),
progenitor(N,BN).
irmao(X,Y):-
homem(X),
progenitor(P,X),
progenitor(P,Y),
X \= Y.
irmaos(X,Y) :-
progenitor(P,X),
progenitor(P,Y),
X \= Y.
tio(X,Y) :-
irmao(X,I),
progenitor(I,Y).
primo(A,B) :-
progenitor(P1,A),
progenitor(P2,B),
irmao(P1,P2).
sogro(Q,W) :-
pai(Q,A),
casado(A,W).
cunhado(A,B) :-
irmaos(A,I),
casado(I,B).

Listas

Uma lista é uma estrutura recursiva binária, cujos elementos podem ser átomos ou termos estruturados, inclusive listas. Uma lista ou é vazia, não contém nenhum elemento, ou é uma estrutura com dois elementos: a cabeça e a cauda. Uma possível representação de uma lista será: [H|T], em que H representa a cabeça da lista e T a cauda da lista. As listas permitem agilizar bastante a resolução de diversos problemas e sobre elas podem ser escritos os mais diversos predicados:
%Verificar se uma estrutura é uma lista
lista([]).
lista([_H|T]) :- lista(T).
%Calcular o tamanho de uma lista
tamanho([],0).
tamanho([_H|T], N) :-
tamanho(T,M),
N is M+1.
%Verificar se um elemento pertence a uma lista
membro(H,[H|_T]).
membro(X,[_H|T]) :-
membro(X,T).
%Concatenar duas listas:
%[2][3,1] => [2,3,1]
concatena([],L,L).
concatena([H|T],L,[H|L1]) :-
concatena(T,L,L1).
%Inverter uma lista:
% [1,2] => [2,1]
inverte([],[]).
inverte([H|T], L) :-
Com as Listas, é possível definir outras estruturas de manipulação de dados, como por exemplo, uma pilha (“Stack”). Uma Stack poderá ser vista como uma estrutura
do gênero:
Stack = [topo, …, base]
%Empilhar um elemento – pop
pop(X,[],[X]).
pop(X,P,[X|P]).
%Desempilhar o elemento do Topo da Stack –
push
push([],[]) :- write(‘Stack vazia!’), !.
push([_|T],T).
%Mostrar o elemento do topo
mostra([]) :- write(‘Stack vazia!’), !.
mostra([X|_]) :- write(‘Elemento do topo: ‘),
write(X).
%Tamanho da Stack
%Resume-se a calcular o tamanho de uma lista

Manipulação de Listas

No caso de programas que têm de lidar com bases de dados consideravelmente grandes, torna-se útil a utilização de predicados que permitam pesquisar informação na base de
dados, destacando-se o predicado findall(?Termos,?Predicados,?Lista), que retorna em
Lista, a lista de todos os Termos que estão de acordo com os P r e d i c a d o s , e o p r e d i c a d o
setof(?Termo,?Predicados,?Lista), que tem um.

Árvores binárias

Outra estrutura também muito usada em PROLOG, são as árvores binárias. A árvore binária vazia poderá ser representada pela palavra void. Uma árvore binária não vazia será representada da seguinte forma:
tree(E, LT, RT) em que E representa o elemento do nó da árvore, LT a sub-árvore esquerda e RT a sub-árvore direita. Exemplo de uma árvore binária:
tree(3, tree(2, tree(1, void, void), void), tree(6,
void, void)).
Também sobre esta estrutura, podem ser escritos diversos predicados:
%Verificar se uma estrutura é uma árvore binária
binaryTree(void).
binaryTree(tree(_E, LT, RT)) :-
binaryTree(LT),
binaryTree(RT).
%Verificar se um elemento pertence árvore
treeMember(X,tree(X,_LT,_RT)).
treeMember(X,tree(_,LT,_)) :-
treeMember(X,LT).
treeMember(X,tree(_,_,RT)) :-
treeMember(X,RT).
%Multiplicar todos os elementos da árvore
multiplica(void, 1).
multiplica(tree(E, LT, RT),N) :-
multiplica(LT, M),
multiplica(RT, P),
N is E * M * P.
%Passar uma árvore para uma lista em pré-ordem
preOrdem(void,[]).
preOrdem(tree(E, LT, RT), L) :-
preOrdem(LT, L1),
preOrdem(RT, L2),
concatena([E|L1], L2, L).
%Substituir um elemento de uma árvore binária por outro elemento
subs(_X,_Y,void,void).
subs(X,Y,tree(X,LT,RT),tree(Y,A,B)):-
subs(X,Y,LT,A),
subs(X,Y,RT,B).
subs(X,Y,tree(Z,LT,RT),tree(Z,A,B)):-
subs(X,Y,LT,A),
subs(X,Y,RT,B).

O operador CUT

O operador “cut”, que se denota por !, influencia o percurso de pesquisa na árvore de procura. Quando utilizado, numa regra ou consulta, modifica a árvore de procura, eliminando as unificações realizadas antes de ser ativado. Ou seja, elimina todos os ramos da árvore de procura, que ainda não foram percorridos e que estão situados à direita do último nó unificado, inclusive, não sendo percorridos a quando do “back-tracking”. O operador “cut”, pode ser utilizado em diversas situações:

• Exclusão mútua incondicional, em que só é dada uma resposta a cada consulta,
cabeça:-!,objectivo2,…,objectivon.
• Exclusão mútua condicional, cabeça:-objectivo1,…,!,…, objectivon.
• Resposta única, cabeça:-objectivo1,…,objectivon, !
Exemplos:

%Implementação de um IF, à imagem de C ou JAVA
if_then_else(C,_T,E):- C, !, E.
if_then_else(_C,_T,E):- E.
membroComCut(H,[H|_T]):-!.
membroComCut(X,[_H|T]):-
membroComCut(X,T).
%Exemplo de consultas, para mostrar a diferença de resultados
?-membro(X,[2,4,6]).
X=2;
X=4;
X=6;
no
?-membroComCut(X,[2,4,6]).
X=2
yes

Laços

Embora a linguagem PROLOG seja totalmente diferente de linguagens como C ou JAVA, é igualmente possível construir laços(loops) em PROLOG, usando o predicado repeat, que já se
encontra pré-definido no PROLOG, da seguinte forma: repeat.
repeat:-repeat.
Associado ao repeat pode-se ter o predicado fail, que falha sempre. Um ciclo repeat-fail, executa um predicado P até que uma condição X seja verdadeira. O predicado fail permite forçar o “back-tracking”. Como usar o repeat e o fail? Eis um exemplo:
%Um menu simples
menu:-
repeat,
write(‘1 – Opção A. ‘),nl,
write(‘2 – Opção B. ‘),nl,
write(‘3 – Opção C. ‘),nl,nl,
write(‘Introduza a opção: ‘),
read(Opcao),
executa(Opcao), fail.

O predicado repeat permite chamadas iterativas ao write e ao read, até que a condição de saída executa(X), tenha êxito.

Laço For

for(X,[X,Z]) :- X =< Z.
for(X,[Y,Z]) :-
W is Y+1,
W =< Z,
for(X,[W,Z]).
?- for(X,[1,3]), write(X), write(‘‘), fail.
1 2 3
yes

Negação Lógica
Combinando o operador “cut” e o predicado fail, implementa-se a negação lógica,
not(A) :- A, !, fail.
not(A).
Se A tiver êxito, então not(A) falha; se A falha, então not(A) tem êxito.

Manipulação de Base de Dados

Os predicados seguintes permitem adicionar ou remover fatos de uma base de dados PROLOG.
• asserta(fato) -> adiciona o fato no ínicio da lista de fatos
• assertz(fato) -> adiciona o fato no fim da lista de fatos
• retract(fato) -> remove o fato da base de dados

Manipulação de Termos

• var(X) -> Sucede se X é uma variável
• novar(X) -> Sucede se X não é uma variável
• atom(X) -> Sucede se X representa um átomo PROLOG
• integer(X) -> Sucede se X é um inteiro
• Estrutura=..Lista -> Converte um elemento composto numa lista, e vice-versa.
Exemplo:
f(a,b)=..L resulta em L=[f,a,b]
L=..[f,a,b] resulta em L=f(a,b)
• arg(Argumento,Termo,Valor)-> Retorna em Valor o Argumento do Termo.
• functor(Termo,Nome,Aridade)-> Retorna em Nome o nome do Termo, e em Aridade o número de argumentos do Termo.

Depuração

Inicialmente, para compreender como funciona o motor de inferência do PROLOG e para se ter acesso ao “raciocínio” do PROLOG, podem-se usar os seguintes predicados:
trace -> Ativa a depuração
notrace -> Desativa a depuração Exemplo:
trace,
%Chama o predicado ‘lista’
lista([1,2,3]), notrace.

Acesso a arquivos

A maioria das vezes, quando se faz um programa, é desejável guardar a informação gerada pela execução desse programa, para utilização futura. Em PROLOG, ler e guardar informação em arquivos é algo bastante simples, mas que requer algum cuidado.

%see abre o arquivo para leitura
see(‘nomeArquivo.pl’),
read(X),
%seen fecha o arquivo
seen.
Após aberto um arquivo, para escrita, se ocorrer algum erro de execução enquanto o arquivo não for fechado, perder-se á todo o conteúdo do mesmo, pelo que é aconselhável manter sempre atualizado, um backup do arquivo. Caso se queira ler para a memória, uma base de dados contida num arquivo, bastaria fazer:
:- initialization(iniciar).
iniciar:- [nomeArquivo].
Para escrever dados num arquivo, bastará fazer:
%tell abre o arquivo para escrita
tell(‘nomeArquivo.pl’),
write(‘qualque coisa’),nl,
%told fecha o arquivo
told.
Penso que neste artigo foram abordados os tópicos essenciais ao início do desenvolvimento de programas em PROLOG. Embora seja uma linguagem com sintaxe relativamente fácil, requer muita prática e bastante raciocínio.
fim:-
write(‘Prolog é isso aí!!!’),nl,
write(‘FIM’).

Créditos: Gaspar Brogueira

Para saber mais, livro: Sterling, Leon; Shapiro, Ehud; The Art of Prolog; Advanced
Programming Techniques; 1994

Alterações: STRØNGM@N

See ya!!!


Responses

  1. Boa Tarde!
    Muito legal o site.
    Gostaria de saber se tem como fazer conexão do prolog com java e se posivel como eu poderia fazer isso.
    Será que vocês poderião me ajudar nessa labuta?
    desde já agradeço a atenção

  2. Boa noite Reinaldo !!!

    Acho que este material que está disponível neste endereço aqui:

    http://www.di.ufpe.br/~compint/aulas-IAS/mci2/taci2-ias-992/JavaProlog.ppt

    pode te ajudar. Veja a parte do InterProlog. E tem este trabalho aqui também:

    http://www.inf.unisinos.br/~barbosa/grefe/atividades/at4/rodrigo_4.pdf

    Abraços.

    STRØNGM@N.

  3. Boa Noite, Queria lhe fazer uma pergunta:

    Tenho o seguinte programa:

    factorial(0,1).

    factorial(N,F) :-
    N>0,
    N1 is N-1,
    factorial(N1,F1),
    F is N * F1.

    ?- factorial(3,W).

    Quando faço a pergunta o prolog retorna yes tem como ele me mostrar o valor de W, já tentei que só e não consegui.
    Desde já agradeço!

  4. Cara consegui!! Falow

  5. Boa Tarde.
    Tenho uma base de dados para consulta. Como faço para gravar todos os resultados(true ou false) no arquivo?
    Desde já agradeço..

  6. Eu preciso escrever um artigo sobre R. N. e biotec.

    Alguém topa escrever junto comigo?

    strapasson@ufpr.br

  7. Bom dia!!! Alguém saberia me dizer como multiplicar os elementos de uma lista por 2 em prolog? E tbm tendo uma função ascendentes como construir uma lista de todos os ascendentes de uma pessoa X?
    Obrigada
    Priscilla

  8. seguinte sou novo em prolog mas posso ajudar em algumas coisinhas, bom o kennedy vi que vc ja cnseguiu só resaltando faltou vc dizer os casos bases do seu programa fatorial, que serião fat(0,1). e fat(1,1). ai rodo certin

    priscilla no seu caso vc teria que fazer um predicado com recursão em cauda +- desse jeito :

    multipor2([X|Y],[X1|Y1]):-
    X1 is X1*2,
    multipor2(Y,Y1).

    bom ta ai é mais ou menos esse raciocínio que vc deve ter, espero ter ajudado

    caso queiram entrar em contato ta ai meu msn gustavofranca10@hotmail.com

    Gustavo graduando em Ciência da Computação – UFU

    vlw galera

  9. ops so corrigindo o erro de digitação na segunda linha do programa é

    X1 is X*2

    vlw


Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Categorias

%d blogueiros gostam disto: