Agradeço comentários, sugestões ou correcções. O meu endereço de correio electrónico é < delfim@mat.ua.pt > . Desde já obrigado.
Os Sistemas Periciais (SP) são um dos primeiros sucessos comerciais da Inteligência Artificial. O seu uso na indústria, educação, ciência, medicina, ... tem aumentado durante os últimos anos.
Os SP são sistemas baseados em conhecimento, conhecimento esse a maior parte das vezes não procedimental, essencialmente declarativo. Isto faz com que o Prolog seja um candidato à construção de tais sistemas.
Várias áreas de trabalho, e investigação, encontram-se associadas ao desenvolvimento de SP. Algumas delas são:
Os SP diferem dos programas de computador convencionais, em vários aspectos importantes. Alguns deles são:
Outro SP pioneiro foi o PROSPECTOR, um sistema que assistia os geólogos na descoberta de depósitos minerais.
Desde a introdução destes SP pioneiros, a vastidão de aplicações aumentou dramaticamente. Os métodos e as teorias de suporte aos sistemas modernos são também mais complexas, integrando vários paradigmas. Assim, para além dos métodos lógicos tradicionais, encontramos abordagens conexionistas (e.g., redes neuronais) e paradigmas evolucionários (e.g., paradigmas genéticos).
Aplicações podem hoje ser encontradas em quase todas as áreas do conhecimento. Para uma lista e breve descrição de aproximadamente 200 SP veja-se []
Iremos aqui dar apenas ``um cheirinho'' das potencialidades e características de um SP.
Podemos dizer que a arquitectura mais comum usada na construção de SP, aliás como em outros tipos de sistemas baseados em conhecimento, são os sistemas baseados em regras. Estes sistemas usam o conhecimento codificado sobre a forma de regras de produção:
Se Cond1 e Cond2 e ... e CondN Entao Conclusao.
Cada regra representa um pedacinho de conhecimento, relacionado com o domínio de peritagem escolhido. Em Prolog estas regras são escritas naturalmente como cláusulas.
A ``concha'' que iremos desenvolver irá usar este formalismo de representação de conhecimento, e o mecanismo de raciocínio (processo de inferência) lógico já disponibilizado pelo Prolog.
Tal como foi dito,
Sistema Pericial = Conhecimento + Inferência
e existe uma separação explícita entre as duas componentes.
Não entraremos aqui nas questões associadas à aquisição, verificação e validação de conhecimento, nem no estudo (e implementação) de mecanismos de aprendizagem.
Quanto ao tratamento de conhecimento incerto, iremos apenas dar (veja-se a secção ) uma pequena introdução a uma das muitas abordagens existentes: o uso de conjuntos difusos.
A Base de Conhecimento contém conhecimento específico de um determinado domínio (factos, regras, métodos, heurísticas, ...) e a indicação dos predicados questionáveis que fazem com que certos dados sobre o problema sejam solicitados ao utilizador quando necessário, de modo atingir o objectivo.
Segue-se um exemplo, em que o domínio de peritagem é a classificação de aves da América do Norte.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Base de Conhecimento (BC) 'aves.pl' %% que conjuntamente com 'perito.pl' %% forma o 'Sistema Pericial aves' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Para uma BC funcionar com o 'perito.pl' % deve possuir: % % - conhecimento; % - identificacao dos atributos questionaveis % (recorrendo aos predicados 'questiona'); % - identificacao da especialidade da BC % (recorrendo ao predicado 'objectivo/1'). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Conhecimento. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ave(albatrozLaysan) :- familia(albatroz), cor(branca). ave(albatrozPePreto) :- familia(albatroz), cor(cinzenta). ave(cisneSibilante) :- familia(cisne), voz(silvoMusicalAbafado). ave(cisneCorneteiro) :- familia(cisne), voz(corneteiroEspalhafatoso). ave(gansoCanadiano) :- familia(ganso), estacao(inverno), pais(estadosUnidos), cabeca(preta), face(branca). ave(gansoCanadiano) :- familia(ganso), estacao(verao), pais(canada), cabeca(preta), face(branca). ave(patoBravo) :- familia(pato), voz(grasno), cabeca(verde). ave(patoBravo) :- familia(pato), voz(grasno), cabeca(manchasCastanhas). ordem(bicoTubular) :- narinas(tubularExterna), vive(mar), bico(curvo). ordem(aquatico) :- patas(membranaInterdigital), bico(espalmado). familia(albatroz) :- ordem(bicoTubular), dimensao(grande), asas(longaEstreita). familia(cisne) :- ordem(bicoTubular), pescoco(comprido), cor(branca), voo(lento). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% E' necessario, para funcionar com o %% 'perito.pl', que especifiquemos quais %% os atributos questionaveis, i.e., quais %% os factos primitivos. %% %% Para cada caso, usar um dos predicados: %% questiona/2 %% questiona/3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% cor(X) :- questiona(cor,X). voz(X) :- questiona(voz,X,[silvoMusicalAbafado,corneteiroEspalhafatoso,grasno]). estacao(X) :- questiona(estacao,X,[inverno,primavera,verao,outono]). pais(X) :- questiona(pais,X). cabeca(X) :- questiona(cabeca,X). face(X) :- questiona(face,X). narinas(X) :- questiona(narinas,X). vive(X) :- questiona(vive,X). bico(X) :- questiona(bico,X). patas(X) :- questiona(patas,X). dimensao(X) :- questiona(dimensao,X,[grande,pequena,media]). asas(X) :- questiona(asas,X). pescoco(X) :- questiona(pescoco,X). voo(X) :- questiona(voo,X). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Identifica a 'especialidade' desta Base %% de Conhecimento: identificar aves. %% %% Para isso devemos usar o predicado %% 'objectivo/1' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% objectivo(X) :- ave(X).
A concha a desenvolver é formada por um interface (perito/0) que controla a comunicação entre o SP e o utilizador; por uma memória de trabalho que evita, por memorização das respostas (conhece/3), que haja perguntas repetidas; e por um motor de inferência (soluciona/0).
A concha permite recorrer a várias BCs (uma de cada vez que
consultamos o perito.pl, para evitar conflitos entre
cláusulas de BCs diferentes) permitindo assim termos vários
SPs para diferentes domínios de peritagem. A concha irá
resolver o problema definido pelo predicado objectivo/1
incluído na BC em questão.
Exemplo de uma sessão com o perito.pl:
?- consult(perito). Yes ?- perito. Concha simples de Sistema Pericial Versao de 27/Maio/1999 Comandos disponiveis (introduza o numero `1.`, `2.` ou `3.`): 1 - Consultar uma Base de Conhecimento (BC) 2 - Solucionar 3 - Sair > 1. Nome da BC: aves. BC consultada com sucesso. Comandos disponiveis (introduza o numero 2 ou 3): 2 - Solucionar 3 - Sair > 2. narinas:tubularExterna? (sim/nao) sim. vive:mar? (sim/nao) sim. bico:curvo? (sim/nao) sim. Qual o valor para dimensao? [grande, pequena, media] |: grande. asas:longaEstreita? (sim/nao) sim. cor:branca? (sim/nao) nao. cor:cinzenta? (sim/nao) sim. Resposta encontrada: albatrozPePreto Comandos disponiveis (introduza o numero 2 ou 3): 2 - Solucionar 3 - Sair > 3. Volte Sempre! Qualquer tecla para sair.
perito.pl:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% perito.pl %% %% Expert System Shell: %% Permite carregar a base de conhecimento desejada. %% %% 27/Maio/1999 %% Delfim F. Marado Torres %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Predicado principal: perito/0 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% perito :- write('Concha simples de Sistema Pericial'), nl, write('Versao de 27/Maio/1999'), nl, nl, esperaOrdens(123). esperaOrdens(MC) :- mostraComandos(MC), write('> '), read(Comando), executa(MC,Comando). mostraComandos(123) :- write('Comandos disponiveis (introduza o numero `1.`, `2.` ou `3.`):'), nl, write('1 - Consultar uma Base de Conhecimento (BC)'), nl, write('2 - Solucionar'), nl, write('3 - Sair'), nl. mostraComandos(23) :- write('Comandos disponiveis (introduza o numero 2 ou 3):'), nl, write('2 - Solucionar'), nl, write('3 - Sair'), nl. executa(_,1) :- write('Nome da BC: '), read(F), consult(F), write('BC consultada com sucesso.'), nl, nl, continua. executa(_,2) :- soluciona, esperaOrdens(23). executa(_,3) :- nl, write('Volte Sempre!'), nl, write('Qualquer tecla para sair.'), get0(_), halt. executa(MC,X) :- write(X), write(' nao e um comando valido!'), nl, esperaOrdens(MC). continua :- retract( executa(_,1) :- _ ), % Ja carrega'mos uma BC. esperaOrdens(23). % De futuro ja nao temos essa opcao. %%%%%%%%%%%%%%% % soluciona/0 %%%%%%%%%%%%%%% soluciona :- abolish(conhece,3), asserta(conhece(def,def,def)), % apenas para o predicado objectivo(X), % conhece/3 estar definido... nl, nl, write('Resposta encontrada: '), write(X), nl, nl. soluciona :- nl, nl, write('Nao foi encontrada resposta :-('), nl. %%%%%%%%%%%%%%% % questiona/2 %%%%%%%%%%%%%%% questiona(Atributo,Valor) :- conhece(sim,Atributo,Valor). questiona(Atributo,Valor) :- conhece(_,Atributo,Valor), !, fail. questiona(Atributo,Valor) :- write(Atributo:Valor), write('? (sim/nao) '), read(R), processa(R,Atributo,Valor). processa(sim,Atributo,Valor) :- asserta(conhece(sim,Atributo,Valor)). processa(R,Atributo,Valor) :- asserta(conhece(R,Atributo,Valor)),!, fail. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % questiona/3 % % Recurso a Menus: % sao apresentados ao utilizador os valores % que cada atributo pode assumir. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% questiona(Atr,Val,_) :- conhece(sim,Atr,Val). questiona(Atr,_,_) :- conhece(sim,Atr,_), !, fail. questiona(Atr,Val,ListaOpcoes) :- write('Qual o valor para '), write(Atr), write('? '), nl, write(ListaOpcoes), nl, read(X), processa(X,Atr,Val,ListaOpcoes). processa(Val,Atr,Val,_) :- asserta(conhece(sim,Atr,Val)). processa(X,Atr,_,ListaOpcoes) :- member(X,ListaOpcoes), asserta(conhece(sim,Atr,X)), !, fail. processa(X,Atr,Val,ListaOpcoes) :- write(X), write(' nao e valor aceite!'), nl, questiona(Atr,Val,ListaOpcoes).
O conhecimento dos peritos, e os seus processos de raciocínio, nem sempre podem ser modelados usando a lógica booleana e as suas técnicas de inferência: muitas vezes o conhecimento é incerto. A incerteza pode-se manifestar de diversas formas:
Se o investidor é de meia idade e tem um salário baixo Então o investidor encaixa no perfil de um investidor de baixo risco.
O perito pode não confiar em absoluto nesta regra (usualmente os investidores com estas características são investidores de baixo risco, mas nem sempre...). Um factor de confiança de 90% pode ser associada à regra que pode ser interpretada como significando que se o investidor satisfaz as condições da regra então ele é classificado como ``investidor de baixo risco'' com uma certeza de 90%. Mas também pode haver incerteza em saber quando as condições da regra são satisfeitas ou não. Podemos só estar 80% certos que o ordenado do investidor é baixo. Nesse caso, qual a certeza de o perfil do investidor ser um perfil de baixo risco? Deve ser menor do que 90%, mas como combinamos as incertezas? Outro factor que contribui para a incerteza é que os termos ``meia idade'' ou ``salário baixo'' são inerentemente difusos e vagos. Como tratar estes termos linguísticos imprecisos? Se fixarmos um intervalo para definir o termo ``meia idade'', por exemplo [45, 55], então o que dizer de uma pessoa que tem 44 anos, 11 meses e alguns dias? A regra não será aplicada a este investidor. O predicado idade tem um intervalo de difinição contínuo e discretizar este intervalo em subintervalos, correspondentes aos conceitos de novo, meia idade, etc., introduz o problema de lidar com os pontos fronteiros.
Introdução
A lógica difusa (Fuzzy logic) é uma tentativa de lidar com conhecimento vago. A teoria dos conjuntos vagos (ou conjuntos difusos) foi desenvolvida nos anos 60 e generaliza as lógicas de n-valores. Numa lógica de n-valores, o conjunto de valores verdade foi estendido do 0 ou 1 (verdadeiro ou falso) para valores no conjunto de verdade
|
Os peritos incorporam muitas vezes, nos seus processos de raciocínio, conceitos qualitativos tais como alto, baixo, calor, etc. e quantificadores como muito, pouco, normalmente, algumas vezes, etc. A imprecisão inerente nestes termos, é naturalmente implementada com a lógica difusa. O raciocínio é depois feito usando inferência difusa. Algumas das aplicações da lógica difusa são:
Na teoria dos conjuntos tradicional, um conjunto A pode ser definido em termos de uma função
|
Um conjunto difuso A é definido por uma função
|
Como exemplo, considere-se o conceito alto no universo
de todos os estudantes, docentes e funcionários, da Universidade de
Aveiro. Na lógica booleana, uma pessoa ou é alta ou
não. Assim sendo, teríamos de escolher um limiar. Todos os
elementos (pessoas) do universo (conjunto U) cuja altura fosse maior
que esse limiar seriam classificadas como altas e aquelas com altura
inferior ao limiar de não altas. Em contraste, na teoria
dos conjuntos vagos um valor de pertença é associado a cada
altura, indicando a quantidade de confiança em ser alto. A uma
altura de 1m e 90cm podemos associar o valor 1.0 (pessoa sem
dúvida alta no universo da Univ. de Aveiro); enquanto a uma
altura de 1m e 80cm podemos associar um valor de pertença
malto(1.80) = 0.90 e a 1m e 55cm malto(1.55) = 0.02.
A construção apropriada da função de pertença
m, é uma das principais dificuldades no uso da lógica
e inferência difusa. Os métodos, que até agora foram
propostos, são experimentais e ad hoc.
O suporte de um conjunto vago A, sup(A), é definido como o conjunto de elementos do universo cujo grau de pertença é estritamente positivo: sup(A) = { u Î U : mA(u) > 0}.
Um conjunto vago A de suporte finito, pode ser denotado por
|
Termos linguísticos
Os graus de certeza de uma frase são representados por termos linguísticos como possível, muito possível, etc. Por exemplo, podemos dizer que: ``É muito provável que o Sr. António seja rico''. Aqui rico é um conjunto vago (por exemplo definido pelo rendimento anual bruto da pessoa) e muito provável um termo linguístico que associa um valor de verdade à afirmação de que o Sr. António é rico.
Quando a pertença de um elemento num conjunto vago é expressa por tais termos linguísticos, temos de definir as funções de pertença para esses quantificadores, de modo a exprimir o seu significado. Por exemplo, se A é um conjunto vago podemos definir a função de pertença dos quantificadores muito, mais ou menos e não como se segue:
|
Operações com conjuntos vagos
Existem, na literatura especializada, muitas definições alternativas para as operações de união, intersecção, ... de conjuntos difusos. As mais usadas são as seguintes:
|
Lógica difusa em Prolog
De seguida segue-se uma possível implementação da lógica difusa em Prolog. Testamos o programa num problema de Tomada de Decisão. O objectivo é construir um ``sistema pericial'' para apoio a hotéis. Concretamente pretendemos ajudar na decisão: ``ligo ou não ligo o aquecedor?''
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Implementacao de Logica Difusa em Prolog. % Delfim F. Marado Torres, 8/Junho/1999 % % Exemplificacao: % % ?- ligaAquecedor(C). % % devolve em C um valor entre 0 e 1. % Os conselhos peremptorios sao: % C = 1 <=> aquecedor deve estar ligado; % C = 0 <=> aquecedor deve estar desligado. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Um conjunto difuso e' representado pelo facto % % conjuntoDifuso(NomeConjunto,[ [X1,Y1], ..., [Xn,Yn] ]). % % O segundo argumento e' uma lista de listas [Xi,Yi] % onde Xi e' um elemento do universo e Yi o respectivo % grau de pertenca: mu(Xi) = Yi. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% conjuntoDifuso(temperaturasAltas,[[0,0.0],[5,0.2],[10,0.4],[20,0.8]]). conjuntoDifuso(pertoDe(0), [[0,1.0],[5,0.8],[10,0.5],[20,0.0]]). conjuntoDifuso(pertoDe(5), [[0,0.8],[5,1.0],[10,0.6],[20,0.2]]). conjuntoDifuso(pertoDe(10),[[0,0.5],[5,0.6],[10,1.0],[20,0.9]]). conjuntoDifuso(pertoDe(20),[[0,0.0],[5,0.2],[10,0.9],[20,1.0]]). %%%%%%%%%%%%%%%%%%%%%%%%% % 'Funcao de pertenca' %%%%%%%%%%%%%%%%%%%%%%%%% pertence(X,C,GP) :- conjuntoDifuso(C,L), pertence([X,GP],L). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Quantificadores vagos, tal como o 'muito', sao % definidos por regras do seguinte tipo: % Se [X,P] esta' na lista do conjunto A % Entao [X,P^2] esta' na lista muito(A) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% conjuntoDifuso(muito(A),LMA) :- conjuntoDifuso(A,LA), mu_muito(LA,LMA). mu_muito([],[]). mu_muito([[X,Y]|R],[[X,Y2]|RM]) :- Y2 is Y * Y, mu_muito(R,RM). conjuntoDifuso(mais_ou_menos(A),LMMA) :- conjuntoDifuso(A,LA), mu_mm(LA,LMMA). mu_mm([],[]). mu_mm([[X,Y]|R],[[X,RY]|RM]) :- RY is sqrt(Y), mu_mm(R,RM). conjuntoDifuso(nao(A),LNA) :- conjuntoDifuso(A,LA), mu_nao(LA,LNA). mu_nao([],[]). mu_nao([[X,Y]|R],[[X,CY]|RM]) :- CY is 1 - Y, mu_nao(R,RM). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Operacoes sobre conjuntos vagos %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% conjuntoDifuso(e([A]),LA) :- conjuntoDifuso(A,LA). conjuntoDifuso(e([A,B]),LAB) :- conjuntoDifuso(A,LA), conjuntoDifuso(B,LB), mu_e(LA,LB,LAB). conjuntoDifuso(e([A|R]),L) :- conjuntoDifuso(e([A,e(R)]),L). mu_e([],_,[]). mu_e([[X,Y1]|R],L2,[[X,Y]|RE]) :- pertence([X,Y2],L2), min(Y1,Y2,Y), mu_e(R,L2,RE). mu_e([_|R],L2,RE) :- mu_e(R,L2,RE). conjuntoDifuso(ou([A]),LA) :- conjuntoDifuso(A,LA). conjuntoDifuso(ou([A,B]),LAB) :- conjuntoDifuso(A,LA), conjuntoDifuso(B,LB), mu_ou(LA,LB,LAB). conjuntoDifuso(ou([A|R]),L) :- conjuntoDifuso(ou([A,ou(R)]),L). mu_ou([],L,L). mu_ou([[X,Y1]|R],L2,[[X,Y]|RE]) :- pertence([X,Y2],L2), max(Y1,Y2,Y), tira([X,Y2],L2,NL2), mu_ou(R,NL2,RE). mu_ou([[X,Y1]|R],L2,[[X,Y1]|RE]) :- mu_ou(R,L2,RE). conjuntoDifuso(implica(Ant,Cons),L) :- conjuntoDifuso(ou([nao(Ant),Cons]),L). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Regra difusa (vaga): % % Se % a Temperatura Exterior nao e' alta e % a Temperatura Interior esta' proxima % da Exterior % Entao % o Aquecedor deve estar ligado. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% aquecedorLigado(GP) :- temperaturaExterior(TE), temperaturaInterior(TI), pertence(TE,e([nao(temperaturasAltas),pertoDe(TI)]),GP), !. %%%%%%%%%%%%%%%%% % Interface %%%%%%%%%%%%%%%%% temperaturaExterior(TE) :- temperatura(exterior,TE). temperaturaInterior(TI) :- temperatura(interior,TI). temperatura(M,T) :- repeat, nl, write('Valor aproximado (0, 5, 10 ou 20) da temperatura '), write(M), write(' = '), read(T), pertence(T,[0,5,10,20]), nl. %%%%%%%%%%%%%%%%%%%%%%%%%%%% % Predicados Auxiliares %%%%%%%%%%%%%%%%%%%%%%%%%%%% pertence(X,[X|_]). pertence(X,[_|R]) :- pertence(X,R). tira(X,[X|R],R). tira(X,[Y|R],[Y|T]) :- tira(X,R,T). min(X,Y,X) :- X =< Y. min(_,Y,Y). max(X,Y,X) :- X >= Y. max(_,Y,Y).
Pense numa maneira, e implemente-a, de alterar o perito.pl de modo a permitir dar resposta a perguntas do utilizador do tipo ``Porque é que quer saber isto?''; ``Como é que chegou a esta conclusão?''.
Altere o perito.pl de modo a permitir lidar com conhecimento incerto, por meio da abordagem difusa atrás considerada.