Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


Prolog Tutorial atualizado, Esquemas de Lógica Matemática

Aprenda a utilizar essa ferramenta que pode lhe ajudar em varios campos da diferentes.

Tipologia: Esquemas

2020

Compartilhado em 21/05/2020

backup-backup99
backup-backup99 🇧🇷

1 documento

1 / 54

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
L´
ogica Computacional
PROLOG
Maria Jo˜
ao Frade
Departamento de Inform´atica
Universidade do Minho
2006
2oAno LMCC (2005/06)
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36

Pré-visualização parcial do texto

Baixe Prolog Tutorial atualizado e outras Esquemas em PDF para Lógica Matemática, somente na Docsity!

L´ogica Computacional

PROLOG

Maria Jo˜ao Frade Departamento de Inform´atica Universidade do Minho 2006

2 o^ Ano LMCC (2005/06)

3

PRPROOLLOOGG Uma^ linguagem^ de^ PROgramação^ em^ LÓGica.

O Prolog é uma linguagem de declarativa que usa um fragmento da lógica de 1 ª ordem (as Cláusulas de Horn ) para representar o conhecimento sobre um dado problema.

Um programa em Prolog é um “conjunto” de axiomas e de regras de inferência (definindo relações entre objectos) que descrevem um dado problema. A este conjunto chama-se normalmente base de conhecimento.

A execução de um programa em Prolog consiste na dedução de consequências lógicas da base de conhecimento.

O utilizador coloca questões e o “motor de inferência” do Prolog pesquisa a base de conhecimento à procura de axiomas e regras que permitam (por dedução lógica) dar uma resposta. O motor de inferência faz a dedução aplicando o algoritmo de resolução de 1 ª ordem.

A linguagem Prolog surgiu no início da década de 70.

Factos

mae(sofia,joao). mae(ana,maria). mae(carla,sofia).

pai(paulo,luis). pai(paulo,sofia). pai(luis,pedro). pai(luis,maria).

progenitor(A,B) :- pai(A,B). progenitor(A,B) :- mae(A,B).

avo(X,Y) :- progenitor(X,Z) , progenitor(Z,Y).

Exemplo de um programa Prolog (um conjunto de Cláusulas de Horn ).

Regras

