Baixe Exercícios Resolvidos em Prolog sobre Sistemas Baseados em Conhecimento por Paulo Cortez e outras Exercícios em PDF para Cultura, somente na Docsity!
Exercícios Resolvidos em Prolog sobre
Sistemas Baseados em Conhecimento
por Paulo Cortez
Unidade de Ensino
Departamento de Sistemas de Informação
Escola de Engenharia
Universidade do Minho
Guimarães, Portugal
Abril, 2008
ii
iv
1 Introdução
Este texto pedagógico reúne um conjunto de exercícios resolvidos na
linguagem Prolog para apoio à unidade curricular Sistemas Baseados em
Conhecimento , do terceiro ano e segundo semestre da Licenciatura em Tecnologias
e Sistemas de Informação. O objectivo é complementar a matéria que foi leccionada
nas aulas teórico-práticas e práticas-laboratoriais.
O texto inicia-se com exercícios gerais sobre a linguagem Prolog (Capítulo 2),
seguindo-se os diversos paradigmas de representação de conhecimento leccionados
nesta unidade curricular (regras de produção, estruturas hierárquicas, procura num
espaço de soluções, dependências conceptuais e programação orientada a padrões).
De realçar que:
todo o código apresentado neste livro foi executado no compilador
gratuito^1 SWI-Prolog [Wielemaker, 2008a] , que corre em múltiplas
plataformas, tais como o Windows , Linux ou MacOS ;
cada solução apresentada deve ser analisada com algum sentido crítico, ou
seja, é uma possível solução, embora não seja a única forma de resolução
do exercício proposto.
1 Open-source.
2 Exercícios sobre Prolog 2.1 A Árvore Genealógica da Família Pinheiro
Enunciado:
Pouco se sabe da história passada da família Pinheiro. Existem alguns registos
antigos que indicam que o casal José e Maria criou dois filhos, o João e a Ana. Que a
Ana teve duas filhas, a Helena e a Joana, também parece ser verdade, segundo os
mesmos registos. Além disso, o Mário é filho do João, pois muito se orgulha ele
disso. Estranho também, foi constatar que o Carlos nasceu da relação entre a Helena,
muito formosa, e o Mário.
a) Utilizando o predicado progenitor(X,Y) (ou seja, X é progenitor de Y),
represente em Prolog todos os progenitores da família Pinheiro.
b) Represente em Prolog as relações: sexo (masculino ou feminino), irmã ,
irmão , descendente , mãe , pai , avô , tio , primo^2.
c) Formule em Prolog as seguintes questões:
1. O João é filho do José?
2. Quem são os filhos da Maria?
3. Quem são os primos do Mário?
4. Quantos sobrinhos/sobrinhas com um Tio existem na família Pinheiro?
5. Quem são os ascendentes do Carlos?
6. A Helena tem irmãos? E irmãs?
Explicação:
Este exercício envolve objectos e relações entre objectos , sendo uma adaptação livre
do programa family da Figura 1.8 do livro [Brakto, 1990]. Dado que o enunciado é
livre neste aspecto, optou-se por utilizar a notação sexo(Nome, Sexo) para representar
o sexo de cada pessoa. Em algumas das relações pode existir mais do que uma forma
de resolver aquilo que é pedido. As questões da alínea c) podem ser ter diferentes
interpretações (por exemplo se a questão deve retornar uma ou todas as soluções),
sendo que nestes casos, optou-se por apresentar as diversas alternativas (e.g. q2a ,
q2b ). Para correr o programa no SWI-Prolog basta executar os seguintes comandos:
?- [pinheiro]. Yes ?- q2b(X). X = [joao, ana]
(executar as restantes questões q2, q3, q3b, ...)
2 Neste caso, por primo entende-se primo ou prima.
Resolução:
pinheiro.pl
% factos progenitor(maria,joao). progenitor(jose,joao). progenitor(maria,ana). progenitor(jose,ana). progenitor(joao,mario). progenitor(ana,helena). progenitor(ana,joana). progenitor(helena,carlos). progenitor(mario,carlos). sexo(ana,feminino). sexo(maria,feminino). sexo(joana,feminino). sexo(helena,feminino). sexo(mario,masculino). sexo(joao,masculino). sexo(jose,masculino). sexo(carlos,masculino). irma(X,Y):- progenitor(A,X), progenitor(A,Y), X==Y, sexo(X,feminino). irmao(X,Y):- progenitor(A,X), progenitor(A,Y), X==Y, sexo(X,masculino). descendente(X,Y):- progenitor(X,Y). descendente(X,Y):- progenitor(X,A), descendente(A,Y). avo(X,Y):- progenitor(X,A), progenitor(A,Y), sexo(X,masculino). mae(X,Y):- progenitor(X,Y), sexo(X,feminino). pai(X,Y):- progenitor(X,Y), sexo(X,masculino). tio(X,Y):- irmao(X,A), progenitor(A,Y). primo(X,Y):-irmao(A,B), progenitor(A,X), progenitor(B,Y), X==Y. primo(X,Y):-irma(A,B), progenitor(A,X), progenitor(B,Y), X==Y. % questoes: q1:- progenitor(jose,joao).
2.2 Exercício sobre Listas
Enunciado:
Represente em Prolog os seguintes predicados genéricos sobre listas (sem utilizar os
correspondentes predicados do módulo lists do SWI-Prolog):
1) adiciona(X,L1,L2) – onde L2 é a lista que contém o elemento X e a lista L1.
Testar este predicado no interpretador Prolog, executando:
?- adiciona(1,[2,3],L).
?- adiciona(X,[2,3],[1,2,3]).
2) apaga(X,L1,L2) – onde L2 é a lista L1 sem o elemento X. Testar com:
?- apaga(a,[a,b,a,c],L).
?- apaga(a,L,[b,c]).
3) membro(X,L) – que é verdadeiro se X pertencer à lista L. Testar com:
?- membro(b,[a,b,c]).
?- membro(X,[a,b,c]). % carregar em ;
?- findall(X,membro(X,[a,b,c]),L).
4) concatena(L1,L2,L3) – onde L3 é resultado da junção das listas L2 e L1.
Testar com:
?- concatena([1,2],[3,4],L).
?- concatena([1,2],L,[1,2,3,4]).
?- concatena(L,[3,4],[1,2,3,4]).
5) comprimento(X,L) – onde X é o número de elementos da lista L. Testar com:
?- comprimento(X,[a,b,c]).
6) maximo(X,L) – onde X é o valor máximo da lista L (assumir que L contém
somente números). Testar com:
?- maximo(X,[3,2,1,7,4]).
7) media(X,L) – onde X é o valor médio da lista L (assumir que L contém
somente números). Testar com:
?- media(X,[1,2,3,4,5]).
8) nelem(N,L,X) – onde N é um número e X é o elemento da lista L na posição
L. Por exemplo (testar com):
?- nelem(2,[1,2,3],2).
?- nelem(3,[1,2,3],X).
?- nelem(4,[a,b,c,d,e,f,g],X).
Explicação:
Este exercício serve para praticar a manipulação de listas , sendo uma adaptação livre
do código apresentado no Capítulo 3 do livro [Brakto, 1990]. A maior parte destes
predicados já se encontra definido no SWI-Prolog em inglês no módulo lists. Por
exemplo: membro - member , adiciona - append , apaga - delete , máximo - max_list ,
nelem - nth1 (ver mais predicados em [Wielemaker, 2008b] ). De notar que a maioria
dos predicados utilizam o mecanismo de recursividade, por forma a se poder navegar
ao longo de uma lista. Para correr o programa no SWI-Prolog basta executar os
seguintes comandos:
?- [listas]. Yes ?- q1a(L). L = [1, 2, 3]
(executar as restantes questões q1b, q2a, q2b, ...)
Resolução:
listas.pl
adiciona(X,L,[X|L]). % 2 apaga(X,[X|R],R). apaga(X,[Y|R1],[Y|R2]):- apaga(X,R1,R2). % 3 membro( X, [X|] ). membro( X, [|R] ) :- membro( X, R ). % 4 concatena([],L,L). concatena([X|L1],L2,[X|L3]):- concatena(L1,L2,L3). % 5 comprimento(0,[]). comprimento(N,[|R]):- comprimento(N1,R), N is 1 + N1. % 6 max(X,[X]). max(X,[Y|R]):- max(X,R), X > Y, !. max(Y,[Y|]). % 7 somatorio(0,[]). somatorio(X,[Y|R]):- somatorio(S,R), X is S+Y. media(X,L):- comprimento(N,L), somatorio(S,L), X is S/N. nelem(N,L,X):-nelem(N,1,L,X). nelem(N,N,[X|],X):-!. nelem(N,I,[|R],X):- I1 is I+1, nelem(N,I1,R,X). % testar os predicados: q1a(L):-adiciona(1,[2,3],L). q1b(X):-adiciona(X,[2,3],[1,2,3]).
2.3 Stands de Automóveis
Enunciado:
Considere a seguinte BD sobre clientes de stands de automóveis:
Stand Nome Nº
Cliente
Idade Profissão Compras
Vegas Rui 2324 23 Médico Carro Audi A2 por 20000 euros
Carro BMW Serie3 por 30000 euros
Vegas Rita 2325 32 Advogado Carro Audi A3 por 30000 euros
Vegas João 2326 26 Professor Moto Honda GL1800 por 26000 eur.
Vegas Ana 2327 49 Médico Carro Audi A4 por 40000 euros
Carro BMW Serie3 por 32000 euros
Carro Ford Focus por 24000 euros
Miami Rui 3333 33 Operário Carro Fiat Panda por 12000 euros
Miami Paulo 3334 22 Advogado Carro Audi A4 por 36000 euros
Miami Pedro 3335 46 Advogado Carro Honda Accord por 32000 eur.
Carro Audi A2 por 20000 euros
1) Registe em Prolog todos os dados relevantes da BD, utilizando factos com a
notação: stand(nome_stand, LC ).
onde LC é uma lista de clientes do tipo:
[cliente(nome,num,id,prof, C1 ),cliente(nome2,num2,id2,prof2, C2 )
,…]
onde C1 , C2 são listas de compras do tipo:
[carro(marca1,modelo1,preco1), moto(marca2,modelo2,preco2),…]
2) Defina em Prolog os seguintes predicados:
1) listar_clientes(X,LC) – devolve a lista LC com o nome de todos clientes do
stand X;
2) listar_dados(X,C,D) – devolve a lista D com todos dados (i.e.: numero, idade
e profissão) do cliente com o nome C do stand X;
3) listar_carros(X,LM) – devolve a lista LM com o nome de todas as marcas de
carros vendidos pelo stand X.
4) listar_advogados(LA) :- devolve a lista LA com o nome de todos os
advogados de todos os stands;
5) preco_medio(X,Med) - devolve o preço médio (Med) de todos os carros
vendidos por um stand. Nota: pode re-utilizar o predicado media(X,L) do
exercício anterior;
6) altera_id(X,C,Id) – altera a idade do cliente C do stand X para Id. Nota: deve
usar os predicados do Prolog assert e retract.
Utilize os seguintes predicados SWI-Prolog:
flatten(L1,L2) – remove todos os [] extra de L1, devolvendo o resultado em L2;
list_to_set_(L1,L2) – remove elementos repetidos de L1, devolvendo L2;
Por exemplo, flatten([[1],[2,3]],[1,2,3]) e list_to_set([1,2,2,3],[1,2,3]) dão verdade.
Explicação:
Pretende-se aqui praticar a representação de bases de dados em Prolog. Neste caso, o
enunciado já explicita qual o formato da representação. A resolução é conseguida à
custa dos (poderosos) predicados findall e member. O facto stand tem de ser
definido como dinâmico, uma vez que é manipulado via predicados assert e retract.
Para correr o programa no SWI-Prolog basta executar os seguintes comandos:
?- [stand]. Yes ?- teste. mudar idade da ana de:[ (2327, 49, medico)] para: [ (2327, 50, medico)]
Resolução:
stand.pl
:- dynamic(stand/2). % 1: representacao da base de dados stand(vegas,[ cliente(rui,2324,23,medico,[ carro(audi,a2,20000), carro(bmw,serie3,30000)]), cliente(rita,2325,32,advogado,[carro(audi,a3,30000)]), cliente(joao,2326,26,professor,[moto(honda,gl1800,26000)]), cliente(ana,2327,49,medico,[ carro(audi,a4,40000), carro(bmw,serie3,32000), carro(ford,focus,24000)]) ]). stand(miami,[ cliente(rui,3333,33,operario,[carro(fiat,panda,12000)]), cliente(paulo,3334,22,advogado,[carro(audi,a4,36000)]), cliente(pedro,3335,46,advogado,[carro(honda,accord,32000), carro(audi,a2,20000)]) ]). % 2.1: devolve a lista com o nome de todos os clientes de um stand listar_clientes(X,LC):- stand(X,L), findall(C,member(cliente(C,,,,),L),LC). % 2.2: devolve os dados de cliente (todos excepto o nome): listar_dados(X,C,D):- stand(X,L), findall((N,ID,P),member(cliente(C,N,ID,P,),L),D). % 2.3: listar_carros(X,LM):- stand(X,L), findall(C,member(cliente(,,,,C),L),LC), flatten(LC,LCC), findall(M,member(carro(M,,),LCC),LM1), list_to_set(LM1,LM).
3 Regras de Produção 3.1 Gemas Preciosas (regras de produção simples)
Enunciado:
Existem diversos tipos de gemas preciosas. Para simplificar, somente serão
classificadas um conjunto reduzido de gemas, segundo as regras:
O berilo é caracterizado pelo facto de ser duro e também por ser um mineral;
O berilo é uma pedra preciosa, sendo que uma qualquer outra gema que
contenha óxido de alumínio também é uma preciosa;
Uma esmeralda é uma gema preciosa com um tom verde;
Se uma gema for preciosa e tiver cor avermelhada, então é do tipo rubi;
Simplificando, podemos admitir que uma safira é uma gema que é preciosa
cuja tonalidade não é verde nem avermelhada.
1. Represente este conhecimento através de regras de produção em Prolog.
2. Admita o seguinte cenário: tem um mineral que contém óxido de alumínio,
cuja cor não é verde nem vermelha. Represente esta informação via factos.
3. Utilize os sistemas de inferência de backward (sem e com explicação) e
forward chaining , para classificar este mineral.
Explicação:
Pretende-se praticar o uso simples de regras de produção e sistemas de inferência de
backward (backward.pl, proof.pl) e forward (forward.pl) chaining leccionados na
unidade curricular. É utilizada a negação simples
3
do SWI-Prolog (operador + ). Mais
detalhes são apresentados nos comentários do código. Para correr o programa no
SWI-Prolog basta executar os seguintes comandos:
?- [gemas]. ?- backward. ?- proof(P). P = (safira<=oxido_aluminio and nao_verde_vermelho) ?- forward. Derived: precioso Derived: safira No more facts
3 +P é verdadeiro se não for possível provar P, caso contrario é falso.
demo:- new_derived_fact( P),!,% A new fact write( 'Derived: '), write( P), nl, assert( fact( P)), demo. % Continue demo:- write( 'No more facts'). % All facts derived new_derived_fact( Concl) :- if Cond then Concl, % A rule + fact( Concl), % Rule's conclusion not yet a fact composed_fact( Cond). % Condition true? composed_fact( Cond) :- fact( Cond). % Simple fact composed_fact( Cond1 and Cond2) :- composed_fact( Cond1), composed_fact( Cond2). % Both conditions true composed_fact( Cond1 or Cond2):- composed_fact( Cond1); composed_fact( Cond2).
proof.pl
% demo( P, Proof) Proof is a proof that P is true :- op( 800, xfx, <=). demo( P, P) :- fact( P). demo( P, P <= CondProof) :- if Cond then P, demo( Cond, CondProof). demo( P1 and P2, Proof1 and Proof2) :- demo( P1, Proof1), demo( P2, Proof2). demo( P1 or P2, Proof) :- demo( P1, Proof); demo( P2, Proof). 3.2 Compras numa Livraria (regras de produção com incerteza)
Enunciado:
Com o propósito de construir um SBC que classifique qual tipo de livro que irá ser
comprado numa Livraria, realizou-se um inquérito sobre consumidores de livros, do
qual se tiraram as seguintes conclusões:
Com uma certeza de 75% vende-se um livro tecnológico , desde que o
consumidor tenha um computador portátil e seja do sexo masculino;
As mulheres sem filhos compraram livros românticos em 100% dos casos;
Durante o período de natal, qualquer livro do tipo policial com o título
“código” ou “vinci” vende-se com 80% de probabilidade;
Os livros de poemas eram adquiridos com uma probabilidade de 20%, desde
que fosse a época natalícia ou o comprador fosse uma mulher.
Os livros românticos ou de poemas podem ser considerados literários em 90%
dos casos.
a) Represente em Prolog a base de conhecimento utilizando o regras de
produção com incerteza.
b) Considere a situação actual: “ Estamos na época natalícia e alguém, que tem
um computador portátil e não tem filhos, entrou na Livraria ”.
Represente em Prolog esta situação.
c) Indique como poderia saber qual é a probabilidade do consumidor da alínea b)
comprar um livro literário?
Explicação:
Pretende-se praticar a representação de regras de produção com incerteza e respectivo
sistema de inferência (certainty.pl) leccionado na unidade curricular. Como não se
sabe qual o sexo actual da pessoa, assume-se o mais provável, ou seja, 50% de
probabilidade para cada tipo de sexo. Mais detalhes são apresentados nos comentários
do código. Para correr o programa no SWI-Prolog basta executar os seguintes
comandos:
?- [livraria]. ?- democ(literario,C). % alínea c) C = 0.
Resolução:
livraria.pl
% Executado automaticamente quando o Prolog executa este ficheiro: :-dynamic(fact/1), % definir fact como dinamico [certainty]. % carregar todos sistemas de inferência % Base de Conhecimento, alínea a) if portatil and homem then tecnologico:0.75. if mulher and sem_filhos then romantico:1.0. if natal and codigo or vinci then policial:0.8. if natal or mulher then poemas:0.20. if romantico or poemas then literario:0.9. % Base de Dados (os factos actuais), alínea b) fact(natal:1). fact(mulher:0.5). fact(homem:0.5). fact(portatil:1.0). fact(sem_filhos:1.0).
certainty.pl