Buscar

Inteligência Artificial e Robótica - Aula4

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 22 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 22 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 22 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

AULA 4 
 
 
 
 
 
 
 
 
 
 INTELIGÊNCIA ARTIFICIAL E 
ROBÓTICA 
 
 
 
 
 
 
 
 
 
 
 
Prof. Luciano Frontino de Medeiros 
 
 
 
 
 
 
2 
TEMA 1 – PROGRAMAÇÃO EM LÓGICA E PROLOG 
Como vimos anteriormente, os agentes/robôs devem processar os dados 
provenientes dos sensores para tomar decisões e acionar os atuadores 
respectivos. O processamento envolve, então, um programa que implementa as 
funções do robô, de forma que ele possa desempenhar o comportamento 
esperado. 
Para tarefas mais simples, a programação pode envolver aspectos relativos 
à forma com que o robô irá se comportar. Para tarefas complexas que envolvam 
algum nível de raciocínio por parte do robô, alguns recursos disponíveis em IA 
podem ser úteis, como a programação em lógica. No entanto, plataformas mais 
robustas devem ser utilizadas para fazer com que tais recursos possam ser 
executados, como por exemplo a Raspberry Pi (<https://www.raspberrypi.org/>). 
Assim, a programação em lógica é um tipo de programação que se utiliza 
de representações lógicas sobre o ambiente e permite deduzir novos 
conhecimentos a partir dos conhecimentos já existentes nesta representação. A 
programação em lógica tem suas raízes na lógica estudada na Filosofia. A partir 
do século XIX, Boole (1815-1864) criou a ferramenta que hoje é chamada de 
“álgebra booleana”. Já no século XIX, o matemático alemão Gottlob Frege (1848-
1925) criou a primeira versão de um cálculo de predicados da lógica, auxiliando a 
formalização exata do raciocínio dedutivo sobre conceitos matemáticos (Palazzo, 
1997, p. 1). 
A fundamentação teórica da lógica computacional estava pronta já no início 
da Segunda Guerra Mundial. No entanto, apenas com a evolução dos 
computadores, a partir dos anos 1950, é que foram feitas as primeiras 
implementações. Na década de 1960, surgiram programas para efetuar a prova 
automática de teoremas. No entanto, apenas em 1972 surge a primeira 
implementação por meio do grupo de pesquisa de Alain Colmerauer, da 
Universidade Aix-Marseille, com o nome de Prolog (acrônimo de “Programmation 
en Logique”). A linguagem foi mais tarde formalizada por pesquisadores da 
Universidade de Edimburgo, que é a referência para as implementações atuais 
(Palazzo, 1997, p. 2). 
Prolog lida com o conceito de programa em lógica. Quando um problema 
pode ser expresso por meio de um conjunto finito de um tipo especial de 
sentenças lógicas denominadas de cláusulas, temos um programa em lógica. O 
 
 
3 
programador simplesmente especifica o problema que deve ser solucionado. O 
controle fica a cargo do sistema de programação em lógica utilizado (Palazzo, 
1997, p. 3). Em Prolog, a tarefa de escrever um programa é bastante diferente de 
escrever em uma linguagem de programação tal com C, Java (ou mesmo 
linguagens visuais). O “programa” do Prolog já está pronto, e o programador deve 
apenas especificar os dados. Esses dados devem ser expressos por meio de uma 
forma bastante específica. Por isso é que um problema em lógica é visto como 
um tipo de base de dados. 
Desde o seu advento, a programação em Prolog tem sido aplicada a 
diversas áreas, como sistemas de apoio à decisão, simulações educacionais, 
tutoriais inteligentes, problemas matemáticos, planejamento e roteirização, 
resolução de problemas, uso em regras de negócio e processamento de 
linguagem natural, dentre outras (Medeiros, 2018, p. 100). 
Uma cláusula em Prolog pode ser de três tipos (Medeiros, 2018, p. 101): 
• Fatos: denotam uma verdade incondicional, a respeito do ambiente que 
está sendo representado. 
• Regras: definem as condições que devem ser satisfeitas para que uma 
declaração seja considerada verdadeira. A partir de uma regra, é possível 
derivar novos fatos. 
• Consulta: é feita a consulta ou pergunta ao programa, de forma a verificar 
a verdade do conhecimento que está contido. 
No Quadro 1, há exemplos de cláusulas em Prolog. 
Quadro 1 – Exemplos de cláusulas em Prolog. 
Cláusula Exemplo Descrição 
Fato pai(joão, luiz). Este fato é traduzido como “João é o pai 
de Luiz”. 
Regra filho(X,Y) :- pai(Y,X). 
 
Se X é filho de Y, então Y é pai de X. O 
sinal “:-“ funciona como uma “seta à 
esquerda”, donde a conclusão à direita é 
obtida a partir das premissas que estão 
na direita. 
Consulta ?- filho(luiz, joão). 
True 
A consulta tenta obter se, a partir dos 
fatos e das regras existentes na base de 
conhecimento, Luiz é filho de João. A 
regra acima deduz um novo fato, a partir 
do fato e da regra anterior. 
Fonte: Medeiros, 2018, p. 101. 
 
 
4 
A dinâmica de programação em Prolog requer que o programador alimente 
os fatos e as regras no sistema PROLOG. Logo após, são feitas as consultas, 
como se fossem perguntas relativas à dedução de novos conhecimentos, a partir 
dos conhecimentos que existem na base de conhecimento. Uma cláusula é 
dividida nos seguintes componentes: 
• Corpo: lista de objetivos separados por vírgulas, que devem ser 
interpretadas por conjunções. 
• Cabeça: contém o resultado do corpo, inferido a partir dos objetivos. 
Um fato contém apenas “cabeça”. A consulta só possui o “corpo”. Uma 
regra contém tanto cabeça quanto corpo (Medeiros, 2018, p. 101). 
Algumas regras sintáticas devem ser levadas em consideração quando se 
escreve um programa em Prolog. No Quadro 1, pode-se notar que as constantes 
são palavras iniciadas com letra minúscula, enquanto que as variáveis devem ser 
escritas com a primeira letra em maiúscula. Portanto, o fator chave que diferencia, 
em Prolog, uma variável de uma constante, é a primeira letra da variável, que 
aparece sempre em maiúsculas (Medeiros, 2018, p. 102). 
Uma das plataformas para Prolog mais utilizadas hoje em dia é SWI-Prolog 
(<http://www.swi-prolog.org>). Desde a sua criação, em 1987, é muito usada em 
pesquisa, educação e também para aplicações comerciais. O software SWI-
Prolog é disponibilizado, inclusive, para uso concomitante com outras linguagens 
de programação, tais como C++, C#, Java Python etc., o que potencializa a 
abordagem de resolução de problemas em IA (Medeiros, 2018, p. 102). 
Figura 1 – Tela do interpretador SWI-PROLOG com exemplo de consulta um 
programa de cálculo de fatorial 
 
Fonte: Medeiros, 2018, p. 103. 
 
 
5 
A dinâmica de programação em Prolog pode ser melhor compreendida a 
partir de exemplos, o que será feito nos próximos temas. 
TEMA 2 – COLORAÇÃO DE MAPAS 
O exemplo da coloração de mapas ilustra o uso do Prolog na busca de 
soluções nas quais há restrições a serem seguidas (Medeiros, 2018, p. 103). Uma 
atividade típica de coloração de mapas requer que cada região do mapa, seja um 
país, estado ou qualquer área delimitada, tenha uma cor específica. As cores 
podem ser diversas, desde que as regiões que fazem fronteira umas com as 
outras não tenham a mesma cor. A Figura 2 traz um exemplo de coloração do 
mapa da América do Sul, mostrando uma solução de cores, com a restrição de 
que cada país tenha uma cor diferente de outro que esteja na vizinhança. 
Figura 2 – Mapa da América do Sul 
 
Crédito: RRZ/Shutterstock. 
Para simplificar na abordagem do problema com Prolog, usaremos o mapa 
simplificado da Figura 2 com 5 regiões. Pode-se notar que as regiões “1” e “4” 
fazem fronteira com todas as outras regiões; já a região “2” faz fronteira com as 
regiões “1”, “3” e “4”; a região “5” faz fronteira somente com as regiões “1” e “4”. 
As regiões “3” e “5” podem ter a mesma cor, pois não fazem fronteira uma com a 
outra (Medeiros, 2018, p. 105). Uma solução para este problema pode ser o grupo 
de cores visto na Figura 4. 
 
 
 
6 
Figura 3 – Exemplo para coloração de mapas com 5 regiões 
 
Figura 4 – Solução possível com grupo de cores que atende à restrição de 
coloração 
 
Então, devemos construir um programa Prolog que irá processar uma base 
de conhecimento que tenha os fatos relativos às regiões e cores do mapa. 
Suponha que as coressão geradas de forma aleatória. O programa Prolog deverá 
responder se tal conjunto de cores está em conflito ou não. Precisamos então 
fazer a representação desse mundo da coloração de mapas, na forma de fatos, 
na base de conhecimento (Medeiros, 2018, p. 106). Podemos identificar três 
conceitos a partir da análise do problema, que poderão ser traduzidos em 
cláusulas de um programa Prolog: 
• Cor: uma cor específica que uma região pode ter. 
• Adjacência: duas regiões que fazem fronteira uma com a outra. 
• Conflito: se um grupo de cores está em conflito com a restrição ou não. 
Um recurso que facilita a descrição em fatos do programa Prolog é traduzir 
o mapa da Figura 2 na representação de uma árvore de adjacência ou vizinhança, 
 
 
7 
como pode ser visto na Figura 4. Toma-se como ponto de partida a região “1”, 
expandindo-se para as outras regiões na forma de nós de uma árvore, e cada uma 
em sequência, sem haver repetição, expandindo no nível mais raso. Essa forma 
facilita a tradução em fatos para o programa Prolog. 
Figura 5 – Representação das adjacências do mapa na forma de uma árvore 
 
Portanto, a primeira tarefa na escrita do programa será representar em 
linguagem Prolog essas adjacências. Para isso, escrevemos a palavra 
“adjacente”, com dois argumentos, um para a primeira região e outro para a 
segunda. Sete cláusulas são escritas inicialmente. Depois, é feita a inversão das 
regiões, com mais sete cláusulas, pois o programa Prolog irá entender apenas 
numa direção, e é necessário complementar com a adjacência inversa. Por 
exemplo, caso ficasse apenas a primeira coluna, o programa saberia que a região 
“1” é adjacente à região “2”. Entretanto, não saberia que a região “2” é adjacente 
à região “1”: 
adjacente(1,2). adjacente(2,1). 
adjacente(1,3). adjacente(3,1). 
adjacente(1,4). adjacente(4,1). 
adjacente(1,5). adjacente(5,1). 
adjacente(2,3). adjacente(3,2). 
adjacente(2,4). adjacente(4,2). 
adjacente(3,4). adjacente(4,3). 
adjacente(4,5). adjacente(5,4). 
O próximo passo é definir a cláusula “cor”, de forma que tenha três 
argumentos: região, cor e grupo. Como ilustração, temos dois grupos de cores, 
“a” e “b”, traduzidos na forma de fatos, conforme vemos a seguir (pode haver 
qualquer outra combinação): 
cor(1,vermelho,a). 
cor(2,azul,a). 
cor(3,verde,a). 
cor(4,amarelo,a). 
 
 
8 
cor(5,azul,a). 
 
cor(1,vermelho,b). 
cor(2,azul,b). 
cor(3,verde,b). 
cor(4,azul,b). 
cor(5,verde,b). 
Até agora expressamos os fatos neste programa Prolog. Para saber se 
existe a mesma cor em regiões adjacentes, é necessário definir uma regra que 
permite identificar o conflito. A regra pode ser expressa da seguinte forma: 
conflito(Grupo):- adjacente(X,Y), cor(X,Cor,Grupo), 
cor(Y,Cor,Grupo). 
Foi criada, portanto, a cláusula “conflito”, que irá responder se existe um 
conflito em um grupo de cores, conforme a variável “Grupo”. As cláusulas 
utilizadas como premissas são “adjacente” e “cor”. A regra de conflito é 
interpretada da seguinte forma: “duas regiões adjacentes estão em conflito se as 
cores destas regiões são as mesmas”. Com exceção das variáveis “X” e “Y”, a 
variável “Cor” e “Grupo” são as mesmas nas duas cláusulas de “cor” (Medeiros, 
2018, p. 108). Dessa forma, quando o programa Prolog for executado, para uma 
consulta: 
?- conflito(a). 
false 
Note a substituição por uma constante dentro da cláusula “conflito”. No 
caso do grupo “a”, o programa deduz que não há conflito. Já no caso do grupo “b” 
acontece o contrário: 
?- conflito(b). 
true 
O programa completo, que chamaremos de “mapas.pl”, será então: 
adjacente(1,2). adjacente(2,1). 
adjacente(1,3). adjacente(3,1). 
adjacente(1,4). adjacente(4,1). 
adjacente(1,5). adjacente(5,1). 
adjacente(2,3). adjacente(3,2). 
adjacente(2,4). adjacente(4,2). 
adjacente(3,4). adjacente(4,3). 
adjacente(4,5). adjacente(5,4). 
 
cor(1,vermelho,a). 
cor(2,azul,a). 
cor(3,verde,a). 
 
 
9 
cor(4,amarelo,a). 
cor(5,azul,a). 
 
cor(1,vermelho,b). 
cor(2,azul,b). 
cor(3,verde,b). 
cor(4,azul,b). 
cor(5,verde,b). 
 
conflito(Grupo):-
adjacente(X,Y),cor(X,Cor,Grupo),cor(Y,Cor,Grupo). 
Quando executamos no SWI-PROLOG, conforme a Figura 5, constatamos 
a partir da execução das consultas de existe conflito nos conjuntos de cores 
presentes na base de conhecimento. 
Figura 6 – Execução do programa “mapas.pl” no SWI-PROLOG 
 
As consultas 1 e 2 mostram o uso direto das constantes dos grupos “a” e 
“b”. A consulta 3 mostra o uso de uma variável (Z) ao invés de uma constante. A 
pergunta associada aqui seria: “Existe algum grupo de cores que apresente 
conflito?”. 
TEMA 3 – TORRE DE HANOI 
Um problema bastante conhecido na IA é denominado Torres de Hanói. 
Nesse problema, o objetivo é colocar as peças no último pino, de forma que, na 
movimentação, uma peça maior não fique sobre uma peça menor. Podemos 
resolvê-lo a partir de uma estratégia de busca em profundidade. A expressão do 
programa em Prolog para essa finalidade é bastante simples. Utilizamos uma 
configuração com três peças (Figura 7) para simplificar a explicação da resolução 
desse problema em Prolog (Medeiros, 2018, p. 115). 
 
 
10 
Existem três pinos (“1”, “2”, e “3”) e três peças (“a”, “b” e “c”). Elas estão 
empilhadas no primeiro pino, de forma crescente quanto ao tamanho. O objetivo 
é fazer com que essa mesma pilha seja colocada no pino 3 (Figura 7). Podemos 
utilizar o pino central para auxiliar na transferência das peças até o pino-objetivo. 
Entretanto, há uma restrição: durante a movimentação das peças, uma peça 
menor não pode ficar sob uma peça maior (Figura 8). 
Figura 7 – Problema da Torre de Hanói com três peças 
 
Figura 8 – Um estado proibido na resolução do problema das Torres de Hanoi 
 
Fonte: Medeiros, 2018, p. 115. 
A resolução desse problema pode ser vista na Figura 9. As peças são 
movimentadas para os pinos seguintes, respeitando a restrição colocada, de 
forma a se reproduzir no último pino a configuração do primeiro pino. 
 
 
 
11 
Figura 9 – Resolução passo a passo do problema 
 
A Figura 9 mostra a resolução do problema. As peças são colocadas, 
utilizando-se o pino central como auxiliar, de maneira a reproduzir no pino objetivo 
a mesma pilha do estado inicial. 
No programa em Prolog, utilizaremos o comando reservado “write” para 
imprimir um determinado texto ou valor de variável. Ao final do uso de “write”, 
podemos mudar a impressão para a próxima linha utilizando “nl”. 
Para resolver o problema, não é necessário criar fatos referentes a cada 
peça sendo movimentada. Basta que movimentemos sempre a peça que esteja 
no topo de um pino. Portanto, criaremos uma cláusula “move” que indicará a 
movimentação de uma peça que esteja no topo de um pino para outro pino 
indicado como argumento: 
move(N,X,Y,Z) 
 
 
12 
Nessa cláusula, N é o número de peças para movimentar, X é o pino inicial, 
Y é o último pino e Z é o pino intermediário. A cláusula “move” será chamada de 
forma recursiva, sendo a raiz outra cláusula “move” que imprimirá o comando de 
movimentação da peça do topo: 
move(1,X,Y,_) 
Esse comando imprimirá a mensagem “Mova a peça do topo de X para Y”. 
Note que o último argumento é dummy (_), pois não nos interessa para a 
impressão da mensagem. 
Assim, o programa a seguir perfaz a movimentação de acordo com a 
restrição imposta ao problema. Note que um dos critérios da execução de forma 
recursiva continuar é que N seja maior do que 1 (verifique a segunda regra 
“move”), expressa como “N>1”. 
move(1,X,Y,_) :- 
 write('Mova o disco do topo de '), 
 write(X), 
 write(' para '), 
 write(Y), 
 nl. 
move(N,X,Y,Z) :- 
 N>1, 
 M is N-1, 
 move(M,X,Z,Y), 
 move(1,X,Y,_), 
 move(M,Z,Y,X). 
Na execução do programa, fazemos a chamada a move(3,1,3,2), indicando 
3 peças a movimentar, apartir do pino 1 até o pino 3, utilizando o pino 2 como 
auxiliar. Verifique a resolução abaixo feita pelo PROLOG com o passo a passo da 
figura 4-22: 
?- move(3,1,3,2). 
Mova a peça do topo de 1 para 3 
Mova a peça do topo de 1 para 2 
Mova a peça do topo de 3 para 2 
Mova a peça do topo de 1 para 3 
Mova a peça do topo de 2 para 1 
Mova a peça do topo de 2 para 3 
Mova a peça do topo de 1 para 3 
 
O programa pode resolver problemas com 3 peças, e também pode ser 
extrapolado para mais. Concluindo, o exemplo da Torre de Hanói mostra a 
versatilidade da linguagem Prolog na abordagem de problemas. Na robótica 
educacional, pode-se imaginar um exemplo físico de uma Torre de Hanói com um 
braço robótico fazendo a movimentação das peças. Por meio de sensores ou 
 
 
13 
câmeras, o robô pode identificar a peça a ser movimentada e fazer o movimento 
acionando o braço. Porém, como mencionamos no início, será preciso contar com 
uma plataforma mais robusta, que tenha condições de rodar um programa Prolog. 
TEMA 4 – CUSTO DE CAMINHOS 
Nos casos em que um robô que se desloca por algum ambiente precisa 
avaliar qual o melhor caminho a ser seguido, é necessário que ele calcule os 
caminhos possíveis para que então escolha aquele que será o mais viável. Pode-
se fazer em Prolog um programa para se resolver este tipo de problema. Uma 
forma de representação para esse problema é simbolizar os pontos onde deve 
chegar o robô como nós (pontos) e a ligação entre cada par de nós como sendo 
os caminhos que ele pode percorrer. Na Figura 10 há um exemplo. Existem 6 nós 
pelos quais o robô precisa passar, com as possíveis conexões (caminhos) entre 
eles. Note que cada caminho tem um valor específico, que pode ser a distância 
ou algum valor que represente o curso para ir de um nó a outro. 
Figura 10 – Exemplo para o problema de avaliação de curso de caminho 
 
Fonte: Elaborado com base em Palazzo, 1997. 
Adotando-se o ponto de saída como sendo o nó “A” e o ponto de chegada 
como o nó “F”, o robô deve percorrer cada caminho entre os nós para sair de “A” 
e chegar até “F”. Pode-se notar que existem vários caminhos para se fazer o 
trajeto. Portanto, com Prolog, pode-se escrever um programa que avalie os 
caminhos possíveis, para que depois se possa tomar a decisão sobre qual deverá 
ser seguido. A ideia geral é que, a cada caminho sondado, o programa vá 
somando os custos (números de cada caminho), chegando ao final com um valor 
determinado. 
 
 
14 
Em primeiro lugar, deve-se representar cada caminho possível como um 
fato no programa Prolog. Isso é feito colocando uma cláusula que será 
denominada de “arco”, com o nó de saída e o nó de chegada. 
arco(a,b,3). 
arco(a,c,4). 
arco(a,d,6). 
arco(b,d,2). 
arco(c,f,5). 
arco(c,d,3). 
arco(d,e,2). 
arco(e,f,3). 
Lembre-se de que cada nó é representado por uma letra, e que eles devem 
ser representados por letra minúscula, pois são constantes. Para simplificar, 
nesse exemplo estamos utilizando apenas uma direção, sem representar os 
caminhos inversos. 
A partir dos fatos registrados, devemos representar as regras relativas aos 
caminhos que ligam entre os nós. O ponto de partida é que cada arco já é um 
caminho. Um caminho pode ser feito de dois, três ou mais arcos. Portanto, haverá 
uma cláusula “caminho” que faz a ligação de um nó até outro: 
caminho(U,V,L) :- arco(U,V,L). 
Assim, a regra nos diz que um caminho para ir do nó “U” ao nó “V”, com o 
custo “L”, é o próprio arco para ir do nó “U” ao nó “V”, que tem o custo “L”. Por 
indução, pode-se adotar o caminho que tem dois arcos: 
caminho(U,W,L) :- arco(U,W,M),arco(W,V,N),L = M+N. 
O custo “L” agora é a soma dos custos dos dois caminhos “M” e “N”. E 
assim segue sucessivamente, para três arcos: 
caminho(U,W,L) :- arco(U,W,M),arco(W,X,N),arco(X,V,O), L = M+N+O. 
No entanto, essa abordagem requer que montemos várias regras, para 
contemplar os caminhos possíveis. E pode ser que um caminho possível com mais 
arcos não venha a ser contemplado, o que não irá resolver o problema. Entretanto, 
em Prolog há uma forma de escrever as regras de forma a economizar a escrita. 
São necessárias apenas duas regras: uma que determine o menor caminho (com 
um arco) e outra que chame a si mesma para contemplar os outros caminhos 
combinados possíveis: 
caminho(U,V,L) :- arco(U,V,L). 
 
 
15 
 
caminho(U,V,L) :- arco(U,W,M),caminho(W,V,N), L = M+N. 
Note que a primeira regra é a mesma vista anteriormente para um caminho. 
Já a segunda está mostrando que um caminho pode ser combinado de um arco 
mais um caminho. Essa regra é chamada de recursiva. Ela pode ser chamada 
continuamente enquanto houver caminhos e arcos possíveis, até o arco que está 
sendo considerado. 
Assim, o programa Prolog completo pode ser visto a seguir: 
arco(a,b,3). 
arco(a,c,4). 
arco(a,d,6). 
arco(b,d,2). 
arco(c,f,5). 
arco(c,d,3). 
arco(d,e,2). 
arco(e,f,3). 
 
caminho(U,V,L) :- arco(U,V,L). 
 
caminho(U,V,L) :- arco(U,W,M),caminho(W,V,N), L = M+N. 
A execução desse programa no SWI-PROLOG é mostrada na Figura 11, 
feita por meio da consulta: 
?- caminho(a,f,L). 
Essa consulta pergunta qual o caminho para ir de “a” até “f”. A variável L é 
colocada para mostrar o raciocínio de Prolog na identificação dos custos dos 
caminhos. Note que não é feita a soma dos valores, apenas mostramos cada arco 
como parcela da soma. Para somar os valores efetivamente, deve-se utilizar o 
comando “L is M+N”, ao invés de “L = M+N”. 
Figura 11 – Execução do programa para saber o custo de caminhos possíveis da 
Figura 10 
 
 
 
16 
TEMA 5 – RACIOCÍNIO LÓGICO 
Para ilustrar o poder de raciocínio que a linguagem Prolog pode 
proporcionar, vamos apresentar agora o programa da árvore genealógica. Esta 
classe de problema pode ser estendida para outros contextos, quando for 
necessário que um robô raciocine sobre um determinado conjunto hierárquico de 
fatos. Um sistema em Prolog poderá proporcionar informações sobre parentescos 
complexos somente com regras que definam tais parentescos relativos aos fatos 
cadastrados na base. Veja a árvore genealógica descrita na Figura 12. 
Figura 12 – Exemplo para o problema da árvore genealógica 
 
Fonte: Medeiros, 2018, p. 109. 
Primeiramente, é necessário definir uma cláusula que mostre o 
relacionamento do parentesco direto existente entre duas pessoas da árvore. 
Assim, estabelece-se uma cláusula “genitor” com dois argumentos: o primeiro 
sendo o genitor do segundo, de acordo com a árvore. Pela análise das relações 
na árvore, podemos então começar nosso programa em Prolog contendo os 
seguintes fatos (Medeiros, 2018, p. 110): 
genitor(carlos,maria). 
genitor(luiza,maria). 
genitor(carlos,fernando). 
genitor(luiza,paulo). 
genitor(maria,leticia). 
genitor(maria,eduardo). 
genitor(eduardo,roberto). 
 
 
17 
Podemos fazer consultas ao Prolog, carregando o programa e 
perguntando, por exemplo, “quem é o genitor de Fernando?”. Introduzimos uma 
variável (X) no campo referente ao primeiro argumento e procedemos à consulta: 
?- genitor(X,fernando). 
X=carlos. 
 
Da mesma forma, se quiséssemos saber “de quem Luiza é genitor?”, 
colocamos novamente a consulta no Prolog através de uma variável no segundo 
argumento: 
?- genitor(luiza,Y). 
Y=paulo. 
Caso exista a necessidade de saber “quem é genitor de quem?”, basta 
colocar as variáveis nos dois argumentos da cláusula “genitor”, com o Prolog 
retornando todas as instâncias existentes na base. Note o ponto-e-vírgula ao final 
de cada par resultante. Na interface de Prolog, é necessário clicar a barra de 
espaço para identificar possíveis soluções adicionais: 
?- genitor(X,Y). 
X = carlos, 
Y = maria ; 
X = luiza, 
Y = maria ; 
X = carlos, 
Y = fernando ; 
X = luiza, 
Y = paulo ; 
X = maria, 
Y = leticia ; 
X = maria, 
Y = eduardo ; 
X = eduardo, 
Y = roberta. 
Como um fato representado na base de dados do Prolog, a cláusula 
“genitor(carlos,maria)” identifica (apenas) quecarlos é genitor de maria. Não 
sabemos ainda se “carlos” é considerado pai, pois isso não está de forma explícita 
na base de fatos. Poderíamos criar uma nova cláusula “pai” que indicaria “carlos” 
como pai de “maria” tal como “pai(carlos,maria)”. Entretanto, se seguíssemos esta 
estratégia, deveríamos indicar para cada fato cadastrado um relacionamento “pai”, 
ou mesmo “mãe”, dessa forma. Adotaremos uma maneira diferente, indicando 
apenas o gênero de cada pessoa. Para obtermos isso, é necessário estipular uma 
cláusula que indique a informação de quem na base é considerado masculino ou 
feminino. Assim, as seguintes cláusulas permitem essa definição: 
 
 
18 
masculino(carlos). 
masculino(fernando). 
masculino(paulo). 
masculino(eduardo). 
feminino(roberta). 
feminino(luiza). 
feminino(maria). 
feminino(leticia). 
Poderíamos agora, em função da base de fatos cadastrada neste programa 
exemplo, identificar diferentes relacionamentos a partir de regras, ao invés de 
escrevermos fatos indefinidamente. Por exemplo, podemos indicar a cláusula “pai” 
com a seguinte regra: 
pai(X,Y) :- genitor(X,Y), masculino(X). 
Assim, quando executarmos o programa com esta regra, o Prolog retornará 
todos aqueles que são genitores e definidos na base de fatos como masculinos. 
No caso de uma cláusula “mãe”, podemos analogamente definir com a seguinte 
regra: 
mae(X,Y) :- genitor(X,Y), feminino(X). 
Para identificar uma relação mais complexa, como por exemplo a relação 
“irmão”, precisamos pensar sobre como a árvore genealógica pode nos dar esta 
informação. Na Figura 11, podemos identificar que “maria” e “fernando" são 
irmãos, assim como “leticia” e “eduardo". Portanto, podemos definir uma regra 
segundo a qual dois indivíduos X, Y são irmãos quando apresentam o mesmo 
genitor. Portanto, uma regra que pode retornar esta informação seria: 
irmao(X,Y) :- genitor(Z,X), genitor(Z,Y), X \= Y. 
Assim, Z é o mesmo genitor para X e Y. Note que colocamos ao final da 
regra uma cláusula para dizer que X é diferente de Y (X \= Y); senão, o Prolog 
pode retornar X como irmão de X. 
Para o exemplo de uma relação mais complexa, como poderíamos criar 
uma regra que identificasse o avô? Pela Figura 11, podemos ver que Carlos é avô 
de Leticia ou Eduardo. Podemos identificar a regra “avo” encadeando os genitores 
no corpo da regra: 
avo(X,Y) :- genitor(X,Z),genitor(Z,Y),masculino(X). 
 
 
19 
Quando executamos a consulta para saber “quem é avô de quem?”, 
obtemos o seguinte: 
?- avo(X,Y). 
X = carlos, 
Y = leticia ; 
X = carlos, 
Y = eduardo ; 
Uma consulta em Prolog pode ainda conter cláusulas combinadas. Por 
exemplo, caso queiramos responder à pergunta “Quem é neto de Carlos?”, 
podemos escrever a consulta combinando duas cláusulas: 
?- genitor(carlos,Y), genitor(Y,Z). 
Y = maria, 
Z = leticia ; 
Y = maria, 
Z = eduardo ; 
Como visto no caso do custo de caminho, a linguagem Prolog permite o 
uso de recursividade. Imagine que queremos saber, na árvore genealógica, quem 
são os antepassados de “Roberta”. Podemos começar com o genitor de Roberta, 
Eduardo. Assim, é necessário definir a relação “antepassado” em função de 
“genitor”: 
antepassado(X,Y) :- genitor(X,Y). 
Essa regra nos diz que alguém é antepassado de outrem se esse alguém 
também for genitor de outrem. Assim, Eduardo e Roberta são incluídos aqui, 
juntamente com todos os outros fatos. Entretanto, o genitor do genitor também é 
um antepassado (avô ou avó). Para definirmos a regra que inclua também esses 
indivíduos, precisamos definir “antepassado” da seguinte forma: 
antepassado(X,Y) :- 
 genitor(X,Z), 
 genitor(Z,Y). 
Podemos fazer agora a consulta, após as duas regras: 
?- antepassado(X,roberta). 
X = eduardo ; 
X = maria ; 
Porém, podemos identificar na Figura 11 que “Carlos” e “Luiza” também 
são antepassados e ficaram de fora do resultado da consulta. É necessário 
adicionar mais uma regra que permita incluí-los na consulta: 
antepassado(X,Y) :- 
 
 
20 
 genitor(X,Z), 
 genitor(Z,U), 
 genitor(U,Y). 
O resultado agora contempla os antepassados faltantes: 
?- antepassado(X,roberta). 
X = eduardo ; 
X = maria ; 
X = carlos ; 
X = luiza ; 
No caso do exemplo, não é necessário retroceder. Porém, em árvores mais 
extensas, deveríamos explicitar cada regra conforme aumentasse o grau de 
ancestralidade, o que torna o programa dependente do contexto. 
Para explicitar um conjunto de regras que contemplasse qualquer grau de 
ancestralidade sem a necessidade de incluir regras para contemplar uma a uma, 
podemos construir as regras de forma recursiva: 
antepassado(X,Y) :- genitor(X,Y). 
antepassado(X,Y) :- genitor(X,Z),antepassado(Z,Y). 
Note que há apenas duas regras: a primeira identifica a relação direta do 
genitor como o primeiro antepassado; as próximas são contempladas pela 
segunda regra, na qual “antepassado” está tanto na cabeça quanto no corpo da 
regra. Isso evita a necessidade de reescrever cada grau de ancestralidade 
conforme a descrição da árvore genealógica. 
Temos, portanto, o seguinte programa em Prolog que resume o exercício 
da linguagem feito aqui: 
% Programa da Árvore Genealógica 
% Fatos 
genitor(carlos,maria). 
genitor(luiza,maria). 
genitor(carlos,fernando). 
genitor(luiza,paulo). 
genitor(maria,leticia). 
genitor(maria,eduardo). 
genitor(eduardo,roberta). 
masculino(carlos). 
masculino(fernando). 
masculino(paulo). 
masculino(eduardo). 
feminino(roberta). 
feminino(luiza). 
feminino(maria). 
feminino(leticia). 
 
 
 
21 
% Regras 
pai(X,Y) :- genitor(X,Y), masculino(X). 
mae(X,Y) :- genitor(X,Y), feminino(X). 
irmao(X,Y) :- genitor(Z,X), genitor(Z,Y), X \= Y. 
avo(X,Y) :- genitor(X,Z),genitor(Z,Y),masculino(X). 
 
antepassado(X,Y) :- genitor(X,Y). 
antepassado(X,Y) :- genitor(X,Z),antepassado(Z,Y). 
 
 
 
22 
REFERÊNCIAS 
MEDEIROS, L. F. DE. Inteligência artificial aplicada. Curitiba: InterSaberes, 
2018. 
PALAZZO, L. A. M. Introdução a Prolog. Pelotas: Ed. UCPel, 1997.

Continue navegando