∀X ∀Y. avo(X,Y) ⇐ ∃Z. progenitor(X,Z) ∧ progenitor(Z,Y!

∀A ∀B. progenitor(A,B) ⇐ pai(A,B)

∀A ∀B. progenitor(A,B) ⇐ mae(A,B)

Variáveis (lógicas)

Átomos

5

Cláusulas de Horn são fórmulas da forma p^ ⇐^ q^1 ∧^ q^2 ∧^ ...^ ∧^ qn

representadas em Prolog por p :- q1, q2, ..., qn

<cabeça da cláusula> :- <corpo da cláusula>

Os factos são cláusulas de Horn com o corpo vazio.

As variáveis que aparecem nas cláusulas são quantificadas universalmente e o seu âmbito é toda a cláusula, mas podemos ver as variáveis que ocorrem apenas no corpo da cláusula (mas não na cabeça), como sendo quantificadas existencialmente dentro do corpo da cláusula.

Notas:

As questões são cláusulas de Horn com cabeça vazia.

As questões são um meio de extrair informação de um programa. As variáveis que ocorrem nas questões são quantificadas existencialmente.

Exemplos de questões à base de conhecimento.

| ?- avo(paulo,X). X = pedro? ; X = maria? ; X = joao? ; no

| ?- pai(X,maria), pai(X,pedro). X = luis? yes

| ?- avo(paulo,X). X = pedro? yes

| ?- avo(ana,joao). no

| ?- progenitor(luis,maria). yes

| ?- progenitor(X,Y). X = paulo, Y = luis? ; X = paulo, Y = sofia? ; X = luis, Y = pedro? ; X = luis, Y = maria? ; X = sofia, Y = joao? ; X = ana, Y = maria? ; X = carla, Y = sofia? ; no

9

TTeerrmmooss O termos são as entidades sintácticas que representam os objectos (do universo de discurso da lógica de 1 ª ordem). Os termos podem ser constantes , variáveis ou termos compostos.

CCoonnssttaanntteess

I Inntteeiirrooss

RReeaaiiss

ÁÁttoommooss

Base 10 5 0 27 - Outras bases (de 2 a 36 ) 2'101 8' Código ASCII 0'A 0'z

2.0 -5.71 47.0E3 -0.9e-

Qualquer sequência de caracteres alfanuméricos começada por letra minúscula

Qualquer sequência de + - * / \ ^ >< = ~ :.? @ # $ &

Qualquer sequência de caracteres entre ' ' ! ; [] {}

( 65 e 122 respectivamente)

VVaarriiáávveeiiss

Qualquer sequência de caracteres alfanuméricos iniciada com letra maiúscula ou _.

X A _ Valores _aa _5 RESP _VAL

variável anónima

Exemplos:

TTeerrmomoss CCoompmpoossttooss

São objectos estruturados da forma f(t1,...,tn) em que

f é o functor do termo e t1, ..., tn são termos (subtermos). O functor f tem aridade n.

Exemplos:

O nome do functor é um átomo.

suc(0) suc(suc(0)) data(15,abril,2006)

Há functores que podem ser declarados como operadores (infixos, prefixos, posfixos).

Exemplo: +(X,Y) X+Y

11

LLiissttaass

Listas são termos gerados à custa do átomo

.( H,T) (o cons)

[] (a lista vazia)

e do functor

Exemplo: O^ termo^ .(1,.(2,.(3,[])))^ representa^ a^ lista^ [1,2,3]

O Prolog tem uma notação especial para listas [ head | tail ]

.(a,.(b,.(c,[]))) = [ a | [b,c] ] = [ a , b | [c] ] = [ a , b , c | [] ] = [ a , b , c ]

Exemplo:

SSttrriinngg Uma string é a lista de códigos ASCII dos seus caracteres.

Exemplo: (^) PROLOG = [80,82,79,76,79,71]

Note que PROLOG é diferente de ' PROLOG '

12

PPrrooggrraammaass

Um programa é um conjunto de cláusulas de Horn. Ou seja, fórmulas da forma

p ⇐ q 1 ∧ q 2 ∧ ... ∧ qn

representadas em Prolog por p :- q1, q2, ..., qn

<cabeça da cláusula> :- <corpo da cláusula>

Factos são cláusula só com cabeça e de corpo vazio. Regras são cláusula com cabeça e corpo não vazio.

% grafo orientado caminho(a,b). caminho(b,c).

/* verifica se existe ligação entre dois nodos dos grafo */ ligacao(X,Y) :- caminho(X,Y). ligacao(X,Y) :- caminho(X,Z), ligacao(Z,Y).

comentários

Exemplo:

Os factos e regras com o mesmo nome (à cabeça) definem um predicado (ou procedimento ). Neste exemplo definimos os predicados caminho/ 2 e ligacao/ 2 (nome/aridade). Note que é possível ter predicados distintos com o mesmo nome mas aridades diferentes.

15

caminho(a,b).

caminho(b,c).

ligacao(X,Y) :- caminho(X,Y).

ligacao(X,Y) :- caminho(X,Z), ligacao(Z,Y).

EsEstrtraattééggiiaa ddee PrProoccuurraa ddee SoSolluuççõõeess

Top Down (de cima para baixo)

Depth-First (profundidade máxima antes de tentar um novo ramo)

Backtracking (volta a tentar encontrar uma prova alternativa)

16

? ligacao(a,K)

? caminho(a,K)

? caminho(c,Z3) , ligação(Z3,K)

? ligacao(b,K)

? ligacao(c,K)

? caminho(b,K)

? caminho(c,K)

? caminho(a,Z 1 ) , ligacao(Z 1 ,K)

? caminho(b,Z 2 ) , ligação(Z 2 ,K)

fail

yes

yes

fail

K = b

K = c

;

;

Backtracking

Backtracking

Backtracking

ÁÁrrvvoorree ddee PPrrooccuurraa

X=c Y=K

X=a Y=K X=a Y=K

X=c Y=K

Z 1 =b

Z 2 =c

X=b Y=K

X=b Y=K

# 3

# 1

# 4

# 2

# 1

# 3

# 3

# 2

# 4

# 4

17

cam(a,b). cam(b,c).

lig(X,Y) :- cam(X,Y).

lig(X,Y) :- lig(Z,Y), cam(X,Z).

OObbsseerrvvaaççããoo::

Se o programa fosse

teriamos uma árvore de procura infinita.

Note que a única diferença entre o ligação e lig é a ordem em que

aparecem os predicados no corpo da 2 ª cláusula.

ligacao(X,Y) :- caminho(X,Z), ligacao(Z,Y).

lig(X,Y) :- lig(Z,Y), cam(X,Z).

? lig(a,K)

? cam(a,K)

? cam(Z 1 ,K), cam(a,Z 1 )^?^ lig(Z^2 ,K),^ cam(Z^1 ,Z^2 ),^ cam(a,Z^1 )

? cam(a,a)

? lig(Z1,K), cam(a,Z1)

? cam(a,b)

fail

yes

yes

K = b

K = c

;

;

Backtracking

Backtracking

Backtracking

ÁÁrrvvoorree ddee PPrrooccuurraa

? cam(Z 2 ,K), cam(Z 1 ,Z 2 ), cam(a,Z 1 )

? cam(Z 1 ,a), cam(a,Z 1 )? cam(Z 1 ,b), cam(a,Z 1 )

? cam(a,a) fail Backtracking

fail Backtracking

Ciclo infinito

21

soma(0,N,N). soma(suc(N),M,suc(Z)) :- soma(N,M,Z).

? soma(suc(suc(0)),suc(0),X)

? soma(suc(0),suc(0),Z1)

? soma(0,suc(0),Z2)

N1=suc(0) M1=suc(0) X=suc(Z1)

N2= 0 M2=suc(0) Z1=suc(Z2)

Z 2 =suc( 0 )

X = suc(suc(suc( 0 )))

yes

= suc(Z 1 ) = suc(suc(Z 2 )) = suc(suc(suc( 0 )))

Uma solução para a soma de números naturais

Exemplo de uma árvore de procura

Resolução:

22

OOppeerraaddoorreess

Para conveniência de notaçao, o Prolog permite declarar functores unários ou binários como operadores prefixos , posfixos ou infixos , associando-lhes ainda uma precedência.

:- op ( precedência , tipo , nome )

A declaração de operadores faz-se através da directiva

Nº de 1 e 1200 infixo yfx xfy xfx

associativo à esquerda associativo à direita não associativo

posfixo yf

xf

prefixo

fy fx

Functor ou lista de functores

Exemplos: :- op(500,yfx,[+,-]) :- op(400,yfx,*)

a-d+bc , (a-d)+(bc) e +(-(a,d),*(b,c)) são termos equivalentes

:- op(300,fy,nao)

nao nao p , nao (nao p) e nao(nao(p)) são termos equivalentes

23

ooppeerraaddoorr ddee uunniiffiiccaaççããoo

O operador infixo = establece uma relação de unificação entre dois termos.

T 1 = T 2 sucede se o termo T 1 unifica com o termo T 2

Dois termo T 1 e T 2 unificam se existir uma substituição θ que aplicada aos termos T 1 e

T 2 os torne literalmente iguais. Isto é, T 1 θ == T 2 θ.

Dois termos compostos unicam se os functores principais dos dois termos forem iguais e com a mesma aridade, e os argumentos respectivos unificam.

Uma variável unifica com qualquer termo (gerando a substituição respectiva).

Dois átomos (ou números) só unificam se forem exactamente iguais.

Exemplo: (^) | ?- data( 23 ,maio, 1998 ) = data( 23 ,maio, 1998 ). yes | ?- data( 23 ,maio, 1998 ) = data( 23 ,maio,Ano). Ano = 1998? yes | ?- data( 23 ,maio, 1998 ) = data( 15 ,maio,Ano). no | ?- data( 23 ,maio, 1998 ) = data(X,maio,X). no

==

| ?- hora( 10 , 30 ) = hora(X,Y). X = 10 , Y = 30? yes | ?- hora(H, 30 ) = hora( 10 ,M). H = 10 , M = 30? yes | ?- hora(H, 30 , 12 ) = hora(X,Y,X). H = 12 , X = 12 , Y = 30? yes | ?- hora(H, 30 , 12 ) = hora(X,X,X). no | ?- X = f(X). X = f(f(f(f(f(f(f(f(f(f(...))))))))))? yes

Exemplo:

O Sicstus Prolog permite unificar uma variável com um termo em que essa variável ocorre, permitindo assim a criação de termos cíclicos. Formalmente isto não é desejável mas o teste de ocorrência não é feito por razões de eficiência.

““OOccccuurrss--CChheecckk””

27

CCoommppaarraaççããoo ddee tteerrmmooss

| ?- X == Y.

no | ?- X4 == X** no

O Sicstus Prolog tem predicados pré-definidos para comparação (sintáctica) de termos (ver User's Manual ).

termo 1 == termo 2

termo 1 == termo 2

Testa se os termos são literalmente iguais.

Testa se os termos não são literalmente iguais.

Exemplos: (^) | ?- X = Y, X == Y. Y = X? yes | ?- X == Y, X = Y. no

@< @> @=< @>=

O Sicstus Prolog establece uma relação de ordem no conjunto de termos (ver o manual). A comparação de termos de acordo com essa ordem pode ser feita com os operadores:

| ?- abcd(1,2) @=< xyz. no

| ?- abcd @< xyz. yes

Exemplos:

| ?- hora(3+5,7-3) = hora(10-2,22).* no | ?- hora(3+5,7-3) == hora(10-2,22).* no | ?- [user]. % consulting user... | :- op(700,xfx,igual). | igual(hora(H1,M1),hora(H2,M2)) :- H1 =:= H2, M1 =:= M2. | % consulted user in module user, 0 msec 504 bytes yes | ?- hora(3+5,7-3) igual hora(10-2,22).* yes | ?-

Permite acrescentar novas regras na base de conhecimento. É um editor muito primitivo (linha a linha). ^D para sair do editor e carregar as novas regras.

[user].

Note que não se está a alterar nenhum ficheiro!

Exemplos:

29

% apaga todas as ocorrências de um dado elemento de uma lista apaga([H|T],H,L) :- apaga(T,H,L). apaga([H|T],X,[H|L]) :- H == X, apaga(T,X,L). apaga([],_,[]).

Defina os seguintes predicados sobre listas:

Exemplos:

% ordenação de uma lista com o algoritmo insertion sort isort([],[]). isort([H|T],L) :- isort(T,T1), ins(H,T1,L).

ins(X,[],[X]). ins(X,[Y|Ys],[Y|Zs]) :- X > Y, ins(X,Ys,Zs). ins(X,[Y|Ys],[X,Y|Ys]) :- X =< Y.

Defina um procedimento que ordene de uma lista segundo o algoritmo quicksort.

somatorio/2 que cálcula o somatório de uma lista.

nesimo/3 que dá o elemento da lista na n-ésima posição

minimo/2 que produz o menor elemento presente numa lista.

Exercícios:

a)

b)

