Professional Documents
Culture Documents
PROLOG
Luiz A. M. Palazzo
Editora da Universidade Catlica de Pelotas / UCPEL
Rua Flix da Cunha, 412 - Fone (0532)22-1555 - Fax (0532)25-3105
Pelotas - RS - Brasil
EDUCAT
Editora da Universidade Catlica de Pelotas
Pelotas, 1997
sim
escreveFam(famlia(Pai, Me, Filhos)) :-
nl, nl, write('Pais:'), nl,
escrevePes(Pai), nl, escrevePes(Me), nl,
write('Filhos:'), nl,
escrevePesList(Filhos).
escrevePes(pessoa(Nome, SNome, dat(D,M,A), Trab)) :-
tab(10), write(Nome), tab(1), write(SNome),
write(', nasc: '),
write(D), write('/'), write(M), write('/'), write(A),
write(','), escreveTrab(Trab).
escrevePesList([]).
escrevePesList([P | L]) :-
escrevePes(P), nl, escrevePesList(L).
escreveTrab(nt) :-
write('no trabalha').
escreveTrab(trab(Emp, Sal)) :-
write('trab: '), write(Emp), write(', '),
write('sal: '), write(Sal).
Figura 8.2 Um programa para a formatao do termo "famlia"
O procedimento barras/1 pode ser definido da seguinte maneira, assumindo que a representao ''
seja vlida no Prolog utilizado:
barras([]).
barras([N | L]) :-
quadrinho(N), nl, barras(L).
quadrinho(N) :-
N>0,
write(' '), N1 is N-1,quadrinho(N1).
quadrinho(N) :-
N=<0, !.
76
8.2.3 FORMATAO DE TERMOS
Vamos considerar novamente a representao sob a forma de termos usada para definir famlias, dis-
cutida na seo 7.1. Se uma varivel F for instanciada com o termo cuja estrutura mostrada na figura
7.1, o objetivo write(F) ir ocasionar a sada do termo correspondente no formato padro do Prolog.
Alguma coisa como:
famlia(pessoa(ari, pl, data(17,05,65), trab(ibn,1500)),
pessoa(ana, pl, data(06,11,58), trab(rbz,1100)),
[pessoa(ada, pl, data(18,02,91), nt)])
O termo acima contm, sem dvida, toda a informao, entretanto sob uma forma bastante confusa,
tornando difcil seguir as partes da informao que formam as unidades semnticas. Iramos, certa-
mente, preferir que a informao fosse apresentada de outra maneira, por exemplo, na forma abaixo:
Pais:
ari pl, nasc: 16/05/65, trab: ibn, sal: 1500
ana pl, nasc: 06/11/68, trab: rbz, sal: 1100
Filhos:
ada pl, nasc: 18/02/91, no trabalha.
Tal formato pode ser obtido por meio do procedimento escreveFam/1 mostrado na Figura 8.2.
8.2.4 PROCESSAMENTO DE ARQUIVOS DE TERMOS
Uma tpica seqncia de objetivos para processar completamente um arquivo "A" se pareceria com o
seguinte:
... see(A), processaArq, see(user), ...
Aqui processaArq/0 um procedimento para ler e processar cada termo em A, um aps o outro, at
que o fim do arquivo seja encontrado. Um esquema tpico para processaArq o seguinte:
processaArq :-
read(Termo), processa(Termo).
processa(end_of_file) :- !.
processa(Termo) :-
trata(Termo), processaArq.
Aqui o procedimento trata/1 representa qualquer coisa que se deseje fazer com cada um dos termos
presentes no arquivo. Um exemplo poderia ser um procedimento para apresentar no terminal cada um
dos termos do arquivo, juntamente com o seu respectivo nmero de ordem. Vamos chamar tal proce-
dimento mostraArq(N), onde N um argumento adicional para contar os termos lidos.
mostraArq(N) :-
read(Termo), mostra(1, Termo).
mostra(_, end_of_file) :- !.
mostra(N, Termo) :-
write(N), tab(2), write(Termo),
N1 is N+1,
mostraArq(N1).
outro exemplo de utilizao do esquema dado para o processamento de arquivos de termos o se-
guinte: Temos um arquivo denominado "arq1" que contm termos na forma:
item(Nro, Descrio, Preo, Fornecedor)
Cada termo descreve uma entrada num catlogo de itens. Desejamos produzir um outro arquivo que
contenha somente os itens fornecidos por um determinado fornecedor. Como o fornecedor nesse novo
arquivo ser sempre o mesmo, o seu nome somente precisa ser escrito no incio do arquivo, sendo
omitido nos demais termos. Denominaremos tal procedimento de
fazArq(Fornecedor)
Por exemplo, se o catlogo original armazenado em arq1 e desejamos produzir um arquivo arq2 com
todos os artigos fornecidos por 'Palmeira & Cia", ento usaremos o procedimento fazArq/1 da se-
77
guinte maneira:
..., see(arq1),tell(arq2),fazArq('Palmeira & Cia'),see(user),tell(user), ...
O procedimento fazArq/1 apresentado na Figura 8.3
fazArq(F) :-
write(F), write('.'), nl, fazResto(F).
fazResto(F) :-
read(Item), processa(Item, F).
processa(end_of_file, _) :- !.
processa(item(N, D, P, F), F) :-
!, write(item(N, D, P)), write('.'), nl, fazResto(F).
processa(_, F) :-
fazResto(F).
Figura 8.3 Processando um arquivo de itens
Note que no programa acima, o predicado processa/2 grava um ponto aps cada termo escrito em
arq2, de modo a possibilitar leituras posteriores desse arquivo por meio do comando read/1.
8.3 PROCESSAMENTO DE CARACTERES
Um caracter escrito na fonte de sada corrente por meio do objetivo:
put(C)
onde C o cdigo ASCII (um nmero entre 0 e 255) do caracter a ser escrito. Por exemplo, a consul-
ta:
?-put(65), put(66), put(67).
produz a sada:
ABC
uma vez que 65 o cdigo ASCII de 'A', 66 de 'B' e 67 de 'C'. Por sua vez um caracter pode ser lido a
partir da fonte de entradacorrente por meio do objetivo:
get0(C)
que ocasiona a leitura do caracter corrente e torna a varivel C instanciada para com o cdigo ASCII
deste caracter. Uma variao do predicado get0/1 o get/1, que utilizado para a leitura apenas de
caracteres imprimveis, saltando sobre todos os caracteres no-imprimveis, particularmente espaos
em branco. Como um exemplo do uso de predicados que transferem caracteres, vamos definir um
procedimento comprime/0 para ler uma sentena da fonte de entrada corrente e apresentar essa sen-
tena reformatada, de forma que mltiplos espaos em branco entre as palavras sejam substitudos por
um nico espao em branco (cdigo ASCII = 32). Para simplificar, vamos assumir que toda sentena
de entrada processada pelo procedimento comprime/0 termina com um ponto final (cdigo ASCII =
46) e que as palavras estejam separadas por um ou mais espaos em branco e nenhum outro caracter.
Uma entrada aceitvel seria:
Genialidade 1% de inspirao e 99% de transpirao.
para a qual o procedimento comprime/0 devolveria:
Genialidade 1% de inspirao e 99% de transpirao.
O procedimento comprime/0 ter uma estrutura similar aos procedimentos para processamento de
arquivos estudados nas sees anteriores. Inicialmente ele vai ler o primeiro caracter e envi-lo sa-
da e ento completar o processo, dependendo do caracter que for lido. A excluso mtua entre as trs
alternativas obtida por meio de cuts:
comprime :-
get0(C), put(C), continua(C).
78
continua(46) :- !.
continua(32) :-
!, get(C), put(C), continua(C).
continua(_) :-
comprime.
8.4 CONVERSO DE TERMOS
Frequentemente deseja-se trabalhar com informaes que foram lidas sob a forma de caracteres, con-
vertidas em termos como representao interna para processamento de entrada e sada. H um predi-
cado pr-definido, name/2, que pode ser usado com essa finalidade, relacionando os tomos com o seu
cdigo ASCII. Assim, name(X, L) verdadeiro, se L a lista dos cdigos dos caracteres em A. Por
exemplo, a assertiva abaixo verdadeira:
name(zx232, [122, 120, 50, 51, 50])
H dois usos tpicos para o predicado name/2:
Decompor um termo dado em seus caracteres, e
Dada uma lista de caracteres, converte-la em um termo.
Um exemplo do primeiro tipo de aplicao seria a decomposio de tomos em tomos menores, com
tamanho pr-definido. Suponhamos que recebemos, de alguma fonte de entrada, tomos de tamanho
fixo de 13 caracteres, dos quais os oito primeiros correspondem ao CEP, os dois seguintes unidade
da federao (UF) e os trs ltimos sigla internacional de cidade. Por exemplo:
90120040rspoa e 70605220dfbsb
e desejamos, para fins de processamento, separ-los nos sub-tomos:
90120040 rs poa e 70605220 df bsb
O predicado separa/4, abaixo, obtm o resultado desejado:
separa(A, S1, S2, S3) :-
name(A, L),
conc([S1, S2, S3], [], L),
tam(S1, 8), !,
tam(S2, 2), !,
tam(S3, 3).
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
tam([], 0).
tam([_|R], N) :-
tam(R, N1), N1 is N+1.
O prximo exemplo ilustra o uso da combinao de caracteres em tomos. Definiremos um predicado,
fazFrase(Lista) que l uma sentena em linguagem natural e instancia Lista com cada palavra da sen-
tena representada por um tomo. Por exemplo, se a entrada fosse a seguinte frase, atribuda a Albert
Einstein dirigindo-se a Sigmund Freud:
"No matter what mind is and never mind what matter is."
o objetivo fazFrase(Lista) ocasionaria a seguinte instanciao:
Lista = ['No',matter,what,mind,is,and,never,mind,what,matter,is]
para simplificar, assume-se que cada sentena termina com um ponto final e que no h smbolos de
pontuao na sentena. O programa completo mostrado na Figura 8.4. O procedimento fazFrase/1 l
o caracter corrente, C, e ento transmite esse caracter ao procedimento fazResto para completar o
servio.
fazFrase(Lista) :-
get0(C), fazResto(C, Lista).
79
fazResto(46, []) :- !.
fazResto(32, Lista) :-
!, fazFrase(Lista).
fazResto(Let, [Pal | Lista]) :-
fazLetras(Let, Lets, Prox),
name(Pal, Lets),
fazResto(Prox, Lista).
fazLetras(46, [], 46) :- !.
fazLetras(32, [], 32) :- !.
fazLetras(Let, [Let | Lets], Prox) :-
get0(C), fazLetras(C, Lets, Prox).
Figura 8.4: Transformando uma sentena em uma lista de palavras
O procedimento fazResto/2, na Figura 8.4, precisa considerar trs casos:
C um ponto (ASCII=46). Ento tudo j foi lido;
C um branco (ASCII=32). Ento deve ser ignorado;
C uma letra. Primeiro ler a palavra Pal, que comea com C, e depois, ppor meio de fazFrase/1,
ler o resto da sentena, produzindo Lista. O resultado cumulativo [Pal | Lista].
O procedimento que l os caracteres de uma palavra :
fazLetra(Let, Lets, Prox)
onde:
(1) Let a letra corrente (j lida) da palavra que est sendo processada,
(2) Lets a lista de letras (comeando com Let), at o final da palavra, e
(3) Prox o caracter de entrada que imediatamente segue a palavra lida, podendo ser um branco ou
um ponto.
O programa fazFrase/1 pode ser usado para o processamento de textos em linguagem natural. As sen-
tenas representadas como listas de palavras encontram-se em uma forma adequada para processa-
mento adicional em Prolog. Um exemplo simples seria o tratamento de certas palavras do texto. Uma
tarefa muito mais difcil seria "entender" a sentena, isto , extrair dela o seu significado, representa-
do por algum formalismo. Esta uma importante rea de pesquisa em inteligncia artificial.
8.5 LEITURA DE PROGRAMAS
possvel carregar programas no sistema Prolog por meio de dois predicados pr-definidos: consult/1
e reconsult/1. Diz-se ao Prolog para ler um programa que esteja contido em um arquivo "progra-
ma.log" da seguinte maneira:
?-consult('programa.log').
cujo efeito a leitura de todas as clusulas em programa.log de modo que estas possam ser usadas
pelo sistema para responder as consultas que se seguirem. Se um outro arquivo for "consultado" du-
rante a mesma seo, as clusulas presentes nesse novo arquivo sero simplesmente adicionadas ao
final do conjunto de clusulas corrente. No necessrio, entretanto, gravar nosso programa em um
arquivo para depois carreg-lo no sistema. Ao invs de ler um arquivo o Prolog pode tambm aceitar o
nosso programa diretamente do terminal, que corresponde ao pseudo-arquivo "user". Obtemos isso
por meio de:
?-consult(user).
que leva o Prolog a aceitar clusulas digitadas diretamente no teclado do terminal.
Uma notao mais curta para a carga de programas consiste em colocar os arquivos que devem ser
80
lidos em uma lista e declar-la como objetivo. Por exemplo:
?-[prog1, prog2, prog3].
que corresponde exatamente ao obtido por:
?-consult(prog1), consult(prog2), consult(prog3).
O predicado pr-definido reconsult/1 opera de maneira semelhante ao consult/1. Um objetivo
?-reconsult(programa).
ter o mesmo efeito de consult com uma exceo: se houver clusulas em "programa" sobre alguma
relao j definida no sistema, a definio anterior ser substituda pelas novas clusulas presentes em
"programa". A diferena entre consult/1 e reconsult/1 que o primeiro sempre adiciona as novas clu-
sulas, ao passo que o segundo redefine as relaes previamente definidas, sem afetar, entretanto, as
relaes para as quais no existem clusulas em "programa".
RESUMO
Entradas e sadas (alm das efetuadas em consultas ao programa) so executadas por meio de
predicados pr-definidos;
Os arquivos so sequenciais. H uma fonte de entrada corrente e uma fonte de sada corrente. O
terminal do usurio tratado como um arquivo denominado "user".
A mudana entre fontes de entrada e de sada correntes /e efetuada pelos predicados:
see(A): A se torna a fonte de entrada corrente
tell(A): A se torna a fonte de sada corrente
seen: Fecha a fonte de entrada corrente
told: Fecha a fonte de sada corrente
Os arquivos so lidos ou gravados de dois modos diferentes: como uma seqncia de caracteres
ou como uma sequncia de termos;
Predicados pr-definidos para a leitura e escrita de termos e caracteres so:
read(Termo)
write(Termo)
put(Cdigo)
get0(Cdigo)
get(Cdigo)
Dois predicados utilizados para formatao so:
nl
tab(N)
O procedimento name(tomo, Lista) decompe e constri tomos. Lista a lista dos cdigos
ASCII dos caracteres em tomo.
EXERCCIOS
8.1 Seja arq um arquivo de termos. Defina um procedimento achaTermo(Termo) que apresenta no
terminal do usurio o primeiro termo em arq que unifica com Termo.
8.2 Seja arq um arquivo de termos. Escreva um procedimento achaTodos(Termo) que apresenta no
terminal todos os termos em arq que unificam com Termo.
8.3 Defina a relao comeaCom(tomo, Caracter), para verificar se tomo inicia com o caracter
Caracter.
8.4 Escreva um procedimento acha(PalavraChave, Sentena) que ir, a cada vez que for chamado,
localizar uma sentena na fonte de entrada corrente que contenha a palavra chave dada. A sen-
81
tena deve ser fornecida em sua forma original, representada como uma seqncia de caracteres
ou como um tomo. O programa fazFrase/2 apresentado neste captulo pode ser adequadamente
modificado para atender as necessidades deste exerccio.
8.5 Escreva um programa relatrio/0 para ler um arquivo de termos na forma cliente(Nome, Endere-
o, Telefone) e produzir um relatrio formatado da seguinte maneira:
NRO CLIENTE ENDEREO TELEFONE
001 XXX... XXX... XXX....
002 XXX... XXX... XXX...
..... ..... ..... .....
8.6 Escreva um programa, plural(Palavra, Plural), para a formao do plural de palavras em portu-
gues. Crie para isso uma base de regras de formao do plural de palavras. O resultado esperado
, por exemplo:
?-plural(pssaro, X).
X=pssaros
82
9. PREDICADOS EXTRALGICOS
Todas as implementaes Prolog oferecem, em maior ou menor quantidade, um certo nmero de pre-
dicados pr-definidos orientados a execuo de rotinas que, ou so necessrias com muita freqncia,
ou so de difcil programao, ou se destinam a um domnio particular realado pela implementao,
ou por todas essas razes em diferentes propores. No presente captulo se introduz alguns desses
predicados, que facilitam muito a construo de programas interativos e orientados a aplicaes con-
cretas.
9.1 TIPOS DE TERMOS
Os termos Prolog podem assumir os mais diversos aspectos, desde simples constantes at estruturas
complexas altamente elaboradas. Se um termo uma varivel, ento esta pode ou no estar instancia-
da em algum momento da execuo do programa. Alm disso, se estiver instanciada, seu valor pode
ser uma constante, uma estrutura, etc. Algumas vezes pode ser de utilidade para o programador identi-
ficar de que tipo esse valor. Por exemplo, podemos querer adicionar os valores de duas variveis, X
e Y, por meio de:
Z is X + Y
Antes desse objetivo ser executado, X e Y devem ser instanciados com valores inteiros. Se no h
certeza de que tal instanciao ocorreu, ento deve-se fazer tal verificao antes de executar a oprera-
o aritmtica envolvida.
Com essa finalidade podemos utilizar o predicado pr-definido integer(X), que verdadeiro se X esti-
ver instanciada com um varlor inteiro. O objetivo de adicionar X e Y ento pode ser protegido da
seguinte maneira, garantindo a validade dos operandos:
..., integer(X), integer(Y), Z is X + Y, ...
`Se X e Y no estiverem ambas instanciadas com valores inteiros, ento a operao aritmtica que se
segue ao teste no ser realizada. Os predicados pr-definidos para a classificao de dados comuns a
maioria das implementaes so os seguintes:
Predicado Descrio
atom(X) bem sucedido se X uma constante textual (tomo).
integer(X) bem sucedido se X um nmero inteiro.
float(X) bem sucedido se X um nmero em ponto flutuante.
number(X) bem sucedido se X um nmero.
string(X) bem sucedido se X um string.
atomic(X) bem sucedido se X do tipo atmico.
var(X) bem sucedido se X uma varivel no-instanciada.
nonvar(X) bem-sucedido se X no uma varivel ou se X uma varivel instanciada.
O programa classifica/1, apresentado na figura abaixo, ilustra o emprego de tais predicados.
O programa classifica/1 (Figura 9.1) ir reconhecer o tipo do seu argumento, informando-o ao usu-
rio. Em particular, se o dado do tipo atmico, o subtipo tambm informado, como ilustrado abai-
xo:
83
?-X=1, classifica(X).
Tipo Atmico
---> Numero Inteiro
?-X=[], classifica(X).
Tipo Atmico
---> Lista Vazia
?-X=tio(jos), classifica(X).
Termo Estruturado
classifica(X) :-
var(X), !, nl, write('Varivel No-instanciada').
classifica(X) :-
atomic(X), !, nl, write('Tipo Atmico:'),
tipoAtomico(X).
classifica([_|_]) :-
!, nl, write('Lista').
classifica(X) :-
nl, write('Termo Estruturado').
tipoAtomico([]) :-
!, nl, tab(5), write('---> Lista Vazia').
tipoAtomico(X) :-
atom(X), !, nl, tab(5), write('---> tomo').
tipoAtomico(X) :-
integer(X), !, nl, tab(5),
write('---> Nmero Inteiro').
tipoAtomico(X) :-
float(X), !, nl, tab(5),
write('---> Nmero em Ponto Flutuante').
tipoAtomico(X) :-
string(X), !, nl, tab(5), write('---> String').
Figura 9.1 Programa para classificar tipos de dados.
Vamos supor agora que se deseje contar quantas vezes um determinado tomo ocorre em uma lista de
objetos dada. Com esse propsito se definir o procedimento
conta(A, L, N)
onde A o tomo, L a lista e N o nmero de vezes que A ocorre em L. Uma primeira tentativa de
definir conta/3 seria:
conta(_, [], 0).
conta(A, [A | L], N) :-
!, conta(A, L, N1), N is N1+1.
conta(A, [_ | L], N) :-
conta(A, L, N).
Algumas tentativas de utilizao de tal programa so:
?-conta(a, [a, b, a, a], N).
N=3
?-conta(a, [a, b, X, Y], Na).
X=a Y=a Na=3
?-conta(b, [a, b, X, Y], Nb).
X=b Y=b Nb=3
?-L=[a, b, X, Y], conta(a, L, Na), conta(b, L, Nb).
X=a Y=a Na=3 Nb=1
Neste ltimo exemplo, X e Y foram ambas instanciadas com "a", e portanto obtivemos Nb=1 somente.
No era isso, entretanto que se tinha em mente na construo do procedimento conta/3. Na verdade o
que se queria era o nmero real de ocorrncias de um dado tomo e no o nmero de termos capazes
de unificar com esse tomo. De acordo com essa definio mais precisa da relao conta/3, devemos
verificar se a cabea da lista um tomo. A nova verso da relao conta a seguinte:
conta(_, [], 0).
conta(A, [B | L], N) :-
atom(B), A=B, !, conta(A, L, N1), N is N1+1.
conta(A, [_ | L], N) :-
84
conta(A, L, N).
9.2 CONSTRUO E DECOMPOSIO DE TERMOS
H trs predicados pr-definidos para a decomposio de termos e construo de novos termos: func-
tor/3, arg/3 e =../2. Estudaremos primeiro o =../2, tambm referido como "univ", que definido como
um operador infixo. O objetivo
Termo =.. L
bem-sucedido se L uma lista contendo como primeiro elemento o functor principal de Termo, se-
guido pelos seus argumentos. Os seguintes exemplos do uma idia do seu funcionamento:
?-f(a, b) =.. L.
L=[f, a, b]
?-T =.. [retngulo, 3, 5].
T=retngulo(3, 5)
?-Z =.. [p, X, f(X, Y)].
Z=p(X, f(X, Y))
Para melhor ilustrar a utilidade do operador =../2, vamos considerar um programa que manipula figu-
ras geomtricas como quadrados, retngulos, tringulos, crculos, etc. Estas entidades podem ser re-
presentadas por meio de termos tais que o functor principal indica o tipo de figura e os argumentos
especificam o tamanho da figura, como em:
quadrado(Lado)
tringulo(Lado1, Lado2, Lado3)
crculo(Raio)
Uma operao sobre tais figuras poderia ser a ampliao das mesmas. Pode-se implement-la como
uma relao de trs argumentos
amplia(Fig, Fator, Fig1)
onde Fig e Fig1so figuras geomtricas do mesmo tipo (mesmo functor) e os parmetros de Fig1 so
os mesmos de Fig, multiplicados por Fator. Para maior simplicidade assumiremos que os parmetros
de Fig so previamente conhecidos, isto , instanciados com nmeros, o mesmo ocorrendo com Fator.
Uma maneira de programar a relao amplia/3 a seguinte:
amplia(quadrado(A), F, quadrado(A1)) :-
A1 is F * A.
amplia(crculo(R), F, circulo(R1)) :-
R1 is F * R.
amplia(retngulo(A, B), F, retngulo(A1, B1)) :-
A1 is F * A, B1 is F * B.
...
Esse procedimento funciona, mas um tanto grosseiro no caso em que h muitos tipos diferentes de
figuras. necessrio prever todos os tipos de figuras que podem acontecer, empregando uma clusula
para cada tipo, apesar de todos dizerem essencialmente a mesma coisa: tome os parmetros da figura
original e multiplique-os pelo fator de ampliao formando uma figura do mesmo tipo com os novos
parmetros. Uma tentativa (mal-sucedida) de manipular pelo menos todas as figuras de um nico ar-
gumento seria:
amplia(Tipo(Arg), F, Tipo(Arg1)) :-
Arg1 is Arg * F.
Entretanto, no permitido representar um functor em Prolog diretamente por meio de uma varivel,
ou seja, functores devem ser sempre tomos, portanto a varivel Tipo no seria aceita pela sintaxe da
linguagem. O mtodo correto utilizar o predicado =../2. Assim a relao amplia/3, genrica, pode ser
escrita como se segue:
amplia(Fig, F, Fig1) :-
Fig =.. [Tipo | Parmetros],
multLista(Parmetros, F, NovosParmetros),
Fig1 =.. [Tipo | NovosParmetros].
multLista([], _, []).
85
multLista([X | L], F, [X1 | L1]) :-
X1 is F*X, multLista(L, F, L1).
Os termos construdos com o predicado =../2 podem tambm ser executados como objetivos. A vanta-
gem disto que o prprio programa pode, durante a execuo gerar e executar objetivos. Uma se-
qncia de objetivos ilustrando esse efeito poderia ser a seguinte:
...
obtenha(Functor),
compute(ListaDeArgumentos),
Obj =.. [Functor | ListaDeArgumentos],
Obj, ...
Aqui, obtenha/1 e compute/1correspondem a procedimentos definidos pelo usurio para obteros com-
ponentes do objetivo a ser construdo. O objetivo formado por meio do predicado =../2 e disparado
para execuo por meio da varivel que o nomeia, Obj.
Algumas implementaes da linguagem Prolog podem requerer que todos os objetivos que aparecem
no programa sejam tomos ou uma estrutura com um tomo como functor principal, de forma que
uma varivel, independentemente de sua eventual instanciao, pode no ser sintaticamente aceita
como um objetivo. Esse problema contornado por meio de outro predicado pr-definido, call/1, cujo
argumento um objetivo a ser executado. Assim o exemplo dado acima poderia ser reescrito como:
...
Obj =.. [Functor | ListaDeArgumentos]
call(Obj).
s vezes pode-se desejar extrair de um termo apenas o seu functor principal, ou um de seus argu-
mentos. Em tais casos pode-se, naturalmente, empregar o predicado =../2, entretanto, pode ser mais
prtico e eficiente usar um dos outros dois predicados pr-definidos para a manipulao de termos:
functor/3 e arg/3, cujo significado o seguinte:
functor(Termo, Functor, Aridade)
verdadeiro se Functor o functor principal de Termo e Aridade o seu nmero de argumentos, ao
passo que
arg(N, Termo, Argumento)
verdadeiro se Argumento o N-simo argumento em Termo, assumindo que os argumentos so
numerados da esquerda para direita iniciando em 1. Os seguintes exemplos servem como ilustrao:
?-functor(teste(f(X), X, t), Functor, Aridade).
Functor=teste Aridade=3
?-arg(2, teste(X, t(a), t(b)), Argumento).
Argumento=t(a)
?-functor(D, data, 3), arg(1, D, 5), arg(2, D, abril), arg(3, D, 1994).
D=data(5, abril, 1994)
Esse ltimo exemplo mostra uma aplicao especial do predicado functor/3. O objetivo functor(D,
data, 3) produz em D um termo "geral" cujo functor principal "data", com 3 argumentos. O termo
geral no sentido em que os trs argumentos so variveis no-instanciadas geradas pelo sistema Pro-
log. Por exemplo:
D=data(_02e, _02f, _030)
Essas trs variveis so ento instanciadas como no exemplo acima, por meio dos trs objetivos arg/3.
Relacionado a esse conjunto de predicados est o predicado name/2, para a construo e decomposi-
o de tomos, introduzido no captulo anterior. Seu significado repetido aqui para manter completa
a seo:
name(tomo, Lista)
verdadeiro se Lista a lista dos cdigos ASCII correspondentes aos caracteres do tomo A.
9.3 EQUIVALNCIAS E DESIGUALDADES
86
At o momento, trs "tipos de igualdade" foram estudados, iniciando pela baseada na unificao, re-
presentada por:
X = Y
que verdadeira se X Y unificam. Um outro tipo de igualdade
X is Expresso
que verdadeira se X unifica com o valor da expresso aritmtica Expresso. Tem-se tambem:
Expreso1 =:= Expresso2
que verdadeira se os os valores das expresses aritmticas Expresso1 e Expresso2 so iguais. Se,
ao contrrio as expresses possuem valor diferente, escreve-se:
Expresso1 =\= Expresso2
Algumas vezes poder ser necessrio um tipo mais estrito de igualdade: a igualdade literal entre dois
termos. Esse tipo de igualdade implementado por meio de um predicado pr-definido escrito como o
operador infixo "==", de modo que
Termo1 == Termo2
verdadeira se os termos Termo1 e Termo2 so idnticos, isto , possuem exatamente a mesma es-
trutura e todos os componentes correspondentes so os mesmos. Em particular, os nomes das vari-
veis devem tambm ser os mesmos. A relao complementar a no-identidade, escrita como:
Termo1 \== Termo2
Os exemplos abaixo abordam o uso de tais operadores:
?-f(a, b) == f(a, b).
sim
?-f(a, b) == f(a, X).
no
?-f(a, X) == f(a, Y).
no
?-X \== Y.
sim
?-t(X, f(a, Y)) \== t(X, f(a, Y)).
no
9.4 PROGRAMAS OU BASES DE DADOS?
De acordo com o modelo relacional, uma base de dados a especificao de um conjunto de relaes.
Sob tal prisma, um programa Prolog pode ser visto como uma base de dados: a especificao das rela-
es parcialmente implcita (regras) e parcialmente explcita (fatos). Alm disso existem predicados
pr-definidos que tornam possvel a atualizao da base de dados durante a execuo do programa.
Isso feito em tempo de execuo, pela adio ou remoo de clusulas do programa. Os predicados
que servem a tais propsitos so assert/1, asserta/1, assertz/1 e retract/1. Um objetivo como:
assert(C)
sempre bem sucedido e, como efeito colateral, ocasiona a adio da clusula C na base de dados.
Por outro lado um objetivo
retract(C)
faz o oposto, isto , apaga uma clusula que unifica com C da base de dados. O dilogo abaixo exem-
plifica esses dois predicados:
?-crise.
no
?-assert(crise).
sim
87
?-crise.
sim
?-retract(crise).
sim
?-crise.
no
As clusulas inseridas por meio do predicado assert/1, atuam exatamente como se fossem parte do
programa original. O seguinte exemplo ilustra o uso de assert/1 e retract/1 como um mtodo para
controlar situaes que se modificam ao longo do tempo. Vamos assumir o programa abaixo, sobre as
condies do tempo:
bom :-
sol, not chuva.
instvel :-
sol, chuva.
deprimente :-
chuva, neblina.
chuva.
neblina.
O dilogo a seguir mostra como a base de dados pode ir sendo gradualmente atualizada:
?-bom.
no
?-deprimente.
sim.
?-retract(neblina).
sim
?-deprimente.
no
?-assert(sol)
sim
?-instvel.
sim
?-retract(chuva).
sim
?-bom
sim
Qualquer tipo de clusula pode ser objeto dos predicados assert/1 ou retract/1. No prximo exemplo
mostraremos que retract/1 tambm no-determinstico: um conjunto completo de clusulas pode ser
removido, por meio do mecanismo de bactracking, atravs de um nico objetivo retract/1. Vamos
assumir um programa com os seguintes fatos:
veloz(senna).
veloz(prost).
meiaBoca(alesi).
meiaBoca(barrichello).
lento(katayama).
lento(moreno).
Podemos adicionar uma regra ao programa da seguinte maneira:
?-assert( (vence(X, Y) :- veloz(X), not veloz(Y)) ).
sim
?-vence(A, B).
A=senna B=alesi;
A=senna B=barrichello;
A=senna B=katayama;
A=senna B=moreno;
A=prost B=alesi;
A=prost B=barrichello;
A=prost B=katayama;
A=prost B=moreno;
88
no
Note que quando uma regra inserida na base de dados, por meio do predicado assert, as regras sint-
ticas do Prolog exigem que esta seja fornecida entre parnteses.
Na introduo de uma clusula, podemos desejar especificar a posio na qual a clusula deve ser
inserida na base de dados. Os predicados asserta/1 e assertz/1 permitem controlar a posio de inser-
o. O objetivo
asserta(C)
introduz a clusula C no incio da base de dados, enquanto que o objetivo
assertz(C)
adiciona a clusula C no final da base de dados. O seguinte exemplo ilustra esses efeitos:
?-assert(p(a)), assertz(p(b)), asserta(p(c)).
sim
?-p(X).
X=c;
X=a;
X=b;
no
H uma relao entre consult/1 e assertz/1. "Consultar" um arquivo pode ser definido em termos de
assertz/1 da seguinte maneira: para "consultar" um arquivo, ler cada um dos seus termos (clusulas) e
inser-los no final da base de dados:
consult(X) :-
see(X), transfere(C), see(user).
transfere(end_of_file) :- !.
transfere(C) :-
read(C), assertz(C), transfere(C1).
J uma aplicao til do predicado asserta/1 armazenar respostas j computadas para consultas for-
muladas ao programa. Por exemplo, vamos considerar que o predicado
resolve(Problema, Soluo)
esteja definido. Podemos agora formular alguma consulta e requerer que a resposta seja lembrada para
consultas futuras:
?-resolve(prob1, Sol), asserta(resolve(prob1, Sol)).
Se o primeiro objetivo acima bem-sucedido, ento a resposta(Soluo) armazenada e utilizada,
como qualquer outra clusula, na resposta a questes futuras. A vantagem de memorizar as respostas
que uma consulta posterior que unifique com "prob1" ser respondida muito mais rapidamente. O
resultado obtido agora pela recuperao de um fato, no sendo necessrias computaes adicionais
que possivelmente consumiriam muito mais tempo.
Uma extenso dessa idia a utilizao do assert para gerar todas as solues possveis na forma de
uma tabela de fatos. Por exemplo, podemos gerar uma tabela com os produtos de todos os pares de
inteiros de 0 a 9 da seguinte maneira: geramos um par de inteiros, X e Y, computamos Z is X*Y, inse-
rimos os trs nmeros como uma linha da tabela de produtos e ento foramos a falha do procedi-
mento que, por meio de backtracking, ir gerar a tabela completa. O procedimento tabMult/0, abaixo,
implementa essa idia:
tabMult :-
L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
membro(X, L), membro(Y, L),
Z is X*Y, assert(produto(X, Y, Z)), fail.
tabMult.
O efeito colateral da execuo de tabMult/0 adicionar a correspondente tabela de multiplicao
base de dados. Depois disso, podemos perguntar, por exemplo, que pares da tabela resultam em 8:
89
?-produto(A, B, 8).
A=1 B=8;
A=2 B=4;
A=4 B=2;
A=8 B=1;
no
Uma advertncia sobre o uso indiscriminado de assert e retract deve ser feita aqui. Os exemplos dados
ilustram algumas aplicaes obviamente teis desses predicados, entretanto o seu uso requer um cui-
dado especial. O uso excessivo e descuidado de tais recursos no recomendado como um bom estilo
de programao, uma vez que se est na realidade modificando o programa original em tempo de exe-
cuo. Assim, relaes vlidas em um determinado momento, podem no mais ser vlidas em um
momento subsequente, isto , em momentos diferentes, a mesma consulta pode ter respostas diferen-
tes. O uso abusivo de assert-retract pode obscurecer o significado do programa e dificultar a compre-
enso do que verdadeiro e o que no num dado instante. O comportamento resultante do programa
pode se tornar dificil de entender, de explicar e de confiar.
9.5 RECURSOS PARA O CONTROLE DE PROGRAMAS
A maioria dos recursos de controle de programas Prolog j foi apresentada anteriormente. Com vistas
a permitir uma viso conjunta de tais predicados, apresenta-se a seguir um resumo de todos eles:
cut: representado nos programas por "!", previne a execuo indesejada do mecanismo de
backtracking;
fail: um objetivo que sempre falha;
true: um objetivo que sempre bem sucedido;
not(P): um tipo de negao que se comporta exatamente como se houvesse sido definido por:
not(P) P, !, fail; true.
call(P): dispara um objetivo P. Ser bem-sucedido se e somente se P tambm o for;
repeat: um objetivo que sempre bem-sucedido. Sua principal propriedade ser no-
determinstico, isto , toda vez que alcanado por backtracking ele gera um caminho alternati-
vo para a execuo. Seu comportamento ocorre como se ele houvesse sido definido por:
repeat.
repeat :- repeat.
Uma forma tpica de uso desse ltimo predicado ilustrada pelo procedimento quadrado/0, que l
uma seqncia de nmeros e fornece o seu quadrado. A seqncia dada por concluda quando for
lido o tomo "fim", que sinaliza o encerramento da execuo:
quadrado :-
repeat, read(X),
(X=fim, !; Y is X*X, write(X), fail).
A construo acima tambm muito empregada em programas interativos, que possuem diversas al-
ternativas de execuo mutuamente exclusivas, como em um menu de opes:
executa :-
repeat, menu(X),
(X=fim, !; exec(X), fail).
Aqui um menu apresentado, uma ao selecionada, executada e o menu novamente apresentado,
repetindo-se esse ciclo at que a opo "fim" seja escolhida.
9.6 BAGOF, SETOF E FINDALL
Podemos gerar, atravs de backtracking, todos os objetos, um a um, que satisfazem algum objetivo.
Cada vez que uma nova soluo gerada, a anterior desaparece e no mais acessvel. Algumas ve-
90
zes, entretanto, deseja-se dispor de todos os objetos gerados, por exemplo, coletados em uma lista. .
Os predicados bagof/3 e setof/3 servem exatamente para tal propsito. O predicado findall/3 , em
algumas implementaes, oferecido como alternativa. O objetivo:
bagof(X, P, L)
ir produzir uma lista L de todos os objetos X que satisfazem ao objetivo P. Isto, naturalmente, s faz
sentido se X e P possuem alguma varivel em comum. Por exemplo, assumindo que temos em um
programa Prolog uma especificao que classifica letras em vogais
e consoante:
classe(a, vog).
classe(b, con).
classe(c, con).
classe(d, con).
classe(e, vog).
. . .
Ento podemos obter a lista de todas as consoantes nessa especificao atravs do objetivo:
?-bagof(Letra, classe(Letra, con), Consoantes).
Consoantes=[b, c, d, ..., z]
Se, neste ltimo objetivo, a classe das letras no estivesse especificada, obter-se-ia, por meio de
backtracking, duas listas, uma correspondendo s vogais e outra s consoantes:
?-bagof(Letra, classe(Letra, Classe), Letras).
Classe=vog Letras=[a, e, i, o, u];
Classe=con Letras=[b, c, d, f, ..., z].
Se no houver soluo para P no objetivo bagof(X, P, L), ento este simplesmente falha. Se algum
objeto X encontrado repetidamente, ento todas as suas ocorrncias iro aparecer em L, o que con-
duz possibilidade de existncia de elementos duplicados em L. O predicado setof/3 similar ao ba-
gof. O objetivo:
setof(X, P, L)
ir novamente produzir uma lista L dos objetos X que satisfazem a P, s que desta vez a lista L estar
ordenada e itens duplicados, se houver, sero eliminados. A ordem dos objetos estabelecida em fun-
o de sua ordem alfabtica ou de acordo com a relao "<" se os objetos na lista form nmeros. Se os
objetos forem estruturas, ento seus functores principais so comparados para fins de ordenao. Se
estes so iguais, ento a deciso fica por conta dos primeiros argumentos diferentes a contar da es-
querda.
No h restrio quanto ao tipo de objeto a ser coletado. Assim podemos, por exemplo construir uma
lista de pares da forma Classe/Letra de forma que as constantes apaream em primeiro lugar na lista
("con" antecede alfabeticamente "vog"):
?-setof(Classe/Letra, classe(Letra, Classe), Letras).
Letras=[con/b, con/c, ..., con/z, vog/a, ..., vog/u]
Um outro predicado dessa mesma famlia findall(X, P, L), que novamente produz a lista L de todos
os objetos X que satisfazem P. A diferena entre esse predicado e o bagof que todos os objetos X
so coletados sem considerar eventuais solues diferentes para as variveis em P que no so com-
partilhadas com X. Essa diferente ilustrada no seguinte exemplo:
?-findall(Letra, classe(Letra, Classe), Letras).
Letras=[a, b, c, ..., z]
Alm disso, se no h nenhum objeto X que satisfaa P, ento o predicado findall(X, P, L) resulta
bem-sucedido com L=[]. Caso o predicado findall/3 no se encontre entre os predicados pr-definidos
em uma determinada implementao Prolog, podemos program-lo facilmente da seguinte maneira:
findall(X, Objetivo, Lista) :-
call(Objetivo), assertz(soluo(X)), fail;
assertz(soluo(fim)), coleta(Lista).
91
coleta(Lista) :-
retract(soluo(X)), !,
(X==fim, !, Lista=[];
Lista=[X | Resto], coleta(Resto)).
No programa acima, todas as solues para o objetivo "Objetivo" so geradas por meio de
backtracking. Toda soluo gerada imediatamente includa na base de dados, de forma que no
perdida quando a prxima soluo encontrada. Depois de encontrar todas as solues, estas devem
ser coletadas em uma lista e retiradas da base de dados.
RESUMO
Uma implementao Prolog normalmente fornece um conjunto de predicados pr-definidos
para diversas operaes de uso frequente que nem sempre so de fcil codificao em Prolog
"puro";
O tipo de um termo Prolog pode ser testado por meio dos seguintes predicados pr-definidos:
var(X) X uma varivel no-instanciada,
nonvar(X) X no uma varivel no-instanciada,
atom(X) X um tomo,
integer(X) X um valor inteiro,
float(X) X um valor em ponto flutuante,
atomic(X) X um tomo ou um valor inteiro, e
string(X) X um string;
Termos Prolog podem ser construdos os decompostos atravs dos seguintes predicados pr-
definidos:
Termo =.. [Functor | Argumentos]
functor(Termo, Functor, Aridade)
arg(Ord, Termo, Argumento)
name(Atomo, Cdigos)
Os seguintes operadores pr-definidos so empregados na verificao de equivalncias e desi-
gualdades:
X = Y X e Y unificam,
X is E X o valor da expresso aritmtica E,
E1 =:= E2 E1 e E2 tem o mesmo valor,
E1 =\= E2 E1 e E2 tem valores diferentes,
T1 == T2 T1 e T2 so idnticos,
T1 \== T2 T1 e T2 no so idnticos;
Um programa Prolog pode ser visto como uma base de dados relacional, que pode ser atualiza-
da por meio dos seguintes predicados:
assert(Clusula)
asserta(Clusula)
assertz(Clusula)
retract(Clusula)
Um predicado pr-definido no-determinstico para o controle de programas o repeat/0, desti-
nado gerao de um nmero ilimitado de alternativas para o backtracking, que definido
como:
repeat.
repeat :- repeat.
Todos os objetos que satisfazem uma dada condio podem ser coletados em uma lista por
meio dos seguintes predicados:
bagof(Objeto, Condio, Lista)
setof(Objeto, Condio, Lista)
findall(Objeto, Condio, Lista)
EXERCCIOS
92
9.1 Escreva um procedimento denominado simplifica/2 para simplificar simbolicamente expresses
de soma envolvendo nmeros e tomos representandovariveis. O procedimento deve rearranjar a
expresso resultante de modo que os tomos precedam os nmeros. Alguns exemplos do seu uso
seriam:
?-simplifica(1+1+a, E).
E=a+2
?-simplifica(1+b+4+2+c+a, E).
E=a+b+c+7
?-simplifica(3+x+x, E).
E=2*x+3
9.2 Defina o predicado bsico(Termo), que verdadeiro se Termo no possui nenhuma varivel no-
instanciada.
9.3 Defina o relao subentende(Termo1, Termo2), que verdadeira se Termo1 "mais geral" que
Termo2. Por exemplo:
?-subentende(X, c).
sim
?-subentende(g(X), g(t(Y))).
sim
?-subentende(f(X, Y), f(a, a)).
sim
?-subentende(f(X, X), f(a, b)).
no
9.4 Defina a relao copia(Termo, Cpia), que produz em Cpia uma cpia de Termo com todas as
suas variveis renomeadas. Isso pode ser facilmente programado empregando os predicados as-
sert/1 e retract/1.
9.5 Use o predicado bagof/3 para definir a relao potncia(Conjunto, Subconjuntos), que computa o
conjunto de todos os subconjuntos de um dado conjunto, sendo todos os conjuntos representados
como listas. Por exemplo:
?-potncia([a, b, c], P).
P=[[], [a], [b], [c], [a, b], [a, c], [b, c], [a, b, c]]
93
10. LGICA E BASES DE DADOS
10.1 BASES DE DADOS RELACIONAIS
Uma "base de dados" pode ser entendida como uma coleo de dados interrelacionados, armazenada
de modo independente do programa que a utiliza, permitindo a recuperao, insero, remoo e mo-
dificao de forma controlada. A quantidade de dados tipicamente grande e o contedo muda ao
longo do tempo. Em Prolog, uma base de dados definida como um conjunto de fatos, no havendo,
entretanto, nada que impea a linguagem de trabalhar diretamente com bases de dados convencionais.
Alm disso a linguagem Prolog possui caractersticas que a tornam um excelente interface para lidar
com bases de dados relacionais.
Um dos marcos mais importantes no desenvolvimento da pesquisa acerca de bases de dados foi a in-
troduo do modelo relacional, por Codd em 1970. Em tal modelo, os dados so definidos por meio
de relaes sobre domnios e os fatos individuais so representados como tuplas de valores sobre tais
domnios. Uma relao com um conjunto de tuplas tambm denominada uma "tabela". O modelo
relacional conceitualmente muito "limpo" e elegante, apoiado por slida fundamentao matemti-
ca.
Diferentemente de outros modelos de bases de dados, o modelo relacional no possui o conceito de
"pointer", de modo que a associao entre diferentes tabelas feita atravs da identidade explcita de
valores de atributos. Este princpio concentra o esforo de implementao em obter maior velocidade
de acesso, ao passo que a vantagem natural a grande flexibilidade e fcil entendimento do processo
de modelagem de dados.
O modelo relacional tem produzido um grande esforo de pesquisa. O propsito de sua introduo
aqui tem sua origem no fato de que tabelas correspondem a uma forma muito natural de armazenar
fatos interrelacionados em Prolog.
10.1.1 EXEMPLO DE UMA BASE DE DADOS RELACIONAL
Considere as seguintes relaes:
pessoa/4, contendo nome, sexo, pai e me;
carro/4, contendo a placa, o fabricante, o proprietrio e a cor.
Tais relaes podem originar tabelas como as apresentadas abaixo:
Tabela 10.1(a): Relao pessoa/4
Nome Sexo Pai Me
Marcelo m Luiz Gilda
Luiz m Alfredo Lina
Gilda f Miguel Ana
Lcia f Luiz Gilda
Paulo m Miguel Ana
Lina f Francisco Jlia
94
Tabela 10.1(b): Relao carro/4
Placa Fabricante Proprietrio Cor
ABC-4590 Volkswagen Alfredo azul
XYZ-1211 Ford Lina branco
RTC-9004 Fiat Luiz vermelho
LLZ-7533 GM Gilda prata
Uma base de dados Prolog, formada a partir das tabelas 10.1(a) e (b), seria representada atravs dos
seguintes fatos:
pessoa(marcelo, m, luiz, gilda).
pessoa(luiz, m, alfredo, lina).
pessoa(gilda, f, miguel, ana).
pessoa(lcia, f, luiz, gilda).
pessoa(paulo, m, miguel, ana).
pessoa(lina, f, francisco, jlia).
carro(abc-4590, vw, alfredo, azul).
carro(xyz-1211, ford, lina, branco).
carro(rtc-9004, fiat, luiz, vermelho).
carro(llz-7533, gm, gilda, prata).
Um ou mais atributos em cada relao possui a propriedade especial de serem nicos na tabela. Tais
atributos so denominados "chaves" e identificam os objetos acerca dos quais armazenamos informa-
es. Usualmente se costuma sublinhar os atributos que so chaves, por exemplo:
pessoa:
nome sexo pai me
10.1.2 RELAES BINRIAS
As relaes mais simples que existem so as relaes binrias, que associam um nico atributo a cada
chave. A relao pessoa/4, que possui a chave "Nome", seria assim dividida em 3 relaes:
Nome-Sexo Nome-Pai Nome-Me
sexo(marcelo, m) pai(marcelo, luiz) me(marcelo, gilda)
etc... ... ...
o mesmo se aplica relao carro/4, cuja chave "Placa":
Placa-Fabricante Placa-Proprietrio Placa-Cor
Fabr(abc-4590, vw) pr(abc-4590, alfredo) cor(abc-4590, azul)
etc... ... ...
entretanto, por questes de convenincia e economia, toda a informao relacionada reunida em
uma nica relao.
Uma situao de exceo ocorre quando necessrio manipular informao incompleta no modelo
relacional. Em uma relao binria, a tupla correspondente desprezada, por exemplo, um carro sem
um proprietrio. Entretanto, no caso em que formada uma tupla com diversos atributos, um smbolo
especial "nil" empregado para representar tal informao. Por exemplo:
carro(ajk-6712, honda, nil, verde)
95
10.1.3 CHAVES COMPOSTAS
Em uma estratgia de implementao simples, assume-se que h uma nica chave em cada tupla,
normalmente ocupando a posio do primeiro argumento. Para chaves compostas assumiremos aqui
uma conveno ad-hoc, representando-as como uma lista de argumentos:
[ch1, ch2, ch3]
que possui o seu prprio nome, mantendo entretanto em separado os atributos individuais ch1, ch2 e
ch3.
10.2 RECUPERAO DE INFORMAES
Recuperar informaes significa combinar e apresentar o contedo da base de dados em uma forma
que satisfaa nossas necessidades. Em bases de dados convencionais isto executado por um progra-
ma que atua sobre a base de dados. Em Prolog isto feito atravs da definio das condies de solu-
o em lgica. Por exemplo:
Quem possui um fiat?
?-carro(_, fiat, Prop, _).
Prop = luiz
Quem fabrica os carros preferidos pelas mulheres?
?-pessoa(N, f, _, _), carro(_, Fabr, N, _).
N = lina Fabr = ford;
N = gilda Fabr = gm;
no
10.2.1 RECUPERAO EFICIENTE
Os sistemas Prolog permitem a representao de informao relacional e a sua recuperao facil-
mente formulada. Grandes bases de dados, entretanto, devem ser tratadas com cuidado, principal-
mente quando da combinao de tuplas distribudas em duas ou mais tabelas. Assim, sistemas Prolog
destinados a tais atividades normalmente devem possuir um "otimizador de consultas", que um pro-
grama escrito em Prolog que manipula consultas como se fossem dados de entrada expressos sob a
forma de termos, isto , tal programa desempenha o papel de um "meta-interpretador".
Uma estratgia possvel a empregar seria selecionar primeiro a condio que apresentasse o menor
nmero de solues possveis, supondo que todas as variveis estivessem instanciadas.
Suponha, por exemplo, que um crime tenha sido cometido e est sendo procurado um homem em um
ford azul. A base de dados da polcia possui duas tabelas: uma com 3000 carros e outra com 10000
pessoas suspeitas. Lembre-se que uma pessoa pode possuir mais de um carro. Vamos imaginar que
haja dez fords azuis e que metade das pessoas na base de dados sejam homens. H duas formas de
formular a questo:
?-carro(Placa, ford, X, azul), pessoa(X, m, _, _).
e
?-pessoa(X, m, _, _), carro(Placa, ford, X, azul).
Supondo que haja um acesso direto quando se dispe da chave da tabela, fcil verificar que, no pri-
meiro caso, sero realizadas 3000 tentativas de unificao na tabela de carros, dais quais apenas 10
sero bem sucedidas (s h 10 fords azuis), produzindo 10 acessos diretos tabela de pessoas para
verificar o sexo, num total de 3010 unificaes. No segundo caso, entretanto, sero realizadas primei-
ro 10000 tentativas de unificao na tabela de pessoas, das quais 5000 sero bem sucedidas. Para cada
uma dessas unificaes bem sucedidas, 3000 acessos devero ser feitos tabela de carros, uma vez
96
que no se dispe da chave, que "Placa". O nmero de tentativas de unificao realizadas aqui ser
portanto 5000 x 3000 + 10 = 15 000 010. Isso mostra porque as condies com o menor nmero de
solues possveis devem ser colocadas em primeiro lugar na formulao de consultas.
10.2.2 TABELAS VIRTUAIS
Uma das facilidades proporcionadas pelo Prolog no tratamento do modelo relacional a possibilidade
de definir novas tabelas sem ter de cri-las, empregando a implicao lgica. Tais tabelas so deno-
minadas "tabelas virtuais". Por exemplo, uma tabela corDoCarro/2 que contm como argumentos
somente a placa e a cor de um carro pode ser definida da seguinte maneira:
corDoCarro(X, Y) carro(X, _, _, Y).
O conceito de tabelas virtuais uma adaptao das "relaes extratoras" introduzidas no captulo an-
terior. Um subconjunto do Prolog convencional, sem os smbolos funcionais e o tratamento de listas,
denominado Datalog, foi proposto com essa finalidade. Na verdade o uso de Prolog para representar
bases de dados relacionais, introduz novos conceitos e regras, ampliando o nvel da informao.. Con-
sidere por exemplo a questo:
Quem tem uma av que possui um ford branco?
Em Prolog as regras para definir as relaes av/2, corDoCarro/2, etc. so facilmente construdas e
incorporadas base de dados, transcendendo o modelo relacional. A questo apropriada poderia ser
construda assim:
?-av(X, P), carro(_, ford, X, branco).
10.2.3 NOMES SIMBLICOS
Quando as tabelas Prolog so acessadas, o programa usa a posio do argumento na relao para aces-
sar a coluna correspondente. Isso se torna difcil, quando o nmero de argumentos muito grande.
Alm disso, constrange o programa a realizar concretamente as relaes. O que se necessita, portanto
uma representao mais abstrata que permita ao programa lidar com modificaes na modelagem
dos dados. Uma soluo empregar tabelas virtuais binrias, contendo o nome do atributo como ar-
gumento explcito. No caso de tabelas com muitos argumentos, esta tcnica pode se tornar uma neces-
sidade. Um predicado geral, atributo/4 pode ser definido para todos os nomes de atributos:
atributo(carro, P, placa, P) :- carro(P, _, _, _).
atributo(carro, P, fabricante, F) :- carro(P, F, _, _).
atributo(carro, P, proprietrio, X) :- carro(P, _, X, _).
atributo(carro, P, cor, C) :- carro(P, _, _, C).
10.3 ATUALIZAO DA BASE DE DADOS
O modelo relacional impe a restrio de que certos campos devem ser campos chaves, cujo valor
deve ser nico em uma tabela. Assim, "Nome " a chave na relao na relao pessoa/4, enquanto
que na relao carro/4 a chave "Placa". Em Prolog, um sistema para o gerenciamento de bases de
dados relacionais pode ser implementado de forma muito natural. As operaes bsicas so:
esquece(T) % Remove a tupla T
memoriza(T) % Insere a tupla T, se j no estiver l
atualiza(V, N) % Remove a velha e insere a nova tupla
Por exemplo:
?-esquece(carro(_, _, gilda, _)).
ir remover da base de dados todos os carros que pertencem a Gilda. Da mesma forma
memoriza(carro(flt-5455, honda, gilda, cor-de-rosa)).
ir introduzir o novo - e nico - carro de Gilda na base de dados.
97
Na construo dos predicados esquece/1 e memoriza/1, emprega-se a chave originalmente definida
como elemento de referncia, devendo-se preserv-la nica em qualquer circunstncia. Assim tais
predicados devem ser construdos na forma abaixo:
esquece(X) :-
esquece1(X), fail.
esquece(X).
esquece1(X) :-
retract(X).
esquece1(X).
memoriza(X) :-
esquece(X), assert(X).
memoriza(X) :-
assert(X).
O predicado esquece(X) ir excluir da base de dados todas as sentenas que unificam com X. Se for
desejada a excluso somente da primeira ocorrncia, deve ser usado o predicado esquece1(X). Am-
bos, esquece/1 e esquece1/1 so sempre bem sucedidos, garantindo o primeiro, com sua execuo, que
no h mais na base de dados nenhuma sentena que unifique com X e o segundo que a primeira sen-
tena encontrada unificando com X foi removida. Por outro lado o predicado memoriza(X) inicia com
uma chamada a esquece/1, preservando assim a unicidade da chave estipulada em X. Deve ser tam-
bm notado que esses predicados so extremamente poderosos e devem ser usados com absoluto cui-
dado para evitar "acidentes". Um cuidado interessante seria restringir a execuo de esquece/1, esque-
ce1/1 e memoriza/1 a argumentos que possussem uma instanciao explcita para a chave da tupla a
esquecer ou memorizar.
10.4 MODELAGEM DE DADOS
Uma base de dados no somente uma coleo de dados ou entidades, mas tambm as associaes ou
relacionamentos entre eles. Tais associaes constituem o denominado "modelo de dados". A tecno-
logia de bases de dados vem oferecendo mtodos e ferramentas para a soluo de problemas em am-
bientes complexos e de grande porte. O projeto de modelos lgicos de dados um importante objetivo
nas reas de representao e aquisio de conhecimento. O que se verifica que a pura lgica de pre-
dicados um formalismo extremamente poderoso, de expressividade ou capacidade de representao
virtualmente ilimitada, de modo que freqentemente temos que impor restries linguagem empre-
gada na modelagem, retornando porm lgica de predicados para explicar a semntica ou projetar
extenses no convencionais.
10.4.1 FORMAS NORMAIS
Como em toda modelagem, as nicas coisas importantes a serem modeladas so os invariantes fun-
damentais do domnio do problema. A mais importante propriedade dos invariantes que os objetos
pertencem a classes que podem ser armazenadas uniformemente como relaes.
Um outro princpio bsico aqui a evidncia de que um determinado dado em uma certa relao
funcionalmente dependente de outro. Um conjunto de dados B dito "funcionalmente dependente" de
um outro conjunto de dados A se para todo elemento a em A h um nico elemento b em B tal que b
est relacionado com a. As notaes mais empregadas so as seguintes:
A ---> B
A, B ---> C
significando respectivamente: "B funcionalmente dependente de A" e "C funcionalmente depen-
dente da combinao de A e B". Por exemplo:
trabalhador ---> empregador
Devido ao fato de que as chaves so nicas, segue automaticamente que todos os atributos de uma
98
entidade so funcionalmente dependentes de sua chave.
10.4.2 FORMAS NORMAIS RELACIONAIS
Outro importante princpio da boa modelagem de dados evitar redundncias. A mesma pea de in-
formao deve ser armazenada uma nica vez. Assim, para qualquer modificao em seus valores, a
base de dados necessitar ser atualizada em um nico ponto. Em bases de dados relacionais, tais prin-
cpios so definidos por meio de um processo denominado "normalizao". As diferentes formas
normais so denominadas: "primeira forma normal", "segunda forma normal", etc., e abreviadas res-
pectivamente por 1FN, 2FN, etc. Aqui introduzimos as trs primeiras delas.
PRIMEIRA FORMA NORMAL (1FN)
Evita repetir grupos, como no exemplo:
empregador empregado
1
, empregado
2
, ..., empregado
n
No usar a representao:
empregados(joo, [jos, jlia, jorge, josefina, jane]).
mas sim a representao
empr(jos, joo).
empr(jlia, joo).
empr(jorge, joo).
empr(josefina, joo).
empr(jane, joo).
onde os empregados (por exemplo, jos) no so funcionalmente dependentes do empregador (joo).
Ao contrrio, o empregador funcionalmente dependente dos empregados. Na prtica, o benefcio
acontece quando um novo empregado (por exemplo, jonas) contratado, porque tal fato pode ser in-
cludo na base de dados com:
?-memoriza(empr(jonas, joo)).
no necessitando o programador:
(1) Selecionar a lista de empregados de joo,
(2) Adicionar Jonas,
(3) Produzir uma nova lista,
(4) Apagar a tupla corrente, com a velha lista, e
(5) Produzir uma nova tupla, com a nova lista.
Um modelo na primeira forma normal deveria portanto ser:
empregador empregado.
SEGUNDA FORMA NORMAL (2FN)
Esta forma relevante para tuplas com chaves compostas:
empregado nomeEmpregado
empregado projeto nomeProjeto horas
Neste caso, cada empregado possui um nmero (a chave "empregado") e um nome (nomeEmpregado).
O empregado trabalha em um conjunto de projetos com nmeros (a chave "projeto") e nomes (nome-
Projeto), dedicando a cada um certo nmero de "horas".
99
A anomalia nesta representao que nomeProjeto no funcionalmente dependente da chave (em-
pregado, projeto) como um todo, mas apenas de uma parte dela (projeto). Assim a informao nome-
Projeto armazenada muitas vezes mais do que o necessrio. Se o nome do projeto muda, todas as
ocorrncias de nomeProjeto devem ser alteradas, uma vez para cada empregado que nele trabalha. Um
modelo na segunda forma normal seria:
empregado nomeEmpregado
empregado projeto horas
projeto nomeProjeto
Aqui nomeProjeto armazenado uma nica vez para cada projeto e modificado atravs de uma nica
atualizao.
TERCEIRA FORMA NORMAL (3FN)
Um bom exemplo da 3FN ocorre quando a informao sobre uma pessoa, seu empregador e o endere-
o de seu empregador so armazenados. Se a relao
empregado empregador endereoEmpregador
existe, ento a entidade endereoEmpregador no funcionalmente dependente da chave "emprega-
do" sozinha, mas na verdade de "empregador", que por sua vez dependente de "empregado". Como
nos casos anteriores, problemas de redundncia e de mltiplas atualizaes surgem, de modo que a
normalizao recomenda que a relao acima seja dividida em duas relaes independentes:
empregado empregador
empregador endereoEmpregador
Os princpios da normalizao podem ser aplicados manualmente para modelos pequenos, entretanto,
para grandes modelos a normalizao deve preferencialmente ser apoiada por ferramentas de enge-
nharia de software.
10.5 ALM DO MODELO RELACIONAL
O modelo relacional puro nem sempre poderoso o bastante para modelagens avanadas, devido
falta de expressividade semntica . Por exemplo, o modelo relacional no requer que, para cada em-
pregado, o atributo empregador corresponda a uma tupla existente na base de dados. Em modelos
reais h dois tipos de regras que relacionam as tabelas uma outra:
regras genricas, que definem novas tabelas virtuais que no so explicitamente armazenadas, e
regras restritoras, que estabelecem restries sobre o que permitido na base de dados.
Um exemplo de regras restritoras dada pelas dependncias funcionais, que especificam que atribu-
tos-chave so e devem ser nicos. Um outro exemplo seria uma regra como:
"Todos os elefantes so cor-de-cinza."
que deduz a cor de um elefante na base de dados, produzindo ainda uma restrio que garante que, nas
atualizaes subsequentes, nenhum elefante de outra cor ser armazenado na base de dados. Tais ba-
ses de dados so denominadas "dedutivas".
10.6 REDES SEMNTICAS
Questes de semntica so mais importantes para o projeto de uma base de conhecimento do que do
que mtodos para a codificao de dados. Quando os projetistas de base de dados adicionam mais
informao semntica s bases de dados, os modelos resultantes comeam a assemelhar-se aos siste-
mas de representao de conhecimento desenvolvidos pelos pesquisadores de inteligncia artificial.
Um desses esquemas de representao de conhecimento conhecido como "rede semntica". Uma
100
rede semntica um formalismo para representar fatos e relacionamentos entre fatos por meio de
relaes binrias. Por exemplo, na Figura 10.1, Jos, Joo e 555-2455 representam objetos. "telefone"
representa uma relao entre os objetos Jos e 555-2455, enquanto que "empregador" representa uma
relao entre Jos e Joo.
Jos
555-2455
Joo
telefone
empregador
Figura 10.1: Uma rede semntica simples
Os relacionamentos individuais so conectados em uma rede, onde os objetos, por exemplo, "Jos",
so representados uma nica vez. Para relaes binrias, as redes semnticas so um excelente forma-
lismo com uma notao grfica simples. Quando se tenta, entretanto, representar relaes n-rias em
redes semnticas -se forado a empregar construes artificiais, perdendo o formalismo das redes
semnticas grande parte dos seus atrativos.
Acredita-se que grande parte do raciocnio humano seja baseado em associaes lineares, de modo
que o modelo das redes semnticas tambm um interessante modelo do pensamento humano. Em
Prolog as relaes binrias so implementadas individualmente, repetindo os nomes dos objetos como
em:
telefone(jos, 555-2455).
empregador(jos, joo).
Armazenar uma rede semntica como uma rede com ponteiros um mtodo de implementao que
oferece rpido acesso no processo de associao. Em Prolog, na falta do conceito de ponteiro, as redes
so armazenadas como relaes binrias. Isto um pouco mais lento, mas muito flexvel, tanto para
recuperar informaes quanto para sua atualizao.
10.6.1 O CONCEITO DE CLASSE
To logo um objeto classificado, grande quantidade de conhecimento se torna disponvel a seu res-
peito. Uma "classe" a descrio de atributos e propriedades que so comuns a determinados indiv-
duos, denominados os "membros" da classe. Jos, por exemplo, um objeto pertencente classe dos
empregados. Um "atributo" alguma coisa que pode assumir um valor. Telefone, por exemplo, um
atributo dos membros da classe dos empregados. Uma "propriedade" um atributo juntamente com
um valor. Por exemplo, uma rosa tem a propriedade cor = vermelha. Jos tem a propriedade telefone =
555-2455.
Uma classe pode ser vazia, por exemplo, a classe dos unicrnios, e duas classes com os mesmos ele-
mentos podem ser bastante diferentes, por exemplo, a classe dos diretores de pesquisa e a classe dos
possuidores de aqurios. So exemplos de classes:
animal
mamfero
baleia
elefante
101
tubaro
So exemplos de atributos:
cor
alimento
habitat
tamanho
temperamento
Uma classe pode ser subclasse de outra classe. Se S uma subclasse de C e x membro de S, ento x
tambm membro de C. Por exemplo, "mamfero" uma subclasse de "animal" e "elefante" uma
subclasse de "mamfero". Se Clyde um elefante (isto , um membro da classe elefante), ento Clyde
ao mesmo tempo membro da classe mamfero e portanto tambm membro da classe animal.
Se a classe possui um atributo, este compartilhado por todas as suas subclasses. Note que uma classe
pode ter um atributo, mesmo se no possui membros no momento. Valores de atributos inexistentes,
tais como o telefone de um elefante, so rejeitados como no significativos, no devendo ser empre-
gado o tomo "nil".
De modo similar, se uma entidade possui um atributo que funcionalmente dependente dela, por
exemplo, "toda pessoa tem um nome", e o valor do atributo estiver faltando, o tomo apropriado para
representar isso "desconhecido" e no "nil" ou algo parecido. Se, por outro lado, um atributo no
funcionalmente dependente, tal como os filhos de uma pessoa, ento a sua ausncia deve ser pelo
tomo "nil" ou "nenhum" e no por "desconhecido".
Por exemplo: todos os animais tem uma cor, que varia. Portanto, todos os mamferos tem uma cor. Os
elefantes, portanto, tem uma cor, de modo que Clyde, que um elefante, tem tambm uma cor. Se a
classe tem uma propriedade, esta automaticamente herdada por todos os seus membros. Por exem-
plo:
"Todos os elefantes tem uma cor = cinza"
implica em:
"Se Clyde um elefante, ento Clyde tem uma cor = cinza"
O armazenamento de informao sobre classes em conjunto com informao sobre objetos, requer
alguns relacionamentos de uso geral, como os apresentados na figura 10.2
A
E
A
A
A
B
B
B
B
V
um tipo de
_um
tem
atributo
A subclasse de B
A entidade E um B
B adjetivo de A
A tem um atributo B
A tem um valor de atributo V
Figura 10.2 Relacionamentos em Redes Semnticas
102
animal
oxignio
mamfero Bonnie
amendoim elefante baleia tubaro
Clyde
circo
cinza
oceano
umTipoDe
umTipoDe
umTipoDe
Um
inalante
umTipoDe
alimento
Um
habitat
cor
cor
habitat
cor
Figura 10.3 Uma rede semntica
Seja ento a rede semntica mostrada na Figura 10.3. A informao ali representada pode ser adequa-
damente descrita atravs de um conjunto de clusulas Prolog. A declarao de operadores infixos
contribui para tornar o programa mais legvel. Define-se assim a sintaxe dos relacionamentos descri-
tos na Figura 10.2 por meio da assertiva:
:- op(900, xfx, [UmTipoDe, Um, , tem, atributo]).
O seguinte programa Prolog descreve a rede semntica acima:
:- op(900, xfx, [UmTipoDe, Um, , tem, temUm]).
animal temUm inalante.
animal temUm alimento.
animal temUm habitat.
animal temUm cor.
mamfero UmTipoDe animal.
mamfero tem inalante=oxignio.
elefante UmTipoDe mamfero.
elefante tem alimento=amendoim.
elefante tem habitat=circo.
elefante tem cor=cinza.
baleia UmTipoDe mamfero.
baleia tem habitat=oceano.
baleia tem cor=cinza.
tubaro UmTipoDe animal.
tubaro tem habitat=oceano
tubaro tem cor=cinza
bonnie Um tubaro.
clyde Um elefante.
A estrutura de classes em redes semnticas definida pelos seguintes axiomas:
X Um Z2 :-
Z1 UmTipoDe Z2, X Um Z1.
X tem Atributo=Valor :-
X Um C, C tem Atributo=Valor.
O primeiro destes axiomas o fecho transitivo de Um/2 e o segundo o fecho transitivo de tem/2.
Com o emprego deles possvel consultar a base de conhecimento em busca de questes de carter
geral tais como:
"Que propriedades possui Clyde?"
?-clyde tem Atr=Val.
Atr=alimento Val=amendoim;
Atr=habitat Val=circo;
Atr=cor Val=cinza;
Atr=inalante Val=oxignio;
no
103
RESUMO
Em bases de dados relacionais os dados so definidos por meio de relaes sobre domnios, e
os fatos individuais so representados como tuplas de valores extrados de tais domnios, cada
um deles representando um "atributo";
Pelo menos um dentre os atributos possui a caracterstica especial de ser "nico" em toda a ta-
bela de tuplas. Tal atributo denominado uma "chave" e identifica os objetos acerca dos quais
armazenada informao;
Duas facilidades importantes oferecidas pelo modelo relacional so as tabelas virtuais, que de-
finem relacionamentos implcitos, e o uso de nomes simblicos;
A atualizao de base de dados deve ser projetada de modo a preservar a unicidade dos atribu-
tos-chave. Os predicados esquece/1, esquece1/1 e memoriza/1 foram desenvolvidos com essa
idia em mente;
Na modelagem de dados importante a adoo de formas normalizadas para garantir certos
princpios organizacionais, evitando redundncias e a necessidade de realizar mltiplas atuali-
zaes;
Nem sempre o modelo relacional ir apresentar a expressividade necessria para a modelagem
avanada. Um modelo mais expressivo, empregado em inteligncia artificial o das redes se-
mnticas;
A modelagem atravs de redes semnticas introduz os conceitos de classe e herana de atribu-
tos, os quais so de fcil construo em Prolog;
Alguns dos relacionamentos empregados em redes semnticas so: UmTipoDe, Um, , tem e
temUm. Todos eles so binrios, e podem ser representados em Prolog por meio de operadores
infixos.
EXERCCIOS
10.1 Defina duas relaes:
empr(Nome, Depto, Salrio)
depto(Departamento, Gerente)
Escreva uma consulta ao sistema Prolog respondendo "Que empregados possuem salrio superior
ao de seu gerente?"
10.2 Defina as seguintes relaes:
pas(X) % X um pas
mar(X) % X um mar
populao(X,Y) % X tem a populao Y
fronteira(X, Y) % X faz fronteira com Y
Escreva uma consulta ao sistema Prolog para responder a questo: "Que pas, banhado pelo me-
diterrneo, faz fronteira com um pas que faz fronteira com um pas cuja populao excede a po-
pulao da ndia?"
10.3 Modifique os predicados para a manipulao de bases de dados relacionais apresentados no pre-
sente captulo de forma que mltiplas chaves sejam armazenadas sem redundncia. (Dica: Use
tabelas virtuais).
10.4 Amplie a base de conhecimento sobre animais. Como representar um avestruz como membro da
classe dos pssaros se se definiu "voar" como uma propriedade dessa classe? Em outras palavras,
como introduzir o conceito de exceo nas propriedades herdadas por um objeto a partir de sua
classe?
104
10.5 Modele uma base de conhecimento, empregando redes semnticas para descrever automveis,
introduzindo os relacionamentos ParteDe(X, Y), que verdadeiro se X parte de Y (por exem-
plo: ParteDe(motor, carro)) e subconjDe(X, Y), que verdadeiro se X subconjunto de Y.
105
11. PROGRAMAO SIMBLICA
11.1 DIFERENCIAO SIMBLICA
Um exemplo conhecido de manipulao de frmulas sem o emprego de computao numrica a
diferenciao de funes matemticas. As regras so simples e diretamente implementadas em Prolog
de uma forma muito elegante, empregando to somente o mecanismo de unificao. No presente
exemplo, todas as diferenciaes iro se referir a uma varivel matemtica fixa, x, que ser tratada
como uma constante pelo sistema Prolog. As regras de diferenciao so definidas pelo predicado
deriv(U, V), que verdadeiro quando V = dU / dx:
deriv(x, 1).
deriv(N, 0) :-
number(N). % number/1: embutido
deriv(U+V, U1+V1) :-
deriv(U, U1),
deriv(V, V1).
deriv(U-V, U1-V1) :-
deriv(U, U1),
deriv(V, V1).
deriv(U*V, U1*V+U*V1) :-
deriv(U, U1),
deriv(V, V1).
deriv(U/V, (V*U1-V1*U)/(V*V)) :-
deriv(U, U1),
deriv(V, V1).
deriv(U^N, N*U^(N1*U1)) :-
number(N),
N1 is N-1,
deriv(U, U1).
deriv(exp(U), exp(U)*U1) :-
deriv(U, U1).
...
Por exemplo:
?-deriv(x*x, Y).
Y=1*X+X*1
Entretanto, certamente seria mais apreciada uma sada melhor, tal como 2*X ou simplesmente 2X. A
razo da apresentao inadequada do resultado que o Prolog no possui simplificao algbrica
inerente, entretanto esta pode ser facilmente implementada, como ser visto mais adiante neste mesmo
captulo.
11.2 MANIPULAO DE FRMULAS
Em uma linguagem de programao simblica, como Prolog, os programadores precisam considerar
as frmulas e no apenas os seus valores. Em geral as frmulas no envolvem apenas aritmtica, mas
podem ser combinadas arbitrariamente atravs dos mais variados operadores e operandos, de acordo
com o princpio recursivo da decomposio: "o valor de uma expresso o resultado da aplicao de
um operador ao resultado dos restantes".
Em linguagens como Pascal e Lisp este princpio recursivo parte da semntica da linguagem. Em
Prolog isto deve ser feito explicitamente, mas pode ser feito sem dificuldades por um predicado recur-
sivamente definido. Este esquema geral e uma rplica do princpio recursivo da decomposio:
"Para resolver uma expresso, primeiro (i) resolva seus operandos, e depois (ii) aplique o
operador sobre os resultados obtidos".
11.3 OS OPERADORES REVISITADOS
106
Para lidar com uma expresso, necessrio ser capaz de manipular os seus subcomponentes. Na Ta-
bela 11.1 relaciona-se um conjunto de operadores embutidos disponveis na maioria das implementa-
es Prolog. H-se que lembrar entretanto que internamente tais operadores so representados sob a
forma de termos funcionais, onde os operadores so functores. Por exemplo:
X+Y armazenado como '+'(X, Y)
O operador embutido =../2 (univ) capaz de atuar sobre uma expresso vista como uma lista de com-
ponentes:
X+Y =.. ['+', X, Y]
-X =.. ['-', X]
Por exemplo:
?- 3+2*7 =.. [X, Y, Z].
X='+' Y=3 Z=2*7
?-X =.. ['-', 3+5, 5*9].
X=3+5-5*9
Tambm so importantes neste contexto os predicados embutidos functor/3 e arg/3 (ver seo 9.2) que
atuam normalmente sobre operadores, empregando a notao funcional.
Tabela 11.1 Operaes Comuns em Prolog
(a) Operaes Binrias
X+Y Adio
X-Y Subtrao
X*Y Multiplicao
X/Y Diviso
X=Y Igual
X<>Y No igual
X>=Y Maior ou Igual
X=<Y Menor ou Igual
X<Y Menor que
X>Y Maior que
X and Y Conjuno
X or Y Disjuno
X impl Y Implicao
(b) Operaes Unrias
-X Negao Aritmtica
not X Negao Lgica
11.4 AVALIAO DE FRMULAS
O efeito do operador "is" conhecido:
?-X is 3*7*37.
X=777
?-X is 7*11*13.
X=1001
A avaliao das frmulas numricas escondida do usurio, apesar de poder ser definida em Prolog.
Sua implementao em Prolog til por duas razes: Primeiro para ensinar os princpios da avaliao
de frmulas em Prolog. Depois, pode vir a ser necessrio incluir regras de operao que no se com-
portam estritamente com a semntica do operador "is". Vamos agora implementar o operador "$" com
a finalidade de estender os efeitos de "is", de modo que a expresso seja esperada do lado esquerdo e
o valor direita, assim:
10 + 10 $ 20
107
que pode ser lido: "o valor de 10+10 20". O operador "$" estende o "is" tambm na avaliao de
variveis globais, armazenadas como valor(A, B). Por exemplo:
valor(a, 3).
valor(b, 7).
?-a*b*37 $ X.
X=777
A avaliao estendida, $, definida da seguinte maneira:
:- op(900, xfx, '$').
(X $ X) :-
number(X), !.
(X $ Y) :-
valor(X, Y), !.
V $ U :-
V =.. [Op, X, Y], !, X $ X1, Y $ Y1,
W=.. [Op, X1, Y1], U is W.
V $ U :-
V =.. [Op, X], !, X $ X1, W=..[Op, X1], U is W.
O operador $ pode ser usado para implementar a atribuio ordinria de variveis globais como no
programa abaixo, onde o predicado esquece/1 o mesmo introduzido no captulo anterior e repetido
aqui como recordao:
:- op(901, xfx, ':=').
(V:=E) :-
E $ T, esquece(valor(V,X)), assert(valor(V, T)).
esquece(X) :-
esquece1(X), fail.
esquece(X).
esquece1(X) :-
retract(X).
esquece1(X).
A partir da definio acima podemos escrever:
?-a:=4, b:=13, c:=b*a, valor(c, X).
X=52
11.5 SIMPLIFICAO ALGBRICA
Outras aplicaes importantes da programao simblica so a manipulao de frmulas, prova de
teoremas no domnio da matemtica e anlise de programas. A prova de teoremas tambm parte
integrante da disciplina de verificao de programas, progrando a correo de programas. Um teorema
pode ser provado se pode ser reduzido constante "true". Descreve-se inicialmente aqui a simplifica-
o algbrica.
H diversas regras para as vrias frmulas, por exemplo, as leis comutativa, associativa e distribuitiva.
Na rea da simplificao algbrica, as regras que reduzem a complexidade das frmulas so especial-
mente interessantes. Algumas dessas regras so fornecidas abaixo atravs do predicado reduz/2.
A partir dos axiomas bsicos de reduo apresentados na figura acima, um pequeno programa simpli-
ficador pode ser construdo baseado no seguinte princpio recursivo:
Simplifique os operandos primeiro, depois a operao, e
Repita at que nenhum dos operandos seja modificado.
reduz(X+0, X). reduz(X=X, true).
reduz(0+X, X). reduz(X or true, true).
redux(X-X, 0). reduz(true or X, true).
reduz(X-0, X). reduz(X and false, false).
reduz(0-X, -X). reduz(false and X, false).
reduz(X*0, 0). reduz(X and true, X).
108
reduz(0*X, 0). reduz(true and X, X).
reduz(X*1, X). reduz(X or false, X).
reduz(1*X, X). reduz(false or X, X).
reduz(0/X, 0). reduz(X impl true, true).
reduz(true impl X, X).
reduz(false impl X, true).
reduz(X impl X, true).
reduz(X and X, X).
reduz(X or X, X).
reduz(U, V) :-
U =..[Op, X, Y], number(X), number(Y), !, V is U.
Figura 11.1 O predicado reduz/2
O algoritmo est correto, porm no completo. Tambm no possui eficincia tima porque ir ten-
tar ressimplificar uma expresso que um algoritmo mais refinado reconheceria como j simplificada.
Tal refinamento ser deixado ao leitor a ttulo de exerccio.
simplifica(U, V) :-
simp(U, V, Teste). % Teste verdadeiro se V<>U.
simp(F, H, true) :-
reduz(F, G), !, simplifica(G, H).
simp(F, Z, true) :-
F=..[Op, X, Y],
simp(X, X1, mudaX),
simp(Y, Y1, mudaY),
membro(true, [mudaX, mudaY]), !,
G=..[Op, X1, Y1],
simplifica(G, Z).
simp(F, F, false).
O efeito do programa acima pode ser visualizado por meio dos seguintes exemplos:
?-simplifica(1*x-x*1, S).
S=0
?-simplifica(1*x+x*1, S).
S=x+x
A diferenciao e a simplificao algbrica podem agora ser integradas em um s predicado:
deriva(U, V) :-
deriv(U, U1), simplifica(U1, V).
?-deriva(x*x, S).
S=x+x
11.5.1 SUBEXPRESSES COMUNS
A simplificao possvel quando operaes adjacentes podem ser encontradas por meio do reconhe-
cimento de padres fixos. Por exemplo:
(a+b*j-f) - (a+b*j-f)
reconhecido pela unificao com o padro X-X. Entretanto, uma classe de problemas resta ainda por
ser solucionada, que quando h subexpresses que poderiam ser movidas de acordo com as regras
comutativas e associativas, e ento reduzidas quando um padro unificvel for reconhecido. A expres-
so
(a+b+c)-b
poderia ser transformada em
((a+c)+b)-b
que segue o padro:
(X+Y)-Y
sendo redutvel a
X=a+c
109
Na verdade a formao de subexpresses comuns um dos importantes princpios heursticos que de
que se valem as pessoas na realizao de simplificaes algbricas. A tarefa bsica, no caso, desco-
brir subexpresses comuns.
Uma subexpresso ocorrendo em uma expresso facilmente formulada como:
ocorre(X, X).
ocorre(S, Z) :-
Z=..[Op, X, Y], (ocorre(S, X); ocorre(S, Y)).
de modo que o problema de descobrir se uma determinada expresso emprega a mesma subexpresso
diversas vezes solucionado por:
comum(Z, U) :-
Z=..[Op, X, Y], ocorre(U, X), ocorre(U, Y).
Por exemplo:
?-comum((w+1+2*(w+1)), Z), fail.
w+1
w
1
no
11.6 INTEGRAO
Tem sido dito que a diferenciao uma tcnica, ao passo que a integrao uma arte. A tarefa de
integrao simblica objeto da engenharia de conhecimento, onde as especializaes humanas so
transferidas para sistemas computacionais. Uma primeira tentativa de obter integrao poderia ser por
meio da explorao da reversibilidade dos predicados Prolog :
integr(Y, Z) :-
deriv(Z, Y).
?-integr(1*x+x*1, Int).
Int=x*x
Infelizmente a capacidade Prolog de inverter predicados limitado. Se for solicitado:
?-integr(0, Int).
em um determinado momento ser ativado o objetivo number(Int). Entretanto, tal predicado pr-
definido no inversvel. Se o fosse, deveria gerar nmeros instanciados (0, 1, 2, ...) , que so todos
integraes corretas de 0. Mas ao invs disso produz a penas a resposta "no".
Um outro problema diz respeito a reverso da simplificao. Se for tentado
?-integr(x+x, Int).
com vistas a obter x*x, nenhuma resposta obtida, porque x+x somente atingido aps uma simplifi-
cao. Se simplifica/2 estiver sendo executado de modo reverso, ir cair num lao recursivo infinito.
Entretanto, possvel modificar o predicado simplifica/2 para controlar a profundidade mxima da
recurso. Essa aplicao pode resultar em um sistema de integrao simblica bastante lento, mas
teoricamente completo, baseado no princpio da gerao e teste exaustivos. A construo de tal siste-
ma deixada como um exerccio ao leitor.
RESUMO
A capacidade de programao simblica uma das principais caractersticas da linguagem
Prolog. A diferenciao facilmente implementada atravs de suas regras;
O princpio recursivo de decomposio que parte da semntica de linguagens tais como Pas-
cal e Lisp, deve ser explicitado em Prolog, o que pode feito com grande facilidade;
110
Os predicados embutidos =../2, functor/3 e arg/3 so de grande valia na programao simblica
para a separao dos subcomponentes das expresses;
O operador "$" estende a semntica do operador "is" permitindo a avaliao de variveis glo-
bais e a implementao do mecanismo de atribuio de valores;
A simplificao algbrica implementada simbolicamente por meio do predicado reduz/2, que
associa os fatos e regras relevantes para a simplificao desejada;
A identificao de subexpresses comuns para fins de simplificao necessita de heursticas es-
peciais para ser eficiente. O predicado comum/2, baseado em ocorre/2, representa uma imple-
mentao simples com esse objetivo;
A integrao pode ser implementada em parte como o inverso da diferenciao, entretanto as
limitaes de reversibilidade do Prolog iro exigir o uso de estratgias e heursticas especiais
para a execuo desta tarefa.
EXERCCIOS
11.1 Escreva um programa de simplificao que nunca re-simplifique uma expresso j simplificada.
11.2 Estenda o predicado deriva/2, incluindo simplificao algbrica para lidar com as funes:
ln, exp, sin, cos, arctan e U^V
onde U e V so expresses genricas.
11.3 Estenda o exemplo das subexpresses comuns para levar em conta a equivalncia comutativa.
11.4 Escreva um programa Prolog para mover subexpresses comuns para prximas umas das outras e
ento executar redues com base no reconhecimento de padres, tal como antes. Por exemplo:
(a+b+c+d - (a+c))
Aqui, c uma subexpresso comum que removida dos dois operandos principais:
(a+b+c+d) ==> ((a+b+d) + c)
-(a+c) ==> -(a+c)
----------------------------
(a+b+d) - a
e ento reduzida de acordo com o padro:
(X+C)-(Y+C) ==> X - Y
que aplicado recursivamente produz o resultado (b + d)
11.5 Modifique o predicado deriva/2 para obter a integrao por inverso da derivao e a simplifica-
o de acordo com o esquema:
integralN(U, V, N) :-
nvel(N), simplificaN(Frmula, U, N), deriv(U, Frmula).
nvel(0).
nvel(N1) :- nvel(N), N1 is N+1.
onde simplificaN/3 simplifica uma frmula em exatamente N passos recursivos (N = 0, 1, ...).
111
12. METODOLOGIA DA PROGRAMAO EM LGICA
A engenharia de software estabeleceu, ao longo do tempo, diversos critrios para a caracterizao de
programas de boa qualidade, assim como tcnicas e prticas que, se empregadas, conduzem natural-
mente construo de bons programas. Ainda que tais tcnicas tenham sido desenvolvidas geralmente
do ponto de vista da programao procedimental convencional, importante lembrar que programas
em Prolog so tambm software e como tal devem estar sujeitos mesma disciplina e mtodo preco-
nizados para o desenvolvimento de programas convencionais.
O estilo declarativo inerente linguagem Prolog permite solucionar automaticamente diversos pro-
blemas relacionados com a recuperao de informaes e representao de estruturas complexas de
dados, entretanto, uma boa parte dos problemas com que se deparam os programadores so algortmi-
cos por natureza, devendo portanto ser interpretados e solucionados de forma algortmica.
No presente captulo so revisados alguns princpios gerais da engenharia de software, abordando os
elementos necessrios ao desenvolvimento de um bom estilo de programao em Prolog. Critrios de
correo e eficincia so tambm introduzidos, visando oferecer ao leitor alguma instrumentao
metodolgica para a construo de programas de boa qualidade.
12.1 PRINCPIOS GERAIS DA BOA PROGRAMAO
Uma questo fundamental a esse respeito : "O que um bom programa?". A resposta a esta questo
no tarefa trivial, uma vez que h diversos critrios para julgar quo bom um programa . Critrios
geralmente aceitos incluem, entre outros, os seguintes:
CORREO: Acima de tudo, um programa deve ser "correto", isto , deve fazer exatamente o
que se espera dele. Um erro comum, cometido por alguns programadores negligenciar esse
critrio bvio em favor de outros, como por exemplo a eficincia;
EFICINCIA: Um bom programa no deve consumir sem necessidade grandes quantidades de
recursos, tais como memria e tempo de execuo;
TRANSPARNCIA E LEGIBILIDADE: Um bom programa deve ser fcil de ler e entender.
No deve ser mais complicado do que o necessrio. Truques de programao que obscurecem o
significado do programa devem ser evitados;
MODIFICABILIDADE: Um bom programa deve ser fcil de ser modificado ou estendido. A
transparncia e a adoo de uma organizao modular auxiliam a atingir tal objetivo;
ROBUSTEZ: Um bom programa deve ser "robusto". Isso significa que ele no deve ser aborta-
do facilmente quando o usurio entrar com dados incorretos ou inesperados. O programa deve,
no caso de tais erros, manter-se em execuo e comportar-se "racionalmente" (por exemplo:
relatando o erro ao usurio e solicitando nova entrada de dados).
DOCUMENTAO: Um bom programa deve ser adequadamente documentado. A documenta-
o mnima aceitvel para um programa a sua listagem enriquecida com comentrios sufici-
entes para o seu entendimento.
A importncia de cada critrio vai depender do problema, das circunstncias em que o programa
desenvolvido e do ambiente em que ser utilizado. No h dvida, entretanto, de que a correo deve
ser o critrio de mais alta prioridade. Aos critrios de transparncia, modificabilidade, robustez e do-
cumentao normalmente atribuda uma prioridade no mnimo igual ao requisito de eficincia.
112
H algumas regras gerais para atingir na prtica os critrios apresentados acima. Uma delas, muito
importante, primeiro "pensar" sobre o problema a ser resolvido e somente iniciar a codificao na
linguagem de programao escolhida depois de se ter formulado uma idia clara sobre o que deve ser
feito. Uma vez que um bom entendimento do problema foi desenvolvido e definida a sua soluo, a
codificao do programa torna-se fcil e rpida, havendo uma boa chance de se obter sem demora um
programa correto.
A formulao inicial obtida para a soluo do problema dever ento ser convertida para a linguagem
de programao escolha. Tal processo, entretanto, pode no ser uma tarefa fcil. Uma abordagem
consagrada a de utilizar o "princpio dos refinamentos sucessivos", que considera a soluo inicial
uma formulao em "alto nvel" e o programa finalmente obtido como uma soluo em "baixo nvel".
De acordo com o princpio dos refinamentos sucessivos, o programa final obtido por meio de uma
sequncia de transformaes ou refinamentos da soluo inicial. Inicia-se com a formulao em alto
nvel da soluo do problema e ento passa-se a transform-la de maneira que cada nova formulao
obtida equivalente anterior, porm expressa de forma mais detalhada. Em cada passo de refina-
mento os conceitos usados na formulao anterior so elaborados em maior detalhe e a sua represen-
tao vai se aproximando da linguagem de programao. Deve-se ter em mente que os refinamentos
se aplicam tanto s definies de procedimentos quanto s estruturas de dados. Nos estgios iniciais
normalmente se trabalha com unidades de informao mais abstratas, cuja estrutura refinada na me-
dida em que avanamos com o processo. A estratgia dos refinamentos sucessivos possui as seguintes
vantagens:
Permite a formulao de uma soluo inicial nos termos mais relevantes ao problema,
Essa soluo inicial , por conseguinte, mais simples e sucinta, sendo a sua correo facilmente
verificvel, e
Cada passo de refinamento deve ser suficientemente pequeno para ser manejado intelectual-
mente. Assim a transformao da soluo em uma representao mais detalhada preserva com
mais facilidade a sua correo.
No caso da linguagem Prolog, pode-se pensar em tal processo como sendo o de refinamento de refi-
namento de relaes. Se, entretanto, a natureza do problema sugerir uma abordagem em termos algo-
rtmicos, tambm possvel pensar em refinamento de algoritmos, adotando ento a viso procedi-
mental do Prolog.
Para refinar apropriadamente uma soluo em algum nvel de detalhamento e introduzir conceitos
adequados ao prximo, necessrio "ter idias". Portanto a programao uma atividade criativa,
especialmente para programadores iniciantes. medida em que a experincia em programao au-
menta, esta se torna menos uma arte e mais uma tcnica. Assim, a questo principal : "Como ter idi-
as?" A maioria das idias surge da experincia com problemas similares, cuja soluo conhecida. Se
no se conhece uma soluo direta, pode-se lanar mo de outros programas parecidos. Uma fonte de
idias nossa vida no dia-a-dia.. Por exemplo, se o problema a resolver classificar uma lista de
itens, pode-se obter uma idia considerando a questo: "Como proceder para classificar as provas de
uma turma de alunos pela ordem alfabtica do nome dos estudantes?".
12.2 COMO PENSAR EM PROLOG
Uma caracterstica importante da linguagem Prolog permitir que seus programas sejam pensados
tanto declarativa quanto procedimentalmente. Essas duas abordagens foram discutidas com algum
detalhe no captulo 3. A que ir se tornar mais eficiente e prtica depende, naturalmente, do problema
a resolver. A experincia tem mostrado que solues declarativas so usualmente mais fceis de des-
envolver e possuem a clareza e limpidez da pura lgica. Por outro lado, podem tambm facilmente
originar programas ineficientes. Durante o processo de desenvolvimento de uma soluo, deve-se
113
buscar as idias adequadas para decompor um problema em subproblemas de soluo mais fcil. Uma
questo importante aqui : "Como encontrar os subproblemas apropriados?". Os princpios funda-
mentais para responder tal questo sero discutidos agora.
12.2.1 USO DE RECURSO
Na soluo de problemas envolvendo o processamento sequencial por meio de recurso, uma boa
heurstica aplicar pensamento indutivo e resolver os seguintes dois casos separadamente:
(1) Os casos triviais, ou bsicos, em que o argumento uma lista vazia ou unitria, e
(2) Os casos gerais, em que o argumento uma lista [Cabea|Corpo] e o problema assumido re-
solvido para "Corpo".
Em Prolog, essa tcnica utilizada frequentemente. Seja por exemplo o problema de processar uma
lista de itens de tal maneira que cada item seja operado por uma mesma regra de transformao:
transforma(Lista, F, NovaLista)
onde Lista a lista original, F uma regra de transformao e NovaLista a lista de todos os itens
transformados. O problema de transformar Lista em NovaLista pode ser subdividido em dois casos:
(1) Caso Bsico: Lista = []
Se Lista = [], ento NovaLista = [], independentemente de F.
(2) Caso Geral: Lista = [X | Resto]
Para transformar uma lista do tipo [X | Resto] em uma lista do tipo [NovoX | NovoResto],
transforme Resto, obtendo NovoResto e transforme X, obtendo NovoX.
Em Prolog:
transforma([], _, []).
transforma([X | Resto], F, [NovoX | NovoResto]) :-
G =.. [F, X, NovoX], call(G),
transforma(Resto, F, NovoResto).
A razo pela qual a recurso se aplica to naturalmente em Prolog reside no fato de que os objetos
estruturados, como rvores e listas, possuem uma organizao recursiva intrnseca. Uma lista, por
exemplo, ou vazia (caso bsico), ou possui uma cabea e um corpo (caso geral).
12.2.2 GENERALIZAO
Muitas vezes uma boa idia generalizar o problema original, de forma a permitir que a soluo do
problema generalizado seja formulada recursivamente. O problema original ento solucionado como
um caso especial da verso mais geral. A generalizao de uma relao envolve tipicamente a intro-
duo de um ou mais argumentos extras. O maior problema, que pode requerer uma profunda intui-
o, : "Como encontrar a generalizao correta?". Como ilustrao examinaremos um clssico da
pesquisa em inteligncia artificial que o "problema das oito damas". O enunciado original desse
problema prope dispor oito damas em um tabuleiro de xadrez de maneira que nenhuma delas ataque
as demais. A relao correspondente poderia ser representada por:
oitoDamas(Posio)
que ser verdadeira se Posio representar uma posio do tabuleiro tal que nenhuma dama ataque as
restantes. Uma idia interessante, nesse caso generalizar o nmero de damas de oito para N, de for-
ma que o nmero de damas se torna o argumento adicional.
nDamas(Posio, N)
114
A vantagem dessa generalizao que h uma formulao recursiva imediata para a relao nDa-
mas/2:
(1) Caso Bsico: N = 0
Colocar "zero" damas em segurana trivial.
(2) Caso Geral: N > 0
Para colocar N damas em segurana no tabuleiro necessrio satisfazer as seguintes condi-
es:
Obter uma configurao segura para N - 1 damas, e
Adicionar as damas restantes de forma que nenhuma delas ataque as demais.
Uma vez que o problema generalizado est solucionado, a soluo do problema original imediata:
oitoDamas(Posio) :-
nDamas(Posio, 8).
12.2.3 REPRESENTAO GRFICA DE PROBLEMAS
Na busca por idias para solucionar um dado problema, frequentemente de grande utilidade introdu-
zir alguma representao grfica do mesmo. Um desenho pode ajudar na percepo de algumas rela-
es essenciais do problema. S ento passa-se a descrever o que se v no desenho na linguagem de
programao escolhida. No caso do Prolog, essa tcnica parece ser especialmente produtiva, eis que:
Prolog particularmente adequado para problemas envolvendo objetos e relaes entre objetos.
De modo geral tais problemas podem ser naturalmente ilustrados por meio de grafos, onde os
nodos correspondem a objetos e os arcos a relaes;
Os objetos estruturados em Prolog so naturalmente representados por meio de rvores;
O significado declarativo dos programas Prolog facilita a traduo de representaes grficas
porque, em princpio, a ordem na qual o desenho feito no constitui um fator importante.
12.3 ESTILO DE PROGRAMAO
O propsito de adotar algumas convenes relacionadas ao mtodo ou estilo de programao adotado
fundamentalmente:
Reduzir o risco de erros de programao, e
Produzir programas de boa legibilidade, fceis de entender, corrigir e modificar.
Algumas normas cuja observncia produz um bom estilo de programao em Prolog sero introduzi-
das a seguir: regras gerais, organizao tabular de procedimentos longos e o uso apropriado de co-
mentrios.
12.3.1 REGRAS GERAIS PARA UM BOM ESTILO
As clusulas do programa devem ser curtas. Seu corpo no deve conter mais que uns poucos
objetivos. Empregar sempre
proc1A :- a, b, c.
proc1B :- d, e, f.
proc1C :- g, h, i.
ao invs de
proc1 :- a, b, c, d, e, f, g, h, i.
115
Os procedimentos do programa devem tambm ser curtos (conter poucas clusulas), porque
procedimentos longos demais so difceis de entender. (Apesar disso, procedimentos longos
podem ser aceitveis, desde que possuam uma estrutura uniforme, conforme ser discutido mais
adiante);
Adotar nomes mnemnicos para procedimentos e variveis, indicando o significado das rela-
es e o papel desempenhado pelos objetos que nelas se fazem presentes;
O lay-out dos programas importante, incluindo um bom espacejamento, uso de linhas em
branco, e identao. Clusulas sobre o mesmo procedimento devem ser agrupadas conjunta-
mente. Deve haver linhas em branco entre os procedimentos. Cada objetivo deve ser escrito em
uma nova linha. Segundo Bratko [Bra 86]:
"Programas Prolog muitas vezes lembram poemas, devido ao apelo esttico produzido pelas
idias e formas que contm.".
Convenes de estilo desse tipo podem variar de programa para programa, uma vez que depen-
dem do problema e do gosto de cada programador. importante que as mesmas convenes
sejam usadas de forma consistente em todo o programa;
O operador cut deve ser usado com cuidado. Seu uso deve ser evitado quando no for absolu-
tamente necessrio. Se no for possvel evitar o uso de cuts, melhor usar apenas os cuts "ver-
des" e jamais os "vermelhos". Como foi discutido no captulo 6, um cut "verde" quando pode
ser removido sem alterar o significado declarativo da clusula em que se encontra. Caso contr-
rio o cut "vermelho";
O operador not, devido a sua relao com o cut tambm pode apresentar comportamento ines-
perado. necessrio ter completo conhecimento sobre a forma em que o not definido em
Prolog:
not(P) :- P, !, fail; true.
bem como as consequncias da adoo da hiptese do mundo fechado na execuo da negao
em Prolog (ver captulo 6). Se entretanto estivermos em dvida entre usar o not ou o cut, o pri-
meiro prefervel a alguma construo obscura com o uso do cut;
A modificao do programa por meio dos predicados assert/1 e retract/1 pode degradar em
grande escala a transparncia do seu comportamento. Em particular, um mesmo programa pode
responder a mesma consulta de maneira diferente em momentos diferentes. Em tais casos, se
quisermos reproduzir o mesmo comportamento, temos que nos certificar que todos os estados
anteriores do programa, desde o incio de sua execuo, foram perfeitamente reproduzidos;
O uso do ponto-e-vrgula (correspondendo ao conetivo "ou") pode obscurecer o significado de
uma clusula. A legibilidade pode ser algumas vezes incrementada pela diviso da clusula que
contm o ";" em duas.
Para ilustrar os pontos discutidos at aqui, vamos considerar a seguinte relao:
merge(L1, L2, L3)
onde L1 e L2 so listas ordenadas que so reunidas ordenadamente em L3. Por exemplo:
merge([2, 4, 7], [1, 3, 4, 8], [1, 2, 3, 4, 4, 7, 8])
A implementao abaixo um contra-exemplo de definio da relao merge/3, empregando um es-
tilo que deixa muito a desejar:
merge(L1, L2, L3) :-
L1 = [], !, L3 = L2;
L2 = [], !, L3 = L1;
L1 = [X | Resto1],
L2 = [Y | Resto2],
(X < Y, !, Z = X, merge(Resto1, L2, Resto3);
(Z = Y, merge(L1, Resto2, Resto3)),
L3 = [Z | Resto3].
116
J a verso a seguir possui um estilo muito mais transparente e legvel, alm de ser com certeza mais
eficiente, uma vez que tira partido da unificao dos argumentos correspondentes ao caso bsico na
prpria cabea da clusula:
merge([], L, L).
merge(L, [], L).
merge([X | R1], [Y | R2], [X | R3]) :-
X < Y, !, merge(R1, [Y | R2], R3).
merge(L1, [Y | R2], [Y | R3]) :-
merge(L1, R2, R3).
12.3.2 ORGANIZAO TABULAR DE PROCEDIMENTOS LONGOS
Procedimentos longos podem vir a ser aceitveis, desde que apresentem uma estrutura uniforme. Uma
estrutura uniforme tpica a formada por um conjunto de fatos que efetivamente definem uma relao
em forma tabular. As vantagens de tal organizao so as seguintes:
A estrutura facilmente entendida,
A estrutura incremental: pode ser facilmente refinada pela adio de novos fatos, e
de fcil verificao, correo e modificao (pela simples substituio de algum fato, inde-
pendentemente dos demais).
12.3.3 O USO DE COMENTRIOS
Os comentrios no programa devem, antes de mais nada, explicar a sua finalidade e como deve ser
utilizado. Somente depois disso que devem aparecer os detalhes do mtodo empregado e outras ca-
ractersticas do programa. O propsito inicial dos comentrios facilitar ao usurio o uso do progra-
ma e, se for o caso, a sua modificao. Os comentrios devem descrever, da forma mais sucinta poss-
vel, porm sem perda de informao, tudo o que for essencial para tais finalidades. Um erro muito
comum a produo de programas sub-comentados, entretanto, programas supercomentados tambm
no so desejveis. A explicao de detalhes bvios da codificao de um programa uma carga des-
necessria. Longos trechos de comentrios devem preceder o cdigo ao qual se referem, enquanto que
pequenas notas devem ser intercaladas na prpria codificao. A informao que normalmente deve
ser includa como comentrio compreende o seguinte:
O que o programa faz, como deve ser utilizado, (por exemplo, que tipo de consulta deve ser
formulada e quais so os resultados esperados) e exemplos de utilizao;
Descrio dos predicados de nvel mais alto;
Descrio dos principais conceitos representados;
Tempos de execuo e requisitos de memria;
Limitaes do programa;
Utilizao de recursos especiais dependentes do hardware;
Idem com relao ao software bsico;
Descrio dos predicados do programa;
Detalhes algortmicos e de implementao.
12.4 DEPURAO DE PROGRAMAS
Quando um programa apresenta um comportamento diferente do esperado, o principal problema passa
a ser a localizao do(s) erro(s). mais fcil localizar um erro em uma parte do programa ou mdulo
117
do que no programa inteiro, portanto, um bom princpio de correo de programas comear pelo
teste de pequenas unidades do programa e, quando estas forem consideradas confiveis, passar a testar
mdulos maiores at que o programa inteiro possa ser testado.
A correo de programas em Prolog facilitada por duas circunstncias: primeiro, Prolog uma lin-
guagem interativa, de forma que qualquer parte do programa pode ser ativada diretamente por meio de
uma consulta apropriada; segundo, as implementaes Prolog normalmente oferecem ferramentas
especiais para "debugging". Como resultado desses dois recursos, a correo de programas em Prolog
pode, em geral, ser executada de forma bem mais eficiente do que a maioria das linguagens de pro-
gramao.
A ferramenta bsica para a depurao de programas o processo de "tracing". Sua aplicao a um
objetivo significa que as informaes associadas satisfao desse objetivo iro sendo apresentadas
durante a execuo. Tais informaes incluem:
Informao de Entrada: O nome do predicado e os valores dos argumentos quando o objetivo
disparado;
Informao de Sada: No caso do objetivo ser bem sucedido, so apresentados os valores dos
argumentos que o satisfazem. Em caso contrrio, a indicao de falha no ponto em que esta
ocorreu;
Informao de Reentrada: Na chamada do mesmo objetivo atravs de backtracking.
Entre a entrada e a sada, pode-se obter a mesma informao de todos os sub-objetivos envolvidos, de
forma que podemos dispor do tracing da execuo de qualquer consulta ao programa, desde os nveis
mais elevados at que os fatos correspondentes sejam encontrados. Isso pode, em determinadas cir-
cunstncias, ocasionar um excesso de informao, assim, permitido ao usurio especificar um tra-
cing seletivo. H dois mecanismos dedicados a essa seleo: primeiro, suprimir a informao de tra-
cing alm de determinado nvel; segundo, executar o tracing apenas sobre algum subconjunto espec-
fico de predicados e no sobre o programa inteiro. Tais ferramentas para a depurao de programas
so ativadas por meio de predicados pr-definidos que variam de uma implementao para outra. Um
conjunto tpico desses predicados o seguinte:
trace: Dispara um processo exaustivo de tracing para todos os objetivos que se seguirem;
notrace: Interrompe o processo de tracing;
spy(P): Especifica o nome de uma relao P para o processo de tracing. O predicado spy/1
empregado quando se est particularmente interessado no comportamento da relao
nomeada e se deseja evitar o tracing de outros objetivos (tanto acima quanto abaixo
de P);
nospy(P): Interrompe o tracing da relao P.
O processo de tracing pode ser interrompido alm de uma certa profundidade por meio de comandos
especiais acionados durante a execuo. Dependendo da implementao pode haver ainda diversos
comandos de depurao disponveis, tais como retornar a um determinado ponto anterior da execuo.
Aps tal retorno podemos, por exemplo, repetir a execuo de forma mais detalhada.
12.5 EFICINCIA
H diversos aspectos de eficincia, incluindo os mais comuns: tempo de execuo e consumo de me-
mria de um programa. Um outro aspecto, pouco considerado mas indubitavelmente de grande im-
portncia o tempo consumido no desenvolvimento de um programa. A arquitetura dos computadores
convencionais no especialmente adequada para o estilo de execuo de programas adotado pelo
Prolog - ou seja, a satisfao de uma lista de objetivos. Portanto, as limitaes de espao e tempo a
118
que todas as linguagens de programao esto sujeitas, podem vir a ser sentidas antes pelos programas
Prolog.
Por outro lado, em muitas reas de aplicao, o uso do Prolog vai reduzir consideravelmente o tempo
de desenvolvimento, pois os programas Prolog so em geral mais fceis de escrever, entender e depu-
rar do que os escritos em linguagens convencionais. Problemas que gravitam em torno do "domnio
Prolog" envolvem processamento simblico, no-numrico, sobre objetos estruturados e as relaes
entre eles. Em particular, o uso de Prolog tem sido especialmente bem sucedido em reas envolvendo
a soluo simblica de equaes, planejamento, bases de dados, solucionadores genricos, prototipa-
o, implementao de linguagens de programao, simulao discreta e qualitativa, projeto arquite-
tnico, aprendizado de mquina, interpretao da linguagem natural, sistemas especialistas e diversas
outras reas da inteligncia artificial. Sob outro ngulo, matemtica numrica uma rea na qual os
programas Prolog no conseguem competir.
Com respeito a eficincia na execuo, um programa compilado sempre mais eficiente do que um
programa interpretado, portanto, se o sistema Prolog adotado possui um interpretador e um compila-
dor, este ltimo deve ser usado preferencialmente ao primeiro quando a eficincia se tornar um ponto
crtico. Se um programa se apresenta ineficiente, muitas vezes isso pode ser radicalmente modificado
por meio de alteraes no seu prprio algoritmo, entretanto, para fazer isso, os aspectos procedimen-
tais do programa devem ser considerados. Uma maneira simples de aumentar a eficincia de um pro-
grama encontrar uma ordenao mais adequada para as clusulas no interior dos procedimentos e
para os objetivos no interior das clusulas. Um outro mtodo, relativamente simples, a introduo de
cuts em posies apropriadas. Idias para aumentar a eficincia de um programa normalmente surgem
de um entendimento mais profundo do problema. Um algoritmo mais eficiente resulta de melhorias de
dois tipos:
Aumento na eficincia de busca, evitando backtracking desnecessrio e interrompendo a execu-
o de alternativas inteis o mais cedo possvel, e
Uso de estruturas de dados mais adequadas para a representao de objetos no programa, de
forma que as operaes sobre esses objetos possam ser implementadas de maneira mais efici-
ente.
Esses dois tipos de melhorias sero abordados em maior detalhe nos exemplos apresentados nas pr-
ximas sees.
12.5.1 O PROBLEMA DE COLORIR UM MAPA
O problema de colorir um mapa corresponde a atribuir, a cada pas em um determinado mapa, uma
certa cor, escolhida de um conjunto de quatro cores diferentes, de maneira que dois pases vizinhos
nunca sejam coloridos com a mesma cor. H um teorema que garante que isso sempre possvel de
ser feito. Vamos assumir que o mapa seja especificado pela relao:
viz(Pas, Vizinhos)
onde Vizinhos a lista de todos os pases que possuem alguma fronteira em comum com Pas. Assim,
o mapa da Amrica do Sul, com 13 pases, seria especificado em ordem alfabtica por:
viz(argentina, [bolvia,brasil,chile,paraguai,uruguai]).
viz(bolvia, [argentina,brasil,chile,paraguai,peru]).
viz(brasil, [argentina,bolvia,colmbia,guiana,
guiana_francesa,paraguai,suriname,
uruguai, venezuela]).
...
Uma possvel soluo para o problema das cores de cada pas seria representar a correspondncia
entre estes e suas cores por uma lista de pares do tipo:
Pas/Cor
119
que especifca uma cor para cada pas em um determinado mapa. Para o mapa proposto, os nomes dos
pases so dados antecipadamente e o problema ser encontrar a cor adequada para colorir cada um
deles. Assim, no caso da Amrica do Sul, o problema corresponde a encontrar uma instanciao ade-
quada para as variveis C1, C2, C3, etc. na lista:
[argentina/C1, bolvia/C2, brasil/C3, ...]
Para isso define-se a relao cores/1, cujo nico argumento a lista acima e que ser verdadeira se a
lista satisfizer a restrio do colorido do mapa, com respeito relao viz/2 definida anteriormente.
Sejam as cores escolhidas azul, amarelo, vermelho e verde. A condio de que dois pases vizinhos
no podem ter a mesma cor pode ser formulada em Prolog por:
cores([]).
cores([Pa/Cor | Resto]) :-
cores(Resto),
membro(Cor, [azul, amarelo, vermelho, verde]),
not(membro(Pas1/Cor,Resto),vizinho(Pas,Pas1)).
vizinho(Pas, Pas1) :-
viz(Pas, Vizinhos), membro(Pas1, Vizinhos).
onde membro/2 a relao usual de ocorrncia em listas. O procedimento cores/1 funciona relativa-
mente bem para mapas simples, com poucos pases, entretanto, para mapas complexos como o da
Amrica do Sul, sua eficincia deixar a desejar. Assumindo que o predicado pr-definido setof/3
esteja disponvel, uma tentativa de colorir a Amrica do Sul poderia ser a seguinte: Primeiro define-se
uma relao auxiliar:
pas(P) :- viz(P, _).
Ento uma consulta adequada para colorir a Amrica do Sul poderia ser formulada por:
?-setof(P/Cor, pas(P), Lista), cores(Lista).
O objetivo setof/3 ir primeiro construir uma lista de itens P/Cor, na qual as cores sero representadas
por variveis no-instanciadas. Depois o objetivo cores/1ir produzir a instanciao adequada. pro-
vvel, entretanto, que essa tentativa falhe devido sua ineficincia. Um estudo detalhado de como o
Prolog tenta satisfazer o objetivo cores/1 revela a fonte de tal ineficincia. Os pases em Lista so
organizados em ordem alfabtica, que no tem nada a ver com a sua disposio geogrfica. A ordem
em que as cores so atribudas aos pases corresponde ordem da Lista (comeando pelo final), o que
, no caso em questo, independente da relao viz/2. Assim, o processo de colorir os pases comea
em algum ponto do mapa, continua em um outro extremo, etc, movendo-se de forma mais ou menos
aleatria. Isso pode conduzir facilmente a uma situao na qual um pas que deva ser colorido encon-
tre-se rodeado por outros pases j coloridos com todas as quatro cores disponveis, sendo ento ne-
cessrio acionar o mecanismo de backtracking, com elevado nus para a eficincia do programa.
Fica claro ento que a eficincia depende da ordem na qual os pases sero coloridos. A intuio suge-
re uma estratgia simples de ordenao que apresenta um desempenho muito superior ao mtodo ale-
atrio. Comea-se com algum pas que tenha muitos vizinhos. Depois so coloridos os seus vizinhos.
Depois os vizinhos dos vizinhos e assim por diante. Para a Amrica do Sul, ento, o Brasil (que faz
fronteira com nove pases, parece ser um bom candidato para iniciar o processo. Assim, quando a lista
de Pas/Cor for construda, o Brasil deve ser colocado no fim, com todos os demais pases o antece-
dendo. Dessa forma o algoritmo, que comea a processar a partir do ltimo elemento da lista iniciar
com o Brasil e continuar dali a processar os pases vizinhos como foi explicado anteriormente.
Essa nova ordenao aumenta muito a eficincia do programa em comparao com a ordenao alfa-
btica original, produzindo sem dificuldade os possveis coloridos do mapa da Amrica do Sul.
Pode-se construir manualmente uma lista apropriada dos pases da Amrica do Sul, mas no neces-
srio fazer isso. O procedimento fazLista/1, definido abaixo executar essa tarefa para ns. Ele inicia
a construo com algum pas especificado (Brasil, no nosso caso) e coleta os pases em uma lista de-
nominada "Fechada". Cada pas , inicialmente colocado em outra lista, denominada "Aberta", antes
120
de ser transferido para Fechada. Toda vez que um pas for transferido de Aberta para Fechada, os seus
vizinhos sero colocados em Aberta.
fazLista(Lista) :-
coleta([brasil], [], Lista).
coleta([], Fechada, Fechada).
coleta([X | Aberta], Fechada, Lista) :-
membro(X, Fechada), !,
coleta(Aberta, Fechada, Lista).
coleta([X | Aberta], Fechada, Lista) :-
viz(X, Vizinhos),
conc(Vizinhos, Aberta, Aberta1),
coleta(Aberta1, [X | Fechada], Lista).
onde a relao conc/3 a relao j estudada anteriormente para a concatenao de listas.
12.5.2 APERFEIOANDO AS ESTRUTURAS DE DADOS
Nos programas apresentados at aqui, a concatenao de listas tem sido programada da seguinte ma-
neira:
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
Essa forma de programar a concatenao de listas pode tornar-se bastante ineficiente quando a primei-
ra lista muito longa, uma vez que esta deve ser inteiramente percorrida at que a lista vazia seja
encontrada. Para tornar a relao conc/3 verdadeiramente eficiente, deve-se pular diretamente para o
fim da primeira lista em um nico passo de computao. Isso somente possvel se soubermos locali-
zar o fim de uma lista, o que no pode ser feito a partir da representao adotada at o momento.
necessrio portanto uma nova representao para listas. Uma soluo possvel representar cada lista
por meio de um par de listas. Por exemplo, a lista [a, b, c] pode ser representada por meio de duas
listas:
L1 = [a, b, c, d, e] e L2 = [d, e]
Esse par de listas, que denotaremos por L1-L2, representa a diferena entre L1 e L2. Isso, natural-
mente, s vai funcionar se a lista L2 for um sufixo de L1. Note que a mesma lista pode ser representa-
da por diversos pares-diferena. Por exemplo, a lista [a, b, c] pode ser representada por:
[a, b, c] - []
[a, b, c, d, e] - [d, e]
[a, b, c, d | T] - [d | T]
[a, b, c, | T] - T
...
A lista vazia representada por qualquer par L-L. Como o segundo membro do par indica o final da
lista, este passa a poder ser acessado diretamente. Isso pode ser usado para uma implementao muito
mais eficiente da concatenao de listas. O mtodo proposto ilustrado na figura 12.1 e a correspon-
dente relao em Prolog que denominaremos concat/3 pode ser representada por um nico fato:
concat(A1-Z1, Z1-Z2, A1-Z2)
L1 L2
A1 Z1 A2 Z2
<------------------------------ L3 ------------------------------->
Figura 12.1 Concatenao de listas representadas por pares-diferena
Na figura acima. L1 representada por A1-Z1, L2 por A2-Z2 e o resultado, L3, por A1-Z2, o que
verdadeiro quando Z1=A2. Vamos usar a relao concat/3 para concatenar as listas [a, b, c] (repre-
121
sentada pelo par [a, b, c, | T1] - T1) e [d, e] (representada pelo par [d, e | T2] - T2). A concatenao
obtida pela simples unificao do objetivo proposto na consulta com a clusula que define concat/3.
?-concat([a, b, c | T1] - T1, [d, e | T2] - T2, Lista.
T1 = [d, e | T2]
Lista = [a, b, c, d, e | T2] - T2
12.5.3 DECLARAO DE FATOS INFERIDOS
Algumas vezes, durante a computao, o mesmo objetivo tem que ser satisfeito vrias vezes. Como o
Prolog no possui nenhum mecanismo adequado para identificar essa situao, toda a sequncia de
computaes ser repetida cada vez que o objetivo tiver de ser satisfeito. Como um exemplo, vamos
considerar um programa para computar o ensimo nmero da sequncia de Fibonacci. A sequncia de
Fibonacci :
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
onde cada nmero, com exceo dos dois primeiros, a soma dos dois nmeros anteriores. Definire-
mos um predicado fib(N, F) para computar para um dado nmero N, o ensimo numero F da sequn-
cia de Fibonacci. Contaremos os nmeros da sequncia iniciando com N=1. O programa a seguir trata
inicialmente os dois primeiros nmeros de Fibonacci como casos especiais e depois especifica a regra
geral para a gerao da seqncia.
fib(1, 1).
fib(2, 1).
fib(N, F) :-
N > 2,
N1 is N-1, fib(N1, F1),
N2 is N-2, fib(N2, F2),
F is F1+F2.
Esse programa tende a refazer partes da computao. Isso pode ser facilmente constatado se gerarmos
o tracing da execuo de uma consulta, por exemplo, ?-fib(6, F). A repetio desnecessria de com-
putaes intermedirias pode ser facilmente evitada se o programa "lembrar" cada um dos nmeros de
Fibonacci gerados como resultados parciais. A idia utilizar o predicado pr-definido assert/1 e adi-
cionar esses resultados parciais base de dados na forma de fatos. Esses fatos devem preceder todas
as outras clusulas sobre fib para prevenir o uso da regra geral nos casos em que o resultado j co-
nhecido. O procedimento modificado fibo/2 difere de fib/2 apenas pela incluso de um objetivo adici-
onal:
fibo(1, 1).
fibo(2, 1).
fibo(N, F) :-
N > 2,
N1 is N-1, fibo(N1, F1), N2 is N-2, fibo(N2, F2),
F is F1+F2,
asserta(fibo(N, F)).
Guardar os resultados intermedirios uma tcnica convencional para evitar computaes repetidas.
No caso dos nmeros de Fibonacci podemos evitar essa repetio por meio do uso de outro algoritmo,
diferente do proposto acima. Esse novo algoritmo produzir um programa mais difcil de entender,
porm de execuo mais eficiente. A idia bsica no definir o ensimo nmero de Fibonacci como
a simples soma de seus dois antecessores imediatos, deixando que chamadas recursivas completem o
processamento recuando at os dois primeiros nmeros de Fibonacci. Ao invs disso, podemos traba-
lhar "para frente" comeando com os dois nmeros iniciais e computando os nmeros na seqncia
natural, parando quando o ensimo nmero for encontrado. A maior parte do trabalho executada
pelo procedimento
geraFib(M, N, F1, F2, F)
122
onde F1, F2 e F so respectivamente o (M-1)-simo, o M-simo e o N-simo nmero da seqncia. O
procedimento geraFib/5 encontra uma seqncia de transformaes at atingir uma configurao final
(quando M=N), a partir de uma configurao inicial.
Quando geraFib/5 ativado, todos os argumentos, com exceo de F, devem estar instanciados e M
deve ser menor ou igual a N. O programa fica ento:
fibonacci(N, F) :-
geraFib(2, N, 1, 1, F).
geraFib(M, N, F1, F2, F) :-
M >= N.
geraFib(M, N, F1, F2, F) :-
M < M, ProxM is M+1, ProxF2 is F1+F2,
geraFib(ProxM, N, F2, ProxF2, F).
12.6 PROGRAMAO ITERATIVA
Como foi visto, Prolog uma linguagem recursiva, requerendo portanto uma certa maturidade em
termos de pensamento recursivo por parte de seus programadores. Tambm o backtracking uma
poderosa tcnica para os mais diversos propsitos. Por outro lado, recurso e backtracking so difceis
de combinar, porque a recurso constri estruturas durante chamadas sucessivas que so esquecidas
durante o backtracking, a menos que o predicado assert/1 (ou suas opes) seja empregado para lem-
br-las. Nesse caso porm a execuo do programa produz uma estrutura muito complexa e intrinca-
da.
Esta situao pode ser melhorada com o emprego de algumas tcnicas de programao estruturada.
Nem todos os problemas recursivos o so no sentido profundo da palavra. Alguns so apenas "iterati-
vos" e devem ser reconhecidos como tal. Um predicado pr-definido desenvolvido para executar ite-
rao o repeat/0, que se comporta exatamente como se houvesse sido definido por:
repeat.
repeat :- repeat.
Por exemplo, um lao para executar processamento de entrada e sada poderia assumir a forma se-
guinte:
loop :-
repeat,
read(X),
(X = fim, !; processa(X,Y), write(Y), nl, fail).
Tal procedimento ir ler um termo, process-lo, imprimir alguma sada e falhar, ocasionando por
backtracking a repetio destas operaes at que o termo lido seja "fim".
Considere agora um programa para imprimir todos os elementos de uma lista L. Uma soluo recursi-
va seria:
imprimeLista([]).
imprimeLista([X | Y]) :-
write(X), nl, imprimeLista(Y).
Esse padro de recurso comum em Prolog. Pode-se entretanto generaliz-lo definindo um predica-
do:
for(X, Y) :-
X, Y, fail.
for(X, Y).
de modo que para todas as solues de X, Y ser ativado. O lao produzido pelo predicado for/2 ter-
mina quando no houver mais solues para X. A impresso de todos os elementos de uma lista as-
sumiria ento a forma abaixo:
imprimeLista(L) :-
for(membro(X, L), (write(X), nl)).
123
Um outro exemplo seria o problema de listar todos os nmeros de um a dez. Uma soluo recursiva
seria:
listaNmeros(N) :- N > 10, !.
listaNmeros(N) :-
write(N), nl, N1 is N+1, listaNmeros(N1).
?-listaNmeros(1).
1
2
...
10
Ao invs disso definiremos um predicado in/3 que, por backtracking, retorna com os valores de 1 a N:
in(I, I, H) :-
H >= I.
in(I, L, H) :-
N is L+1, in(I, N, H).
?-for(in(I, 1, 10), (write(I), nl)).
O predicado for/3 pode ser combinado de diversas formas diferentes. Por exemplo, para imprimir
tabelas de multiplicao:
tabMult :-
for(in(I, 1, 10),
(for(in(J, 1, 10),
(K is I*J, out(K))), nl)).
out(X) :-
write(X), write(' ').
Como uma aplicao do conceito acima, e ao mesmo tempo como um exerccio de utilizao de ope-
radores, eis como possvel fazer programas iterativos em Prolog se parecerem com Pascal:
:-op(1110, xfy, do).
:-op(1109, fx, for).
:-op(1108, xfx, to).
:-op(1107, fx, begin).
:-op(700, xfx, ':=').
do1(begin end) :- !.
do1(begin X ; Y) :- !, do1(X), do1(begin Y).
do1(begin X) :- !, do1(X).
do1(X) :- X.
X := Y :- X is Y.
(for X := Y to Z do U) :- for(in(X, Y, Z), do1(U)).
writeln(X) :- write(X), nl.
A partir da definio acima, podemos escrever o seguinte programa para calcular e imprimir os qua-
drados dos nmeros de 1 a 10:
quadrados :-
for I := 1 to 10 do
begin
K := I*I;
writeln(K);
end.
Essa construo, apesar da aparncia, continua sendo um programa em Prolog. Deve-se entretanto
advertir o leitor para no tomar esse exemplo como uma tentativa sria de implementar um interpreta-
dor Pascal em Prolog. Por exemplo, difcil modelar estruturas aninhadas tais como begin-end, por-
que tais constantes so na verdade delimitadores, como os parnteses, e no operadores.
RESUMO
H diversos critrios para a avaliao de programas, entre outros:
Correo;
124
Eficincia;
Transparncia e Legibilidade;
Modificabilidade;
Robustez;
Documentao.
O princpio dos refinamentos sucessivos uma boa maneira de organizar o processo de desen-
volvimento de programas. Em Prolog essa tcnica pode ser tanto aplicada s relaes e algorit-
mos quanto s estruturas de dados;
As seguintes tcnicas frequentemente auxiliam o programador Prolog a encontrar idias para os
refinamentos:
Recurso;
Generalizao;
Uso de Grficos.
de grande utilidade o emprego de convenes de estilo para reduzir o perigo de erros de pro-
gramao e tornar os programas mais fceis de ler, depurar e modificar;
As diferentes implementaes da linguagem Prolog normalmente oferecem ferramentas auxilia-
res para a depurao de programas, dentre as quais o mecanismo de tracing uma das mais
teis;
Maneiras de aumentar a eficincia de programas Prolog so:
Reordenao de objetivos e clusulas;
Controle do backtracking por meio de cuts;
Uso de assert/1 para evitar recomputao;
Uso de algoritmos e estruturas mais eficientes;
Uso de iterao preferivelmente recurso.
EXERCCIOS
12.1 Defina um predicado para inverter o predicado que encontra a soma dos elementos em uma lista
de valores inteiros.
12.2 Defina um programa que registre os elementos de uma lista nomeada como fatos individualmente
numerados. Por exemplo:
enumera(tab, [a, b, p(c), a])
produziria os seguintes fatos:
elem(tab, 1, a).
elem(tab, 2, b).
elem(tab, 3, p(c)).
elem(tab, 4, a).
12.3 Defina a relao adiciona(Lista, Item, NovaLista) para adicionar Item ao final de Lista produzin-
do NovaLista, sendo que tanto Lista quanto NovaLista devem ser representadas por pares-
diferena.
12.4 Defina a relao inverte(Lista, ListaInvertida) onde ambas as listas so representadas por pares-
diferena.
12.5 Defina os operadores e as relaoes necessrias para representar as construes if-then-else e
while-do no estilo Pascal.
125
13. OPERAES SOBRE ESTRUTURAS DE DADOS
Uma questo fundamental da programao como representar objetos complexos, tais como conjun-
tos e implementar operaes eficientes sobre tais objetos. Como foi visto no captulo anterior, a sele-
o da estrutura de dados apropriada essencial para garantir a eficincia de tais operaes. No pre-
sente captulo sero examinadas as estruturas de dados mais frequentemente utilizadas, que pertencem
a trs grandes famlias: listas, rvores e grafos, e diversos exemplos sero desenvolvidos visando
ilustrar o seu uso e adequao.
13.1 CLASSIFICAO EM LISTAS
Classificao uma operao frequentemente necessria em diversos contextos. Uma lista pode ser
classificada desde que haja uma relao de ordem entre os elementos que a compem. Para os prop-
sitos assume-se a relao de ordem representada por
mq(X, Y)
significando que "X maior que Y", independentemente do que significa "maior que". Se os itens da
lista so nmeros, ento a relao mq/2 ser talvez definida por:
mq(X, Y) :- X > Y.
Se os itens da lista so tomos, ento a relao mq pode corresponder, por exemplo, ordem do cdi-
go ASCII correspondente aos caracteres. Vamos considerar que
classifica(Lista, Sada)
denote uma relao onde Lista uma lista de itens e Sada uma lista dos mesmos itens classificados
em ordem crescente, de acordo com a relao mq/2. Desenvolveremos trs definies de tal relao
em Prolog, baseadas em diferentes idias sobre a classificao de listas. A primeira delas bastante
simples, chegando a ser ingnua: Para classificar uma lista Lista:
(1) Encontre dois elementos adjacentes, X e Y, nesta ordem em Lista, tais que mq(X, Y). Troque as
posies de X e Y, obtendo Lista1 e, depois, classifique Lista1;
(2) Se no houver nenhum par de elementos adjacentes, X e Y, nesta ordem em Lista, ento esta j
est classificada.
O propsito da troca das posies dos itens X e Y, que aparecem fora de ordem em Lista que, aps a
troca, a nova lista obtida est mais prxima de ser uma lista classificada.. Aps um determinado n-
mero de trocas de posio, a lista estar completamente ordenada. Esse princpio de classificao
denominado "bubble sort" (ou classificao "blha"). A relao correspondente, bubblesort/2, apre-
sentada abaixo:
bubblesort(Lista, Sada) :-
troca(Lista, Lista1), !, bubblesort(Lista1, Sada).
bubblesort(Sada, Sada).
troca([X, Y | Resto], [Y, X | Resto]) :-
mq(X, Y).
troca([Z | Resto], [Z | Resto1]) :-
troca(Resto, Resto1).
Um outro algoritmo simples de classificao o sort por insero (insert sort), que se baseia na se-
guinte idia: Para classificar uma lista no vazia, L = [X | R]:
(1) Classifique o corpo R da lista L;
(2) Insira a cabea, X, de L no corpo classificado em uma posio tal que a lista resultante esteja classificada.
O resultado a lista completamente classificada. Esse algoritmo representado em Prolog pela rela-
o insertsort/2:
126
insertsort([], []).
insertsort([X | Resto], Sada) :-
insertsort(Resto, Resto1), insere(X, Resto1, Sada).
insere(X, [Y | Sada], [Y | Sada1]) :-
mq(X, Y), !, insere(X, Sada, Sada1).
insere(X, Sada, [X | Sada]).
Os procedimentos de classificao bubblesort/2 e insertsort/2 so simples, porm ineficientes. Dos
dois, o ltimo o mais eficiente, entretanto, o tempo mdio que o insertsort/2 requer para classificar
uma lista de tamanho n cresce proporcionalmente a n
2
. Para listas muito longas, portanto, um algorit-
mo melhor o quicksort/2, baseado na idia abaixo e ilustrado na Figura 13.1. Para classificar uma
lista no vazia, L:
(1) Separe algum elemento X de L e divida o restante em duas listas, denominadas Menor e Maior,
da seguinte maneira: Todos os elementos de L que so maiores do que X pertencem a Maior e
os restantes pertencem a Menor;
(2) Classifique Menor, obtendo Menor1;
(3) Classifique Maior, obtendo Maior1;
(4) A lista completa a concatenao de Menor1 com [X | Maior1].
[5, 3, 7, 8, 1, 4, 7, 6]
[3, 7, 8, 1, 4, 7, 6]
retira X=5
[3,1, 4] [7, 8, 7, 6]
[1. 3, 4] [6, 7, 7, 8]
[3, 7, 8, 1, 4, 7, 6]
todos > 5
classifica
adiciona X
todos =< 5
classifica
concatena
Figura 13.1: Classificando uma lista com o algoritmo quicksort/2
Se a lista a ser classificada estiver vazia, ento o resultado da classificao tambm uma lista vazia.
Uma implementao do quicksort/2 em Prolog apresentada na Figura 13.2. Um detalhe particular
dessa implementao que o elemento X que retirado de L sempre a cabea da lista. O procedi-
mento que divide L em Maior e Menor uma relao de quatro argumentos:
divide(X, L, Maior, Menor)
A complexidade temporal deste algoritmo depende de nossa sorte ao dividirmos a lista a ser classifi-
cada. Se a lista for dividida em duas outras com aproximadamente o mesmo tamanho, ento a com-
plexidade temporal do procedimento ser proporcional a n.log(n), onde n o tamanho da lista a classi-
ficar. Se, ao contrrio, a diviso resultar em duas listas de tamanho muito desigual, ento a complexi-
dade ser da ordem n
2
. Anlises mais acuradas mostram que, felizmente, o desempenho mdio do
algoritmo quicksort/2 se aproxima bem mais da primeira situao do que da segunda.
127
quicksort([X | R], Sada) :-
divide(X, R, Maior, Menor),
quicksort(Menor, Menor1),
quicksort(Maior, Maior1),
conc(Menor1, [X | Maior1], Sada).
divide(X, [], [], []).
divide(X, [Y | R], [Y | Menor], Maior) :-
mq(X, Y), !, divide(X, R, Menor, Maior).
divide(X, [Y | R], Menor, [Y | Maior]) :-
divide(X, R, Menor, Maior).
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
Figura 13.2: Uma implementao do algoritmo quicksort/2 em Prolog
13.2 REPRESENTAO DE CONJUNTOS
Uma aplicao usual para listas a representao de conjuntos de objetos, entretanto, tal representa-
o no adequada, uma vez que o teste de ocorrncia de um item em uma lista se mostra relativa-
mente ineficiente como teste de pertinncia de um elemento a um conjunto. O predicado membro(X,
L), que verifica se X membro da lista L, usualmente programado como:
membro(X, [X | _ ]).
membro(X, [_ | Y]) :-
membro(X, Y).
Para encontrar X em uma lista L, esse procedimento percorre a lista elemento por elemento at que X
seja encontrado ou o fim da lista seja atingido. Isso se torna especialmente ineficiente no caso de lis-
tas muito longas. Para a representao de conjuntos h diversas estruturas em rvore que possibilitam
uma implementao muito mais eficiente da relao de pertinncia. Vamos considerar neste ponto as
denominadas "rvores binrias". Uma rvore binria, ou vazia, ou constituda por trs argumentos:
(1) uma raiz,
(2) uma sub-rvore esquerda, e
(3) uma sub-rvore direita.
A raiz pode ser qualquer coisa, mas as sub-rvores devem necessariamente ser rvores. Na Figura
13.3, apresentado um exemplo. A rvore ali mostrada representa o conjunto {a, b, c, d}. Os ele-
mentos do conjunto so armazenados nos nodos da rvore e, normalmente, sub-rvores vazias no so
representadas. Por exemplo, o nodo "b" possui duas sub-rvores que so ambas vazias.
a
b c
d
raiz
sub-rvore
esquerda
sub-rvore
direita
Figura 13.3 Uma rvore binria
H diversas maneiras de se representar uma rvore binria atravs de um termo Prolog. Uma possibi-
lidade simples tornar a raiz da rvore o functor principal do termo e as sub-rvores os seus argu-
mentos. Assim a rvore da Figura 13.3 seria representada pelo termo:
a(b, c(d)).
128
Entre outras desvantagens, essa representao requer um novo functor para cada nodo da rvore. Isso
pode ocasionar problemas, se os nodos, por sua vez, forem objetos estruturados. Uma maneira melhor
e mais usual de representar rvores binrias o seguinte: Emprega-se um smbolo especial para repre-
sentar a rvore vazia e um functor para representar rvores no-vazias a partir de seus trs compo-
nentes (a raiz e as duas sub-rvores). Assumiremos o seguinte:
A rvore vazia ser representada pelo tomo "nil", e
Ser empregado um functor t, de forma que a rvore que possui uma raiz R, uma sub-rvore es-
querda E e uma sub-rvore direita D seja representada pelo termo:
t(E, R, D).
Nessa representao a rvore da Figura 13.3 corresponderia ao termo:
t(t(nil, b, nil), a, t(t(nil, d, nil), c, nil))
Vamos agora considerar a relao de pertinncia para conjuntos, que denominaremos pertence/2. O
objetivo pertence(X,T) verdadeiro se X um nodo da rvore T. A relao pertence/2 pode ser defi-
nida da seguinte maneira:
X pertence a uma rvore T se:
A raiz de T X, ou
X est na sub-rvore esquerda de T, ou
X est na sub-rvore direita de T.
Tais regras podem ser traduzidas diretamente para Prolog, da seguinte maneira:
pertence(X, t(_, X, _)) :- !.
pertence(X, t(E, _, _)) :-
pertence(X, E).
pertence(X, t(_, _, D)) :-
pertence(X, D).
5
3 8
1 4 6 9
7
Figura 13.4: Um dicionrio binrio
Obviamente o objetivo pertence(X, nil) ir falhar para qualquer valor de X. Vamos investigar agora o
comportamento do predicado pertence/2. Considerando a rvore apresentada na Figura 13.3, temos:
?-pertence(X, T).
X=a; X=b; X=c; X=d;
no
onde os valores de X so obtidos por backtracking. Sob o ponto de vista da eficincia, entretanto, o
procedimento pertence/2 to ineficiente quanto o emprego do predicado membro/2. Um aumento
considervel de eficincia poder entretanto ser obtido se houver uma relao de ordem entre os ele-
mentos do conjunto. Ento os dados na rvore podem ser ordenados da esquerda para a direita de
acordo com essa relao de ordem. Dizemos que uma rvore no-vazia t(E, R, D) est ordenada da
esquerda para a direita se:
(1) Todos os nodos na sub-rvore E so menores do que X,
(2) Todos os nodos na sub-rvore D so maiores do que X, e
129
(3) Ambas as sub-rvores esto tambm ordenadas.
Tal rvore binria denominada um "dicionrio binrio". Um exemplo apresentado na Figura 13.4.
13.3 DICIONRIOS BINRIOS
A vantagem da ordenao que, para procurar um objeto em um dicionrio binrio suficiente pes-
quisar no mximo uma sub-rvore. A chave dessa economia, na busca por um elemento X que po-
demos comparar X e a raiz, imediatamente descartando pelo menos uma sub-rvore. Por exemplo, a
pesquisa pelo elemento 6 na Figura 13.4 est indicada em negrito e corresponde ao seguinte:
Comea-se na raiz, 5;
Compara-se 6 com 5, estabelecendo que 6>5;
A pesquisa continua na sub-rvore direita;
Compara-se 6 com 8, estabelecendo que 6<8;
A pesquisa continua na sub-rvore esquerda;
Compara-se 6 com 6, estabelecendo que 6=6;
A pesquisa encerrada com sucesso.
O mtodo de pesquisa em um dicionrio binrio , portanto:
Para encontrar um item X em um dicionrio binrio D:
Se X a raiz de D, ento X j foi encontrado, seno
Se X menor do que a raiz de D, ento X deve ser procurado na sub-rvore esquerda de D, se-
no
Procurar X na sub-rvore direita de D, e
Se D estiver vazio a pesquisa falha.
Essas regras so programadas em Prolog como o procedimento pertence/2, mostrado abaixo na Figura
13.5, onde a relao mq(X, Y) significa que X maior do que Y. Se os itens armazenados na rvore
so numricos, ento a relao simplesmente X > Y.
pertence(X, t(_,X,_)).
pertence(X, t(E, R, _)) :-
mq(R, X), pertence(X, E).
pertence(X, t(_, R, D) :-
mq(X, R), pertence(X, D).
Figura 13.5: Encontrando um item X em um Dicionrio Binrio
O procedimento pertence/2 pode tambm ser empregado para construir um dicionrio binrio. Por
exemplo, a consulta abaixo ir construir um dicionrio binrio D que contm os elementos 5, 3 e 8:
?-pertence(5, D), pertence(3, D), pertence(8, D).
D=t(t(D1, 3, D2), 5, t(D3, 8, D4))
As variveis D1, D2, D3 e D4 so sub-rvores no especificadas, que podem conter qualquer coisa. O
dicionrio que ser construdo ir depender da ordem dos objetivos na consulta.
Um comentrio sobre a eficincia da pesquisa em dicionrios binrios interessante neste ponto. Em
geral a busca por um item em um dicionrio binrio bem mais eficiente do que em uma lista. Tal
eficincia devida ao seguinte: Vamos supor que n seja o nmero de itens em nosso conjunto de da-
dos. Se o conjunto representado por uma lista. ento o tempo esperado de pesquisa proporcional
ao tamanho n da lista. Em mdia iremos pesquisar a lista at a metade para encontrar um determinado
item, se os valores tiverem uma distribuio normal. Agora, se o conjunto for representado por um
dicionrio binrio, o tempo de procura ser proporcional "altura" da rvore, representada pelo maior
caminho entre a raiz e uma folha da rvore, dependendo portanto de sua conformao.
Diz-se que uma rvore binria (aproximadamente) balanceada se, para cada nodo da rvore, as duas
130
sub-rvores so (aproximadamente) do mesmo tamanho, isto , acomodam o mesmo nmero de itens.
Se um dicionrio de n nodos balanceado de maneira tima, ento sua altura proporcional a log(n).
Pode-se dizer ento que uma rvore balanceada possui complexidade logartmica. A diferena entre n
e log(n) o ganho de eficincia que um dicionrio binrio possui sobre uma lista. Isso vale entretanto
somente quando a rvore for aproximadamente balanceada. Se a rvore se afasta de uma conformao
balanceada, ento o seu desempenho ir degradar. Em casos extremos, de rvores completamente
desbalanceadas, uma rvore fica reduzida a uma lista, tanto em conformao quanto em desempenho.
13.4 INSERO E REMOO DE ITENS EM DICIONRIOS BINRIOS
Na manuteno de um conjunto dinmico de dados, pode-se desejar inserir novos dados ou remover
dados desatualizados do conjunto. Assim, um repertrio comum de operaes sobre um conjunto S de
dados dado na tabela abaixo:
RELAO SIGNIFICADO
pertence(X, S) X pertence a S
inserir(S, X, S1) Inserir X em S produzindo S1
remover(S, X, S1) Remover X de S produzindo S1
A relao pertence/2 foi definida na seo anterior. Definiremos agora a relao insere/3. mais fcil
inserir novos dados no nvel mais "alto" de uma rvore, de modo que um novo item se torna uma "fo-
lha" da rvore em uma posio tal que a ordenao da rvore seja preservada. Representaremos esse
tipo de insero por:
insFolha(D, X, D1)
cujas regras so as seguintes:
O resultado da insero de X a uma rvore vazia a rvore t(nil,X,nil);
Se X a raiz de D, D1=D (itens duplicados no so inseridos);
Se a raiz de D maior do que X, ento X deve ser inserido na sub-rvore esquerda de D. Caso
contrrio X deve ser inserido na sub-rvore direita de D.
Na Figura 13.6, as rvores correspondem a seguinte sequncia de inseres:
insFolha(D1, 6, D2),
insFolha(D2, 7, D3),
insFolha(D3, 4, D4).
para a relao insFolha/3, definida pelo procedimento abaixo:
insFolha(nil, X, t(nil, X, nil)).
insFolha(t(E, X, D), X, t(E, X, D)).
insFolha(t(E, R, D), X, t(E1, R, D)) :-
mq(R, X), insFolha(E, X, E1).
insFolha(t(E, R, D), X, t(E, R, D1)) :-
mq(X, R), insFolha(D, X, D1).
Vamos agora considerar a operao remover/3. fcil remover uma folha, mas a remoo de um nodo
mais complicada. A remoo de uma folha pode, na verdade, ser definida como o inverso da inser-
o, isto :
remFolha(D1, X, D2) :-
insFolha(D2, X, D1).
131
5
3 8
5
3 8
6
5
3 8
5
3 8
6 6
7 7
D1 D2
D3 D4
4
Figura 13.6: Insero ao nvel de folha em um dicionrio binrio
Entretanto, se X um nodo interno, isso no vai funcionar, devido ao problema ilustrado na Figura
13.7: X tem duas sub-rvores, E e D. Aps a remoo de X ficamos com uma lacuna na rvore e E e D
ficam desconectadas do restante dela, sem possibilidade de se conectarem ao nodo pai de X, A, uma
vez que este pode somente acomodar uma delas.
A
X
E D
A
?
E D
remove X
------------------------>
Figura 13.7: O problema de remover um nodo interior em um dicionrio binrio
Se uma das duas sub-rvores, E ou D, estiver vazia, ento a soluo simples: A sub-rvore no-vazia
conectada a A. Se ambas forem no-vazias, ento uma idia a seguinte: O nodo mais esquerda de
D, digamos Y, removido de sua posio e conduzido a ocupar a lacuna deixada por X. Aps esta
transferncia, a rvore resultante continuar ordenada. Naturalmente a mesma idia funciona simetri-
camente, com a transferncia do nodo mais direita de E. De acordo com essas consideraes, a ope-
rao de remover um item de um dicionrio binrio pode ser programada conforme mostrado na
Figura 13.8. A transferncia do nodo mais esquerda da sub-rvore direita realizada pela relao:
trans(T, Y, T1)
onde Y o nodo mais esquerda de T e T1 T aps remover Y.
H ainda uma outra soluo, mais elegante, para as relaes de insero e remoo de nodos. Uma
relao insere/3 pode ser definida, de forma no-determinstica, de maneira que um novo item seja
inserido em qualquer nvel da rvore e no apenas como um nodo folha. As regras correspondentes
so:
Para inserir um nodo X em um dicionrio binrio D:
Inserir X como raiz de D, ou
132
remove(t(nil, X, D), X, D).
remove(t(E, X, nil), X, E).
remove(t(E, X, D), X, t(E, Y, D1)) :-
trans(D, Y, D1).
remove(t(E, R, D), X, t(E1, R, D)) :-
mq(R, X)), remove(E, X, E1).
remove(t(E, R, D), X, t(E, R, D1)) :-
mq(X, R), remove(D, X, D1).
trans(t(nil, Y, D), Y, D).
trans(t(E, R, D), Y, t(E1, R, D)) :-
trans(E, Y, E1).
Figura 13.8: Removendo um nodo interior em um dicionrio binrio
Se a raiz de D maior do que X, ento inserir X na sub-rvore esquerda de D. Caso contr-
rio inserir X na sub-rvore direita de D.
A dificuldade aqui a insero de X como raiz de D. Vamos formular essa operao como a relao:
insRaiz(D, X, D1)
onde X o item a ser inserido como raiz de D e D1 o dicionrio resultante, com X como raiz. A
figura 13.9 ilustra as relaes entre X, D e D1.
Y
E D
X
E1 Y
X
Y D1
E2 D E D2
ou
Figura 13.9: Insero de um item X como raiz de um dicionrio binrio
A questo agora : O que so as sub-rvores E1 e E2 na figura 13.9? (ou D1 e D2, altenativamente). A
resposta deriva das seguintes restries:
E1 e E2 devem ser, necessariamente, dicionrios binrios;
O conjunto de nodos em E1 e E2 igual ao conjunto de nodos em E;
Todos os nodos em E1 so menores do que X e todos os nodos em E2 so maiores do que X.
A relao que impe todas essas restries exatamente a relao procurada, insRaiz/3. Assim, se X
foi inserido em E como raiz, ento as sub-rvores resultantes so E1 e E2 que, em Prolog, devem sa-
tisfazer a:
insRaiz(E, X, t(E1, X, E2))
assim como se X for inserido em D, D1 e D2 devem respeitar:
insRaiz(D, X, t(D1, X, D2))
A Figura 13.10 apresenta o programa completo para a insero no-determinstica em um dicionrio
binrio. A caracterstica principal de tal programa que no h restrio quanto ao nvel de insero.
Assim, insere/3 pode ser empregada na direo inversa para a remoo de um item do dicionrio.
133
insere(DB, X, DB1) :-
insRaiz(DB, X, DB1).
insRaiz(nil, X, t(nil, X, nil)).
insRaiz(t(E, X, D), X, t(E, X, D)).
insRaiz(t(E, Y, D), X, t(E1, X, t(E2, Y, D))) :-
mq(Y, X), insRaiz(E, X, t(E1, X, E2)).
insRaiz(t(E, Y, D), X, t(t(E, Y, D1), X, D2)) :-
mq(X, Y), insRaiz(D, X, t(D1, X, D2)).
Figura 13.10: Insero no-determinstica em um dicionrio binrio
13.5 APRESENTAO DE RVORES
Como todos os objetos em Prolog, uma rvore binria pode ser apresentada por meio do predicado
embutido write/1. Entretanto o objetivo write(T) ir apresentar toda a informao contida em T, sem
indicar graficamente a real estrutura de uma rvore. Pode ser bastante cansativo imaginar a estrutura
de uma rvore a partir do termo Prolog que a representa. Assim muitas vezes desejvel se dispor de
um procedimento que permita a representao grfica de sua estrutura.
H um mtodo relativamente simples de apresentar graficamente a estrutura de rvores binrias. O
truque apresentar a rvore da esquerda para a direita, e no da raiz para as folhas, como so usual-
mente representadas. Vamos definir um procedimento, apresenta(T) para apresentar desse modo a
estrutura de uma rvore T. O princpio o seguinte:
Para apresentar uma rvore no-vazia T:
Apresentar a sub-rvore esquerda de T, identada por alguma distncia, H, para a direita,
Apresentar a raiz de T, e
Apresentar a sub-rvore direita de T, identada por alguma distncia, H, para a direita.
A distncia de identao, H, que pode ser adequadamente escolhida, um parmetro adicional para a
identao de rvores. Pela introduo de H, precisamos de um procedimento, ap(T, H), para apresen-
tar T identada H espaos a partir da margem esquerda. A relao entre os procedimentos apresenta/1 e
ap/2 a seguinte:
apresenta(T) :- ap(T, H).
A Figura 13.11 mostra o procedimento apresenta/1 codificado em Prolog. O princpio adotado para
obter esse formato de sada pode ser facilmente adaptado para a apresentao dos mais diversos tipos
de rvores.
apresenta(T) :- ap(T, 0).
ap(nil, _).
ap(t(E, R, D), H) :-
H2 is H+2,
ap(D,H2),
tab(H), write(R), nl,
ap(E,H2).
Figura 13.11: Apresentao de uma rvore Binria
13.6 GRAFOS
13.6.1 REPRESENTAO
As estruturas em forma de grafos so empregadas em diversas aplicaes, tais como a representao
134
de relaes, situaes e problemas. Um grafo definido por um conjunto de nodos e um conjunto de
arestas, onde cada aresta interliga um par de nodos. Quando as arestas so direcionadas, so tambm
denominadas arcos. Os arcos so representados por meio de pares ordenados. Os grafos assim consti-
tudos so denominados grafos direcionados. Aos arcos podem ser associados custos, nomes ou qual-
quer tipo de rtulo, dependendo da aplicao. Na figura 13.12 so apresentados exemplos de grafos.
b
a c
d
t
s v
u
3
1
2
5
2
(a) (b)
Figura 13.12: (a) Grafo. (b) Grafo direcionado com custos associados aos arcos
Os grafos podem ser representados em Prolog de diversas maneiras. Um mtodo representar cada
aresta ou arco separadamente, por meio de uma clusula. Por exemplo, os grafos da figura acima po-
dem ser representados pelos seguintes conjuntos de clusulas:
conecta(a, b). arco(s, t, 3).
conecta(b, c). arco(t, u, 5).
conecta(c, d). arco(t, v, 1).
conecta(d, b). arco(v, u, 2).
arco(u, t, 2).
Um outro mtodo representar o grafo completo, como um nico objeto. Um grafo pode ser ento
representado por um par de conjuntos: nodos e arcos. Vamos escolher o functor grafo/2 para combinar
esses conjuntos em um par, e o functor ar/2 para as arestas. Ento o grafo da Figura 13.12(a) pode ser
representado por:
G1 = grafo([a,b,c,d],[ar(a,b),ar(b,c),ar(b,d),ar(c,d)])
Para representar um grafo direcionado escolheremos os functores grd/2 para o grafo e a/3 para os
arcos. A representao do grafo direcionado apresentado na Figura 13.12(b) fica ento:
G2 = grd([s,t,u,v],[a(s,t,3),a(t,v,1),a(t,u,5),a(u,t,2), a(v,u,2)])
Se cada nodo estiver conectado a pelo menos um outro nodo - isto : no h nodos "soltos" - o grafo
denominado "conexo". Na representao de grafos conexos pode-se omitir a lista de nodos, uma vez
que esta fica implicitamente definida pela lista de arestas.
Ainda um outro mtodo para representar grafos em Prolog associar a cada nodo a lista de todos os
nodos que lhe so adjacentes. Nessa representao um grafo uma lista de pares constitudos por um
nodo e a sua correspondente lista de nodos adjacentes. Os grafos anteriormente exemplificados podem
ento ser representados por:
G1 = [a [b], b [a, c, d], c [b, d], d [b, c]]
G2 = [s [t/3], t [u/5, v/1], u [t/2], v [u/2]]
onde os smbolos "" e "/" so operadores infixos.
A representao mais adequada vai naturalmente depender da aplicao e das operaes que devero
ser executadas sobre os grafos. Duas operaes tpicas so:
Encontrar um caminho entre dois nodos dados, e
Encontrar um subgrafo com alguma propriedade caracterstica.
135
13.6.2 CAMINHAMENTO EM GRAFOS
Seja G um grafo e A e Z dois nodos de G> Vamos definir uma relao
caminho(A, Z, G, C)
onde C um caminho acclico entre A e Z em G. O caminho C representado por uma lista de nodos.
Se G o grafo representado na Figura 13.12(a), ento podemos escrever, por exemplo:
caminho(a, d, G, [a, b, d])
caminho(a, d, G, [a, b, c, d])
Uma vez que o caminho no deve conter nenhum ciclo, cada nodo pode aparecer na lista no mximo
uma vez. Um mtodo para se encontrar um caminho entre dois nodos em um grafo o seguinte:
Para encontrar um caminho acclico C entre os nodos A e Z de um grafo G:
Se A = Z, ento C = [A], seno
Encontrar um caminho acclico C1, de algum nodo Y at o nodo Z e encontrar um cami-
nho de A at Y, evitando os nodos em C1.
Essa formulao implica em outra relao: Encontre um caminho sob a restrio de evitar um deter-
minado conjunto de nodos. Assim, definiremos um segundo procedimento:
caminho1(A, C1, G, C)
cuja relao com o procedimento caminho/4 mostrada na Figura 13.13 a seguir:
A X
<----------------- caminho1 ----------------->
<---------------------------------------------- caminho1 -------------------------------------------------->
Y Z ... ... ...
Figura 13.13: Relao entre os procedimentos caminho/4 e caminho1/4
Como ilustrado na Figura 13.13, os argumentos do procedimento caminho1/4 so:
A, que um nodo,
G, que um grafo,
C1, que um caminho acclico em G, e
C, que um caminho acclico em G, de A at o incio de C1 e continuando ao longo de C1 at o
seu final.
A relao entre caminho/4 e caminho1/4 dada por:
caminho(A, Z, G, C) caminho(A, [Z], G, C).
A Figura 13.13 sugere uma definio recursiva de caminho1/4. O caso bsico surge quando o nodo
inicial de C1 (Y, na figura) coincide com o nodo inicial de C, que A. Se isso no ocorrer, ento deve
haver um nodo X tal que:
(1) Y adjacente a X,
(2) X no est em C1, e
(3) C satisfaz a caminho1(A, [X | C1], G, C)
O programa completo apresentado na Figura 13.14, abaixo, onde membro/2 a relao de ocorrn-
cia para listas e a relao adjacente(X, Y, G) significa que h um arco conectando os nodos X e Y no
grafo G.
caminho(A, Z, G, C) :-
136
caminho1(A, [Z], G, C).
caminho1(A, [A | C1], _, [A | C1]).
caminho1(A, [Y | C1], G, C) :-
adjacente(X, Y, G),
not membro(X, C1),
caminho1(A, [X, Y | C1], G, C).
adjacente(X, Y, grafo(Nodos, Arestas)) :-
membro(ar(X, Y), Arestas);
membro(ar(Y, X), Arestas).
Figura 13.14: Encontrando caminhos acclicos entre os nodos A e Z no grafo G
Um problema clssico sobre estruturas em grafo encontrar um caminho "hamiltoniano", isto , um
caminho acclico que percorra todos os nodos do grafo. Usando o procedimento caminho/4, anterior-
mente definido, isso pode ser realizado da maneira apresentada abaixo, onde nodo(N, Grafo) significa
que N um nodo do grafo Grafo.
hamiltoniano(Grafo, Caminho) :-
caminho( _, _, Grafo, Caminho),
cobre(Caminho, Grafo).
cobre(Caminho, Grafo) :-
not(nodo(N, Grafo), not membro(N, Caminho).
Pode-se associar custos aos caminhos em um grafo. O custo total de um caminho a soma dos custos
associados aos arcos que formam o caminho. Se no h custos associados aos arcos, ento pode-se
falar sobre a "extenso" do caminho, contando uma unidade para cada um dos arcos que o constituem.
As relaes caminho/4 e caminho1/4 podem ser modificadas de modo a manipular os custos, por meio
da introduo de um argumento adicional para cada caminho:
caminho(A, Z, G, C, Custo)
e
caminho1(A, C1, Custo1, G, C, Custo)
onde Custo o custo do caminho C e Custo1 o custo do caminho C1. A relao adjacente/5 tam-
bm resultado da adio de um argumento extra - o custo de um arco - relao original adjacente/4.
A Figura 13.15 mostra um programa que computa caminhos e os seus custos, podendo ser utilizado
para encontrar um "caminho de custo mnimo" entre dois nodos de um grafo. Isso obtido por meio
dos objetivos:
?-caminho(n1, n2, G, CaminhoMin, CustoMin),
not(caminho(n1, n2, G, _, Custo), Custo < CustoMin).
caminho(A, Z, G, C, Custo) :-
caminho1(A, [Z], 0, G, C, Custo).
caminho1(A, [A | C1], Custo1, G, [A | C1], Custo1).
caminho1(A, [Y | C1], Custo1, G, C, Custo) :-
adjacente(X, Y, CustoXY, G),
not membro(X, C1),
Custo2 is Custo1+CustoXY,
caminho1(A, [X, Y | C1], Custo2, G, C, Custo).
Figura 13.15: C um caminho acclico de A a Z em G cujo custo Custo
De modo semelhante tambm possvel encontrar um "caminho de custo mximo" entre qualquer par
de nodos em um grafo G atravs da conjuno de objetivos abaixo:
?-caminho(_, _, G, CaminhoMax, CustoMax),
not(caminho(_, _, G, _, Custo), Custo > CustoMax).
Deve-se ressaltar que esse mtodo de encontrar caminhos de custo mnimo ou mximo extrema-
mente ineficiente, uma vez que investiga todos os caminhos possveis de forma completamente no
seletiva, sendo totalmente inadequado para grandes grafos, devido sua elevada complexidade tempo-
ral.
137
13.6.3 RVORES GERADORAS
Como j foi comentado, um grafo dito ser conexo se h um caminho entre quaisquer dois nodos que
dele fazem parte. Seja G = (N, A) um grafo conexo com um conjunto de nodos N e um conjunto de
arestas A. Uma "rvore geradora" de G um grafo conexo T = (N, A'), onde A' um subconjunto de
A tal que:
(1) T conexo, e
(2) No h ciclos em T.
Essas duas condies garantem que T uma rvore. Para o grafo apresentado na Figura 13.12(a), por
exemplo, h trs rvores geradoras que correspondem s seguintes trs listas de arestas:
T1 = [a-b, b-c, c-d]
T2 = [a-b, b-d, d-c]
T3 = [a-b, b-d, b-c]
onde cada termo da forma X-Y denota uma aresta entre os nodos X e Y. Pode-se escolher qualquer
nodo na lista para raiz da rvore. As rvores geradoras so de interesse, por exemplo, em problemas
de comunicao, porque fornecem, com o menor nmero de linhas de comunicao possvel, um ca-
minho entre qualquer par de nodos. Definiremos um procedimento:
arvG(T, G)
onde T uma rvore geradora de G. Assumiremos para isso que G um grafo conexo. Podemos ima-
ginar a construo algortmica de uma rvore geradora da seguinte maneira: Iniciamos com um con-
junto vazio de arestas, ao qual gradualmente vamos adicionando arestas de G, tomando cuidado para
que nunca seja gerado um ciclo, at que mais nenhuma aresta de G possa ser adicionada ao conjunto,
porque isso determinaria a gerao de um ciclo. O conjunto de arestas resultante define uma das rvo-
res geradoras de G. A condio de no-ciclo pode ser mantida por meio de uma regra simples: Uma
aresta pode ser adicionada ao conjunto somente se um de seus nodos j pertence rvore geradora em
formao e o outro ainda no pertence. Um programa que implementa essa idia mostrado na Figura
13.11. A relao fundamental ali desenvolve(T1, T, G), onde todos os trs argumentos so conjuntos
de arestas. G um grafo conexo. T1 e T so subconjuntos de G tais que ambos representam rvores. T
uma rvore geradora de G, obtida pela adio de zero ou mais arestas de G a T1. Pode-se dizer que
T1 origina o desenvolvimento de T.
interessante desenvolver tambm um programa para a construo de rvores geradoras de forma
completamente declarativa, pelo simples estabelecimento de relaes matemticas. Assumiremos que
tanto grafos conexos como rvores sejam representados por meio de listas de arestas como no pro-
grama da Figura 13.16. As definies necessrias so:
(1) T uma rvore geradora de G se:
T um subconjunto de G,
T uma rvore, e
T "cobre" G, isto , todo nodo de G est tambm em T.
(2) Um conjunto de arestas T uma rvore se:
T conexo, e
T no possui ciclos.
Usando a relao caminho/4, definida na seo anterior, tais definies podem ser estabelecidas em
Prolog conforme mostrado na figura 13.17. Deve-se notar, entretanto, que o programa ali definido
de pequeno interesse prtico devido a sua ineficincia.
138
arvG(G, T) :-
membro(Aresta, G),
desenvolve([Aresta], T, G).
desenvolve(T1, T, G) :-
novaAresta(T1, T2, G),
desenvolve(T2, T, G).
desenvolve(T, T, G) :-
not novaAresta(T, _, G).
novaAresta(T, [A-B | T], G) :-
adjacente(A, B, G),
nodo(A, T),
not nodo(B, T).
adjacente(A, , G) :-
membro(A-B, G); membro(B-A, G).
nodo(A, G) :-
adjacente(A, _, G).
Figura 13.16: Um procedimento algortmico para obter a
rvore geradora T de um grafoG, assumido conexo
arvG(G, T) :-
subconj(G, T),
rvore(T),
cobre(T, G).
rvore(T) :-
conexo(T),
not temCiclos(T).
conexo(T) :-
not(nodo(A,T), nodo(B,T), not caminho(A,B,T, _)).
temCiclos(T) :-
adjacente(A,B,T),
caminho(A,B,T, [A, X, Y | _]).
cobre(T, G) :-
not(nodo(A, G), not nodo(A, T)).
subconj([], []).
subconj([X | L], S) :-
subconj(L, L1),
(S = L1; S = [X | L1]).
Figura 13.17: Um procedimento declarativo para obter as rvores geradoras de G
RESUMO
No presente captulo estudou-se diferentes mtodos de classificao de listas, tecendo conside-
raes acerca da sua eficincia:
(1) bubblesort/2;
(2) insertsort/2;
(3) quicksort/2.
Representao de conjuntos como rvores binrias e dicionrios binrios:
(1) Procura por um item em uma rvore;
(2) Insero de itens;
(3) Remoo de itens;
(4) Balanceamento de rvores e sua relao com a eficincia;
(5) Apresentao de rvores.
Grafos:
139
(1) Representao de grafos;
(2) Caminhamento em grafos;
(3) Obteno das rvores geradoras de um grafo.
EXERCCIOS
13.1 Escreva um programa para intercalar duas listas classificadas, produzindo uma terceira lista,
tambm classificada. Por exemplo:
?-intercala([3,4,5], [1,2,2,5,7], L).
L = [1,2,2,3,4,5,5,7]
13.2 Escreva um programa para descrever a relao quicksort/2, empregando pares-diferena na repre-
sentao de listas.
13.3 O programa quicksort/2, apresentado neste captulo, possui um desempenho sofrvel quanta a
lista a ser classificada j est classificada ou quase classificada. Analise porque isso ocorre e
proponha modificaes no algoritmo capazes de solucionar tal problema.
13.4 Um outro algoritmo de classificao de listas baseia-se na seguinte proposta: Para classificar uma
lista L:
(1) Divida L em duas listas, L1 e L2, com aproximadamente o mesmo tamanho,
(2) Classifique L1 e L2, obtendo S1 e S2, e
(3) Intercale S1 e S2, obtendo a lista L classificada.
Implemente este princpio de classificao e compare sua eficincia com a obtida no programa
quicksort/2.
13.5 Defina os predicados:
arvBin(Objeto) e dicBin(Objeto)
para reconhecer, respectivamente se Objeto uma rvore binria ou um dicionrio binrio.
13.6 Defina o procedimento
altura(rvoreBinria, Altura)
para computar a altura de uma rvore binria. Assuma que a altura de uma rvore vazia zero e
que a de uma rvore com um nico elemento 1.
13.7 Defina a relao
lineariza(rvore, Lista)
para representar uma rvore linearizada sob a forma de lista.
13.8 Considere as rvores geradoras de um grafo que possui custos associados s arestas. Seja o custo
de uma rvore geradora definido como a soma dos custos de todas as arestas nela presentes. Es-
creva um programa para encontrar a rvore geradora de custo mnimo em um grafo.
140
14. ESTRATGIAS PARA A SOLUO DE PROBLEMAS
O presente captulo introduz um esquema genrico para a soluo de problemas denominado "espao
de estados". Um espao de estados um grafo cujos nodos correspondem a possveis situaes de um
problema, de modo que sua soluo reduzida, em tal representao, procura de um caminho sobre
tal grafo. Estudaremos exemplos de formulao de problemas usando a abordagem do espao de esta-
dos e discutiremos mtodos gerais para a soluo de problemas representados por meio desse forma-
lismo. A soluo de problemas envolve, portanto, a pesquisa em grafos e, tipicamente, a lidar com
alternativas. As estratgias bsicas apresentadas neste captulo para a explorao de alternativas so a
pesquisa em profundidade (depth-first search) e a pesquisa em amplitude (breadth-first search).
14.1 CONCEITOS BSICOS
Vamos considerar o exemplo apresentado na Figura 14.1. O problema formular um planejamento
para reorganizar uma pilha de blocos sobre uma mesa da maneira mostrada na figura, obedecendo as
seguintes trs regras:
(1) Pode-se mover somente um bloco de cada vez;
(2) Um bloco pode ser movido somente se no houver nada sobre ele;
(3) Os blocos somente podem ser colocados diretamente na mesa ou sobre algum outro bloco.
B
A
C
C
B
A
Figura 14.1 O problema da reorganizao dos blocos A, B, C
Deve-se observar que o objetivo no apenas obter a situao final desejada. O que se quer realmente
o "plano" que nos permite alcan-la. Para isso necessrio descobrir uma seqncia de operaes
que permita realizar a transformao proposta.
Podemos pensar neste problema como um caso de explorao entre alternativas. Na situao inicial,
existe apenas uma possibilidade: colocar o bloco C na mesa. Aps fazer isto, surgem trs alternativas
possveis:
Colocar o bloco A na mesa, ou
Colocar o bloco A sobre o bloco C, ou
Colocar o bloco C sobre o bloco A.
Como o exemplo ilustra, dois conceitos devem ser considerados nesse tipo de problema:
(1) As situaes do problema, e
(2) Os movimentos ou aes vlidas que transformam uma situao em outra.
As situaes e os movimentos possveis formam um grafo direcionado, denominado "espao de esta-
dos". Um espao de estados para o problema exemplificado apresentado na Figura 14.2. Os nodos
do grafo correspondem a situaes do problema e os arcos correspondem a transies legais entre os
141
estados. Encontrar um plano cuja execuo solucione o problema original equivalente a encontrar
um caminho entre a situao inicial dada (o nodo inicial) e alguma situao final especificada, tam-
bm denominada "o nodo objetivo".
A B C
B
A C
C
B
A
C
A B
B
C
A
A
B C
A
B C
C
A
B
B
C
A
B
A C
C
A B
A
B
C
A
C
B
Figura 14.2: O espao de estados do problema da reorganizao de A, B e C
A Figura 14.3 apresenta um outro exemplo do mesmo tipo de problema: o "jogo do oito" e a sua re-
presentao reduzida ao problema de caminhamento em um grafo. O jogo do oito um clssico da
pesquisa em inteligncia artificial e consiste em oito peas deslizantes, numeradas de 1 a 8 e dispostas
em uma matriz 3x3 de nove casas. Uma das casas est sempre vazia e qualquer pea a ela adjacente
pode ser movida para essa casa. Podemos imaginar que a casa vazia pode "mover-se", trocando de
lugar com qualquer uma das peas adjacentes. A situao final algum arranjo especial das peas,
como pode ser visto na Figura 14.3.
1 3
8 4 2
7 6 5
1 2 3
8 4
7 6 5
1 3
8 4 2
7 6 5
1 3
8 4 2
7 6 5
1 2 3
8 4
7 6 5
1 3 4
8 5 2
7 6
1 3
8 4 2
7 6 5
1 3 4
8 2
1 3 4
8 2
7 6 5
7 6 5
Figura 14.3: O "jogo do oito" em uma particular configurao
fcil construir aplicaes grficas similares para outros quebra-cabeas populares que se enquadram
no mesmo tipo de problema como, por exemplo, o problema das torres de Hani, ou de como conduzir
a raposa, o ganso e o milho atravs do rio. Neste ltimo problema h um bote que somente pode con-
duzir o fazendeiro e algum outro objeto. O fazendeiro tem que proteger o ganso da raposa e o milho
do ganso. Muitos problemas prticos tambm se encaixam nesse mesmo paradigma, dentre os quais
142
talvez o mais importante seja o "problema do caixeiro-viajante", que modelo formal de diversas
aplicaes prticas. Este problema definido por um mapa com n cidades interligadas por diversas
rodovias. A idia encontrar a rota mais curta, partindo de alguma cidade inicial, visitando todas as
demais cidades e retornando ao ponto de partida. Nenhuma cidade, com exceo da inicial, pode apa-
recer duas vezes no trajeto. O problema pode ser facilmente solucionado atravs de uma adaptao
dos procedimentos de caminhamento em grafos estudados no captulo 13.
Vamos resumir os conceitos introduzidos nestes exemplos. O espao de estados de um dado problema
especifica "as regras do jogo". Os nodos no espao de estados correspondem a situaes possveis e
os arcos correspondem a movimentos vlidos ou "passos de soluo". Um problema particular pode
ser definido por:
Um espao de estados,
Um nodo inicial, e
Uma condio-objetivo, isto , a situao a ser atingida. Denomina-se nodos-objetivos aos no-
dos que satisfazem essa condio.
Podemos associar custos s aes vlidas de um espao de estados. Por exemplos, custos associados
movimentao, no problema de organizao de blocos, indicariam que alguns blocos so mais difceis
de mover do que outros. No problema do caixeiro-viajante, os movimentos correspondem a viagens
diretas entre duas cidades. Ali os custos dos movimentos podem corresponder a distncias entre as
cidades envolvidas.
Nos casos em que temos custos associados aos movimentos, estaremos normalmente interessados em
obter as solues de menor custo possvel. O custo total de uma soluo a soma de todos os custos
associados aos que compem o caminho entre o nodo inicial e o nodo objetivo. Mesmo que no haja
custos, iremos sempre nos deparar com um problema de otimizao: qual o caminho mais curto entre
esses dois pontos?
Antes de apresentar alguns programas que implementam algoritmos clssicos para a pesquisa em es-
paos de estados, vamos estudar como um espao de estados pode ser representado em Prolog. Repre-
sentaremos um espao de estados pela relao
s(X, Y)
que verdadeira se h um movimento vlido no espao de estados de um nodo X a um nodo Y. Dize-
mos que o nodo Y um sucessor de X. Se h custos associados aos movimentos, ento adicionaremos
um terceiro argumento, representando o custo do movimento:
s(X, Y, Custo)
Essa relao pode ser representada explicitamente no programa por meio de um conjunto de fatos,
entretanto, para espaos de estado de maior complexidade, isso se torna impraticvel. Assim a relao
s/3 usualmente definida de maneira implcita, pelo estabelecimento de regras para computar os no-
dos sucessores de um determinado nodo.
Outra questo de importncia geral como representar as situaes do problema, isto , os nodos do
espao de estados. A representao deve ser compacta, mas por outro lado deve permitir uma execu-
o eficiente das operaes requeridas, particularmente a relao de sucesso, s/3.
Vamos considerar, por exemplo, o problema de organizao de blocos apresentado na Figura 14.1.
Estudaremos um caso mais geral, em que existe um nmero qualquer de blocos organizados em uma
ou mais pilhas. O nmero de pilhas ser limitado a um determinado mximo para tornar o problema
mais interessante. Isso pode corresponder tambm a uma restrio realstica, uma vez que a um rob
que manipule blocos somente pode ser oferecido um espao de trabalho limitado, sobre uma mesa.
143
Uma situao do problema pode ser representada por uma lista de pilhas. Cada pilha, por sua vez, ser
representada por uma lista de blocos, ordenada de forma que o bloco no topo da pilha a cabea da
lista. pilhas vazias sero representadas por listas vazias. A situao inicial do problema apresentado
na Figura 13.1 pode ser representada por:
[[c, a, b], [], []]
Uma situao objetivo qualquer arranjo com uma pilha ordenada de todos os blocos. H trs situa-
es objetivo possveis:
[[a, b, c], [], []]
[[], [a, b, c], []]
[[], [], [a, b, c]]
A relao s/3 pode ser programada de acordo com a seguinte regra: Uma situao s2 sucessora de
alguma situao s1, se h duas pilhas, P1 e P2 em s1 e bloco no topo de P1 pode ser movido para P2,
configurando a nova situao s2. Como todas as situaes so representadas por listas de pilhas, isso
pode ser escrito em Prolog da seguinte maneira:
s(Pilhas, [P1, [T1 | P2] | OutrasPilhas]) :-
remove([T1 | P1], Pilhas, Pilhas1),
remove(P2, Pilhas1, OutrasPilhas).
remove(X, [X | L], L).
remove(X, [Y | L], [Y | L1]) :-
remove(X, L, L1).
A condio objetivo para o problema dado :
objetivo(Situao) :-
membro([a, b, c], Situao).
Os algoritmos de pesquisa em espaos de estados sero solucionados por meio da relao:
resolve(Incio, Soluo)
onde Incio o nodo inicial do espao de estados e Soluo um caminho entre Incio e qualquer
nodo objetivo. Para o problema da organizao de blocos proposto, a consulta correspondente seria:
?-resolve([[c, a, b], [], []], Soluo).
Como resultado de uma pesquisa bem sucedida, a varivel Soluo ser instanciada para uma lista de
arranjos de blocos representando um "plano" para transformar o estado inicial em um estado onde os
trs blocos estejam em uma pilha organizada segundo a lista [a, b, c].
14.2 PESQUISA EM PROFUNDIDADE
Dada uma formulao do espao de estados de um problema, h diversas abordagens para encontrar o
caminho da soluo. Duas estratgias bsicas so: a pesquisa em profundidade (depth-first search) e a
pesquisa em amplitude (breadth-first search). na presente seo ser estudada a pesquisa em profundi-
dade, que pode ser formulada a partir de uma idia bastante simples:
Para encontrar uma linha de soluo, Sol, a partir de um determinado nodo, N, at algum nodo
objetivo:
Se N um nodo objetivo, ento Sol = [N], seno
Se h um nodo sucessor de N, N1, tal que existe um caminho, Sol1, de N1 at algum nodo
objetivo, ento Sol = [N | Sol1].
Pode-se representar essa formulao em Prolog por meio da seguinte relao resolve/2:
resolve(N, [N]) :-
objetivo(N).
resolve(N, [N | Sol1]) :-
s(N, N1), resolve(N1, Sol1).
144
Esse programa , na verdade, uma implementao da estratgia de pesquisa em profundidade. O m-
todo denominado "em profundidade" devido ordem em que as alternativas so exploradas no espa-
o de estados. Sempre que o algoritmo de pesquisa em profundidade tem oportunidade de continuar
sua pesquisa escolhendo entre diversos nodos alternativos, a deciso conduz ao n que se encontra em
maior profundidade, isto , ao mais distante possvel do nodo inicial. A Figura 14.4 ilustra a ordem na
qual os nodos so visitados, que corresponde ordem seguida pelo Prolog na soluo da consulta:
?-resolve(a, Sol).
A figura 14.4 representa um espao de estados onde "a" o nodo inicial e "f" e "g" so nodos objeti-
vos. A ordem na qual a pesquisa realizada dada pelo nmero entre parnteses esquerda de cada
nodo. A pesquisa em profundidade a mais adequada ao estilo recursivo da linguagem Prolog, uma
vez que esta, na execuo de seus objetivos, explora as alternativas segundo esse mesmo princpio.
Essa tcnica simples, fcil de programar, e funciona bem na maioria dos casos. Entretanto, h vrias
situaes em que o procedimento resolve/2, que adota o mtodo de pesquisa em profundidade , pode
se mostrar ineficiente. Se isso vai acontecer ou no, depende do espao de estados. Para complicar o
procedimento resolve/2, suficiente uma leve modificao no problema apresentado na Figura 14.4:
adicionar um arco do nodo h ao nodo d, originando um ciclo, como mostrado na Figura 14.5. Nesse
caso a pesquisa em profundidade ir ocorrer da seguinte maneira: inicia em a e desce at h, seguindo o
ramo mais esquerda no grafo. Neste ponto, ao contrrio do que ocorre na Figura 14.4, h tem um
sucessor, que d. Por sua vez, d tem h como sucessor, resultando em um ciclo infinito:
a, b, d, h, d, h, d, h, ...
a
b c
d e f g
i j k l h
(1)
(2)
(3) (5)
(4) (6) (7)
(8)
(9) (10)
(11) (12)
Figura 14.4: Pesquisa em Profundidade
a
b c
d e f g
i j k l h
Figura 14.5: Um espao de estados originando um caminho cclico
Um aperfeioamento bvio, portanto, em nosso programa de pesquisa em profundidade acrescentar
um mecanismo detector de ciclos. Assim, qualquer nodo que j houver sido visitado no deve ser
considerado novamente. Tal idia pode ser formulada por meio da relao:
145
profundidade(Caminho, Nodo, Soluo)
Na relao profundidade/3 , Nodo o estado a partir do qual o nodo objetivo deve ser encontrado.
Caminho um caminho (uma lista de nodos) entre o nodo inicial e Nodo, enquanto que Soluo
uma extenso de Caminho, passando por Nodo, at atingir um nodo objetivo. Essas idia so apre-
sentadas na Figura 14.6.
N
Nodo
inicial
Caminho
Nodo
objetivo
Soluo
Figura 14.6: A relao profundidade(Caminho, N, Soluo)
Para garantir uma programao simplificada, os caminhos sero representados em nossos programas
como listas em ordem inversa, isto , iniciando em um nodo objetivo (ou corrente, durante a execu-
o) e terminando no nodo inicial. O argumento "Caminho" pode ser utilizado para dois propsitos:
(1) Garantir que o algoritmo no ir considerar os sucessores de Nodo que j foram visitados (de-
teco de ciclos), e
(2) Construir um caminho, Soluo, que soluciona o problema.
Na Figura 14.7 apresentamos um programa que executa a pesquisa em profundidade em grafos com a
deteco de ciclos, conforme foi anteriormente comentado. Vamos considerar agora uma variao
desse programa. Dois argumentos que ali aparecem, N e Caminho, podem ser combinados em uma
lista [N | Caminho], assim, ao invs de se ter um "nodo candidato", N, para ser adicionado a um cami-
nho que conduza ao objetivo desejado, temos um "caminho candidato", C = [N | Caminho], para ser
ampliado at alcanar o objetivo. A programao do predicado correspondente, profundidade1(C,
Soluo) deixada como um exerccio.
resolve(N, Soluo) :-
profundidade([], N, Soluo).
profundidade(Caminho, N, [N | Caminho]) :-
objetivo(N).
profundidade(Caminho, N, Soluo) :-
s(N, N1),
not membro(N1, Caminho),
profundidade([N | Caminho], N, Soluo).
Figura 14.7: Pesquisa em profundidade com deteco de ciclos
Com o mecanismo de deteco de ciclos, o procedimento de pesquisa em profundidade vai encontrar
o caminho apropriado para atingir uma soluo em espaos de estados tais como o apresentado na
Figura 14.5. H entretanto espaos de estados para os quais esse procedimento no funcionar ade-
quadamente. Muitos espaos de estado so infinitos. Em tais espaos o algoritmo de pesquisa em pro-
fundidade pode se desviar do caminho correto para atingir um determinado objetivo, explorando inde-
finidamente uma ramificao infinita que jamais se aproximar do objetivo formulado. Para evitar a
pesquisa em profundidade em ramificaes infinitas (no- cclicas, neste caso) do espao de estados,
adicionaremos mais um refinamento em nosso procedimento bsico de pesquisa em profundidade:
limitamos a profundidade mxima de pesquisa, obtendo uma nova relao, profundidade2/3, repre-
sentada por:
profundidade2(Nodo, Soluo, ProfMxima)
146
onde a pesquisa no permitida alm de ProfMxima. Essa restrio pode ser programada decremen-
tando o valor estabelecido para ProfMxima a cada chamada recursiva, no permitindo que esse limite
se torne negativo. O programa resultante mostrado na Figura 14.8.
profundidade2(Nodo, [Nodo], _) :-
objetivo(Nodo).
profundidade2(Nodo, [Nodo | Sol], ProfMxima) :-
ProfMxima > 0,
s(Nodo, Nodo1),
Max1 is ProfMxima -1,
profundidade2(Nodo1, Sol, Max1).
Figura 14.8: Um programa para pesquisa em profundidade limitada
14.3 PESQUISA EM AMPLITUDE
Em contraste com a pesquisa em profundidade, a pesquisa em amplitude escolhe visitar primeiro os
nodos que esto mais prximos do nodo inicial. Isso resulta em um processo de busca que tende a se
desenvolver mais em amplitude do que em profundidade, como pode ser visto na Figura 14.9. O espa-
o de estados ali apresentado basicamente o mesmo da Figura 14.4, entretanto, a ordem em que os
nodos sero visitados, dada pelo nmero entre parnteses esquerda de cada nodo, agora diferente.
a
b c
d e f g
i j k l h
(1)
(2)
(4) (5)
(8) (9) (10)
(3)
(6) (7)
(11) (12)
Figura 14.9: Pesquisa em amplitude
A estratgia de pesquisa em amplitude no to fcil de programar quanto a de pesquisa em profun-
didade. A razo dessa dificuldade que temos de manter um conjunto de nodos candidatos alternati-
vos, e no apenas um nodo como na pesquisa em profundidade. Entretanto, mesmo esse conjunto de
nodos no suficiente se desejarmos extrair um caminho-soluo por meio desse processo. Assim, ao
invs de manter um conjunto de nodos candidatos, iremos manter um conjunto de caminhos candida-
tos. Isso representado pela relao:
amplitude(Caminhos, Soluo)
que verdadeira quando algum caminho pertencente ao conjunto de candidatos Caminhos pode ser
estendido at algum nodo objetivo. O argumento soluo representa tal caminho estendido.
14.3.1 REPRESENTAO DO CONJUNTO DE CAMINHOS CANDIDATOS
Vamos adotar inicialmente a seguinte representao para o conjunto de caminhos candidatos: O con-
junto ser representado como uma lista de caminhos, onde cada caminho uma lista de nodos em
ordem inversa, isto , a cabea da lista ser o nodo mais recentemente visitado e o ltimo elemento da
lista ser o nodo inicial da pesquisa. O conjunto inicia como um conjunto unitrio de caminhos candi-
datos:
[ [NodoInicial] ]
Um esquema para definir o processo de pesquisa em amplitude pode ser formulado da seguinte manei-
147
ra:
Para executar a pesquisa em amplitude, dado um conjunto de caminhos candidatos:
Se o primeiro caminho contm um nodo objetivo como cabea da lista que o representa, en-
to ele uma soluo para o problema, seno
Remover o primeiro caminho da lista de caminhos candidatos e gerar o conjunto de todas as
possveis extenses de um s nodo a esse caminho, adicionando o conjunto das extenses
geradas ao final da lista de caminhos candidatos. Aps, voltar a executar a pesquisa em am-
plitude sobre esse conjunto atualizado.
Por exemplo, para o espao de estados apresentado na Figura 14.9, onde f e j so nodos objetivo, o
processo se desenvolve da seguinte maneira:
(1) O conjunto de caminhos candidatos inicialmente contm apenas o nodo raiz:
[ [a] ]
(2) Determinar o conjunto de extenses de um s nodo de [a]:
[ [b,a], [c,a] ]
(3) Remover o primeiro caminho candidato, [b, a] do conjunto e determinar suas extenses de um
s nodo:
[ [d,b,a], [e,b,a] ]
Acrescentar essa lista de extenses ao final do conjunto de caminhos candidatos:
[ [c,a], [d,b,a], [e,b,a] ]
(4) Remover [c, a] e acrescentar suas extenses ao final do conjunto de caminhos candidatos pro-
duzindo:
[ [d,b,a], [e,b,a], [f,c,a], [g,c,a] ]
(5) Remover [d, b, a] e acrescentar sua nica extenso ao final do conjunto de caminhos candida-
tos:
[ [e,b,a], [f,c,a], [g,c,a], [h,d,b,a] ]
(6) Executar a mesma operao para [e, b, a], obtendo:
[ [f,c,a], [g,c,a], [h,d,b,a], [i,e,b,a], [j,e,b,a] ]
Aqui o processo de busca encontra |, c, a|, que contm como cabea o nodo objetio . Lntao
esse caminho apresentado como soluao.
Um programa que executa esse processo apresentado na Figura 14.10. Ali, todas as extenses aos
conjuntos candidatos so geradas atravs do predicado pr-definido bagof/3. Um teste para prevenir a
gerao de ciclos tambm includo. Note que no caso em que nenhuma extenso possvel, o predi-
cado bagof/3 falha, portanto fornecida uma chamada alternativa ao procedimento amplitude/2. Os
predicados membro/2 e conc/3 so respectivamente as relaes de ocorrncia de um item em uma lista
e a concatenao de listas, ambas j estudadas.
O problema desse programa a ineficincia da operao conc/3. Isso entretanto pode ser reparado se
representarmos listas por meio de pares-diferena conforme foi apresentado no captulo 12. O con-
junto de caminhos candidatos seria ento representado como um par de listas: Caminhos e Z, e escrito
como
Caminhos-Z
Introduzindo essa representao no programa da Figura 14.10, este pode ser sistematicamente trans-
formado no programa apresentado na Figura 14.11. A transformao (simples) deixada ao leitor a
ttulo de exerccio.
resolve(Incio, Soluo) :-
148
amplitude([ [Incio] ], Soluo).
amplitude([ [N | Caminho] | _ ], [N | Caminho]) :-
objetivo(N).
amplitude([ [N | Caminho] | Caminhos ], Soluo) :-
bagof([M, N | Caminho],
(s(M, N), not membro(M, [N | Caminho])),
NovosCaminhos),
conc(Caminhos, NovosCaminhos, Caminhos1), !,
amplitude(Caminhos1, Soluo);
amplitude(Caminhos, Soluo).
Figura 14.10: Uma implementao da pesquisa em amplitude
resolve(Incio, Soluo) :-
amplitude1([ [Incio] | Z ] - Z, Soluo).
amplitude1([ [N | Caminho] | _ ] - _, [N | Caminho]) :-
objetivo(N).
amplitude1([ [N | Caminho] | Caminhos ] - Z, Soluo) :-
bagof([M, N | Caminho],
(s(M, N), not membro(M, [N | Caminho])),
NovosCaminhos),
conc(NovosCaminhos, ZZ, Z), !,
amplitude1(Caminhos1 - ZZ, Soluo);
Caminhos \== Z,
amplitude1(Caminhos - Z, Soluo).
Figura 14.11: Uma implementao mais eficiente do programa da Figura 14.10
14.3.2 REPRESENTAO EM RVORE DO CONJUNTO DE CAMINHOS CANDIDATOS
Vamos considerar agora outra modificao no programa de pesquisa em amplitude. At ento o con-
junto de caminhos candidatos vinha sendo representado como uma lista de caminhos. Isso gera um
consumo exagerado de memria, uma vez que a parte inicial a mesma para diversos caminhos, sen-
do armazenada de forma redundante. A maneira mais eficiente de representar os caminhos candidatos
em forma de rvore, onde a parte comum a diversos caminhos armazenada sem redundncia, nos
ramos superiores da rvore. Adotaremos a seguinte representao de rvore. necessrio considerar
dois casos:
(1) A rvore consiste em um nico nodo N. Ento ela ser representada pelo termo f(N), onde o
functor f indica que N uma folha da rvore;
(2) A rvore consiste em um nodo raiz, N, e um conjunto de sub-rvores. Tal rvore dada pelo
termo t(N, Subs), onde Subs = [S1, S2, ...] uma lista de sub-rvores.
Por exemplo, vamos considerar uma situao onde os trs primeiros nveis da rvore apresentada na
Figura 14.9 foram gerados. O conjunto de caminhos candidatos nesse momento o seguinte:
[ [d, b, a], [e, b, a], [f, c, a], [g, c, a] ]
Na representao em rvore, esse mesmo conjunto de caminhos candidatos representado pelo termo:
t(a, [t(b, [f(d), f(e)]), t(c, [f(f), f(g)])])
Essa representao pode parecer complexa e ainda mais consumidora de memria do que a represen-
tao em listas, entretanto isso apenas a aparncia superficial, devido representao compacta que
o Prolog utiliza para listas. Na representao do conjunto candidato por meio de listas, o efeito da
pesquisa em profundidade era atingido pela movimentao dos caminhos expandidos para o fim do
conjunto candidato. No possvel usar o mesmo truque na representao em rvore, portanto nosso
novo programa ser algo mais complicado. A relao chave aqui ser:
expande(Caminho, Arv, Arv1, Sol, Soluo)
A Figura 14.12 ilustra a relao entre os argumentos da relao expande/5. Sempre que esta for ativa-
149
da, as variveis Caminho e Arv j devem estar instanciadas. Arv uma sub-rvore do espao de esta-
dos e representa o conjunto de caminhos candidatos a um objetivo nessa sub-rvore. Caminho o
caminho entre o nodo inicial e a raiz de Arv. A idia geral da relao expande/5 produzir Arv1 como
uma extenso de um nvel de Arv. Se, entretanto, durante a expanso de Arv, um nodo objetivo for
encontrado, expande/5 produzir o correspondente caminho soluo. Assim a relao expande/5 ir
produzir dois tipos de resultados. O tipo de resultado produzido ser indicado pelo valor da varivel
Sol, como se segue:
(1) Sol = sim,
Soluo = um caminho para solucionar o problema, e
Arv1 = no instanciada.
Resultados desse tipo somente sero produzidos quando houver um nodo objetivo em Arv (uma
"folha-objetivo").
(2) Sol = no,
Soluo = no instanciada,
Arv1 = Arv expandida de um nvel.
Aqui Arv1 no contm nenhum desvio bloqueado, (desvios que no podem ser expandidos por-
que no possuem sucessores)
a Caminho
Arv Arv1
g
Soluo
Figura 14.12: A relao expande(Caminho,Arv,Arv1,Sol,Soluo)
A Figura 14.13 apresenta um programa completo, baseado nas idias discutidas acima, empregando
representao em rvore para o conjunto de caminhos candidatos. Um procedimento auxiliar
expTodos/6, similar ao expande/5, que realiza a expanso de um nvel sobre um conjunto de rvores e
armazena todas as rvores expandidas resultantes, removendo todas as rvores bloqueadas. Alm dis-
so esse procedimento produz, atravs de backtracking, todas as solues encontradas nessa lista de
rvores.
150
resolve(Incio, Soluo) :-
ampl(f(Incio), Soluo).
ampl(Arv, Soluo) :-
expande([], Arv, Arv1, Sol, Soluo),
(Sol=sim; Sol=no, ampl(Arv1, Soluo)).
expande(P, f(N), _, sim, [N | P]) :-
objetivo(N).
expande(P, f(N), t(N, Subs), no, _) :-
bagof(f(N), (s(N, M), not membro(M, P)), Subs).
expande(P, t(N, Subs), t(N, Subs1), Sol, Soluo) :-
expTodos([N | P], Subs, [], Subs1, Sol, Soluo).
expTodos(_, [], [T | Ts], [T | Ts], no, _).
expTodos(P, [T | Ts], Ts1, Subs1, Sol, Soluo) :-
expande(P, T, T1, Sol1, Soluo),
( Sol1=sim, Sol=Sim;
Sol1=no, !, expTodos(P,Ts,[T1 | Ts1], Subs, Sol, Soluo));
expTodos(P, Ts, Ts1, Subs1, Sol, Soluo).
Figura 14.13: Uma implementao do mtodo de pesquisa em profundidade usando representao em
rvore para o conjunto de caminhos candidatos
14.4 PESQUISA EM GRAFOS, OTIMIZAO E COMPLEXIDADE
Neste ponto conveniente tecer alguns comentrios sobre as tcnicas estudadas at agora para a pes-
quisa em espaos de estados: pesquisa em grafos, otimizao das solues produzidas e complexidade
de pesquisa.
Os exemplos apresentados neste captulo podem produzir a falsa impresso de que os programas de
pesquisa em amplitude somente funcionam para espaos de estado que podem ser representados por
meio de rvores e que no so adequados para grafos em geral. O fato de se haver adotado uma repre-
sentao em rvore no significa que o espao de estados tenha obrigatoriamente de ser uma rvore.
Na verdade, quando um espao de estados na forma de um grafo pesquisado, ele se desdobra em
uma rvore, de forma que os mesmos caminhos percorridos podem ser representados em ambas as
estruturas. Isso ilustrado pela figura 14.14.
a
b c
d e
a
b c
d e c e
e
(1) (2)
Figura 14.14: Desdobrando um grafo em uma rvore.
Em (1) representa-se um espao de estados na forma de grafo. Se "a" arbitrado o nodo inicial, ento
o grafo pode ser desdobrado na forma da rvore mostrada em (2), que contm todos os caminhos no-
cclicos possveis desenvolvidos a partir de "a". A tcnica de pesquisa em amplitude gera caminhos de
soluo, um aps outro, ordenados de acordo com o seu tamanho: os caminhos mais curtos aparecem
primeiro. Isso importante se a otimizao (no que toca ao comprimento do caminho deva ser consi-
151
derada. A tcnica de pesquisa em amplitude garantidamente produz o caminho mais curto primeiro, o
que no ocorre com a tcnica de pesquisa em profundidade. O programa dado na Figura 14.13, entre-
tanto, no leva em conta os custos associados aos arcos do espao de estados. Se o custo mnimo de
um caminho de soluo o critrio para otimizao (e no o seu tamanho), ento a tcnica de pesqui-
sa em amplitude no suficiente.
Outro problema tpico associado com a pesquisa de espaos de estado o da complexidade combina-
tria. Para os domnios de problemas no-triviais, o nmero de alternativas a ser explorado to
grande que o problema da complexidade freqentemente se torna crtico. fcil entender porque isso
acontece: se cada nodo no espao de estados tem n sucessores, ento o nmero de caminhos de com-
primento c a partir do nodo inicial n
c
(assumindo a inexistncia de ciclos). Assim, o conjunto de
caminhos candidatos cresce exponencialmente com o seu tamanho, o que conduz ao que se denomina
exploso combinatria. As tcnicas de pesquisa em profundidade e em amplitude no possuem ne-
nhum recurso contra essa complexidade, uma vez que todos os caminhos candidatos so tratados de
forma no-seletiva.
Um procedimento mais sofisticado para a pesquisa em espaos de estados complexos deveria empre-
gar informaes especificamente relacionadas ao problema de decidir a maneira mais promissora de
agir em cada ponto da pesquisa. Isso teria o efeito de projetar o processo de pesquisa diretamente para
o objetivo procurado, evitando os caminhos improdutivos. Informao associada ao problema espec-
fico que pode ento ser empregada para dirigir a pesquisa denominada heurstica. Os algoritmos que
utilizam heursticas so denominados heuristicamente guiados e executam um tipo de pesquisa cha-
mada pesquisa heurstica, que ser introduzida no prximo captulo.
RESUMO
Um espao de estados um formalismo para a representao de problemas de planejamento.
Um espao de estados representado por meio de um grafo direcionado cujos nodos corres-
pondem a situaes do problema e os arcos a movimentos vlidos que transformam uma situa-
o em outra. Um problema particular definido por um nodo inicial e um nodo objetivo. Uma
soluo do problema corresponde ento a um caminho no grafo. Assim, a soluo do problema
reduzida procura por um caminho em um grafo.
Problemas de otimizao podem ser modelados pela associao de custos aos arcos de um es-
pao de estados.
Duas estratgias basicas que sistematicamente exploram um espao de estados sao: a pes-
quisa em proundidade ,depth-irst search, e a pesquisa em amplitude ,breadth-irst se-
arch,.
A pesquisa em profundidade mais fcil de programar, mas suscetvel presena de ciclos
entre os nodos, conduzindo a ramificaes infinitas da arvore de pesquisa.
A implementao da estratgia de pesquisa em amplitude mais complexa, uma vez que requer
a manuteno de um conjunto de caminhos candidatos. Isso pode ser mais facilmente represen-
tado por meio de uma lista de listas, entretanto, o mtodo mais eficiente emprega representao
em rvore.
No caso de grandes espaos de estados h o perigo da exploso combinatria. Tanto a pesquisa
em profundidade quanto a pesquisa em amplitude so ferramentas pobres no combate a tal difi-
culdade, onde a aplicao de tcnicas de pesquisa heurstica se faz necessria.
EXERCCIOS
14.1 Escreva um procedimento denominado
152
profundidade1(CaminhoCandidato, Soluo)
com deteco de ciclos, para encontrar um caminho, Soluo, como uma extenso de Caminho-
Candidato. Represente ambos os caminhos como listas de nodos em ordem inversa, de forma que
o nodo objetivo a cabea da lista Soluo.
14.2 Escreva um procedimento para pesquisa em profundidade combinando os mecanismos de detec-
o de ciclos e o de limitao da profundidade pesquisada.
14.3 Escreva um procedimento denominado
apresenta(Situao)
para representar um estado do mundo dos blocos. Situao deve ser representada por uma lista de
pilhas e cada pilha como uma lista de blocos. Por exemplo, o objetivo
mostra( [ [a], [e, d], [c, b] ]).
ir ocasionar a apresentao de
e c
a d b
=======================
14.4 Como se pode usar os procedimento de pesquisa em amplitude estudados para permitir a pesqui-
sa a partir de um conjunto de nodos iniciais, ao invs de um nico?
14.5 Como se pode usar os procedimentos de pesquisa em profundidade e amplitude estudados para
executar a pesquisa em direo inversa, isto , a partir dos nodos objetivos retroagir at atingir
um nodo inicial. (Dica: redefina a relao s/2). Em que situaes a pesquisa retroativa seria van-
tajosa em relao pesquisa progressiva?
14.6 Considere que h custos associados aos arcos de um espao de estados. Escreva um programa
(com deteco de ciclos que efetue a progresso em profundidade ou em amplitude, buscando
minimizar o custo total da pesquisa.
153
15. PESQUISA HEURSTICA
A pesquisa em grafos para a soluo de problemas pode conduzir ao problema da exploso combina-
tria, devido proliferao de alternativas. A pesquisa heurstica representa uma maneira de combater
tal situao. Uma forma de utilizar informao heurstica sobre um problema computar estimativas
heursticas numricas para os nodos no espao de estados. Tal estimativa em um nodo indica o quanto
promissor ele se mostra para atingir um nodo objetivo. A idia continuar a pesquisa sempre a partir
do nodo mais promissor dentre os que compem o conjunto de candidatos. O programa de pesquisa
heurstica (best-first search), apresentado no presente captulo, baseia-se nesse princpio.
15.1 BEST-FIRST SEARCH
Um programa de pesquisa heurstica pode ser derivado como um refinamento do programa de pesqui-
sa em amplitude apresentado no captulo anterior. A pesquisa heurstica tambm inicia no primeiro
nodo e mantm um conjunto de caminhos candidatos. A pesquisa em amplitude sempre escolhe para
expanso os caminhos mais curtos. A pesquisa heurstica refina este princpio pela computao de
uma estimativa heurstica para cada candidato e escolhe para expanso o melhor candidato de acordo
com essa estimativa. A partir de agora vamos assumir que h uma funo de custo definida sobre os
arcos do espao de estados. Assim, c(n, n') o custo de movimentao de um nodo n para um nodo
sucessor n' no espao de estados.
Seja a estimativa heurstica traduzida por uma funo f tal que para cada nodo n do espao de estados,
f(n) estima a "dificuldade" de n. Ento, o nodo candidato mais promissor ser aquele que minimizar o
valor de f. A funo f(n) projetada de forma que, para estimar o custo de um caminho que conduza
at a soluo, percorrendo o caminho entre um nodo s, inicial, e um nodo objetivo, final, deva neces-
sariamente passar por um determinado nodo n. Vamos supor que existe tal caminho e que um nodo
objetivo que minimize o seu custo seja t. Ento a funo f(n) pode ser construda como a soma de dois
termos:
f(n) = g(n) + h(n)
conforme ilustrado na figura 15.1.
s
n
t
g(n)
h(n)
Figura 15.1: Construo de uma estimativa heurstica f(n) do custo
do caminho mais barato de s a t via n: f(n) = g(n) + h(n).
A funo g(n) representa a estimativa do custo de um caminho timo de s a n. h(n) representa a esti-
mativa do custo de um caminho timo de n a t.
Quando um nodo n encontrado pelo processo de pesquisa, temos a seguinte situao: Um caminho
de s a n j foi encontrado e o seu custo pode ser computado como a soma dos custos dos arcos nesse
caminho. Esse caminho no necessariamente um caminho timo de s a n (pode haver um caminho
154
melhor de s a n ainda no encontrado pela pesquisa) mas o seu custo pode servir *como um valor
estimativo g(n) do custo mnimo de s a n. O outro termo, h(n) mais problemtico porque o espao
entre n e t ainda no foi explorado nesse ponto. Assim o valor de h(n) tipicamente uma perspectiva
heurstica real, baseada no conhecimento geral do algoritmo acerca do domnio do problema particu-
lar que esta sendo solucionado. Como h(n) depende muito fortemente do domnio do problema, no
h um mtodo universal para a sua construo. Exemplos concretos de como essa previso heurstica
pode ser estabelecida sero apresentados mais adiante. De momento vamos assumir que a funo h
dada e nos concentrar nos outros detalhes do programa de pesquisa heurstica.
Pode-se imaginar que a pesquisa heurstica funcione da seguinte maneira: o processo de pesquisa
consiste em diversos subprocessos competindo entre si, cada um dos quais explorando suas prprias
alternativas, isto , executando a pesquisa sobre os ramos de suas prprias sub-rvores. As sub-
rvores, por sua vez, so constitudas de outras sub-rvores que so exploradas por subprocessos de
subprocessos e assim por diante.
Entre todos esses processos competitivos, somente um est ativo em cada instante: o que lida com a
alternativa mais promissora naquele momento, isto a alternativa cujo valor para a funo f o mais
baixo. Os processos restantes permanecem congelados at que o valor de f do processo em curso seja
modificado de maneira que uma outra alternativa se revele mais promissora. Ento a atividade dada
a essa alternativa. Pode-se imaginar esse mecanismo de ativao e desativao da seguinte maneira:
ao processo trabalhando sobre a alternativa mais promissora dado um crdito e o processo permane-
ce ativo at que esse crdito tenha se esgotado. Durante o perodo em que est ativo, o processo conti-
nua a expanso da sua sub-rvore, informando uma soluo se algum nodo objetivo for encontrado. O
crdito para cada passo de execuo definido pela estimativa heurstica da alternativa competidora
mais prxima. Esse comportamento exemplificado na Figura 15.2, que se divide em duas partes
principais. Em (a) representado uma mapa rodovirio (sem qualquer pretenso de representao em
escala) onde as cidades so os nodos e os arcos representam estradas, rotuladas com as respectivas
distncias em alguma unidade qualquer. O objetivo atingir a cidade t partindo de s, no menor trajeto
rodovirio possvel. os valores entre colchetes representam a distncia em linha reta entre cada cidade
e a cidade objetivo t. Esses valores sero utilizados para computar a funo heurstica que prev a
distncia que resta a ser percorrida a partir de cada nodo, h(n). Em (b) representada a ordem na qual
o mapa explorado por meio da pesquisa heurstica. A funo estimativa heurstica considera a dis-
tncia at ento percorrida e a que resta percorrer estimada em funo da distncia em linha reta at
t, dada em (a) pelos valores entre colchetes. os valores entre parnteses em (b) indicam a troca de
atividade entre os caminhos alternativos, representando a ordem em que os nodos so expandidos e
no a ordem em que so gerados. Na estimativa do custo da distncia que resta a percorrer a partir de
uma cidade X at o objetivo t, usamos a distncia em linha reta denotada por dist(X, t), de modo que:
f(X) = g(X) + h(X) = g(X) + dist(X, t)
No exemplo dado podemos imaginar a pesquisa heurstica como constituda por dois processos, cada
um deles explorando uma das duas rotas alternativas: o processo 1 a rota a partir de a e o processo 2 a
rota a partir de e. Nos estgios iniciais, o processo 1 mais ativo porque os valores de f ao longo des-
se caminho so os mais baixos. No momento em que o processo 1 est em c e o processo 2 ainda no
saiu de e, a situao muda:
f(c) = g(c) + h(c) = 6 + 4 = 10
f(e) = g(e) + h(e) = 2 + 7 = 9
ento, como f(e) < f(c), o processo 2 ativado, deslocando a rota para f enquanto o processo 1 espera.
Aqui, entretanto, a situao mais uma vez se inverte, pois:
f(f) = 7 + 4 = 11
f(c) = 6 + 4 =10
f(c) < f(f)
155
s e
a
b
c
d t
f
g
2 5
2
2
2
3
3
2
2
(a)
[7]
[5]
[4]
[4]
[3]
(b)
[4]
[2]
s
a e
b
c
d
f
g
t
f(a)=2+5=7
4+4=8
6+4=10
9+3=12
f(e)=2+7=9
7+4 =11
9+2=11
11+0=11
(1)
(2)
(4)
(3)
(5)
(6)
Figura 15.2: Encontrando a rota mais curta entre s e t em um mapa
Portanto o processo 2 pra e o processo 1 novamente ativado. mas em seguida, no nodo d, temos
f(d) = 12 > 11. A ativao passa mais uma vez ao processo 2 que, a partir da, acaba por atingir o ob-
jetivo t. Vamos programar a pesquisa heurstica como um refinamento do programa de pesquisa em
amplitude estudado no captulo anterior. O conjunto de caminhos candidatos ser mais uma vez repre-
sentado por uma rvore dada por meio de dois tipos de termos:
(1) n(N, F/G) representa um nico nodo (uma folha). N um nodo no espao de estados. G
g(N), o custo do caminho percorrido desde o nodo inicial at N, e F f(N)=G+h(N), e
(2) t(N, F/G, Subs) representa uma rvore com sub-rvores no-vazias. N a raiz da rvore, Subs
uma lista de sub-rvores, G g(N) e F o valor atualizado da funo f, isto , o valor de f
para o sucessor mais promissor de N. A lista Subs ordenada de acordo com valores crescentes
de f para as sub-rvores que a compem.
A atualizao dos valores de f necessria para permitir ao programa reconhecer a sub-rvore mais
promissora a cada nvel da rvore de pesquisa, isto , a sub-rvore que contm o nodo mais promissor.
Essa modificao dos valores de f conduz , na verdade, a uma generalizao da definio da funo f.
Tal generalizao amplia o domnio de definio de f, de nodos para rvores. Para um nico nodo da
rvore (uma folha), n, temos a definio original:
f(n)= g(n) + h(n)
Para uma rvore T cuja raiz n e cujos sucessores de n so m1, m2, m3, etc, temos:
f(T) = min f(m
i
)
Um programa para executar pesquisa heurstica segundo as linhas apresentadas dado na Figura 15.3
156
heurist(Incio, Soluo) :-
maior(M), % M > qualquer valor de f
expande([], n(Incio, O/O), M, _, sim, Soluo).
expande(P, n(N, _), _, _, sim, [N | P]) :-
objetivo(N).
expande(P, n(N, F/G), Limite, , Arv1, Sol, Soluo) :-
F =< Limite,
(bagof(M/C, (s(N,M,C), not membro(M,P)), Suc), !,
sucLista(G, Suc, Ts), bestf(Ts, F1),
expande(P,t(N,F1/G,Ts),Limite,Arv1,Sol,Soluo);
Sol = nunca).
expande(P,t(N,F/G,[T|Ts]),Limite, ,Arv1,Sol,Soluo) :-
F =< Limite,
bestf(Ts, BF),
min(Limite, BF, Limite1),
expande([N|P], T, Limite1, T1, Sol, Soluo),
continua(P, t(N, F/G, [T1|Ts]),
Limite, Arv1, Sol1, Sol, Soluo).
expande(_, t(_, _, []), _, _, nunca, _).
expande(_, Arv, Limite, Arv, no, _) :-
f(Arv, F), F > Limite.
continua(_,_,_,_,sim, sim, Soluo).
continua(P,t(N,F/G,[T1|Ts]),Lim,Arv1,Sol1,Sol,Soluo):-
(Sol1=no, insere(T1,Ts,NTs); Sol1=nunca, Ts=Ts),
bestf(NTs, F1),
expande(P,t(N,F1/G,NTs),Lim,Arv1,Sol,Soluo).
sucLista(_, [], []).
sucLista(G0, [N/C | NCs], Ts) :-
G is G0+C, h(N, H), F is G+H,
sucLista(G0, NCs, Ts1),
insere((n(N, F/G), Ts1, Ts).
insere(T, Ts, [T|Ts]) :-
f(T, F),
bestf(Ts, F1),
F =< F1, !.
insere(T, [T1|Ts], [T1|Ts1]) :-
insere(T, Ts, Ts1).
f(n(_, F/_), F).
f(t(_, F/_, _), F).
bestf([T|_], F) :-
f(T, F).
bestf([], M) :-
maior(M).
min(X, Y, X) :- X =< Y, !.
min(X, Y, Y).
Figura 15.3: Um programa de pesquisa heurstica.
Como no programa de pesquisa em amplitude apresentado no captulo anterior, o procedimento chave
aqui expande/6, agora com um argumento adicional:
expande(P, Arv, Limite, Arv1, Sol, Soluo)
e que corresponde expanso da sub-rvore corrente enquanto o seu valor de f for menor ou igual a
Limite. Os argumentos de expande/6 so:
P: Caminho entre o nodo inicial e Arv;
Arv: Sub-rvore de pesquisa corrente;
Limite: Limite do valor de f para a expanso de Arv;
Arv1: Arv expandida dentro do valor Limite. Consequentemente o valor de f para Arv1
maior do que Limite, a menos que um nodo objetivo tenha sido atingido;
Sol: Indicador que pode assumir os valores sim, no ou nunca;
157
Soluo: Um caminho-soluo a partir do nodo inicial, passando por Arv1 at um nodo objetivo
dentro do valor Limite.
Os parmetros P, Arv e Limite so os argumentos de entrada do procedimento expande/6, isto , eles
devem estar instanciados sempre que esse procedimento for chamado. O procedimento expande/6
produz trs tipos de resultados, o que indicado pelo valor do argumento Sol, da seguinte maneira:
(1) Sol = sim;
Soluo = Um caminho-soluo, encontrado pela expanso de Arv dentro do valor Limite;
Arv1 = No instanciada.
(2) Sol = no;
Soluo = No instanciada;
Arv1 = Arv expandida de forma que seu valor para f excede o valor de Limite.
(3) Sol = nunca;
Soluo = No instanciada;
Arv1 = No instanciada..
O ltimo caso indica que Arv uma alternativa "morta" qual no deve ser dada nenhuma chance de
expanso posterior. Esse caso surge quando o valor de f para Arv menor ou igual ao valor de Limite
mas a rvore no pode ser expandida porque nenhum nodo nela possui sucessor, ou ento tal sucessor
iria originar um ciclo.
Algumas das clusulas sobre expande/6 merecem uma explicao mais detalhada: As clusulas que
lidam com o caso mais complexo, quando Arv possui sub-rvores, isto :
Arv = t(N, F/G, [T | Ts])
Em tais casos, primeiro a sub-rvore mais promissora, T expandida. essa expanso no dado o
limite Limite, mas possivelmente algum valor mais baixo, dependendo dos valores de f para as outras
sub-rvores competidoras, Ts. Isso assegura que a sub-rvore em expanso em um determinado mo-
mento sempre a mais promissora. Aps o melhor caminho candidato ter sido expandido, um proce-
dimento auxiliar, continua/7 decide o que fazer a seguir. Isso depende do tipo de resultado produzido
pela ltima expanso. Se uma soluo foi encontrada, ento ela relatada ao usurio, seno o proces-
so continua.
A clusula que lida com o caso
Arv = n(N, F/G)
gera os nodos sucessores de N, juntamente com os custos dos arcos entre N e esses sucessores. O
procedimento sucLista/3 organiza uma lista de sub-rvores a partir desses nodos sucessores, tambm
computando seus valores para as funes f e g. A rvore resultante ento expandida enquanto o va-
lor de Limite permitir. Se, por outro lado, no h sucessores, ento o nodo abandonado para sempre,
pela instanciao de Sol = nunca. Outras relaes a considerar so:
s(N, M, C): M um nodo sucessor de N no espao de estados. C o custo do arco que liga N a
M.
h(N, H): H uma estimativa heurstica do custo do melhor caminho do nodo N a algum nodo
objetivo.
maior(M): M algum valor especificado pelo usurio, reconhecidamente maior do que qualquer
valor possvel para f
O programa apresentado na Figura 15.3 uma variao de um algoritmo heurstico, conhecido na
literatura como A
*
. Esse algoritmo sempre atraiu a ateno dos pesquisadores devido a suas caracte-
rsticas particulares. Um importante resultado extrado da anlise matemtica de A
* o seguinte:
Um algoritmo de pesquisa dito ser admissvel se sempre produz uma soluo tima (isto ,
158
um caminho de custo mnimo), se tal soluo existe. O programa da Figura 15.3, que produz
por backtracking todas as solues possveis, pode ser considerado admissvel se a primeira
soluo encontrada for uma soluo tima. Considerando que para cada nodo n no espao de
estados, h*(n) denota o custo do caminho timo de n at um nodo objetivo. Um teorema sobre
a admissibilidade de
A
* diz que: Um algoritmo
A
* que utiliza uma funo heurstica h tal que
para todos os nodos n de um espao de estados, h(n)
h
*(n), admissvel.
Esse resultado possui um grande valor prtico. Mesmo sem conhecer o valor exato de h* podemos
encontrar um limite inferior de h* e empreg-lo como se fosse h em
A
*. Isso garantia suficiente de
que
A
* ir produzir uma soluo tima. H um limite inferior trivial: h(n) = 0, para todo n no espao
de estados. Isso, na verdade, garante a admissibilidade. A desvantagem de se ter h = 0 que isso no
possui qualquer potencial heurstico e no oferece nenhuma orientao para a pesquisa.
A
* usando h
= 0 se comporta de maneira similar pesquisa em amplitude. Na verdade se reduz pesquisa em am-
plitude no caso em que a funo de custo dos arcos c(n, n') possui o valor 1 para todos os arcos (n, n')
do espao de estados. A falta de potencial heurstico resulta em elevada complexidade, assim deseja-
ramos ter valores para h que fossem limites inferiores de h* (para assegurar a admissibilidade), mas
que fossem to prximos quanto possvel de h* (para assegurar a eficincia). No caso ideal, se conhe-
cemos o valor de h*, usamos esse prprio valor. Um algoritmo
A
* usando h* encontra a soluo ti-
ma diretamente, sem a necessidade de backtracking.
15.2 UMA APLICAO DA PESQUISA HEURSTICA
Para aplicar o programa da Figura 15.3 a algum problema particular, temos que adicionar as relaes
especficas do problema em questo. Tais relaes, alm de definir o problema, tambm transmitem,
na forma de funes heursticas, a informao heurstica necessria sua resoluo. Os predicados
especficos do problema so (1) s(Nodo, Nodo1, Custo), que verdadeiro se existe um arco de custo
Custo entre Nodo e Nodo1 no espao de estados, (2) objetivo(Nodo), que verdadeiro se Nodo um
nodo objetivo no espao de estados, e (3) h(Nodo, H), onde H uma estimativa heurstica do custo do
caminho mais barato de Nodo at um nodo objetivo.
Como um exemplo iremos retomar o processo do jogo do oito, apresentado no captulo anterior. As
relaes especficas do jogo do oito so apresentadas na figura 15.5. Um nodo no espao de estados
corresponde, nesse caso, a alguma configurao das peas do jogo. No programa isto representado
por meio de uma lista contendo as posies correntes das peas. Cada posio representada por um
par de coordenadas X/Y. A ordem das posies na lista a seguinte:
(1) Posio da casa vazia,
(2) Posio da pea 1,
(3) Posio da pea 2, etc...
A situao objetivo (ver Figura 15.4) definida pela clusula
objetivo( [ 2/2, 1/3, 2/3, 3/3, 3/2, 3/1, 2/1, 1/1, 1/2 ] ).
Uma relao auxiliar usada no programa d(S1, S2, D), onde D a distncia horizontal entre S1 e S2,
somada com a distncia vertical entre essas mesmas posies. Queremos minimizar o tamanho das
solues, logo definiremos o custo de todos os arcos no espao de estados como sendo igual a 1. No
programa da Figura 15.5 definimos, como posies iniciais, os estados apresentados a seguir.
159
2 1 6
4 8
7 5 3
1 2 3
8 4
7 6 5
(a) (b) (c) objetivo
1 3 4
8 2
7 6 5
2 8 3
1 4 6
7 5
Figura 15.4: Trs posies iniciais para atingir um objetivo:
(a) requer 4 movimentos, (b) requer 5 movimentos e (c) requer 18 movimentos.
No programa apresentado na Figura 15.5, a funo heurstica, h, definida por meio da relao h(Pos,
H), onde Pos uma posio do jogo e H a combinao de dois fatores:
(1) disTot: a distncia total das oito peas em Pos s suas casas correspondentes na situao
objetivo. Por exemplo, na posio inicial apresentada na Figura 15.4, disTot = 4.
(2) seq: o "escore de sequncia", que mede o grau de ordenao das peas na posio corrente
em relao ordem estabelecida na configurao objetivo. seq computado pela soma dos es-
cores de todas as peas de acordo com as seguintes regras:
Uma pea no centro do tabuleiro tem escore 1;
Uma pea em uma posio no-central tem escore 0 se seguida pelo seu sucessor apro-
priado, em sentido horrio;
Em qualquer outra situao, uma pea tem escore 2.
Por exemplo, para a posio inicial apresentada na Figura 15.4, seq = 6.
A estimativa heurstica, H, computada por:
H = disTot + 3*seq
Essa funo heurstica funciona bem, no sentido em que dirige, de maneira muito eficiente, a pesquisa
para o objetivo estabelecido. Por exemplo, na soluo do jogo proposto pelas configuraes iniciais
apresentadas na Figura 15.4(a) e (b), nenhum nodo expandido alm dos que compem o caminho
mais curto para a soluo. Isso significa que as solues timas, nesses dois casos so encontradas
diretamente, sem necessidade de backtracking. Mesmo o problema mais difcil, proposto na Figura
15.4(c) solucionado quase que diretamente. Um problema com essa heurstica, entretanto, que ela
no garante que a soluo tima ser encontrada sempre antes de qualquer outra soluo mais longa.
A funo h no satisfaz a condio de admissibilidade: h h* para todos os nodos do espao de esta-
dos. Por exemplo, na posio inicial da Figura 15.4(a) temos:
h = 4 + 3*6 = 22
e
h* = 4
Por outro lado, a medida de distncia total admissvel, pois para todas as posies vale:
disTot h*
Essa relao pode ser facilmente demonstrada por meio do seguinte argumento: Se simplificassemos o
problema, permitindo s peas passar umas por cima das outras, ento cada pea poderia alcanar sua
casa-objetivo seguindo uma trajetria cuja distncia exatamente a soma da sua distncia horizontal
com a distncia vertical at esse objetivo. Ento a soluo tima seria exatamente do tamanho com-
putado por disTot. No problema original, entretanto, h interao entre as peas, que se encontram
umas nos caminhos das outras. Isso evita que as peas possam ser movidas ao longo de suas trajetri-
as mais curtas, o que assegura que o tamanho da soluo tima encontrada ser sempre maior ou igual
a disTot.
160
s([Vazio | L], [T | L1], 1) :-
move(Vazio, T, L, L1).
move(E, T, [T | L], [E | L]) :-
d(E, T, 1).
move(E, T, [T1 | L], [T1 | L1]) :-
move(E, T, L, L1).
d(X/Y, X1/Y1, D) :-
dif(X, X1, Dx),
dif(Y, Y1, Dy),
D is Dx + Dy.
dif(A, B, D) :-
D is A - B, D >=0, !;
D is B - A.
h([Vazio | L], H) :-
objetivo([Vazio | G]),
disTot(L, G, D),
seq(L, S), H is D + 3*S.
disTot([], [], 0).
disTot([T | L], [T1 | L1], D) :-
d(T, T1, D), disTot(L, L1, D2), D is D1+D2.
seq([Prim | L], S) :-
seq([Prim | L], Prim, S).
seq([T1, T2 | L], Prim, S) :-
escore(T1,T2,S1),
seq([T2 | L], Prim,S2), S is S1+S2.
seq([Ult], Prim, S) :-
escore(Ult, Prim, S).
escore(2/2, _, 1) :- !. escore(1/3, 2/3, 0) :- !.
escore(2/3, 3/3, 0) :- !. escore(3/3, 3/2, 0) :- !.
escore(3/2, 3/1, 0) :- !. escore(3/1, 2/1, 0) :- !.
escore(2/1, 1/1, 0) :- !. escore(1/1, 1/2, 0) :- !.
escore(1/2, 1/3, 0) :- !. escore(_, _, 2).
objetivo([2/2, 1/3, 2/3, 3/3, 3/2, 3/1, 2/1, 1/1, 1/2]).
incio1([2/2, 1/3, 3/2, 2/3, 3/3, 3/1, 2/1, 1/1, 1/2 ]).
incio2([2/1, 1/2, 1/3, 3/3, 3/2, 3/1, 2/2, 1/1, 2/3]).
incio3([2/2, 2/3, 1/3, 3/1, 1/2, 2/1, 3/3, 1/1, 3/2]).
mostraSol([]).
mostraSol([P | L]) :-
mostraSol(L),
nl, write('---'),
mostraPos(P).
mostraPos( [ S0, S1, S2, S3, S4, S5, S6, S7, S8 ] ) :-
membro(Y, [3, 2, 1]), membro(X, [1, 2, 3]),
membro(P-X/Y, [' '-S0, 1-S1, 2-S2, 3-S3, 4-S4
5-S5, 6-S6, 7-S7, 8-S8] ),
nl, write(P), fail.
mostraPos(_).
Figura 15.5: Procedimentos especficos para o jogo do oito.
RESUMO
Informaes heursticas podem ser usadas para estimar a distncia entre um nodo e um objetivo
em um espao de estados. Neste captulo considerou-se estimativas heursticas numricas;
O princpio da pesquisa heurstica orienta o processo de pesquisa de forma que o nodo expan-
dido sempre o mais promissor, de acordo com a estimativa heurstica;
O algoritmo de pesquisa heurstica A*, que adota esse princpio, foi implementado na Figura
15.3;
Para usar o algoritmo A* na soluo de problemas concretos, um espao de estados e uma fun-
o heurstica devem ser definidos. Para problemas de grande complexidade a dificuldade resi-
de em encontrar a funo heurstica apropriada;
161
O teorema da admissibilidade ajuda a estabelecer se A*, usando uma particular funo heursti-
ca, ir sempre encontrar uma soluo tima.
EXERCCIOS
15.1 Proponha outras aplicaes para o programa de pesquisa heurstica apresentado no presente ca-
ptulo e formalize sua representao em Prolog.
15.2 Para os problemas propostos no exerccio 15.1, determine a admissibilidade da funo heurstica
escolhida.
162
16. REDUO DE PROBLEMAS E GRAFOS E/OU
Os grafos E/OU so uma representao adequada para problemas que podem ser decompostos em
subproblemas mutuamente independentes. Exemplos de tais problemas incluem a seleo de roteiros,
integrao simblica, jogos, prova automtica de teoremas, etc. No presente captulo sero desenvol-
vidos programas para a pesquisa heurstica em grafos E/OU.
16.1 REPRESENTAO DE PROBLEMAS
Nos captulos anteriores, a soluo de problemas estava centrada na representao de seu espao de
estados. Assim, um problema podia ser reduzido a encontrar um caminho adequado em um espao de
estados. Uma outra representao, a dos grafos E/OU, parece adequar-se mais naturalmente a certos
tipos de problemas, tirando partido da possibilidade de decomposio do problema original em sub-
problemas mutuamente exclusivos, que podem ser solucionados de forma independente.
Isso ser ilustrado por meio de um exemplo. Seja o problema de encontrar uma rota em um mapa ro-
dovirio entre duas cidades dadas, como ilustrado na Figura 16.1. As distncias entre as cidades so
inicialmente desconsideradas. O problema poderia, naturalmente, ser reduzido a encontrar um cami-
nho em um espao de estados, que teria a mesma aparncia do mapa, com os nodos correspondendo a
cidades, os arcos a conexes diretas entre cidades e os custos dos arcos correspondendo s distncias
entre elas. Entretanto, vamos construir outra representao, baseada em uma decomposio natural do
problema.
No mapa da Figura 16.1 h tambm um rio. Vamos assumir que h tambm duas pontes atravs das
quais o rio pode ser cruzado: Uma ponte na cidade f e outra na cidade g. Obviamente a rota dever
incluir uma dessas pontes, de modo que forosamente deve-se passar por f ou por g. Surgem ento
duas alternativas:
Para encontrar um caminho entre a e z:
(1) Encontrar um caminho de a at z via f, ou
(2) Encontrar um caminho de a at z via g.
a
b e c
d
f
g
h i
z
j
k
2
2
3
3 1
3
4
2
2
1
3 2
3
2
3
5
3
(rio)
Figura 16.1: Encontrar um roteiro de a a z em um mapa rodovirio
163
As duas alternativas dadas podem agora ser decompostas da seguinte maneira:
(1) Para encontrar um caminho de a a z via f:
1.1 Encontrar um caminho de a a f;
1.2 Encontrar um caminho de f a z.
(2) Para encontrar um caminho de a a z via g:
2.1 Encontrar um caminho de a a g;
2.2 Encontrar um caminho de g a z.
Em resumo, tem-se duas alternativas para a soluo do problema principal: (1) via f ou (2) via g.
Alm disso, cada uma dessas duas alternativas pode ser decomposta em dois subproblemas (1.1 e 1.2
ou 2.1 e 2.2 respectivamente). O que importante aqui que, em ambas as alternativas, cada um dos
subproblemas pode ser solucionado independentemente do outro. Essa decomposio pode ser repre-
sentada graficamente atravs de um grafo E/OU, como mostrado na Figura 16.2, onde os arcos in-
terligados indicam a condio E entre os subproblemas.
a - z
a-z via f a-z via g
a-f f-z a-g g-z
Figura 16.2: Representao E/OU do problema proposto na Figura 16.1
Na figura acima, os nodos correspondem a problemas ou subproblemas. Arcos interligados significam
que todos os subproblemas devem ser solucionados. Como so, entretanto, representados os nodos
objetivos em um grafo E/OU? Estes iro corresponder, nessa representao, a subproblemas triviais
ou primitivos. No exemplo dado, um subproblema desse tipo seria: "Encontrar um roteiro de a at b".
Para isso existe uma conexo direta no mapa entre as cidades a e b.
At aqui alguns conceitos importantes foram introduzidos: Um grafo E/OU um grafo direcionado,
no qual os nodos representam problemas e os arcos indicam relaes entre tais problemas. H tambm
relaes entre os prprios arcos. Essas relaes so E e OU, dependendo de termos de resolver todos
os problemas sucessores ou apenas um deles. Essa idia exemplificada na Figura 16.3.
P Q
P1 P2 P3 Q1 Q2 Q3
(a) (b)
Figura 16.3: (a) Para resolver P, resolva P1 ou P2 ou P3. (b) Para resolver Q resolva Q1 e Q2 e Q3.
Em princpio um nodo pode possuir simultaneamente alguns sucessores conectados por meio de arcos
E e outros por meio de arcos OU. Assumiremos, entretanto, que cada nodo somente possui sucessores
de um nico tipo. Todo grafo E/OU pode ser representado dessa forma atravs da introduo de arcos
164
OU auxiliares, quando necessrio. Assim um nodo a partir do qual so emitidos somente arcos E so
denominados nodos E e os que emitem apenas arcos OU so chamados nodos OU.
Na representao atravs de espaos de estado, uma soluo para um problema era dada por um cami-
nho nesse espao de estados. na representao E/OU, uma soluo tem necessariamente que incluir
todos os subproblemas decorrentes de um nodo E, de maneira que esta no representada mais por
um caminho e sim por uma rvore. Essa rvore-soluo, que denominaremos T definida da seguinte
maneira:
O problema original P a raiz da rvore T;
Se P um nodo OU, ento somente um nico dentre os seus sucessores, juntamente com a sua
particular sub-rvore soluo est em T;
Se P um nodo E, ento todos os seus sucessores, juntamente com suas sub-rvores soluo
esto em T.
A Figura 16.4 ilustra essa definio. Ali temos custos associados aos arcos, que nos permitem formu-
lar um critrio de otimizao. Podemos, por exemplo, definir o custo de uma rvore soluo como
sendo a soma dos custos de todos os seus arcos. Como normalmente estamos interessados em minimi-
zar os custos, a rvore soluo apresentada em (c) dever ser a preferida.
a
b
d e
h
c
f g
i
(a)
1 3
1 1 2 1
6 2
3
a
b
d e
h
(b)
1
1 1
6
a
h
c
f g
(c)
3
2 1
2
Figura 16.4: (a) Um grafo E/OU: d, g e h so nodos objetivos.
(b) e (c) so rvores soluo com custos 9 e 8 respectivamente
No temos, entretanto, que basear nossa medida de otimizao exclusivamente no custo dos arcos.
Algumas vezes pode ser mais natural associar os custos com os nodos ao invs de com os arcos, ou
mesmo com arcos e nodos simultaneamente. Resumindo os conceitos relacionados com a representa-
o de grafos E/OU:
165
A representao em grafos E/OU baseia-se no princpio da reduo de problemas em subpro-
blemas;
Os nodos em um grafo E/OU correspondem aos problemas. As ligaes entre os nodos corres-
pondem s relaes entre problemas;
Um nodo do qual partem ligaes OU um nodo OU. Para solucionar um nodo OU basta solu-
cionar um de seus sucessores;
Um nodo do qual partem ligaes E um nodo E. Para solucionar um nodo E deve-se solucio-
nar todos os seus sucessores;
Para um determinado grafo E/OU, um particular problema especificado atravs de duas coi-
sas:
(1) Um nodo inicial, e
(2) Uma condio de reconhecimento de nodos objetivos;
Nodos objetivos ou terminais correspondem a problemas triviais ou primitivos;
Uma soluo representada por um grafo-soluo, um subgrafo do grafo E/OU original;
A representao dos espaos de estado pode ser vista como um caso especial da representao
E/OU, na qual todos os nodos so nodos OU;
Para nos beneficiarmos da representao E/OU, os nodos relacionados a uma condio E devem
representar subproblemas que possam ser solucionados de forma mutuamente independente. O
critrio de independncia pode ser relaxado se h uma ordenao entre os subproblemas E tal
que as solues dos subproblemas anteriores no sejam destrudas na soluo dos que se suce-
dem;
Custos podem ser associados aos arcos ou aos nodos ou a ambos, para a formalizao de um
critrio de otimizao.
a-z
a-z via f
a-f f-z
a-f via d f-z via i
a-d d-f f-i i-z
a-d via b
a-b b-d
Figura 16.5: Uma soluo para o problema de roteiros da Figura 16.1
16.2 EXEMPLOS DE REPRESENTAO DE PROBLEMAS EM GRAFOS E/OU
16.2.1 O PROBLEMA DE SELEO DE ROTEIROS
166
Para encontrar o caminho mais curto no problema proposto na Figura 16.1, um grafo E/OU, incluindo
uma funo de custo, pode ser definido da seguinte maneira:
Os nodos OU so da forma X-Z, significando: encontre o caminho de X at Z;
Os nodos E so da forma X-Z via Y, significando: encontre o caminho mais curto de X at Z,
sob a restrio de que o caminho passe por Y;
Um nodo X-Z um nodo objetivo (um problema primitivo), se X e Z esto diretamente conec-
tados no mapa;
O custo de cada nodo objetivo X-Z dado pela distncia "rodoviria" entre as cidades X e Z;
O custo de todos os demais nodos (no terminais) zero.
16.2.2 O PROBLEMA DAS TORRES DE HANI
O problema das torres de Hani, mostrado na Figura 16.6 um outro exemplo clssico de uma aplica-
o efetiva do princpio de decomposio de problemas representado atravs dos grafos E/OU. Para
fins de simplicidade consideraremos uma verso reduzida do problema contendo apenas trs anis.
c
b
a a
b
c
1 2 3 1 2 3
?
Figura 16.6: O problema das Torres de Hani
Podemos enunciar o problema das Torres de Hani da seguinte maneira: H trs "estacas", 1, 2 e 3, e
trs "anis", a, b e c (sendo a o menor e c o maior). Inicialmente, todos os anis esto empilhados
ordenadamente na estaca 1. O problema transfer-los para a estaca 3, na mesma ordem original, mo-
vendo apenas um anel de cada vez e respeitando a restrio de que nenhum anel pode ser colocado
sobre outro menor do que ele. Este problema pode ser decomposto em trs subproblemas:
(1) Colocar o anel a na estaca 3;
(2) Colocar o anel b na estaca 3;
(3) Colocar o anel c na estaca 3.
Tais objetivos, entretanto, no so mutuamente independentes. Por exemplo, o anel a pode ser coloca-
do imediatamente na estaca 3, entretanto isso impedir a soluo dos outros dois subproblemas (a
menos que se desmanche a soluo do primeiro), porque o enunciado original do problema probe a
colocao de qualquer anel sobre outro menor do que ele. Por outro lado h uma ordenao conveni-
ente dos objetivos que permite a derivao de uma soluo. Essa ordenao deriva do seguinte racio-
cnio: O terceiro objetivo (anel c na estaca 3) o mais difcil, porque a movimentao do anel c est
sujeita a mais restries. Uma boa idia em casos como esse, que na maioria das vezes funciona,
tentar atingir primeiro o objetivo mais difcil. A lgica por trs deste princpio a seguinte: como os
outros objetivos so mais fceis (no sujeitos a tantas restries, possivelmente sero atingidos sem a
necessidade de desmanchar a soluo do mais difcil. A estratgia de soluo que resulta desse princ-
pio para o problema em questo :
(1) Primeiro satisfazer o objetivo: anel c na estaca 3;
167
(2) Depois, satisfazer os demais objetivos.
Mas esse primeiro objetivo no pode ser imediatamente atingido, porque na soluo inicial o anel c
no pode ser movido. Portanto necessrio primeiro possibilitar esse movimento, refinando a estrat-
gia para:
(1) Possibilitar a movimentao do anel c da estaca 1 para a estaca 3;
(2) Mover o anel c da estaca 1 para a estaca 3;
(3) Satisfazer os demais objetivos.
O anel c somente pode ser movido de 1 para 3 se tanto a como b estiverem empilhados na estaca 2.
Assim o problema inicial, de mover a, b e c para a estaca 3 fica reduzido seguinte formulao, com-
posta de trs subproblemas:
(1) Mover a e b de 1 para 2;
(2) Mover c de 1 para 3;
(3) Mover a e b de 2 para 3.
O subproblema (2) trivial (tem soluo imediata). Os outros dois subproblemas podem ser resolvi-
dos independentemente do problema (2) porque os anis a e b podem ser movidos sem considerar a
posio de c. Para resolver os problemas (1) e (3), o mesmo princpio de decomposio pode ser em-
pregado (agora a movimentao do anel b o problema mais difcil). O problema (1) pode ento ser
reduzido a trs subproblemas triviais:
Para mover a e b de 1 para 2:
(1) Mover a de 1 para 3;
(2) Mover b de 1 para 2;
(3) Mover a de 3 para 2.
A decomposio do problema restante (mover a e b de 2 para 3) fica como um exerccio para o leitor.
16.3 PROCEDIMENTOS BSICOS DE PESQUISA EM GRAFOS E/OU
O modo mais simples de pesquisar grafos E/OU em Prolog empregar o prprio mecanismo de pes-
quisa do Prolog. Isso trivial, uma vez que o significado operacional dos programas Prolog nada mais
do que um procedimento para pesquisa em grafos E/OU. Por exemplo, o grafo E/OU apresentado na
Figura 16.4 (ignorando os custos associados aos arcos), pode ser especificado por meio das seguintes
clusulas:
a :- b.
a :- c.
b :- d, e.
c :- f, g.
e :- h.
f :- h, i.
d. g. h.
Para perguntar se o problema a pode ser resolvido, simplesmente formula-se a consulta:
?- a.
e o sistema Prolog ir efetivamente pesquisar a rvore apresentada na Figura 16.4 em profundidade e
responder "sim" aps haver visitado a parte do grafo de pesquisa correspondente a rvore soluo. A
grande vantagem desta tcnica de pesquisa E/OU a sua simplicidade, entretanto ela possui algumas
desvantagens:
Somente se consegue obter respostas do tipo sim/no, e no a rvore soluo como seria dese-
168
jvel. Poder-se-ia inclusive reconstruir a rvore-soluo a partir do mecanismo de tracing, mas
essa seria uma soluo grosseira e insuficiente no caso de se desejar a rvore soluo explici-
tamente acessvel como um objeto do programa;
Programas desse tipo so difceis de estender de modo a permitir a manipulao de custos;
Se o grafo E/OU for um grafo genrico, contendo ciclos, ento a estratgia de pesquisa em pro-
fundidade do Prolog poderia entrar em um lao recursivo infinito.
Tais deficincias sero removidas gradualmente. Inicialmente definiremos uma estratgia mais ade-
quada para a pesquisa em profundidade em grafos E/OU. Para isso ser introduzida uma relao bin-
ria que ser representada pelo operador infixo "--->". Por exemplo, o nodo a, ligados ao seus dois
sucessores "OU" ser representado pela clusula:
a ---> ou:[b, c]
Os smbolos "--->" e ":" so ambos operadores infixos que podem ser definidos da seguinte maneira:
:- op(600, xfx, '--->').
e
:- op(500, xfx, ':').
de modo que o grafo E/OU da Figura 16.4 pode ser completamente especificado por meio das clusu-
las:
a ---> ou:[b, c].
b ---> e:[d, e].
c ---> e:[f, g].
e ---> ou:[h].
f ---> ou:[h, i].
objetivo(d).
objetivo(g).
objetivo(h).
A correspondente pesquisa em profundidade para grafos E/OU pode ser definida a partir dos seguintes
princpios:
Para resolver um nodo N:
(1) Se N um nodo objetivo, ento j est solucionado de forma trivial;
(2) Se N possui sucessores OU, ento solucione um deles. (Tente um de cada vez at que uma so-
luo seja encontrada);
(3) Se N possui sucessores E, ento solucione todos eles. (Tente um de cada vez at que todos es-
tejam solucionados);
(4) Se as regras acima no produzirem uma soluo, ento assuma que o problema no pode ser re-
solvido.
Um programa para executar tais regras pode ser o seguinte:
resolve(Nodo) :-
objetivo(Nodo).
resolve(Nodo) :-
Nodo ---> ou:Nodos,
membro(Nodo1, Nodos), resolve(Nodo1).
resolve(Nodo) :-
Nodo ---> e:Nodos, resolveTodos(Nodos).
resolveTodos([]).
resolveTodos([Nodo|Nodos]) :-
resolve(Nodo), resolveTodos(Nodos).
onde membro/2 a relao usual de ocorrncia em listas. O programa acima, no entanto, tem ainda as
seguintes desvantagens:
169
No produz uma rvore soluo, e
suscetvel a laos infinitos, dependendo da presena de ciclos no grafo E/OU.
Pode-se entretanto modific-lo facilmente para produzir uma rvore soluo. Para isso modifica-se a
relao resolve/1 de modo que ela passe a ter dois argumentos:
resolve(Nodo, ArvSol).
Para a representao da rvore soluo h trs casos a considerar:
(1) Se Nodo um nodo objetivo, ento a rvore soluo correspondente o prprio Nodo;
(2) Se Nodo um nodo OU, ento sua rvore soluo da forma:
Nodo ---> SubArv
onde SubArv uma rvore soluo para um dos sucessores de Nodo;
(3) Se Nodo um nodo E, ento sua rvore soluo da forma:
Nodo ---> e:SubArvs
onde SubArvs a lista das rvores soluo de todos os sucessores de Nodo.
Por exemplo, para o grafo E/OU da Figura 16.4, a primeira soluo obtida a partir do nodo a repre-
sentada por:
a ---> b ---> e:[d, e ---> h]
As trs formas de uma rvore soluo correspondem s trs clusulas da relao resolve/1 original.
Assim, para modificar o programa suficiente adicionar uma rvore soluo como segundo argu-
mento de resolve/1. Na Figura 16.7 apresentado o programa resultante acrescido de um procedi-
mento adicional, mostra/2 para a apresentao de rvores soluo. Tal programa, entretanto, ainda
est sujeito a laos infinitos. Uma maneira simples de evit-los manter o acompanhamento da pro-
fundidade da pesquisa, impedindo o programa de ultrapassar um certo limite. isso obtido por meio
da introduo de um terceiro argumento na relao resolve/2:
resolve(Nodo, ArvSol, ProfMax)
Como anteriormente, Nodo representa um problema a ser solucionado e ArvSol uma soluo cuja
profundidade no ultrapassa ProfMax, que a profundidade mxima permitida de pesquisa no grafo.
No caso em que ProfMax=0, nenhuma expanso adicional permitida. Por outro lado, se ProfMax>0,
ento Nodo pode ser expandido e seus sucessores sero examinados at uma profundidade limitada
em ProfMax-1. Isso pode ser facilmente incorporado ao programa da Figura 16.7. Por exemplo, a
segunda clusula de resolve/2, acrescida do novo argumento fica:
resolve(Nodo, Nodo ---> Arv, ProfMax) :-
ProfMax > 0, Nodo ---> or:Nodos,
membro(Nodo1, Nodos),
P1 is ProfMax-1, resolve(Nodo1, Arv, P1).
Esse procedimento de pesquisa em rpofundidade limitada pode tambm ser utilizado para simular a
pesquisa em amplitude. A idia aqui executar a pesquisa em profundidade de forma repetitiva, cada
vez com um limite maior de profundidade, at que uma soluo seja encontrada. Isto , tentar o pro-
blema com ProfMax=0, depois 1, depois 2, etc. Um programa que implementa essa idia :
simulaAmpl(Nodo, ArvSol) :-
tentaProf(Nodo, ArvSol, 0).
tentaProf(Nod, ArvSol, Prof) :-
resolve(Nodo, ArvSol, Prof),
Prof1 is Prof+1,
tentaProf(Nodo, ArvSol, Prof1).
resolve(Nodo, Nodo) :-
objetivo(Nodo).
resolve(Nodo, Nodo ---> Arv) :-
Nodo ---> ou:Nodos,
170
membro(Nodo1, Nodos), resolve(Nodo1, Arv).
resolve(Nodo, Nodo ---> e:Arvs) :-
Nodo ---> e:Nodos,resolveTodos(Nodos,Arvs).
resolveTodos([], []).
resolveTodos([Nodo|Nodos], [Arv|Arvs]) :-
resolve(Nodo,Arv),
resolveTodos(Nodos, Arvs).
mostra(Arv) :-
mostra(Arv, 0), !.
mostra(Nodo ---> Arv, H) :-
write(Nodo),write(--->),
H1 is H+7,mostra(Arv,H1),!.
mostra(e:[T], H) :-
mostra(T, H).
mostra(e:[T|Ts], H) :-
mostra(T, H), tab(H), mostra(e:Ts, H), !.
mostra(Nodo, H) :-
write(Nodo), nl.
Figura 16.7: Um programa para a pesquisa em profundidade em grafos E/OU
A desvantagem desse programa que ele reprete a pesquisa nos nveis superiores do grafo de pesquisa
cada vez que a profundidade limite incrementada.
16.4 PESQUISA HEURSTICA EM GRAFOS E/OU
Os procedimentos de pesquisa em grafos E/Ou apresentados na seo anterior executam sua tarefa de
forma sistemtica e exaustiva sem empregar qualquer perspectiva heurstica. Para problemas comple-
xos, tais procedimentos se apresentam ineficientes, devido complexidade combinatria do espao de
pesquisa. portanto necessrio empregar funes heursticas com o propsito de evitar as alternativas
que acabaro por se tornar improdutivas. As perspectivas heursticas que sero introduzidas na pre-
sente seo iro se basear em estimativas numricas relacionadas com a dificuldade dos problemas em
grafos E/OU. O programa que ser desenvolvido pode ser visto como uma generalizao do programa
de pesquisa heurstica em espaos de estados apresentado no captulo anterior.
Inicialmente deve-se introduzir um critrio de otimizao baseado nos custos dos arcos em um grafo
E/OU. Primeiro a representao de tais grafos ser estendida para incluir custos. Por exemplo, o grafo
E/OU da Figura 16.4 pode ser representado atravs das seguintes clusulas:
a ---> ou:[b/1, c/3]
b ---> e:[d/1, e/1].
c ---> e:[f/2, g/1].
e ---> ou:[h/6].
f ---> ou:[h/2, i/3].
objetivo(d).
objetivo(g).
objetivo(h).
O custo da rvore soluo ser definido como sendo a soma dos custos de todos os arcos na rvore. O
objetivo ser uma rvore soluo de custo mnimo. Para ilustrao empregaremos mais uma vez a
Figura 16.4.
interessante definir o custo de um nodo em grafos E/OU como sendo o custo da rvore soluo ti-
ma para esse nodo. Assim definido, o custo do nodo passa a representar a dificuldade desse nodo.
Assumiremos agora que podemos estimar os custos dos nodos no grafo E/OU, atravs de alguma fun-
o heurstica h, mesmo sem conhecer suas rvores soluo. Tais estimativas sero utilizadas para
orientar a pesquisa. O programa comear a pesquisa no nodo inicial e, atravs de expanses realiza-
das sobre os nodos j visitados, construir gradualmente uma rvore de pesquisa. Esse processo ir
construir uma rvore mesmo nos casos em que o grafo E/OU no seja uma rvore. Em tais casos o
grafo ir se desdobrar em uma rvore pela duplicao de algumas de suas partes.
171
O processo de pesquisa ir, a cada momento, selecionar para expanso a rvore candidata mais pro-
missora ao desenvolvimento da rvore soluo. A questo agora : Como a funo h usada para
estimar o quanto promissora uma certa rvore candidata? Ou o quanto promissor um determinado
nodo candidato a raiz de uma rvore soluo?
Para um determinado nodo N na rvore de pesquisa, H(N) ir denotar a sua dificuldade estimada. para
um nodo folha da rvore de pesquisa corrente, H(N) = h(N). Por outro lado, para um nodo interior
dessa rvore, no necessrio empregar a funo h diretamente porque j se possui alguma informa-
o adicional sobre ele, isto , j conhecemos os seus sucessores. Portanto, como ilustrado pela Fi-
gura 16.8, a dificuldade de um nodo OU interior pode ser dada aproximadamente por:
H(N) = min(custo(N, Ni)+H(Ni))
onde custo(N, Ni) o custo do arco entre N e Ni. A regra de minimizao se justifica pelo fato de que,
para solucionar N, deve-se solucionar um dos seus sucessores. J a dificuldade de um nodo E, N,
aproximada por:
H(N) = S(custo(N, Ni) + H(Ni))
N
N1 N2 ...
Nodo OU
custo(N, N1)
H(N) = min(custo(N,Ni)+H(Ni))
N
N1 N2 ...
Nodo E
custo(N, N1)
H(N) = (custo(N,Ni)+H(Ni))
Figura 16.8: Estimativa da dificuldade, H, de problemas em grafos E/OU
Em nosso programa de pesquisa ser mais prtico, ao invs de valores de H utilizar uma outra medida,
F, definida em termos de H da seguinte maneira: Seja M um nodo antecessor de N na rvore de pes-
quisa e custo(M, N) o custo do arco que interliga M a N. Podemos definir:
F(N) = custo(M, N) + H(N)
De acordo com isso, se M um nodo antecessor de N e N1, N2, ... so nodos sucessores de N, ento:
F(N) = custo(M, N) + min F(Ni)
se N um nodo OU, e
F(N) = custo(M, N) + S F(Ni)
se N um nodo E.
O nodo inicial (representado por S) no possui antecessor, de modo que tem o seu custo (virtual) de
chegada definido como zero. Entretanto, se h for igual a zero para todos os nodos objetivos do grafo
E/OU e uma rvore soluo tima houver sido encontrada, ento F(S) tem o custo desta rvore solu-
o, isto , a soma dos custos de todos os seus arcos. Em qualquer estgio da pesquisa, cada sucessor
de um nodo OU representa uma sub-rvore soluo alternativa. O processo de pesquisa sempre ir
escolher continuar a explorao atravs do sucessor cujo valor de F mnimo. Esse processo pode ser
acompanhado, mais uma vez, a partir da Figura 16.4. Inicialmente a rvore de pesquisa o prprio
nodo a. Depois essa rvore se expande at que uma soluo seja encontrada. A Figura 16.9 mostra
alguns momentos dessa expanso. para simplificar assumiremos que h = 0 para todos os nodos. Os
nmeros associados aos nodos na figura so os valores de F para esses nodos (que naturalmente sero
alterados durante a pesquisa, medida em que novas informaes forem se acumulando).
172
A expanso da rvore inicial de pesquisa , (A), produz a rvore (B). O nodo a um nodo OU, de
modo que temos duas rvores soluo candidatas: b e c. Como (F(b) = 1) < (F(c) = 3), a alternativa b
ser escolhida para expanso. Agora, at onde a alternativa b pode ser expandida? A expanso da
rvore escolhida pode prosseguir at que:
(1) O valor de F para o nodo b se torne maior do que o nodo c, que disputa com b a possibilidade
de ser expandido, ou
(2) Se torne claro que uma rvore soluo foi encontrada.
Na Figura 16.9, o candidato b o primeiro a ser expandido, uma vez que F(b) 3 = F(c). Inicialmente
os sucessores de b, d e e so gerados (situao C) e o valor de F para o nodo b aumentado para 3.
Uma vez que isso no excede o valor limite, a rvore com raiz em b continua a ser expandida. O nodo
d reconhecido como um nodo soluo e ento o nodo e expandido, resultando na situao D. Neste
ponto, F(b) = 9 > 3, o que interrompe a expanso da alternativa b. Isso impede que o processo perceba
que h tambm um nodo objetivo e que uma rvore soluo j foi gerada. Ao invs disso a atividade
passa agora ao nodo c. O "crdito" para a expanso de F(c) agora 9, uma vez que nesse ponto F(b) =
9. Dentro desse limite a rvore candidata de raiz c expandida at que a situao E seja atingida.
Agora o processo identifica que uma rvore soluo (que inclui os objetivos g e h) foi encontrada, e o
processo encerrado. Deve-se notar que a soluo final a mais barata das duas possveis rvores-
soluo, correspondendo apresentada na Figura 16.4 (c).
16.4.1 UM PROGRAMA DE PESQUISA HEURSTICA EM GRAFOS E/OU
Um programa que implementa as idias apresentadas na seo anterior dado na Figura 16.11
8
. Antes
de comentar os detalhes do programa iremos considerar as convenes empregadas na representao
escolhida para a rvore de pesquisa.
8
Este programa gera uma nica soluo, que garantidamente a mais barata se a funo heurstica empregada gerar valores no maiores do
que os custos reais das rvores-soluo.
A rvore de pesquisa pode ser:
arv(Nodo,F,C,SubArvs), correspondendo a uma rvore de solues candidatas;
folha(Nodo,F,C), correspondendo a uma folha de uma rvore de pesquisa;
arvSol(Nodo,F,SubArvs), correspondendo a uma rvore soluo;
folSol(Nodo,F), correspondendo a uma folha da rvore soluo.
C o custo do arco que chega a um nodo.
F = C+H, onde H a estimativa heurstica de uma rvore soluo tima cuja raiz Nodo.
As sub-rvores so sempre ordenadas de modo que:
(1) Todas as sub-rvores solucionadas se encontram no fim da lista, e
(2) As demais sub-rvores so ordenadas em ordem crescente do seu valor de F
173
a
(A)
0
a
(B)
1
b c
1 3
1 3
candidato 1 candidato 2
a
(C)
3
b c
1 3
3 3
candidato 1
candidato 2
d e
1 1
a
(D)
3
b c
1 3
9 3
candidato 1
candidato 2
d e
6
7
1 1
h
a
(E)
8
b c
1 3
9 8
f g d e
6
7
1 1
h
4
h i
1 3
1 2
Figura 16.9: Aspectos de uma pesquisa heurstica em um grafo E/OU
H diversos casos a analisar, como pode ser visto na Figura 16.10. As diferentes formas que a rvore
de pesquisa assume surgem em decorrncia das seguintes possibilidades de combinao entre o tama-
nho da rvore e o seu estado de soluo.
TAMANHO:
(1) A rvore de pesquisa formada por um nico nodo (uma folha), ou
(2) A rvore possui uma raiz que tem sub-rvores no-vazias.
ESTADO DE SOLUO:
(1) A rvore j foi considerada como solucionada ( uma rvore-soluo), ou
(2) Ela ainda uma rvore candidata a ser uma rvore-soluo.
174
Caso 1: Folha de Pesquisa
folha(N, F, C)
F = C + h(N) N
C
Caso 2: rvore de Pesquisa com sub-
rvores OU
arv(N, F, C, ou:[T1, T2, ...])
N
C
...
F1 F2
F = C + min F(Ni)
T2 T1
Caso 3: rvore de Pesquisa com sub-
rvores E
arv(N, F, C, e:[T1, T2, ...])
N
C
... F1 F2
F = C + F(Ni)
N
T2 T1
Caso 4: Folha Soluo
folSol(N, F)
F = C N
C
Caso 5: rvore Soluo com raiz em um
nodo OU
arvSol(N, F, T)
F = C + F1 N
C
F1
T1
Caso 6: rvore Soluo com raiz em um
nodo E
arvSol(N, F, e:[T1, T2, ...]) N
C
... F1 F2
F = C + F(Ni)
N
T2 T1
Figura 16.10: Representao da rvore de Pesquisa
O functor principal usado para representar a rvore de pesquisa indica uma combinao dessas possi-
bilidades, podendo ser um dos seguintes:
folha/3 arv/4 folSol/2 arvSol/3
Alm disso, a representao abrange pelo menos algumas das informaes seguintes:
O nodo raiz da rvore;
O valor da funo F para a rvore;
O custo C do arco no grafo E/OU que chega at a raiz da rvore;
A lista das sub-rvores;
A relao entre as sub-rvores (E ou OU).
A lista das sub-rvores estar sempre ordenada segundo valores crescentespara a funo F. Uma sub-
rvore pode inclusive j estar solucionada, sendo, nesse caso, acomodada no final da lista.
175
:- op(500, xfx, ':'). :- op(600, xfx, '--->').
eou(Nodo, ArvSol) :- expande(folha(Nodo,0,0), 9999, ArvSol, sim).
% Procedimento expande(Arv, Limite, NovaArv, Sol)
% Caso 1: Limite Ultrapassado.
expande(Arv, Limite, Arv, no) :- f(Arv, F), F > Limite, !.
% Caso 2: Objetivo Encontrado
expande(folha(Nodo,F,C), _, folSol(Nodo,F), sim) :- objetivo(Nodo).
% Caso 3: Expandindo uma Folha
expande(folha(Nodo,F,C), Limite, NovaArv, Sol) :-
expNodo(Nodo, C, Arv1), !, expande(Arv1,Limite,NovaArv,Sol); Sol=nunca.
% Caso 4: Expandindo uma rvore
expande(arv(N,F,C,SubArvs), Limite, NovaArv, Sol) :-
Limite1 is Limite - C, expLista( SubArvs, Limite1, NovaSubs, Sol1),
continua(Sol1, N, C, NovaSubs, Limite, NovaArv, Sol).
% Procedimento expLista(Arvs, Limite, NovaArvs, Sol) - Expande uma lista de rv.
% Arvs produzindo NovaArvs
expLista(Arvs, Limite, NovaArvs, Sol) :-
selArv(Arvs,Arv,OutrasArvs,Limite,Limite1),
expande(Arv, Limite1, NovaArv, Sol1), combina(OutrasArvs, NovaArv, Sol1, NovaArvs,Sol).
% Procedimento continua(Sol1,N,C,SubArvs,Limite,NovaArv,Sol) - Decide como continuar aps
% expandir uma lista de rvores
continua(sim, N, C, SubArvs, _, arvSol(N,F,SubArvs), sim) :- backup(SubArvs, H), F is C+H, !.
continua(nunca, _, _, _, _, _, nunca) :- !.
continua(no, N, C, SubArvs, Limite, NovaArv, Sol) :-
backup(SubArvs, H), F is C+H, !, expande(arv(N,F,C,SubArvs), Limite, NovaArv, Sol).
% Procedimento combina(Arvs,Arv,Sol1,NovaArvs,Sol) - Combina as sub-rvores expandidas em uma
% lista
combina(ou:_, Arv, sim, Arv, sim) :- !.
combina(ou:Arvs, Arv, no, ou:NovaArvs, no) :- insere(Arv, Arvs, NovaArvs), !.
combina(ou:[], _, nunca, _, nunca) :- !.
combina(ou:Arvs, _, nunca, ou:Arvs, no) :- !.
combina(e:Arvs, Arv, sim, e:[Arv|Arvs], sim) :- solTodas(Arvs), !.
combina(e:_, _, nunca, _, nunca) :- !.
combina(e:Arvs, Arv, Sol1, e:NovaArvs, no) :- insere(Arv, Arvs, NovaArvs), !.
% Procedimento expNodo(Nodo, C, Arv) - Constri uma rvore com um nodo e seus sucessores
expNodo(Nodo, C, arv(Nodo, F, C, Op:SubArvs)) :-
Nodo ---> Op:Sucessores, avalia(Sucessores, SubArvs), backup(Op:SubArvs, H), F is C+H.
avalia([], []).
avalia([Nodo/C | CustosDosNodos], Arvs) :-
h(Nodo,H), F is C+H, avalia(CustosDosNodos,Arvs1), insere(folha(Nodo,F,C),Arvs1,Arvs).
% Procedimento solTodas(Arvs) - Verifica se todas as rvores da lista esto resolvidas
solTodas([]).
solTodas([Arv | Arvs]) :- sol(Arv), solTodas(Arvs).
sol(arvSol(_,_,_)).
sol(folSol(_,_)).
% Procedimento Insere(Arv, Arvs, NovaArvs) - Insere Arv na lista Arvs, produzindo Nova Arvs
insere(T, [], [T]) :- !.
insere(T, [T1 | Ts], [T, T1 | Ts]) :- sol(T1), !.
insere(T, [T1 | Ts], [T1 | Ts1]) :- sol(T), insere(T, Ts, Ts1), !.
insere(T, [T1 | Ts], [T, T1 | Ts]) :- f(T, F), f(T1, F1), F =< F1, !.
insere(T, [T1 | Ts], [T1 | Ts1]) :- insere(T, Ts, Ts1).
f(Arv, F) :- arg(2, Arv, F).
% Procedimento backup(Arvs, F)
% Recupera o valor de F armazenado em Arvs
backup(ou:[Arv | _], F) :- f(Arv, F), !.
backup(e:[], 0) :- !.
backup(e:[Arv1 | Arvs], F) :- f(Arv1, F1), backup(e:Arvs, F2), F is F1+F2, !.
backup(Arv, F) :- f(Arv, F).
% Relao selArv(Arvs, MelhorArv, Outras, Lim, Lim1) - Seleciona a melhor rvore, MelhorArv,
% de uma lista Arvs, deixando Outras. Lim o limite de expanso para Arvs e Lim1 o limite
% de expanso para MelhorArv.
selArv(Op:[Arv], Arv, Op:[], Lim, Lim) :- !.
selArv(Op:[Arv | Arvs], Arv, Op:Arvs, Lim, Lim1) :-
backup(Op:Arvs, F), (Op=ou, !, min(Lim, F, Lim1); Op=e, Lim1 is Lim-F).
min(A, B, A) :- A < B, !.
min(A, B, B).
Figura 16.11: Programa de Pesquisa Heurstica em Grafos E/OU.
176
No programa da Figura 16.11, a relao principal :
eou(Nodo, ArvSol)
onde Nodo o nodo inicial da pesquisa. O programa produz uma rvore soluo arvSol (se esta exis-
tir) que deve corresponder a uma soluo tima para o problema. Se esta ser realmente a soluo
mais barata, isso vai depender da funo heurstica h adotada pelo algoritmo. H um teorema, seme-
lhante ao teorema da admissibilidade estudado no captulo anterior, que se refere a essa dependncia.
Seja CUSTO(N) uma funo que denota o custo de uma rvore soluo mais barata para um nodo N.
Se, para cada nodo N no grafo E/OU, a estimativa heurstica h(N) CUSTO(N), ento a relao eou/2
garantidamente ir encontrar uma soluo tima. Se a funo h(N) no satisfaz a essa condio, ento
a soluo encontrada pode no ser uma soluo tima. Uma funo heurstica trivial que satisfaz a
condio de admissibilidade h = 0 para todos os nodos. A desvantagem dessa funo , naturalmen-
te, a ausncia de potencial heurstico. A relao chave acionada por eou/2
expande(Arv, Limite, Arv1, Sol)
onde Arv e Limite so argumentos de entrada e Arv1 e Sol so argumentos de sada. Seu significado
o seguinte:
Arv uma rvore de pesquisa que deve ser expandida;
Limite o limite para o valor de F que deve ser respeitado na expanso de Arv;
Sol um indicador cujo valor indica um dos seguintes trs casos:
(1) Sol=sim: Arv pode ser expandida dentro de Limite de forma a abranger uma rvore solu-
o Arv1,
(2) Sol=no: Arv pode ser expandida at Arv1, de forma que o valor de F para Arv1 exceda
Limite e no seja encontrada nenhuma sub-rvore soluo, ou
(3) Sol=nunca: Arv insolvel;
Arv1 , dependendo dos casos acima, uma rvore soluo, uma extenso de Arv cujo valor de F
ultrapassou o valor Limite ou permanecer no instanciada no caso em que Sol=nunca.
O procedimento expLista/4, definido por
expLista(Arvs, Limite, Arvs1, Sol)
similar a expande/4. Assim como em expande/4, Limite o limite de expanso de uma rvore e Sol
um indicador do que ocorreu durante a expanso (sim, no ou nunca). O primeiro argumento, entre-
tanto uma lista de rvores-E ou de rvores-OU:
Arvs = e:[T1, T2, ...] ou Arvs = ou:[T1, T2, ...]
O procedimento expLista/4 seleciona a rvore mais promissora, T (conforme os valores de F) dentre
os membros de Arvs. Devido ordenao das sub-rvores em Arv, a mais promissora ser sempre a
primeira da lista, e ser expandida com um novo limite, Limite1, que depende de Limite e tambm das
outras sub-rvores em Arvs.
Se Arvs uma lista OU, ento Limite1 corresponde ao valor de F para a prxima rvore mais promis-
sora em Arvs. Se Arvs for uma lista E, ento Limite1 Limite menos a soma dos valores de F das
rvores restantes em Arvs. O contedo de Arvs1 depende da situao indicada por Sol. No caso em
que Sol=no, Arvs1 Arvs com a sua rvore mais promissora expandida at Limite1. Quando
Sol=sim, Arvs1 uma soluo da lista Arvs encontrada antes de Limite haver sido alcanado. Se
Sol=nunca, Arvs1 no possui instanciao.
O procedimento continua/7, chamado aps a expanso de uma lista de rvores, decide o que deve ser
feito a seguir, dependendo do resultado de expLista/4: Se constri uma rvore soluo, se atualiza a
rvore de pesquisa e continua a sua expanso ou se informa "nunca" no caso em que a lista foi consi-
derada insolvel. J o procedimento
177
combina(OutrasArvs, NovaArv, Sol1, NovaArvs, Sol)
relaciona diversos objetos manipulados por expLista/4. NovaArvs a rvore expandida obtida por
expLista/4, OutrasArvs so as rvores restantes e Sol1 o estado de soluo de NovaArv. Esse proce-
dimento manipula diversos casos, dependendo de Sol1 e de se a lista de rvores do tipo OU ou E.
Por exemplo, a clusula:
combina(ou:_, Arv, sim, Arv, sim)
significa: No caso em que a lista do tipo OU e a rvore expandida foi solucionada e sua rvore solu-
o Arv, ento toda a lista foi solucionada e a sua soluo a prpria Arv. Para a apresentao de
rvores soluo pode-se definir um procedimento semelhante a mostra/2, apresentado na Figura 16.7.
A construo de tal procedimento deixada como um exerccio para o leitor.
16.4.3 UM EXEMPLO DE DEFINIO DE PROBLEMA
Vamos agora formular o problema de seleo de roteiros sob a forma de um grafo E/OU de modo que
a formulao obtida possa ser usada diretamente pelo procedimento eou/2, definido na Figura 16.11.
Assumiremos que o mapa rodovirio ser representado pela relao:
s(Cidade1, Cidade2, D)
significando que h uma ligao direta entre Cidade1 e Cidade2 a uma distncia D. Assumiremos
tambm a relao:
chave(Cidade1-Cidade2, Cidade3)
significando que, para encontrar um roteiro entre Cidade1 e Cidade2, devemos considerar somente os
caminhos que passam por Cidade3 (Cidade3 ponto de passagem obrigatrio entre Cidade1 e Cida-
de2). Por exemplo, no mapa da Figura 16.1, f e g so pontos de passagem obrigatria entre a e z:
chave(a-z, f) e chave(a-z, g)
Implementaremos ento os seguintes princpios relacionados com a seleo de roteiros:
Para encontrar um roteiro entre duas cidades, a e z
(1) Se h pontos-chaves, Y1, Y2, ..., entre a e z, encontrar:
Um roteiro de a at z passando por Y1", ou
Um roteiro de a at z passando por Y2", ou
...
(2) Se no h nenhum ponto-chave entre a e z, ento simplesmente encontre alguma cidade b, vizi-
nha de a, tal que exista um roteiro entre b e z.
Temos ento dois tipos de problemas que sero representados por:
(1) a-z: Encontre um roteiro entre a e z;
(2) a-z via y: Encontre um roteiro entre a e z passando em y.
Aqui "via" um operador infixo com prioridade superior a "-" e inferior a "--->". O grafo E/OU cor-
respondente pode agora ser implicitamente definido por:
:- op(550, xfx, via).
A-Z ---> ou:Lista :-
bagof((A-Z via Y)/0, chave(A-Z, Y), Lista), !.
A-Z ---> ou:Lista :-
bagof((Y-Z)/D, s(A, Y, D), Lista).
A-Z ---> e:[(A-Y)/0, (Y-Z)/0).
objetivo(A-A).
178
RESUMO
A representao atravs de grafos E/OU um formalismo adequado para a representao de
problemas que podem ser decompostos em subproblemas independentes;
Os nodos em um grafo E/OU podem ser nodos E ou nodos OU;
Um problema concreto definido por um nodo inicial e uma condio objetivo. A soluo de
um problema apresentada atravs de um grafo soluo;
Custos de arcos e nodos podem ser introduzidos em um grafo E/OU na modelagem de proble-
mas que exijam otimizao;
A soluo de problemas representados por meio de grafos E/OU envolvem pesquisa nesse gra-
fo. A pesquisa em profundidade executada de maneira sistemtica e fcil de programar, en-
tretanto, pode ser ineficiente em problemas complexos devido exploso combinatria;
Funes heursticas podem ser introduzidas para estimar a dificuldade dos problemas. O princ-
pio da pesquisa heurstica pode ser usado como orientao, entretanto, a implementao dessa
estratgia no to simples.
EXERCCIOS
16.1 Defina em Prolog um espao E/OU para o Problema das Torres de Hani. Use a definio en-
contrada com os procedimentos de pesquisa estudados no presente captulo.
16.2 Considere algum jogo simples para duas pessoas e escreva a sua representao E/OU. Use um
programa de pesquisa em profundidade em grafos E/OU para encontrar estratgias vitoriosas sob
a forma de rvores E/OU.
179
APNDICE A
FUNDAMENTOS TERICOS DA
PROGRAMAO EM LGICA
O presente texto apresenta a eoluao ordenada dos conceitos associados a Programaao em Lgica,
inclusie desenolendo as semanticas Modelo e Proa-1eorticas. Seu objetio oerecer ao leitor uma
isao abrangente das idias undamentais que sustentam a Programaao em Lgica, ensejando a indagaao
cientica e o desenolimento de noos estudos nessa area.
A.1 PROGRAMAO EM LGICA DE PRIMEIRA ORDEM
A.1.1 PROGRAMAS EM LGICA
Um programa em lgica constitudo por sentenas que expressam o conhecimento relevante para o
problema que se pretende solucionar. A formulao de tal conhecimento emprega dois conceitos bsi-
cos: a existncia de objetos discretos, que denominaremos indivduos, e a existncia de relaes entre
eles. Os indivduos, considerados no contexto de um problema particular, constituem o domnio do
problema. Por exemplo, se o problema solucionar uma equao algbrica, ento o domnio deve
incluir pelo menos os nmeros reais.
Para que possam ser representados por meio de um sistema simblico tal como a lgica, tanto os indi-
vduos quanto as relaes devem receber nomes. A atribuio de nomes , entretanto, apenas uma
tarefa preliminar na criao de modelos simblicos para a representao de conhecimento. A tarefa
principal a construo de sentenas expressando as diversas propriedades lgicas das relaes no-
meadas. O raciocnio sobre algum problema baseado no domnio representado obtido atravs da
manipulao de de tais sentenas por meio de inferncia lgica. Em um ambiente tpico de programa-
o em lgica, o programador estabelece sentenas lgicas que, reunidas, formam um programa. O
computador ento executa as inferncias necessrias para a soluo dos problemas propostos.
A lgica de primeira ordem possui dois aspectos: sinttico e semntico. O aspecto sinttico diz res-
peito s frmulas bem-formadas (fbfs) admitidas pela gramtica de uma linguagem formal. O aspecto
semntico est relacionado com o significado atribudo aos smbolos presentes nas fbfs da teoria.
Apresenta-se a seguir os principais conceitos necessrios para a definio de linguagens lgicas de
primeira ordem.
DEFINIO A1: Teoria de Primeira Ordem
Uma Teoria de Primeira Ordem (TPO) consiste em uma linguagem de primeira ordem definida sobre
um alfabeto de primeira ordem, um conjunto de axiomas e um conjunto de regras de inferncia. A
linguagem de primeira ordem consiste nas fbfs da teoria. Os axiomas e regras de inferncia so utilza-
dos para a derivao dos teoremas da teoria.
DEFINIO A2: Alfabeto de Primeira Ordem
Um Alfabeto de Primeira Ordem constitudo por sete classes de smbolos:
(i) Variveis Individuais,
(ii) Constantes Individuais,
(iii) Constantes Funcionais,
(iv) Constantes Predicativas,
(v) Conetivos,
(vi) Quantificadores, e
(vii) Smbolos de Pontuao.
180
As classes (v} a (vii) so as mesmas para todos os alfabetos, sendo denominadas smbolos lgicos. As
classes (i) a (iv) podem variar de alfabeto para alfabeto e so denominadas smbolos no-lgicos. Para
qualquer alfabeto de primeira ordem, somente as classes (ii) e (iii) podem ser vazias. Adotaremos aqui
as seguintes convenes para a notao dos smbolos do alfabeto: As variveis individuais sero de-
notadas por cadeias de smbolos iniciando com letras minsculas (a, b, ..., z). Os conetivos so: , ,
, , e . Os quantificadores so e . Os smbolos de pontuao so '(', ')' e ','. Adotaremos a se-
guinte hierarquia para a precedncia entre conetivos e quantificadores. Em ordem decrescente:
, ,
,
DEFINIO A3: Termo
Um termo definido recursivamente da seguinte maneira:
(i) Uma varivel individual um termo;
(ii) Uma constante individual um termo;
(iii) Se f uma funo n-ria e t
1
, t
2
, ..., t
n
so termos, ento f(t
1
,t
2
,...,t
n
) um termo.
DEFINIO A4: Frmula Bem-Formada (fbf)
Uma frmula bem-formada (fbf) definida indutivamente da seguinte maneira:
(i) Se p uma constante predicativa e t
1
, t
2
, ..., t
n
so termos, ento, p(t
1
, t
2
, ..., t
n
) uma
frmula bem formada (denominada frmula atmica ou simplesmente tomo);
(ii) Se f e g so frmulas bem formadas, ento (f), (f g), (f g), (f g) e (f g) so
frmulas bem formadas;
(iii) Se f uma frmula bem formada e X uma varivel, ento (Xf) e (Xf) so frmulas
bem formadas.
Adotou-se a conveno de escrever a implicao de modo reverso, isto (f g), devido a sua conve-
nincia na representao da frma clausal, que ser descrita mais adiante. Tambm, por abuso da lin-
guagem, de agora em diante se empregar indistintamente a palavra frmula para fazer referncia a
frmulas bem formadas.
DEFINIO A5: Linguagem de Primeira Ordem
Uma linguagem de primeira ordem sobre um alfabeto de primeira ordem o conjunto de todas as
frmulas bem formadas construdas a partir dos smbolos deste alfabeto.
A semntica informal dos conetivos e quantificadores a seguinte: representa a negao, a con-
juno (e), a disjuno (ou), a implicao e a equivalncia. o quantificador existencial, tal
que 'X' significa 'existe um X', enquanto que o quantificador universal e 'X' significa 'para todo
X' ou 'qualquer que seja X'. Assim a semntica informal de X(p(X, g(X)) q(X) r(X) : 'para
todo X, se q(X) verdadeiro e r(X) falso, ento p(X,g(X)) verdadeiro'.
DEFINIO A6: Escopo de um Quantificador e Ocorrncia Ligada de uma Varivel em uma
Frmula
O escopo de X em Xf e de X em Xf f. Uma ocorrncia ligada de uma varivel em uma fr-
mula uma ocorrncia que imediatamente segue o quantificador e qualquer ocorrncia dessa mesma
varivel no escopo desse quantificador. Qualquer outra ocorrncia de varivel dita ser livre.
DEFINIO A7: Frmula Fechada
Uma frmula dita ser fechada quando no contm nenhuma ocorrncia de variveis livres.
181
DEFINIO A8: Fecho Universal e Fecho Existencial
Se f uma frmula, ento (f) denota o fecho universal de f, que a frmula fechada obtida pela
imposio de um quantificador universal a todas as variveis que ocorrem livremente em f. Da mesma
forma, (f) denota o fecho existencial de f, obtido pela imposio de um quantificador existencial a
todas as variveis que ocorrem livremente em f.
DEFINIO A9: Literal
Um literal um tomo ou a negao de um tomo. Um literal positivo um tomo, enquanto que um
literal negativo a negao de um tomo.
DEFINIO A10: Clusula
Uma clusula uma frmula do tipo: X
1
... X
s
(l
1
... l
m
), onde cada l
i
um literal e X
1
, ..., X
s
so todas as variveis que ocorrem em l
1
, ..., l
m
.
Por exemplo, so clusulas:
XYZ (p(X,Z) q(X,Y) r(Y,Z))
e
XY (p(X,Y) r(f(X,Y),a))
Uma vez que as clusulas so to comuns na programao em lgica, conveniente adotar-se uma
notao clausal particular. Assim a clusula:
X1 ... Xs (a
1
... a
k
b
1
... b
n
),
onde a
1
, ..., a
k
, b
1
, ..., b
n
so tomos e X
1
, ..., X
s
so todas as variveis que ocorrem nestes tomos, ser
representada por:
a
1
, ..., a
k
b
1
, ..., b
n
Na notao clausal, todas as variveis so assumidas universalmente quantificadas. As vrgulas no
antecedente, b
1
, ..., b
n
, denotam conjuno, enquanto que as vrgulas no conseqente, a
1
, ..., a
k
, deno-
tam disjuno. Tais convenes se justificam uma vez que:
X
1
... X
s
(a
1
... a
k
b
1
... b
n
)
equivalente a
X
1
... X
s
(a
1
... a
k
b
1
... b
n
)
DEFINIO A11: Clusula de Programa
Uma clusula de programa uma clusula do tipo a b
1
, ..., b
n
, que contm exatamente um literal
positivo. O literal positivo, a, denominado a cabea da clusula, enquanto que a conjuno de lite-
rais b
1
, ..., b
n
o corpo da mesma.
DEFINIO A12: Clusula Unitria
Uma clusula unitria uma clusula do tipo a . Isto , uma clusula de programa com o corpo
vazio.
A semntica informal de a b
1
, ..., b
n
: "para todas as possveis atribuies de cada uma das vari-
veis presentes na clusula, se b
1
, ..., b
n
so todos verdadeiros, ento a verdadeiro". Assim, se n > 0,
uma clusula de programa condicional. Por outro lado, a clusula unitria incondicional. Sua se-
mntica informal "para todas as possveis atribuies de cada uma das variveis presentes em a, a
verdadeiro".
DEFINIO A13: Programa em Lgica
Um programa em lgica um conjunto finito de clusulas de programa.
182
DEFINIO A14: Definio de um Predicado
Em um programa em lgica, o conjunto de todas as clusulas de programa que possuem o mesmo
predicado p na cabea denominado a definio do predicado p.
DEFINIO A15: Clusula Objetivo
Uma clusula objetivo uma clusula do tipo b
1
, ..., b
n
, isto , uma clusula que possui o conse-
quente vazio. Cada b
i
(i = 1, ..., n) denominado um sub-objetivo da clusula.
DEFINIO A16: Clusula vazia
A clusula vazia, denotada por , a clusula que possui tanto o antecedente quanto o conseqente
vazios. Tal clusula deve ser interpretada como uma contradio.
DEFINIO A17: Clusula de Horn
Uma clusula de Horn uma clusula de programa ou uma clusula objetivo.
As clusulas de Horn so assim denominadas em homenagem ao matemtico Alfred Horn, que pri-
meiro lhes estudou as propriedades, em 1951. Uma de suas mais importantes caractersticas que
qualquer problema solvel capaz de ser representado por meio delas, pode ser representado de tal
forma que apenas uma das clusulas seja uma clusula objetivo, enquanto que todas as restantes sero
clusulas de programa. Para um grande nmero de aplicaes da lgica, suficiente empregar o con-
texto restrito das clusulas de Horn. Na Figura A1 posicionamos as clusulas de Horn em sua relao
com a lgica matemtica, o clculo de predicados de primeira ordem e a forma clausal.
Lgica Matemtica
Clculo de Predicados de Primeira Ordem
Forma Clausal
Clusulas de Horn
Figura A.1: Supercontextos das Clusulas de Horn
A.2 SEMNTICA MODELO-TEORTICA
A.2.1 MODELOS DE PROGRAMAS EM LGICA
Para que sejamos capazes de discutir sobre a verdade ou falsidade representadas atravs de frmulas
da lgica de primeira ordem, necessrio atribuir inicialmente algum significado a cada um dos sm-
bolos nelas presentes. Os diversos conetivos e quantificadores possuem um significado fixo, entre-
tanto, o significado atribudo atribudo s constantes individuais, constantes funcionais e constantes
predicativas pode variar. Uma interpretao consiste simplesmente em algum universo de discurso,
ou domnio, sobre o qual as variveis podem assumir valores, na atribuio de um elemento desse
universo a cada constante individual, na atribuio de um mapeamento sobre o domnio a cada cons-
tante funcional, e de uma relao sobre o domnio a cada constante predicativa. Cada interpretao
especifica assim um significado para cada smbolo na frmula. Estamos particularmente interessados
em interpretaes para as quais as frmulas expressam uma declarao verdadeira. Tais interpretaes
so denominadas modelos para as frmulas. Normalmente haver alguma interpretao especial, de-
nominada interpretao pretendida, que ir especificar o significado principal dos smbolos. Natu-
183
ralmente a interpretao pretendida sempre ser um modelo. A partir de agora emprega-se os termos
constante, funo e predicado para designar respectivamente constantes individuais, constantes fun-
cionais e constantes predicativas. A lgica de primeira ordem oferece mtodos para a deduo dos
teoremas presentes em alguma teoria. Estes podem ser caracterizados como sendo as frmulas que so
consequncia lgica dos axiomas da teoria, isto , que so verdadeiras em todas as interpretaes que
so modelos para cada um dos axiomas da teoria. Em particular, cada teorema deve ser verdadeiro na
interpretao pretendida da teoria. Os sistemas de programao em lgica que so objeto do presente
estudo adotam o Princpio da Resoluo como nica regra de inferncia. Suponha-se que se deseja
provar que a frmula
Y
1
... Y
r
(b
1
... b
n
)
uma consequncia lgica de um programa P. Com esse objetivo emprega-se o Princpio da Resolu-
o por meio de um sistema de refutao, isto , a negao da frmula a ser provada adicionada aos
axiomas e uma contradio deve ser derivada. Negando-se a frmula que se deseja provar obtem-se a
clusula objetivo:
b
1
, ..., b
n
A partir dessa frmula objetivo e operando de forma top-down sobre os axiomas de P, o sistema deri-
va sucessivas clusulas objetivo. Se, em um determinado momento, for derivada a clusula vazia,
ento uma contradio foi obtida (a clusula vazia contraditria) e esse resultado assegura que
Y
1
...Y
r
(b
1
... b
n
) uma conseqncia lgica de P. De agora em diante se usar simplesmente
objetivo para designar clusulas objetivo.
Do ponto de vista da prova de teoremas, o nico interesse demonstrar a existncia da relao de
conseqncia lgica. Por outro lado, do ponto de vista da Programao em Lgica, o interesse se con-
centra muito mais sobre as ligaes que foram realizadas sobre as variveis Y
1
, ..., Y
r
, uma vez que
estas fornecem o resultado da execuo do programa. Segundo [Llo 84], a viso ideal de um sistema
de Programao em Lgica a de uma caixa preta para a computao de ligaes e o nico interesse
reside no seu comportamento de entrada e sada, isto , as operaes executadas internamente pelo
sistema deveriam ser transparentes para o programador. Infelizmente tal situao no ocorre, em mai-
or ou menor grau nos sistemas Prolog atualmente disponveis, de forma que muitos programas Prolog
somente podem ser entendidos a partir de sua interpretao operacional, devido ao emprego de cuts e
outros mecanismos extra-lgicos.
DEFINIO A18: Interpretao
Uma interpretao de uma linguagem L de primeira ordem constituda por:
(i) Um conjunto no-vazio D, denominado o Domnio da interpretao;
(ii) Para cada constante em L a atribuio de um elemento em D;
(iii) Para cada funo n-ria em L, a atribuio de um mapeamento de D
n
em D;
(iv) Para cada predicado n-rio em L a atribuio de um mapeamento de D
n
em {V, F}, isto
, de uma relao sobre D
n
.
DEFINIO A19: Atribuio de Variveis
Seja I uma interpretao de uma linguagem L de primeira ordem. Uma atribuio de variveis (com
respeito a I) uma atribuio de um elemento do domnio de I a cada uma das variveis em L.
DEFINIO A20: Atribuio de Termos
Seja I uma interpretao de uma linguagem L de primeira ordem, com domnio D, e seja A uma atri-
buio de variveis. Uma atribuio de termos (com respeito a I e A) para os termos em L definida
da seguinte maneira:
(i) A cada varivel em L dada uma atribuio de acordo com A;
(ii) A cada constante em L dada uma atribuio de acordo com I;
(iii) Se t
1
', ..., t
n
' so as atribuies dos termos t
1
, ..., t
n
e f' a atribuio de f, ento f'(t
1
', ...,
184
t
n
') a atribuio de termos f(t
1
, ..., t
n
).
DEFINIO A21: Valor Verdade de uma Frmula
Seja I uma interpretao de domnio D de uma linguagem L de primeira ordem, e seja A uma atribui-
o de variveis. Ento a uma frmula em L pode ser atribudo um valor-verdade (verdadeiro ou fal-
so, que detotaremos por F e V respectivamente) com respeito a I e a A, da seguinte maneira:
(i) Se a frmula um tomo, p(t
1
, ..., t
n
), ento o valor verdade obtido pelo clculo do
valor verdade de p'(t
1
', ..., t
n
'), onde p' o mapeamento atribudo a p por I e t
1
', ..., t
n
' a
atribuio de termos para t
1
, ..., t
n
com respeito a I e a A;
(ii) Se a frmula tem a forma f, f g, f g, f g ou f g, ento o valor verdade da
frmula dado pela tabela verdade:
(iii) Se a frmula tem a forma Xf, ento o valor verdade da frmula V se existe d D tal
que f tem valor verdade V com respeito a I e a A(X/d), onde A(X/d) A, exceto que a
X atribudo o valor d. Caso contrrio o seu valor verdade F;
(iv) Se a frmula tem a forma Xf, ento o valor verdade da frmula V se para todo d D,
f tem valor verdade V com respeito a I e a A(X/d). Caso contrrio o seu valor verdade
F.
f g f f g f g f g f g
V V F V V V V
V F F F V V F
F V V F V F F
F F V F F V V
DEFINIO A22: Modelo de uma Frmula
Seja I uma interpretao de uma linguagem L de primeira ordem e seja f uma frmula fechada de L.
Ento I um modelo para f se o valor verdade de f com respeito a I V.
DEFINIO A23: Modelo de um Conjunto de Frmulas Fechadas
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem e seja I uma inter-
pretao de L. Dizemos que I um modelo para S se I for modelo para cada uma das frmulas em
S.
DEFINIO A24: Conjunto de Frmulas Satisfatvel
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem. Dizemos que S
satisfatvel, se L possui uma interpretao que um modelo para S.
DEFINIO A25: Conjunto de Frmulas Vlido
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem. Dizemos que S
vlido se toda interpretao de L um modelo para S.
DEFINIO A26: Conjunto de Frmulas Insatisfatvel
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem. Dizemos que S
insatisfatvel, se S no possui modelos em L. Note que {f, f} insatisfatvel, assim como a clusula
vazia, denotada por .
DEFINIO A27: Conseqncia Lgica de um Conjunto de Frmulas Fechadas
Seja S um conjunto de frmulas fechadas e seja f uma frmula fechada de uma linguagem L de pri-
meira ordem. Dizemos que f conseqncia lgica de S, isto , S |= f, se para toda interpretao I de
L, se I um modelo para S, ento I tambm um modelo para f. Note que se S = {f
1
, ..., f
n
} um
conjunto finito de frmulas fechadas, ento f conseqncia lgica de S se e somente se f f
1
...
f
n
vlida.
185
PROPOSIO A.1
Seja S um conjunto de frmulas fechadas e f uma frmula fechada de uma linguagem L de primeira
ordem. Ento f conseqncia lgica de S se e somente se S {f} insatisfatvel.
Prova:
() Vamos supor que f seja conseqncia lgica de S. Se S {f} satisfatvel, ento existe uma
interpretao I da linguagem L tal que I modelo de S {f}. Por outro lado, se f conse-
qncia lgica de S, ento I tambm modelo de f, ou seja de {f, f}, o que no possvel.
Logo S {f} insatisfatvel.
() Inversamente, vamos supor que S {f} seja insatsfatvel e seja I uma interpretao da lin-
guagem L. Suponhamos que I seja um modelo para S. Uma vez que S {f} insatisfatvel, I
no pode ser um modelo para f. Assim, I um modelo para f e portanto f conseqncia lgi-
ca de S.
Aplicando essas ltimas definies a programas em lgica, constata-se que quando se fornece um
objetivo G ao sistema com o programa P carregado, est-se pedindo ao sistema para provar que P
{G} insatisfatvel. Se G o objetivo b
1
, ..., b
n
com as variveis Y
1
, ..., Y
r
, ento a Proposio A.1
estabelece que provar que P {G} insatisfatvel equivale a provar que Y
1
... Y
r
(b
1
... b
n
)
conseqncia lgica de P. Assim o problema bsico a determinao da insatisfatibilidade de P
{G}, onde P um programa e G um objetivo. De acordo com a definio de insatisfatibilidade, isso
implica em mostrar que nenhuma interpretao de P {G} um modelo.
DEFINIO A28: Termo Bsico e tomo Bsico
Um termo bsico um termo que no contm variveis. Da mesma forma um tomo bsico um to-
mo que no contm variveis.
DEFINIO A29: Universo de Herbrand
Seja L uma linguagem de primeira ordem. O Universo de Herbrand, UL para L o conjunto de todos
os termos bsicos que podem ser obtidos a partir das constantes e funes presentes em L. No caso em
que L no possui constantes, introduz-se uma constante (por exemplo, "a") para a formao de termos
bsicos.
DEFINIO A30: Base de Herbrand
Seja L uma linguagem de primeira ordem. A Base de Herbrand, BL para L o conjunto de todos os
tomos bsicos que podem ser formados usando os predicados de L com os termos bsicos do corres-
pondente Universo de Herbrand como argumentos.
DEFINIO A31: Interpretao de Herbrand
Seja L uma linguagem de primeira ordem. Uma interpretao sobre L uma Interpretao de Her-
brand, se as seguintes condies forem satisfeitas:
(i) O domnio da interpretao o Universo de Herbrand, UL;
(ii) As constantes em L so atribudas a si prprias em UL;
(iii) Se f uma funo n-ria em L, ento a f atribudo o mapeamento de (UL)
n
em UL de-
finido por (t
1
, ..., t
n
) f(t
1
, ..., t
n
).
Nenhuma restrio feita sobre a atribuio de predicados em L de forma que diferentes interpreta-
es de Herbrand surgem quando se emprega diferentes atribuies sobre eles. Uma vez que, para as
interpretaes de Herbrand, as atribuies de constantes e funes fixa, possvel identificar uma
interpretao de Herbrand como um subconjunto da Base de Herbrand. Para toda interpretao de
Hebrand, o correspondente subconjunto da Base de Herbrand o conjunto de todos os tomos bsicos
que so verdadeiros com respeito a essa interpretao. Inversamente, dado um subconjunto arbitrrio
da Base de Herbrand, h uma interpretao de Herbrand que a ele corresponde.
186
DEFINIO A32: Modelo de Herbrand
Seja L uma linguagem de primeira ordem e S um conjunto de frmulas fechadas de L. Um Modelo de
Herbrand para S uma interpretao de Herbrand que um modelo para S.
PROPOSIO A.2
Seja S um conjunto de clusulas e suponha que S tem um modelo. Ento S tem um modelo de Her-
brand.
Prova:
Seja I uma interpretao de S. Uma interpretao de Herbrand de S, I', definida por:
I
H
= {p(t
1
, ..., t
n
) S | p(t
1
, ..., t
n
) V c.r.a I}
Segue diretamente que se I um modelo para S, ento I
H
tambm .
PROPOSIO A.3
Seja S um conjunto de clusulas. Ento S insatisfatvel se e somente se S no possui um modelo de
Herbrand.
Prova:
Se S satisfatvel, ento a Proposio A.2 demonstra que S tem um modelo de Herbrand.
A.2.2 SUBSTITUIES RESPOSTA
Conforme foi anteriormente estabelecido, o propsito principal de um sistema de programao em
lgica a computao de ligaes. Na presente seo ser introduzido o conceito de substituio res-
posta correta, que permite um entendimento declarativo da sada desejada de um programa e um ob-
jetivo.
DEFINIO A33: Substituio
Uma substituio um conjunto finito da forma {v
1
/t
1
, ..., v
n
/t
n
}, onde cada v
i
uma varivel e cada
t
i
um termo distinto de v
i
. Alm disso, as variveis v
1
, ..., v
n
devem ser distintas. Cada elemento v
i
/t
i
denominado uma ligao para v
i
. Se os t
i
so todos bsicos, ento denominada uma substituio
bsica. Se os t
i
so todos variveis, ento denominada uma substituio varivel pura.
DEFINIO A34: Expresso
Uma expresso um termo, um literal ou uma conjuno ou disjuno de literais. Uma expresso
simples um termo ou um tomo.
DEFINIO A35: Instncia de uma Expresso
Seja = {v
1
/t
1
, ..., v
n
/t
n
} uma substiruio e E uma expresso. Ento E, a instncia de E pela substi-
tuio , a expresso obtida a partir de E atravs da substituio simultnea de todas as ocorrncias
da varivel v
i
em E, pelo termo t
i
, para i = 1, ..., n. Se E bsica, ento E denominada uma instn-
cia bsica de E. Se S = {E
1
, ..., E
n
} um conjunto finito de expresses e uma substituio, ento S
denota o conjunto {E
1
, ..., E
n
}.
DEFINIO A36: Composio de Substituies
Sejam = {u
1
/s
1
, ..., u
m
/s
m
} e = {v
1
/t
1
, ..., v
n
/t
n
} duas substituies. Ento a composio a subs-
tituio obtida do conjunto {u
1
/s
1
, ..., u
m
/s
m
, v
1
/t
1
, ..., v
n
/t
n
}, retirando-se dele todas as ligaes u
i
/s
i
para as quais u
i
= s
i
e todas as ligaes v
j
/t
j
para as quais v
j
{u
1
, ..., u
m
}.
DEFINIO A37: Substituio Identidade
Substituio Identidade a substituio dada pelo conjunto vazio. Denota-se a substituio identidade
187
por . Note que E = E para todas as expresses E.
PROPOSIO A.4
Sejam , e substituies e a substituio identidade. Ento:
(i) = =
(ii) E (E) = E()
(iii) () = ()
Prova:
(i) Segue diretamente da definio de .
(ii) suficiente provar o resultado quando E uma varivel, digamos X.
Seja = {u
1
/s
1
, ..., u
m
/s
m
} e = {v
1
/t
1
, ..., v
n
/t
n
}.
Se X {u
1
, ..., u
m
} {v
1
, ..., v
n
},
ento (X) = X() = X.
Se X {u
1
, ..., u
m
}, digamos X = u
i
,
ento (X) = s
i
= X().
Se X {v
1
, ..., v
n
} \ {u
1
, ..., u
m
}, digamos X = v
j
,
ento (X) = t
j
= X().
(iii) suficiente mostrar que, se X uma varivel, ento X(()) = X(()).
De fato, X(()) = ((X)) = (X)() = X(()), em funo de (ii).
DEFINIO A38: Variantes
Sejam E e F expresses. Diz-se que E e F so variantes se existem as substituies e tais que E =
F e F = E. Diz-se tambm que E variante de F ou que F variante de E.
DEFINIO A39: Renomeao
Seja E uma expresso e V o conjunto das variveis que ocorrem em E. Uma renomeao para E uma
substituio varivel pura {X
1
/Y
1
, ..., X
n
/Y
n
} tal que {X
1
, ..., X
n
} V, os Y
i
so distintos e (V\{X
1
, ...,
X
n
}) {Y
1
, ..., Y
n
} = .
PROPOSIO A.5
Sejam E e F expresses variantes. Ento existem as substituies e s tais que E = F e F = E, onde
uma renomeao para F e uma renomeao para E.
Prova:
Uma vez que E e F so variantes, existem as substituies
1
e
1
tais que E = F
1
e F = E
1
.
Seja V o conjunto das variveis que ocorrem em E e seja a substituio obtida de s
1
atravs
da remoo de todas as ligaes da forma X/t, onde X V. Claramente ento F = E. Alm
disso, E = F
1
= E
1
, de onde segue que s deve ser uma renomeao para E.
Estaremos interessados principalmente nas substituies que unificam um conjunto de expresses,
isto , que tornam as expresses contidas em um conjunto sintaticamente idnticas. O conceito de
unificao remonta aos estudos de Herbrand em 1930, tendo sido empregado por Robinson [Rob 65]
no estabelecimento do princpio da Resoluo. O foco do presente texto se restringir a conjuntos
finitos (no-vazios) de expresses simples (termos ou tomos).
DEFINIO A40: Unificador
Seja S um conjunto finito de expresses simples. Uma substituio dita ser um unificador para S
se S nica. Um unificador dito ser um unificador mais geral (umg) para S se, para todo unifi-
cador s de S h uma substituio tal que = .
188
Segue da definio de umg que se e so ambos umg's de {E
1
, ..., E
n
}, ento E
i
variante de E
i
.
A Proposio A.5 garante ento que E
i
pode ser obtida de E
i
por simples renomeao de variveis.
DEFINIO A41: Conjunto de Desacordo
Seja S um conjunto finito de expresses simples. O conjunto de desacordo de S definido da seguinte
maneira: Localizamos a posio do smbolo mais esquerda que no o mesmo para todas as expres-
ses de S e extramos de cada uma delas a sub-expresso que inicia com tal smbolo. O conjunto de
todas as sub-expresses assim retiradas o conjunto de desacordo de S.
ALGORITMO DA UNIFICAO
(i) Faa k = 0 e
k
= ,
(ii) Se S
k
nico, ento pare:
k
um umg de S,
seno encontre o conjunto de desacordo D
k
de S
k
;
(iii) Se existem V e t em D
k
tais que V uma varivel que no ocorre em t,
ento faa
k+1
=
k
{V/t}, incremente o valor de k e volte ao passo (ii),
seno pare: S no unificvel.
Na forma apresentada acima, o algoritmo da unificao no-determinstico, uma vez que podem ser
consideradas diversas escolhas para V no passo (iii), entretanto a aplicao de quaisquer dois umg's
produzidos pelo algoritmo ir conduzir a expresses que diferem entre si somente pelo nome das vari-
veis envolvidas. Deve ficar claro tambm que o algoritmo sempre termina, uma vez que S contm um
conjunto finito de variveis e cada aplicao do passo (iii) elimina uma delas. Ainda devemos consi-
derar que no passo (iii) uma verificao feita para garantir que V no ocorre em t. Tal verificao
denominada verificao de ocorrncia (occurs check).
TEOREMA A.1 (TEOREMA DA UNIFICAO)
(a) S um conjunto unificvel de de expresses simples se e somente se o Algoritmo da Unificao
termina, retornando um umg para S.
(b) S no um conjunto unificvel de de expresses simples se e somente se o Algoritmo da Unifica-
o termina, retornando a resposta "no".
DEFINIO A42: Substituies Resposta
Seja P um programa e G um objetivo. Uma substituio resposta para P {G} uma substituio
para as variveis de G.
Entende-se que tal substituio no precisa necessriamente conter uma ligao para cada uma das
variveis em G. Em particular, se G no contm variveis, a nica substituio possvel a substitui-
o identidade.
DEFINIO A43: Substituio Resposta Correta
Seja P um programa, G um objetivo A
1
, ..., A
k
e uma substituio resposta para P {G}. Dize-
mos que uma substituio resposta correta para P {G} se ((A
1
... A
k
)) conseqncia
lgica de P.
A partir da Proposio A.1 pode-se afirmar que uma substituio resposta correta se e somente se
P {((A
1
... A
k
))} for insatisfatvel. Esta definio de substituio resposta correta captura o
sentido intuitivo de "resposta correta". Da mesma forma que fornece substituies respostas, um sis-
tema de programao em lgica pode tambm retornar com a resposta "no". Dizemos que a resposta
"no" correta, se P {G} for satisfatvel.
189
A.3 SEMNTICA PROVA-TEORTICA
A lgica clssica de primeira ordem definida pela especificao de um esquema de axiomas e regras
de inferncia. (Para as definies bsicas ver a Seo A.1).
AXIOMAS
Para todas as frmulas bem-formadas A, B e C de uma certa linguagem L da lgica de predicados de
primeira ordem:
(i) A (B A)
(ii) (A (B C)) ((A B) (A C)).
(iii) (B A) ((B A) B).
(iv) X A(X) A(t), onde t um termo livre de X em A(X), isto , nenhuma ocorrncia
livre de X em A surge no escopo de qualquer quantificador (X'), onde X' uma vari-
vel em t.
(v) (X) (A B) (A X B), onde A no contm nenhuma ocorrncia livre de X.
REGRAS DE INFERNCIA
(i)
B
B A A,
[MP - modus ponens]
(ii)
X,A,
A
[GEN - generalizao]
DEFINIO A44: Prova
Uma prova qualquer seqncia da forma A
1
, ..., A
n
onde cada A
i
ou uma instncia de um esquema
de axiomas ou deriva dos membros anteriores da seqncia por meio da aplicao de MP ou GEN.
DEFINIO A45: Teorema
Um teorema qualquer fbf que resulte de uma prova, isto , o ltimo membro de uma seqncia de
prova.
DEFINIO A46: Frame de Primeira Ordem
Um frame de primeira ordem M para uma linguagem L da lgica de primeira ordem consiste em um
domnio no vazio D, juntamente com uma funo que atribui a cada smbolo funcional n-rio f uma
funo f' de D
n
D e a cada constante relacional C, um elemento C' de
2
D
n
.
Para estabelecer a semntica da linguagem L com respeito a esse frame, utilizaremos uma funo de
atribuio g que atribui a cada varivel individual um elemento de D. A notao M (g) |= A indica que
a funo de atribuio g satisfaz a fbf A no frame M.
(i) M (g) |= C(t
0
, ..., t
n-1
) (V(t
0
, g), ..., V(t
n-1
, g)) C'
onde V(t, g) = g(t) se t uma varivel individual e em f'(V(t
0
', ..., V(t
m-1
', g)) os t
i
so da for-
ma f(t
0
', ..., t
m-1
').
(ii) M (g) |= A M (g) | A.
(iii) M (g) |= A B M (g) |= A e M (g) |= B.
(iv) M (g) |= X A M (g{d\X}) |= A,
onde g{d\X} uma funo de atribuio idntica a g, exceto para a varivel X, qual atri-
budo o valor d.
190
As condies de verdade para os demais conetivos podem ser estabelecidas a partir das seguintes
equivalncias:
(v) A B (A B)
(vi) A B A B
(vii) A B (A B) (B A)
(viii) X A X A
DEFINIO A47: Frmula Universalmente Vlida
Uma fbf A dita ser universalmente vlida se e somente se, para todo frame M e para toda funo de
atribuio g, M (g) |= A.
TEOREMA A.2: Completeza do Clculo de Predicados
Uma fbf do clculo de predicados de primeira ordem um teorema se e somente se universalmente
vlida.
191
BIBLIOGRAFIA
[AMB 87] AMBLE, T.: Logic Programming and Knowledge Engineering. Reading: Addison-
Wesley, 1987, 348p.
[AND 93] ANDREWS, J.: Prolog Frequently Asked Questions. E-Text (Internet) by ja-
mie@cs.sfu.ca. Stanford University, 1993.
[ARI 86] ARITY Corporation, The Arity Prolog Programming Manual, Arity Corporation,
1986.
[BOW 82] BOWEN, K.A.; KOWALSKI, R.A.: Amalgamating Language and Metalanguage in
Logic Programming. In: LOGIC PROGRAMMING. London: Academic Press, 1982.
366p. p.153-172.
[BOW 85] BOWEN, K.A.: Meta Level Programming and Knowledge Representation. New
Generation Compuiting, Tokyo, v.3 n.12, p.359-383, Oct. 1985.
[BOW 86] BOWEN, K.A.: Meta Level Techniques in Logic Programming. In: INTERNA-
TIONAL CONFERENCE ON ARTIFICIAL INTELLIGENCE AND ITS APPLICA-
TIONS, 1986, Singapore. Proceedings ... Amsterdam: North-Holland, 1986. p.262-271.
[BRA 86] BRATKO, I.: Prolog Programming for Artificial Intelligence. Englewood Cliffs:
Addison-Wesley, 1986. 423p.
[BRO 86b] BRODIE, M.L.; JARKE, M.: On Integrating Logic Programming and Databases. In:
EXPERT DATABASE SYSTEMS. Menlo Park: Benjamin/Cummings, 1986. 701p.
p.191-208.
[CAR 88] CARNOTA, R.J.; TESZKIEWICZ, A.D.: Sistemas Expertos y Representacin del
Conoscimiento. Buenos Aires: EBAI, 1988.
[CAS 87] CASANOVA, M.A.; GIORNO, F.A.; FURTADO, A.L..: Programao em Lgica e a
Linguagem Prolog. So Paulo: Edgard Blcher, 1987. 461p.
[CER 86] CERRO, L.F.D.: MOLOG: A System that Extends PROLOG with Modal Logic.
New Generation Computing, Tokyo, v.4, n.1, p.35-50, 1986.
[CHA 82] CHANDRA, A.K.; HAREL, D.: Horn Clauses and Fixpoint Query Hierarchy. In:
ACM SYMPOSIUM ON PRINCIPLES OF DATABASE SYSTEMS, March 1982, Los
Angeles. Proceedings ... New York: ACM, 1982. 304p. p.158-163.
[CLA 82] CLARK, K.; TRNLUND, S-A.: Logic Programming. London: Academic Press, 1982.
[CLO 84] CLOCKSIN, W.; MELLISH, C.: Programming in Prolog, Springer-Verlag, 1984.
[COE 80] COELHO, H. et al.: How to Solve it in Prolog. Lisboa: LNEC, Universidade Nova de
Lisboa, 1980.
[DAH 83] DAHL, V.: Logic Programming as a Representation of Knowledge. Computer, Los
Alamitos, v.16, n.10, p.106-111, Oct. 1983.
[DAT 83] DATE, C.J.: An Introduction to Database Systems. 3rd. Edition. Reading: Addison-
Wesley, 1983. 513p.
[DOD 90] DODD, T.: Prolog: A Logical Approach. New York: Oxford University Press, 1990.
556p.
[FIS 87] FISCHLER, M.; FIRSCHEIN, O.: The Eye, The Brain and The Computer. Reading:
Addison-Wesley, 1987. 331p.
192
[FUR 84] FURUKAWA, K. et al.: Mandala: A Logic Based Programming System. In: IN-
RTERNATIONAL CONFERENCE ON FIFTH GENERATION COMPUTER SYS-
TEMS, 1984, Tokyo. Proceedings ... Amsterdam: North-Holland, 1984. 703p. p.613-622.
[GAL 78] GALLAIRE, H.; MINKER, J.: Logic and Databases. New York: Plenum Press, 1978.
[GAL 83] GALLAIRE, H.: Logic Databases vs, Deductive Databases. In LOGIC PROGRAM-
MING WORKSHOP '83, 1983, Albufeira, Portugal. Proceedings ... Amsterdam: North-
Holland, 1983.
[GAL 84] GALLAIRE, H.; MINKER, J.; NICOLAS, J.-M.: Logic and Databases: A Deductive
Approach. Computing Surveys, New York, v.16, n.2, p.153-185, Jun. 1984.
[GD 31] GDEL, K.: ber Formal Unentscheidbare Satze der Principia Mathematica und
Verwandter System 1. Traduo em Ingles em: From Frege to Gdel: A Sourcebook in
Mathematical Logic. Harvard University Press, Cambridge, Mass.
[GRE 69] GREEN C.: Theorem Proving by Resolution as a Basis for Question-Answering Sys-
tems. In: MACHINE INTELLIGENCE, 4. Edimburgh: Edimburgh University Press,
1969. p.183-205.
[HOF 79] HOFSTADTER, D.: Gdel, Escher and Bach. New York: Basic Books, 1979.
[HOG 84] HOGGER, C.J.: Introduction to Logic Programming. London: Academic Press, 1984.
278p.
[ISR 83] ISRAEL, D.; BERANEK, B.: The Role of Logic in Knowledge Representation. Com-
puter, Los Alamitos, v.16, n.10, p.37-41, Oct. 1983.
[IWA 88] IWANUMA, K.; HARAO, M.: Knowledge Representation and Inference Based on
First-Order Modal Logic. In: LOGIC PROGRAMMING '88. Proceedings ... Berlin:
Springer-Verlag, 1988. p.237-251.
[JAC 86] JACKSON, P.: Introduction to Expert Systems. Reading: Addison-Wesley, 1986.
292p.
[KAN 93] KANTROWITZ, M.: Prolog Resource Guide. E-Text (Internet) by mkant+prolog-
guide@cs.cmu.edu. Carnegie-Mellon University, 1993.
[KIT 84] KITAKAMI, H.S.; MIYACHI, T.; FURUKAWA, K.: A Methodology for Implementa-
tion of a Knowledge Acquisition System. In: INTERNATIONAL SYMPOSIUM ON
LOGIC PROGRAMMING, Feb. 1984, Atlantic City. Proceedings ... New York: ACM,
1984.
[KOW 74] KOWALSKI, R.A.: Predicate Logic as a Programming Language. In: IFIP '74. Pro-
ceedings ... Amsterdam: North-Holland, 1974. p.569-574.
[KOW 75] KOWALSKI, R.A.: A Proof Procedure Using Conection Graphs. Journal of ACM,
New York, v.22, n.4, p.572-595, Apr. 1975.
[KOW 78] KOWALSKI, R.A.: Logic for Data Description. In: LOGIC AND DATABASES. New
York: Plenum Press, 1978.
[KOW 79a] KOWALSKI, R.A.: Algorithm = Logic + Control. Communications of ACM, New
York, v.22, n.7, p.424-436, Jul. 1979.
[KOW 79b] KOWALSKI, R.A.: Logic for Problem Solving. New York: Elsevier, 1979. 287p.
[LID 84] LI, D.: A Prolog Database System. Hertfordshire: Research Studies Press, 1984. 207p.
[LLO 84] LLOYD, J.W.: Foundations of Logic Programming. Berlin: Springer-Verlag, 1984.
124p.
193
[MAE 88] MAES, P.: Issues in Computational Reflection. In: META LEVEL ARCHITEC-
TURES AND REFLECTION. Amsterdam: North-Holland, 1988. 355p. p.21-36.
[MAT 89] MATTOS, N.M.: An Approach to Knowledge Basis Management. Kaiserslautern:
University of Kaiserslautern, 1989. PhD Thesis, Department of Computer Science. 255p.
[MCC 69] McCARTHY, J.; HAYES, P.J.: Some Philosophical Problems from the Standpoint of
Artificial Intelligence. In: MACHINE INTELLIGENCE, 4. Edimburgh: Edimburgh
University Press, 1969. p.463-502.
[MCC 77] McCARTHY, J.: Epistemological Problems of Artificial Intelligence. In: INTERNA-
TIONAL JOINT CONFERENCE ON ARTIFICIAL INTELLIGENCE, 5., Aug. 1977,
Cambridge, Massachusetts. Proceedings ... New York: ACM, 1977
[MCC 80] McCARTHY, J.: Circunscription: A Form of Non-Monotonic Reasoning. Artificial
Intelligence, v.13, n.1, p.27-39, 1980.
[MIN 75] MINSKI, M.: A Framework for Representing Knowledge. In: THE PSICOLOGY OF
COMPUTER VISION. New York: McGraw-Hill, 1975. p.211-280.
[MIN 82] MINSKI, M.: Why People Think Computers Can't? AI Magazine, v.3, n.1, p.2-8,
1982.
[MON 88] MONTEIRO, L..; PORTO A.: Contextual Logic Programming. Lisboa: Departamento
de Informtica, Universidade Nova de Lisboa, 1988.
[MOO 84] MOORE, R.C. A Formal Theory of Knowledge and Action. In: FORMAL THEORIES
OF THE COMMON SENSE WORLD. Norwood: Ablex, 1984. p.319-358.
[NEW 82] NEWELL, A.: The Knowledge Level. Artificial Intelligence v.18, n.1, p.87-127, 1982.
[NIL 80] NILSSON, N.J.: Principles of Artificial Intelligence. Palo Alto: Tioga, 1980.
[PAL 89] PALAZZO, L.A.M.: Rhesus: Um Modelo Experimental para Representao de Con-
hecimento. Porto Alegre: CPGCC da UFRGS, 1989. 115p.
[PAL 91] PALAZZO, L.A.M.: Representao de Conhecimento: Programao em Lgica e o
Modelo das Hiperredes. Porto Alegre: CPGCC da UFRGS, 1991. Dissertao de Mes-
trado. 291p.
[PAR 86] PARKER Jr, D.S. et al.: Logic Programming and Databases. In: EXPERT DATA-
BASE SYSTEMS. Menlo Park: Benjamin Cummings, 1986. 701p. p.35-48.
[PEN 83] PENTLAND, A.P.; FISCHLER, M.A.: A More Rational View of Logic. AI Magazine,
v.4, n.4, Winter, 1983.
[PER 82] PEREIRA, L.M.: Logic Control with Logic. In: INTERNATIONAL CONFERENCE
ON LOGIC PROGRAMMING, 1., Sept. 1982, Marseille, France. Proceedings ... Berlin:
Springer-Verlag, 1982.
[PER 88] PERLIS, D.: Meta in Logic. In: META LEVEL ARCHITECTURES AND REFLEC-
TION. Amsterdam: North-Holland, 1988. 355p. p.37-50.
[ROB 65] ROBINSON, J.A.: A Machine-Oriented Logic Based On The Resolution Principle.
Journal of ACM, New York, v.12, n.1, p.23-41, Jan. 1965.
[STE 86] STERLING, L.; SHAPIRO, E.: The Art of Prolog. Cambridge: MIT Press, 1986. 427p.
[SAK 86] SAKAKIBARA, I.: Programming in Modal Logic: An Extension of Prolog Based on
Modal Logic. In: LOGIC PROGRAMMING CONFERENCE, 5., 1986, Tokyo. Pro-
ceedings ... Berlin: Springer-Verlag, 1987.
[SHA 83] SHAPIRO, E.Y.: Logic Programming with Uncertanties: A Tool for Implementing
Rule-Based Systems. In: INTERNATIONAL JOINT CONFERENCE ON ARTIFICIAL
194
INTELLIGENCE, 8., 1983, Karlsrue. Proceedings ... L:os Altos, Calif.: Distributed by
W. Kaufmann, 1983. p.529-532.
[SHA 93] SHAPIRO, E.; WARREN, D.: The Fifth Generation Project: Personal Perspectives.
Communications of ACM, v.36, n.3, March 1993. p.48-101.
[STI 85] STICKEL, M.; TYSON, W.: An Analisys of Consecutively Bounded Depth-First
Search With Applications in Automated Deduction. In: INTERNATIONAL JOINT
CONFERENCE ON ARTIFICIAL INTELLIGENCE, 9., 1985, Los Angeles. Proceed-
ings ... Los Altos, Calif.: Distributed by M. Kaufmann, 1985. p.465-471.
[STE 86] STERLING, L.; SHAPIRO, E.: The Art of Prolog. Cambridge: MIT Press, 1986.
[TAR 75] TRNLUND, S.-A.: An Interpreter for the Programming Language Predicate
Logic. In: INTERNATIONAL JOINT CONFERENCE ON ARTIFICIAL INTELLI-
GENCE, 4., 1975, Tblisi. Proceedings ... New York: ACM, 1975. p.601-608.
[TUR 84] TURNER, R.: Logics for Artificial Intelligence. West Sussex: Ellis Horwood, 1984,
121p.