programação em lógicaeol/lp/1011/documents/praticas/...implementação em prolog…? números de...
TRANSCRIPT
Grafos
Grafos
– connected(joao_deus, camara_gaia, amarela).
– connected(camara_gaia, general_torres, amarela).
– (…)
– connected(estadio_dragao, campanha, vermelha).
– connected(campanha, heroismo, vermelha).
– (…)
Grafos
– Consideram-se proximas duas estações se estiveremna mesma linha e existir no maximo uma estaçãoentre essas duas:• nearby(joao_deus, camara_gaia).
• nearby(camara_gaia, general_torres).
• nearby(joao_deus, general_torres).
• …
– Ou (bem) melhor .. ;)• nearby(X,Y):-connected(X,Y,L).
• nearby(X,Y):-connected(X,Z,L),connected(Z,Y,L).
Grafos
– Comparar:
• nearby(X,Y):-connected(X,Y,L).
• nearby(X,Y):-connected(X,Z,L),connected(Z,Y,L).
– Com:…
• not_too_far(X,Y):-connected(X,Y,L).
• not_too_far(X,Y):-connected(X,Z,L1),connected(Z,Y,L2).
– Pode ser re-escrito:
• not_too_far(X,Y):-connected(X,Y,_).
• not_too_far(X,Y):-connected(X,Z,_),connected(Z,Y,_).
Grafos - Recursividade
– É possível ir de uma estação a outra se estiverem namesma linha, ou com uma mudança de linha, ou duas, outrês, ou..:• reachable(X,Y):-connected(X,Y,L).
• reachable(X,Y):-connected(X,Z,L1),connected(Z,Y,L2).
• reachable(X,Y):-connected(X,Z1,L1),connected(Z1,Z2,L2),connected(Z2,Y,L3).
• (…)
– Ou BEM melhor!!...:• reachable(X,Y):-connected(X,Y,L).
• reachable(X,Y):-connected(X,Z,L),reachable(Z,Y).
Grafos – Listas
• path(X,Y,[]):-connected(X,Y,L).
• path(X,Y,[Z|R])):-connected(X,Z,L),path(Z,Y,R).
– ?-path(estadio_dragao,bolhao,R).
• R =[campanha, heroismo, 24_agosto]
.
campanha .
heroismo
24_agosto []
.
Podemos escrever esta lista de muitas maneiras:.(campanha,.(heroismo,.(24_agosto,[])))[campanha |[heroismo |[24_agosto |[]]]][campanha |[heroismo |[24_agosto]]][campanha |[heroismo, 24_agosto]][campanha, heroismo, 24_agosto][campanha, heroismo |[24_agosto]]…
Factorial
– Calcular o factorial de N• Computar o factorial de N-1 usando recursividade.
• Para quando o atingirmos o problema trivial que é..: o factorial ZERO = 1
fact_td(0,1).
fact_td(N,F):-N>0, N1 is N-1, fact_td(N1,F1), F is N*F1.
– Nota: a complexidade do procedimento acima é linear, ou seja, precisamos de N+1 chamadas a fact_td
Números de Fibonnaci
– Os Números de Fibonacci são uma sucessão definida como recursiva pela fórmula abaixo:
– Começando com 1, o próximo número de Fibonacci é encontrado somando os dois anteriores:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987,1597, 2584, 4181, 6765, 10946…
Implementação em Prolog…?
Números de Fibonnaci
– Solução:
fibonacci(0,1).
fibonacci(1,1).
fibonacci(N,F):-
N > 1,
N1 is N - 1,fibonacci(N1,F1),
N2 is N - 2, fibonacci(N2,F2),
F is F1 + F2.
Números Primos
Escreva um predicado e_primo(N) que determine se um dado número é primo
Números Primos
Escreva um predicado e_primo(N) que determine se um dado número é primo
– Solução:
e_primo(2).
e_primo(3).
e_primo(P) :- integer(P), P > 3, P mod 2 =\= 0, \+tem_factor(P,3).
tem_factor(N,L) :- N mod L =:= 0.
tem_factor(N,L) :- L * L < N, L2 is L + 2, tem_factor(N,L2).
Listas
Preveja os resultados das seguintes questões em Prolog:
a) ?- [a|[b,c,d]] = [a,b,c,d].
b) ?- [a|b,c,d] = [a,b,c,d].
c) ?- [H|T] = [apple, broccoli, refrigerator].
d) ?- [H|T] = [a, b, c, d, e].
e) ?- [H|T] = [apples, bananas].
f) ?- [H|T] = [a, [b,c,d]].
g) ?- [H|T] = [apples].
h) ?- [H|T] = [].
i) ?- [One, Two | T] = [apple, sprouts, fridge, milk].
Listas
Preveja os resultados das seguintes questões em Prolog:(…)
– Solução:a) yesb) noc) H = appleT = [broccoli, refrigerator]d) H = aT = [b, c, d, e]e) H = applesT = [bananas]f) H = aT = [[b, c, d]]g) H = applesT = []h) noi) One = appleTwo = sproutsT = [fridge, milk]
Listas
Implemente o predicado membro(X,L) que sucede se X for um membro da lista L. (member).
Listas
Implemente o predicado membro(X,L) que sucede se X for um membro da lista L. (member).
– Solução:
member(X,[X|_]).
member(X,[_|Ys]) :- member(X,Ys).
Listas
Implemente o predicado append(L1,L2,L) em que L é constituída pela concatenação das listas L1 e L2.
Listas
Implemente o predicado append(L1,L2,L) em que L é constituída pela concatenação das listas L1 e L2.
– Solução:
append([],L,L).
append([X|L1],L2,[X|L3]):- append(L1,L2,L3).
Listas
Implemente o predicado duplicar(L,LL) em que LL é a lista L duplicada.
Listas
Implemente o predicado duplicar(L,LL) em que LL é a lista L duplicada.
– Solução:
duplicar([], []).
duplicar([X|R], [X,X|R2]) :- duplicar(R,R2).
Listas
Implemente o predicado substi(X,Y,L1,L2) em que L2 é L1 com todas as ocorrências de X substituídas por Y.
Listas
Implemente o predicado substi(X,Y,L1,L2) em que L2 é L1 com todas as ocorrências de X substituídas por Y.
– Solução:
substi(_,_,[],[]).
substi(X,Y,[X|R1],[Y|R2]) :- substi(X,Y,R1,R2).
substi(X,Y,[C|R1],[C|R2]) :- C \= X, substi(X,Y,R1,R2).
Listas
Implemente o predicado ordenada(Lista) que é verdadeiro se Lista é uma lista de inteiros ordenada.
Listas
Implemente o predicado ordenada(Lista) que é verdadeiro se Lista é uma lista de inteiros ordenada.
– Solução:
ordenada([N]).
ordenada([N1,N2]):- N1 =< N2.
ordenada([N1,N2|Resto]):-
N1 =< N2,
ordenada([N2|Resto]).
Listas
Implemente o predicado slice(L1,I,K,L2) em que L2 é a lista dos elementos de L1 entre os índices I e K (ambos incluídos).
Listas
Implemente o predicado slice(L1,I,K,L2) em que L2 é a lista dos elementos de L1 entre os índices I e K (ambos incluídos).
– Solução:slice([X|_],1,1,[X]).
slice([X|Xs],1,K,[X|Ys]) :- K > 1,
K1 is K - 1, slice(Xs,1,K1,Ys).
slice([_|Xs],I,K,Ys) :- I > 1,
I1 is I - 1,
K1 is K - 1,
slice(Xs,I1,K1,Ys).
Listas
Implemente o predicado inverte(List,Tsil) em que Tsil é List com a ordem dos elementos invertida.
Listas
Implemente o predicado inverte(List,Tsil) em que Tsil é List com a ordem dos elementos invertida.
– Solução:
inverte(L, Inv) :- inverte(L, [], Inv).
inverte([], Inv, Inv).
inverte([X|R], InvAux, Inv) :- inverte(R, [X|InvAux], Inv).
Factorial
– Calcular o factorial de N• Computar o factorial de N-1 usando recursividade.
• Para quando o atingirmos o problema trivial que é..: o factorial ZERO = 1
fact_td(0,1).
fact_td(N,F):-N>0, N1 is N-1, fact_td(N1,F1), F is N*F1.
– Nota: a complexidade do procedimento acima é linear, ou seja, precisamos de N+1 chamadas a fact_td
Factorial - iterativo
– Calcular o factorial de N
fact_it(N,F):-fact_it(N,1,F).fact_it(N,T,F):-N>0, T1 is T*N, N1 is N-1,fact_td(N1,T1F).Fact_it(0,F,F).
– Notas:• o acc é uma variável lógica: o valor é passado entre iterações,
não o endereço. • o mecanismo de write once leva a que uma variável nova seja
passada a cada iteração -> esta versão é mais eficiente em termos de espaço que a versão recursiva
Árvores de Pesquisa
– Árvore de pesquisa de um objectivo G relativamente a um programa P• raiz da árvore: G• nós: resolventes, com um objectivo seleccionado• arcos a sair de um nó: um por cada cláusula de P cuja cabeça unifica
com o objectivo seleccionado no nó• cada caminho na árvore, desde a raiz: computação de G por P• folhas: nós de sucesso, se corresponderem a resolventes vazias;• nós de falha se o objectivo seleccionado não puder ser reduzido
– Prolog pesquisa (daí o nome) a árvore primeiro em profundidade…• implementável por uma stack, onde se guardam os objectivos da
resolvente actual
Antes de avançar…
– Não terminação…• homem(mario).• homem(afonso).• homem(henrique).• homem(jorge).
• mulher(assuncao).• mulher(ana).• mulher(joana).• mulher(sofia).
– casou_com(X,Y) e… casou_com(Y,X) … como resolver?• casou_com(X,Y):-casou_com(Y,X) ???
Antes de avançar…
– casou_com(X,Y):-casou_com(Y,X).
– Trace de casou_com(mario, ana).• casou_com(mario, ana)
– casou_com(ana, mario)
» casou_com(mario, ana)
• casou_com(ana, mario)
• …
– Melhor solução: evitar recursividade à esquerda• sao_casados(X,Y):-casou_com(X,Y).
• sao_casados(X,Y):-casou_com(Y,X).
Grafos
Grafos
– connected(joao_deus, camara_gaia, amarela).
– connected(camara_gaia, general_torres, amarela).
– (…)
– connected(estadio_dragao, campanha, vermelha).
– connected(campanha, heroismo, vermelha).
– (…)
Grafos – pesquisa em profundidade
– É possível ir de uma estação a outra se estiverem na mesmalinha, ou com uma mudança de linha, ou duas, ou três, ou..:• reachable(X,Y):-connected(X,Y,L).
• reachable(X,Y):-connected(X,Z,L1),connected(Z,Y,L2).
• reachable(X,Y):-connected(X,Z1,L1),connected(Z1,Z2,L2),connected(Z2,Y,L3).
• (…)
– Ou BEM melhor!!...:• reachable(X,Y):-connected(X,Y,L).
• reachable(X,Y):-connected(X,Z,L),reachable(Z,Y).
– Quais as soluções para reachable(trindade,Y)…?
Grafos – pesquisa em profundidade
• Soluções para reachable(trindade,Y)– aliados– s_bento– jardim_morro– general_torres– camara_gaia– joao_deus
– faria_guimaraes– marques– combatentes– salgueiros– polo_universitario– ipo– hospital_s_joao
– bolhao– campo_24_agosto– heroismo– campanha– estadio_dragao
– lapa– carolina_michaelis– casa_musica– …
Grafos – pesquisa em profundidade
– E se trocássemos a ordem das regras fosse trocada…?
reachable(X,Y):-connected(X,Z,L),reachable(Z,Y).
reachable(X,Y):-connected(X,Y,L).
– Quais as soluções agora para reachable(trindade,Y)?
Grafos – pesquisa em profundidade
• Soluções para reachable(trindade,Y)– joao_deus– camara_gaia– general_torres– jardim_morro– s_bento– aliados
– hospital_s_joao– ipo– polo_universitario– salgueiros– combatentes– marques– faria_guimaraes
– estadio_dragao– campanha– heroismo– campo_24_agosto– bolhao
A ordem das regras não altera a a árvore de pesquisa, apenas a ordem com que as soluções são encontradas. A ordem dos golos altera a árvore de pesquisa.
Grafos – pesquisa em profundidade
– É possível ir de uma estação a outra se estiverem na mesmalinha, ou com uma mudança de linha, ou duas, ou três, ou..:• reachable(X,Y):-connected(X,Y,L).
• reachable(X,Y):-connected(X,Z,L1),connected(Z,Y,L2).
• reachable(X,Y):-connected(X,Z1,L1),connected(Z1,Z2,L2),connected(Z2,Y,L3).
• (…)
– Ou BEM melhor!!...:• reachable(X,Y):-connected(X,Y,L).
• reachable(X,Y):-connected(X,Z,L),reachable(Z,Y).
– Quais as soluções para reachable(trindade,Y)…?
Pensando bem…reachable(X,Y):-connected(X,Y,L).
reachable(X,Y):-connected(X,Z,L),reachable(Z,Y).
Funciona?...
Grafos – pesquisa em profundidade
Pensando bem…reachable(X,Y):-connected(X,Y,L).
reachable(X,Y):-connected(X,Z,L),reachable(Z,Y).
Funciona?...
reachable(X,Y):-reachable(X,Y, [X]).
reachable(A,A,Visitados).
reachable(A,B,Visitados):-connected(A,N,L), not member(N,Visitados), reachable(N,B,[N|Visitados]).
Grafos – pesquisa em profundidade
Pesquisa– Considere que um grafo não dirigido é representado por um conjunto de cláusulas
unitárias da forma ligacao(No1, No2).
• Escreva um predicado caminho(+NoInicio, +NoFim, -Lista), que dados dois nós do grafo, calcule um possível caminho (não necessariamente o mais curto) entre esses nós, supondo que a dimensão máxima do caminho é 5
– Nota: faça uso dos utilitários de manipulação de Listas
membro(X, [X|_]):- !.
membro(X, [_|Y]):- membro(X,Y).
» e
concatena([], L, L).
concatena([X|Y], L, [X|Lista]):- concatena(Y, L, Lista).
Exemplo:
?- caminho(2, 3, Lista).
Lista = [2,4,3] ; Lista = [2,4,6,3] ; Lista = [2,1,3] ; no
Pesquisa – Solução (sem cut…)
ligacao(1, 2).
ligacao(1, 3).
ligacao(2, 4).
ligacao(3, 4).
ligacao(3,6).
ligacao(4, 6).
ligacao(5,6).
ligacao2(X,Y):- ligacao(X,Y) ; ligacao(Y,X).
caminho(NoInicio, NoFim, Lista):-
caminho(NoInicio, NoFim, [NoInicio], Lista, 5).
caminho(NoInicio, NoFim, Lista, ListaFim,_):-
ligacao2(NoInicio, NoFim),
append(Lista, [NoFim], ListaFim).
caminho(NoInicio, NoFim, Lista, ListaFim, N):-
N>0,
ligacao2(NoInicio, NoInterm),
NoInterm \= NoFim,
\+(member(NoInterm, Lista)),
append(Lista, [NoInterm], Lista2),
N2 is N-1,
caminho(NoInterm, NoFim, Lista2, ListaFim, N2).
Efeitos do cut
– Implicações:
• O golo p unificado com uma clausula que contem um cut e que sucede, não gera soluções usando clausulas que ocorrem abaixo dessa clausula
• O cut poda todas as soluções alternativas para o conjunção de golos à esquerda da sua ocorrência na clausula
• O cut não afecta os golos à sua direita, podendo produzir mais soluções no caso de backctracking
Efeitos do cut%merge(Xs,Ys,Zs) :- Zs é uma lista de inteiros ordenada obtida a partir da
fusao das listas de inteiros ordenadas Xs e Ys
merge([X|Xs],[Y|Ys],[X|Zs]) :-
X < Y, merge(Xs,[Y|Ys],Zs).
merge([X|Xs],[Y|Ys],[X,Y|Zs]) :-
X =:= Y, merge(Xs,Ys,Zs).
merge([X|Xs],[Y|Ys],[Y|Zs]) :-
X > Y, merge([X|Xs],Ys,Zs).
merge(Xs,[],Xs).
merge([],Xs,Xs).
Com cutsmerge([X|Xs],[Y|Ys],[X|Zs]) :-
X < Y, !, merge(Xs,[Y|Ys],Zs).
merge([X|Xs],[Y|Ys],[X,Y|Zs]) :-
X =:= Y, !, merge(Xs,Ys,Zs).
merge([X|Xs],[Y|Ys],[Y|Zs]) :-
X > Y, !, merge([X|Xs],Ys,Zs).
merge(Xs,[],Xs) :- !.
merge([],Xs,Xs) :- !.
merge([1,2,3],[3,5], Zs).
Efeitos do cut
O cut assim definido permite encurtar o caminho percorrido pelo Prolog, tornando a computação mais eficiente em termos de tempo e, especialmente, em termos de espaço. Neste exemplo, o uso de cut não altera o significado da computação (soluções obtidas) – é um cut verde ( ≠ cut vermelho…)
Cut verde e vermelho– Considere que um grafo não dirigido é representado por um conjunto de cláusulas
unitárias da forma ligacao(No1, No2).
• Escreva um predicado caminho(+NoInicio, +NoFim, -Lista), que dados dois nós do grafo, calcule um possível caminho (não necessariamente o mais curto) entre esses nós, supondo que a dimensão máxima do caminho é 5
– Nota: faça uso dos utilitários de manipulação de Listas
membro(X, [X|_]):- !.
membro(X, [_|Y]):- membro(X,Y).
» e
concatena([], L, L).
concatena([X|Y], L, [X|Lista]):- concatena(Y, L, Lista).
Exemplo:
?- caminho(2, 3, Lista).
Lista = [2,4,3] ; Lista = [2,4,6,3] ; Lista = [2,1,3] ; no
Cut verde e vermelho
• cut vermelhomembro(X, [X|_]).
membro(X, [_|Y]):- membro(X,Y).
» e
membro(X, [X|_]):- !.
membro(X, [_|Y]):- membro(X,Y).
Os programas apresentam o mesmo comportamento?– member(X,[1,2,3])
» …
Uma técnica habitual em Prolog é a omissão de condiçõesexplicitas. É muito útil por vezes, especialmente no caso condiçõesexplicitas de negação, que são mais rebuscadas de escrever. noentanto susceptível a erros.
Negação por falha
• O cut pode ser utilizado para implementar negação por falha/*
not X :- X não sucessede.
*/
not X :- X, !, fail.
not X.
Relembrar caminho:
caminho(NoInicio, NoFim, Lista, ListaFim, N):-
(…)
NoInterm \= NoFim,
\+(member(NoInterm, Lista)),
append(Lista, [NoInterm], Lista2),
(…)
not do Prolog não implementa verdadeira negação lógica.. A negação por falha não é garantido que funcione para termos não-fechados.
If-Then-Else
• Implementação usando cut
/*
if_then_else(P,Q,R) :- OU P E Q, OU nao P E R.
*/
if_then_else(P,Q,R) :- P, !, Q.
if_then_else(P,Q,R) :- R.
cut
• Considere a seguinte base de dados:p(1).
p(2):-!.
p(3).
– Indique todas as respostas dadas pelo interpretador às questões:
a) ?- p(X).
b) ?- p(X), p(Y).
c) ?- p(X), !, p(Y).
cut
• Considere a seguinte base de dados:p(1).
p(2):-!.
p(3).
– Indique todas as respostas dadas pelo interpretador às questões:
a) ?- p(X).
b) ?- p(X), p(Y).
c) ?- p(X), !, p(Y).
Solução:
a) X=1 ; X=2
b) X=1 Y=1 ; X=1 Y=2 ; X=2 Y=1 ; X=2 Y=2
c) X=1 Y=1 ; X=1 Y=2
cut• Suponha a seguinte base de factos em Prolog
dados(um).
dados(dois).
dados(tres).
• a) Qual o resultado da seguinte pergunta?
cut_teste_a(X) :- dados(X).cut_teste_a('ultima_clausula').
• ?- cut_teste_a(X), write(X), nl, fail.
• a) Qual o resultado do seguinte programa com um cut no final da primeira clausula?cut_teste_b(X):-
dados(X), !.
cut_teste_b('ultima_clausula').
• ?- cut_teste_b(X), write(X), nl, fail.
• c) Qual o resultado do seguinte programa com um Cut no meio dos dois objectivos?cut_teste_c(X,Y) :-
dados(X),!,dados(Y).
cut_teste_c('ultima_clausula').
• ?- cut_teste_c(X,Y), write(X-Y), nl, fail.
cutSolução:
a) um
dois
tres
ultima_clausula
no
b) um
no
c) um - um
um - dois
um - tres
no
Unificação– Defina o predicado unificavel(L1, Termo, L2) em que L2 é uma lista com todos os
elementos de L1 que são unificáveis com Termo. Os elementos de L2 não são no entanto unificados com Termo. Exemplo:
?- unificavel([X,b,t(Y)],t(a),L).
L=[X,t(Y)]
– Note que se Termo1=Termo2 resulta então not(Termo1=Termo2) falha e a instanciação resultante de Termo1=Termo2 é anulada.
Unificação– Solução
%unificavel(LIn, T, Lout)
unificavel([], _, []).
unificavel([T1|RIn], T, ROut) :-
T1 \= T,
!,
unificavel(RIn, T, ROut).
unificavel([T1|RIn], T, [T1|ROut]) :-
unificavel(RIn, T, ROut).
Operadores
• Forma standard de ler e escrever os termos é com o functor seguido dos respectivos argumentos entre parênteses, ex: casado_com(X,Y)
• Certas expressões ficam mais legíveis usando operadores (Ex: as expressões matemáticas com: 2*a + b*c)
• comando: op( Precedencia, Tipo, Op )– Precedência de 1 a 1200
• ',' tem precedência 1000; logo, operadores que possam aparecer como argumentos devem ter precedência inferior a 1000 ou ficar entre parênteses, que corresponde a precedência 0
– Tipo pretende desambiguar expressões definindo o tipo de associatividade e a posição (infixo: xfx, xfy, yfx; prefixo: fx, fy; posfixo: xf, yf)
• x argumento com precedência INFERIOR ao do operador
• y argumento com precedência IGUAL OU SUPERIOR ao do operador
– Ex: Manuel joga futeboljoga(Manuel, futebol)
op(600, xfx, joga)
Operadores– Suponha que temos definidos os seguintes operadores :
:- op(500,xfx,na).
:- op(500,xfy,ad).
:- op(500,yfx,ae).
Mostre como seriam representadas em PROLOG as seguintes expressões se não tivéssemos as directivas acima (indique os casos em que o PROLOG assinalaria um erro sintáctico):
– a) a na b ae c.
– b) a na b ad c.
– c) a ad b na c.
– d) a na b na c.
– e) a ad b ad c.
– f) a ae b ae c.
– g) a ad b ad c na d ae e ae f.
Operadores
– Solução:
– a) ae(na(a,b),c).
– b) Erro.
– c) ad(a,na(b,c)).
– d) Erro.
– e) ad(a,ad(b,c)).
– f) ae(ae(a,b),c).
– g) ad(a,ad(b,ae(ae(na(c,d),e),f))).
Operadores– Crie as directivas que tornam termos abaixo sintacticamente válidos :
a) se X entao Y senao Z.
b) Y gostaria_de X se X fosse bom e X fosse inteligente.
Operadores
– Solução:
a)
:-op(500, xfx, entao).
:-op(400, fx, se).
:-op(400, xfx, senao).
b)
:-op(800, xfx, se).
:-op(600, xfx, gostaria_de).
:-op(500, xfy, e).
:-op(400, xfx, fosse).
Tipos de termos
• Predicados var, nonvar, atom, integer, atomic– Inteiros
– Termos
– Variáveis podem estar ou não instanciadas• Atómico
• Estrutura
• …
– …
– Saber qual o tipo em determinada altura
Z is X + Y
…integer(X), integer(Y), Z is X + Y,…
• Predicados var, nonvar, atom, integer, atomic– var(X) (Predicados de tipo meta-lógicos)
– nonvar(X) (Predicados de tipo meta-lógicos)
– atom(X)
– integer(X)
– atomic(X)
Tipos de termos
Tipos de termos
• Predicados var, nonvar, atom, integer, atomic– var(X)
• ?-var(Z), Z=2.
• ?-Z=2,var(Z).
– nonvar(X)
– atom(X)• ?atom(22).
– integer(X)
– atomic(X)• ?atomic(22).
Tipos de termos
• Ex:– Count(A,L,N)
• ?-var(Z), Z=2.
• ?-Z=2,var(Z).
– nonvar(X)
– atom(X)• ?atom(22).
– integer(X)
– atomic(X)• ?atomic(22).
Tipos de termos
• Ex:– Count(A,L,N)
count(_,[],0).
count(A,[A|L],N):-!,
count(A,L,N1),
N is N1+1.
count(A,[_,L],N):-count(A,L,N).
Funciona?
?-count(a,[a,b,a,a],N).
N=3
?-count(a,[a,b,X,Y],Na).
Na=3
?-count(b,[a,b,X,Y],Nb).
Nb=3
?-L=[a,b,X,Y], count(a,[a,b,X,Y],Na), count(b,[a,b,X,Y],Nb).
…?
Tipos de termos
• Ex:– Count(A,L,N)
count(_,[],0).
count(A,[A|L],N):-!,
count(A,L,N1),
N is N1+1.
count(A,[_,L],N):-count(A,L,N).
Funciona?
?-L=[a,b,X,Y], count(a,[a,b,X,Y],Na), count(b,[a,b,X,Y],Nb).
Na=3
Nb=1
…
Isto é o número de termos que unificam com o atomo e não o real número de ocorrências do átomo conforme pretendíamos…
Tipos de termos
• Ex:– Count(A,L,N)
count(_,[],0).
count(A,[B|L],N):-
atom(B),A=B,!,
count(A,L,N1),
N is N1+1
;
count(A,L,N).
Funciona?
• Predicados bagof, setof, findall– bagof( Termo, Objectivo, Lista )¬ Lista é o multiconjunto de todas as
instâncias de Termo para as quais o Objectivo é satisfeito (inclui repetidos)
– setof( Termo, Objectivo, Lista ) ¬ semelhante, mas sem valores repetidos e ordenado
– findall(X,P,L) - todos os objectos de X sem ligar a diferenças em variáveis de P
• Sucede mesmo se Res=[ ]
– Ex:
classifica(a, vog).
classifica(b, con).
classifica(c, con).
classifica(d, con).
classifica(e, vog).
classifica(f, con).
Predicados de conjuntos
• Predicados bagof, setof, findall– Ex:
classifica(a, vog).
classifica(b, con).
classifica(c, con).
classifica(d, con).
classifica(e, vog).
classifica(f, con).
?-bagof(Letra, classifica(Letra,com), Letras).
? - setof(Class/Letra, classifica(Letra,Class), Res).
?-findall(Letra, classifica(Letra, Class), Letras).
Predicados de conjuntos
• Predicados bagof, setof, findallclassifica(a, vog).
classifica(b, con).
classifica(c, con).
classifica(d, con).
classifica(e, vog).
classifica(f, con).
?-bagof(Letra, classifica(Letra,com), Letras).
Letras=[b,c,d]
? - setof(Class/Letra, classifica(Letra,Class), Res).
Res = [con/b, con/c, con/d, con/f, vog/a, vog/e]]
? - findall(Letra, classifica(Letra, Class), Letras).
Letras = [a, b, c, d, e, f]
Predicados de conjuntos
• Predicados functor, arg, =..
– O golo Termo=..L é verdadeiro se L é uma lista cuja cabeça é o principal functor de Termo e a cauda são os seus argumentos
– functor( Termo, Functor, Aridade )¬ o functor principal de Termo é Functorcom aridade Aridade
– arg( N, Termo, Arg ) ¬ Arg é o Nésimo argumento de Termo
Predicados de manipulação da estrutura de termos
• Predicados functor, arg, =..
– O golo Termo=..L é verdadeiro se L é uma lista cuja cabeça é o principal functor de Termo e a cauda são os seus argumentos
?- f(a,b) =.. L
L= [f,a,b]
?- T =.. [rectangulo, 3, 5]
T=rectangulo(3,5)
?- Z=.. [p, X, f(X,Y)]
Z = p(X, f(X,Y))
Predicados de manipulação da estrutura de termos
• Predicados functor, arg, =..
– functor( Termo, Functor, Aridade )¬ o functor principal de Termo é Functorcom aridade Aridade
?- functor(likes(mary, pizza), Functor, Arity).
Functor = likes
Arity = 2
?- functor(likes(X, Y), Functor, Arity).
X = _G180
Y = _G181
Functor = likes
Arity = 2
Predicados de manipulação da estrutura de termos
• Predicados functor, arg, =..
– arg( N, Termo, Arg ) ¬ Arg é o Nésimo argumento de Termo
?- arg(2, buys(john, beer), Arg).
Arg = beer
?- X = likes(mary, Y), arg(2, X, pizza).
X = likes(mary, pizza)
Y = pizza
Predicados de manipulação da estrutura de termos
Decomposição de termos
– É frequente desejarmos realizar uma dada transformação em todos os elementos de uma lista. Para o efeito vamos recorrer a um predicado de aridade 2. A esta transformação chama-se também mapeamento duma lista. Construa um predicado de mapeamento utilizando o operador =.. na sua definição.• Exemplo1:
– Tendo
f(X,Y):-Y is X*X.
– vem
?-map([2,4,8],f,L).
L=[4,16,64]
• Exemplo2:– Tendo
duplica(X,Y) :- Y is 2*X.
– vem
?-map([1,2,3],duplica,L).
L=[2,4,6]
Decomposição de termos• Exemplo1:
– Tendo
f(X,Y):-Y is X*X.
vem
?-map([2,4,8],f,L).
L=[4,16,64]
• Exemplo2:– Tendo
duplica(X,Y) :- Y is 2*X.
vem
?-map([1,2,3],duplica,L).
L=[2,4,6]
– Solução:map([],_,[]).
map([C|R],Transfor,[TC|CR]):-
aplica(Transfor, [C,TC]),
map(R,Transfor,CR).
aplica(P,LArgs) :- G =.. [P|LArgs], G.
Decomposição de termos
– Definição de functor(Term,F,N) e arg(N,Term,Arg) em termos do operador =..
• a) Defina o predicado functor2(Term,F,Arity) que é verdadeiro se Term é um termo cujo functor principal tem o nome F e a aridade Arity.
• b) Defina o predicado arg(N,Term,Arg) que é verdadeiro se Arg é o N-ésimo argumento do termo Term.
Decomposição de termos
• a) Defina o predicado functor2(Term,F,Arity) que é verdadeiro se Term é um termo cujo functor principal tem o nome F e a aridade Arity.
Solução:functor_(Term,F,N):- Term=..[F|Args], length(Args,N).
• b) Defina o predicado arg(N,Term,Arg) que é verdadeiro se Arg é o N-ésimo argumento do termo Term.
Solução:arg_(N,Term,Arg):- Term=..[F|Args], position(N,Args,Arg).
position(1,[X|_],X).
position(N,[_|Xs],Y):-N>1, N1 is N-1, position(N1,Xs,Y).
PLR – exercícios
– Fechadura:A combinação de uma fechadura é composta por três números com valores entre 1 e 50. O segundo número é o dobro do primeiro. O terceiro número é igual ao segundo mais 10. A soma dos dois primeiros números é maior que 10. O primeiro número tem um dígito par e um ímpar. O segundo número ou tem ambos os dígitos pares ou ambos os dígitos ímpares.
Construa um predicado puzzle(-Lista), capaz de calcular possíveis combinações da fechadura obedecendo às restrições mencionadas utilizando o paradigma da Programação em Lógica com Restrições.
– Exemplo:
?- Puzzle(Lista).
Lista = [10, 20, 30] ; Lista = [12, 24, 34] ; Lista = [14, 28, 38] ; no
PLR – exercícios - solução
:-use_module(library(clpfd)).
puzzle([A,B,C]):-
domain([A,B,C],1,50),
domain([A1,B1],0,5),
domain([A2,B2],0,9),
A #= A1*10+A2,
B #= B1*10+B2,
B #= 2*A,
C #= 10+B,
A+B #> 10,
A1 mod 2 #\= A2 mod 2,
B1 mod 2 #= B2 mod 2,
labeling([ff],[A,B,C]).
PLR – exercícios
– SolveDígitos:Construa um programa solveDigitos(A,B), utilizando PLR para encontrar os dois números (A e B) de três dígitos que obedecem às seguintes condições:
• Os seis dígitos que compõe os números A e B são todos distintos e nenhum deles é o 0.
• O primeiro dígito de B é igual a metade do último digito de A.
• Em ambos os números os dígitos encontram-se ordenados por ordem crescente.
• A soma dos dígitos de A é igual à soma dos dígitos de B.
• A multiplicação dos dígitos de A adicionado a 12 é igual à multiplicação dos dígitos de B.
- Exemplo: ?- solveDigitos(A,B).
A = 378, B = 459
PLR – exercícios - solução
:-use_module(library(clpfd)).
resolveDigitos(A,B):-
Vars = [A1,A2,A3,B1,B2,B3],
domain(Vars, 1, 9),
A #= A1*100+A2*10+A3,
B #= B1*100+B2*10+B3,
all_distinct(Vars),
B1*2 #= A3,
A1 #< A2, A2 #< A3, B1 #< B2, B2 #< B3,
A1+A2+A3 #= B1+B2+B3,
A1*A2*A3+12 #= B1*B2*B3,
labeling([],Vars).
PLR – exercícios
– Adega:
Três freiras herdaram a adega do tio. A primeira teve direito a 5/12 das garrafas, a segunda a 30% e a terceira às 187 garrafas restantes. Construa um programa em PLR para descobrir quantas garrafas estavam na adega.
PLR – exercícios - solução
:-use_module(library(clpfd)).
garrafas(Num):-
Num in 187..10000,
Num #= A + B + 187,
A*12 #= 5*Num,
B*10 #= 3*Num,
labeling([],[Num]).
PLR – exercícios
– Doze automóveis:Doze automóveis estão parados, em fila indiana, num cruzamento com semáforos. Sabe-se que:
• Os automóveis têm a seguinte distribuição de cores: 4 amarelos, 2 verdes, 3 vermelhos e 3 azuis;
• O primeiro e o último automóvel são da mesma cor;
• O segundo e o penúltimo são da mesma cor;
• O quinto automóvel é azul;
• Todos os conjuntos de três automóveis consecutivos têm três cores distintas;
• Partindo do primeiro automóvel para o último automóvel, é possível visualizar a sequência: amarelo-verde-vermelho-azul uma única vez.
Construa um programa em PLR para determinar a cor de cada um dos automóveis
PLR – exercícios - solução:-use_module(library(clpfd)).
carros(Lista):-
length(Lista,12),
domain(Lista,1,4), %1-y, 2-g, 3-r, 4-b
global_cardinality(Lista, [1-4, 2-2, 3-3, 4-3]),
Lista=[A1,A2,_,_,A5,_,_,_,_,_,A11,A12],
A1 #= A12, A2 #= A11, A5 #= 4,
trios(Lista),
quad(Lista,ListVal),
sum(ListVal, #=, 1), !,
labeling([ff],Lista).
trios([_,_]).
trios([A,B,C|Resto]):-
all_different([A,B,C]),
trios([B,C|Resto]).
quad([_,_,_], []).
quad([A,B,C,D|Resto], [Val|ResVal]):-
A#<B #/\ B#<C #/\ C#<D #<=> Val,
quad([B,C,D|Resto], ResVal).
PLR – exercícios
– Escalonamento simples:O Sr. Paulino nunca acorda antes das 6h da manhã mas necessita de acordar uma hora antes de apanhar o autocarro para o trabalho. A viagem de autocarro demora pelo menos uma hora. O Sr. Paulino não sai do trabalho antes de trabalhar pelo menos 8 horas, após o que demora pelo mais de uma hora a chegar a casa e poder ligar a sua televisão. No entanto o Sr. Paulino não resiste a ver pelo menos 3 horas de televisão antes de se deitar.
Utilize as variáveis: WakeUp, TakeBus1, StartWork, TakeBus2, TurnTVOn, FallASleep e construa um escalonador para o dia do Sr. Paulino. As variáveis devem estar nos limites 1..24.
PLR – exercícios - solução:-use_module(library(clpfd)).
schedule(Times) :-
Times = [WakeUp,TakeBus1,StartWork,TakeBus2,TurnTVOn,FallASleep],
domain(Times,1,24),
WakeUp #>= 6,
WakeUp #< TakeBus1 - 1,
TakeBus1 #< StartWork - 1,
StartWork #< TakeBus2 - 8,
TakeBus2 #< TurnTVOn - 1,
TurnTVOn #< FallASleep - 3.
% Test 1 :
% schedule(Day).
% Test 2 :
% WU::7..9,FAS::20..22,schedule([WU,TB1,SW,TB2,TV,FAS])
% e com o labeling…?
% e mudando:
%StartWork #< TakeBus2 - 7,
%TurnTVOn #< FallASleep - 2.
PLR – exercícios
– Cumulative:Considere 7 tarefas, cada qual com uma duração e quantidade de recursos utilizados fixos::
O obejctivo é encontrar o escalonamento com o mínimo tempo de conclusão não excedendo a capacidade do recurso - que é 13..
Tarefa Duração Recursos
T1 16 2
T2 6 9
T3 13 3
T4 7 7
T5 5 10
T6 18 1
T7 4 11
PLR – exercícios - solução:-use_module(library(clpfd)).
schedule(Ss, End) :-
Ss = [S1,S2,S3,S4,S5,S6,S7],
Es = [E1,E2,E3,E4,E5,E6,E7],
Tasks = [task(S1,16,E1, 2, 1),
task(S2, 6,E2, 9, 2),
task(S3,13,E3, 3, 3),
task(S4, 7,E4, 7, 4),
task(S5, 5,E5,10, 5),
task(S6,18,E6, 1, 6),
task(S7, 4,E7,11, 7)],
domain(Ss, 1, 30),
domain(Es, 1, 50),
domain([End], 1, 50),
maximum(End, Es),
cumulative(Tasks, [limit(13)]),
append(Ss, [End], Vars),
labeling([minimize(End)], Vars).