c)

inverte([],[]). inverte([H|T],L) :- inverte(T,T1), concatena(T1,[H],L).

inv(Xs,Ys) :- inv(Xs,[],Ys).

inv([X|Xs],Ac,Ys) :- inv(Xs,[X|Ac],Ys). inv([],Ys,Ys).

acumulador

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

Defina uma outra versão de factorial que utilize um parâmetro de acumulação.

Exercício:

U Ussoo ddee AAccuummuullaaddoorreess

Exemplo:

Considere o seguinte procedimento para o cálculo do factorial

Inversão de uma lista com e sem acumuladores.

2. Defina^ uma^ versão^ do^ predicado^ somatório^ que^ utilize^ um^ acumulador.

33

Exercícios:

Escreva um programa para reconhecer se uma fórmula da lógica proposicional está na forma normal conjuntiva, ou seja, é uma conjunção de disjunções de literais. Um literal é um símbolo proposicional ou a sua negação.

:- op(500,yfx,/). :- op(500,yfx,/). :- op(300,fy,~).

Considere a declaração das seguintes conectivas lógicas:

1. Defina a relação flatten/2 (que lineariza uma lista) de forma a que, por exemplo:

| ?- flatten([a,b,[c,d],[],[[[e,f]],g],h],X). X = [a,b,c,d,e,f,g,h]? yes

Defina o predicado conta_ocorr/3 para contar quantas vezes uma constante ocorre numa lista. (Sugestão: usar atomic/1).

Suponha que tem factos da forma quadrado(Lado). Defina o predicado zoom(+X,?Y,+F) tal que Y é o quadrado que resulta de multiplicar pelo factor F os lados do quadrado X. (Sugestão: usar =..).

34

arv_bin(vazia). arv_bin(nodo(X,Esq,Dir)) :- arv_bin(Esq), arv_bin(Dir).

na_arv(X,nodo(X,,)). na_arv(X,nodo(Y,Esq,)) :- na_arv(X,Esq). na_arv(X,nodo(Y,,Dir)) :- na_arv(X,Dir).

UUmm eexxeemmpplloo ccoomm áárrvvoorreess bbiinnáárriiaass

a

b (^) c

Esta árvore é representada pelo termo

nodo(a, nodo(b,vazia,vazia), nodo(c,vazia,vazia))

Exemplo:

Defina predicados que permitam fazer as travessias preorder , inorder e postorder.

Defina um predicado search_tree/1 que teste se uma dada árvore é uma árvore binária de procura.

Exercícios:

3. Defina a relação insert_tree(+X,+T1,?T2) que sucede se T2 é uma árvore

binária de procura resultado da inserção de X na árvore binária de procura T1. Defina a relação path(+X,+Tree,?Path) que sucede se Path é o caminho da raiz da árvore binária de procura Tree até X.

35

OO ccuutt !!

O cut****! não deve ser visto como um predicado lógico. Apenas interfere na semântica procedimental do programa. A sua acção é a seguinte: Durante o processo de prova, a 1 ª passagem pelo cut é sempre verdadeira (com sucesso). Se por backtracking se voltar ao cut, então o cut faz falhar o predicado que está na cabeça da regra. O cut “corta” ramos da árvore de procura. Os predicados antes do cut são apenas instanciados uma vez.

x :- p,! , q. x :- r. (^) if p then q else r

Exemplo: x tem um comportamento semelhante a

Green Cut

Red Cut

Chamam-se green cuts aos cuts que só alteram a semântica procedimental do programa, mas não alteram o significado do predicado. Este cuts são usados apenas para melhorar a eficiência. Se forem retirados serão produzidos os mesmos resultados.

Chamam-se red cuts aos cuts que alteram não só a semântica procedimental do programa, como também o seu significado declarativo. Se forem retirados serão produzidos resultados diferentes. A utilização destes cuts deve ser evitada.

minimo(X,Y,Y) :- X >= Y. minimo(X,Y,X) :- X < Y.

min(X,Y,Y) :- X >= Y,!. min(X,Y,X) :- X < Y.

? minimo(3,2,M)

yes

M=

M = 2

fail

M=

? min(3,2,M)

yes

M=

M = 2

Ramo cortado pelo cut

Exemplos: (^) minimo e min são predicados equivalentes.

O cut só está a cortar ramos que falham.