Árvore Genealógica — do zero à regras complexas
Neste post vamos construir uma base de conhecimento genealógica completa e definir diversas relações usando regras. O exercício é baseado na árvore genealógica da Figura 1.2 do livro-texto, que descreve três gerações de uma família.
1. A Árvore Genealógica
A figura apresenta a seguinte estrutura familiar (nomes fictícios):
Relações de parentesco (pai/mãe):
- João é pai de Carlos e Beatriz.
- Maria é mãe de Carlos e Beatriz.
- Carlos é pai de Pedro, Clara e Lucas.
- Ana é mãe de Pedro, Clara e Lucas.
- Beatriz é mãe de João Jr. e Sofia.
- Roberto é pai de João Jr. e Sofia.
📝 2. Definindo os Fatos Básicos
Exercício 1: Crie um arquivo familia.pl e defina os fatos pai/2 e mae/2 com base na árvore acima.
Sua vez: Escreva os fatos no Prolog. Depois, carregue o arquivo e teste as consultas:
?- pai(joao, carlos). → deve retornar true.?- mae(ana, pedro). → deve retornar true.?- pai(X, pedro). → deve listar X = carlos.
Solução:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
% Fatos pai/2 pai(joao, carlos). pai(joao, beatriz). pai(carlos, pedro). pai(carlos, clara). pai(carlos, lucas). pai(roberto, joao_jr). pai(roberto, sofia). % Fatos mae/2 mae(maria, carlos). mae(maria, beatriz). mae(ana, pedro). mae(ana, clara). mae(ana, lucas). mae(beatriz, joao_jr). mae(beatriz, sofia). |
⚧️ 3. Adicionando homem/1 e mulher/1
Exercício 2: Para definirmos relações como “filho” e “filha”, precisamos saber o gênero de cada pessoa. Adicione os fatos homem/1 e mulher/1.
Sua vez: Liste todos os homens e mulheres da árvore.
?- homem(pedro). → true?- mulher(clara). → true?- homem(X). → deve listar todos os homens.
Solução:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
% Fatos homem/1 homem(joao). homem(carlos). homem(roberto). homem(pedro). homem(lucas). homem(joao_jr). % Fatos mulher/1 mulher(maria). mulher(ana). mulher(beatriz). mulher(clara). mulher(sofia). |
4. Regra gerou/2
Exercício 3: Defina a regra gerou(X, Y) que é verdadeira se X é pai ou mãe de Y.
Sua vez: Crie a regra gerou/2 usando os fatos já definidos.
?- gerou(maria, carlos). → true?- gerou(carlos, lucas). → true?- gerou(X, pedro). → deve listar X = carlos e X = ana.
Solução:
|
1 2 |
gerou(X, Y) :- pai(X, Y). gerou(X, Y) :- mae(X, Y). |
A regra usa dois cláusulas (ou é pai ou é mãe). O Prolog tenta a primeira, se falhar, tenta a segunda.
5. Desafios — Definindo Relações Derivadas
Agora vamos construir relações mais complexas. Para cada uma:
- Desenhe o grafo de relacionamento (nós = pessoas, arcos = relações).
- Codifique a regra em Prolog.
- Teste com as consultas sugeridas.
a) filho/2 e filha/2
Sua vez: Defina filho(Y, X) (Y é filho de X) e filha(Y, X) (Y é filha de X).
?- filho(pedro, carlos). → true?- filha(clara, ana). → true?- filho(X, carlos). → deve listar X = pedro, lucas.
Solução:
|
1 2 3 4 5 |
filho(Y, X) :- pai(X, Y), homem(Y). filho(Y, X) :- mae(X, Y), homem(Y). filha(Y, X) :- pai(X, Y), mulher(Y). filha(Y, X) :- mae(X, Y), mulher(Y). |
Raciocínio: Para ser filho(a), a pessoa deve ser descendente (pai ou mãe) e ter o gênero correspondente.
b) tio/2 e tia/2
Sua vez: Defina tio(T, S) e tia(T, S).
?- tio(roberto, pedro). → true (Roberto é irmão de Carlos)?- tia(beatriz, lucas). → true (Beatriz é irmã de Carlos)?- tio(X, clara). → deve listar X = roberto.
Dica: Você precisará primeiro definir irmao/2 (já vimos) e irma/2 (versão feminina).
Solução:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
% Primeiro, definimos irmão/irmã irmao(X, Y) :- pai(Z, X), pai(Z, Y), X \= Y, homem(X). irma(X, Y) :- pai(Z, X), pai(Z, Y), X \= Y, mulher(X). % Agora tio e tia tio(T, S) :- pai(P, S), irmao(T, P). tio(T, S) :- mae(M, S), irmao(T, M). tia(T, S) :- pai(P, S), irma(T, P). tia(T, S) :- mae(M, S), irma(T, M). |
Raciocínio: T é tio(a) se é irmão(ã) de um dos pais de S. Usamos as regras irmao/2 e irma/2 como auxiliares.
c) primo/2 e prima/2
Sua vez: Defina primo(P1, P2) e prima(P1, P2).
?- primo(joao_jr, pedro). → true (João Jr. e Pedro são primos)?- prima(sofia, clara). → true (Sofia e Clara são primas)?- primo(X, lucas). → deve listar X = joao_jr.
Dica: Use a regra tio/2 ou tia/2 que você acabou de definir.
Solução:
|
1 2 3 4 5 6 7 8 9 |
primo(P1, P2) :- tio(T, P1), pai(T, P2), P1 \= P2, homem(P1). primo(P1, P2) :- tia(T, P1), mae(T, P2), P1 \= P2, homem(P1). primo(P1, P2) :- tio(T, P2), pai(T, P1), P1 \= P2, homem(P1). primo(P1, P2) :- tia(T, P2), mae(T, P1), P1 \= P2, homem(P1). prima(P1, P2) :- tio(T, P1), pai(T, P2), P1 \= P2, mulher(P1). prima(P1, P2) :- tia(T, P1), mae(T, P2), P1 \= P2, mulher(P1). prima(P1, P2) :- tio(T, P2), pai(T, P1), P1 \= P2, mulher(P1). prima(P1, P2) :- tia(T, P2), mae(T, P1), P1 \= P2, mulher(P1). |
Raciocínio: Para ser primo(a), a pessoa deve ter um tio(a) em comum com a outra, e não ser a mesma pessoa. Incluímos as quatro combinações possíveis (tio/pai, tia/mae, etc.) para garantir que a relação funcione em ambos os sentidos.
d) avo/2 (avô/avó)
Sua vez: Defina avo(A, N) (avô) e avo(A, N) (avó).
?- avo(joao, pedro). → true (João é avô de Pedro)?- avo(maria, lucas). → true (Maria é avó de Lucas)?- avo(X, clara). → deve listar X = joao, maria.
Solução:
|
1 2 3 4 5 6 7 8 9 |
% Avô (homem) avo(A, N) :- pai(A, P), pai(P, N), homem(A). avo(A, N) :- pai(A, P), mae(P, N), homem(A). % Avó (mulher) avo(A, N) :- mae(A, P), pai(P, N), mulher(A). avo(A, N) :- mae(A, P), mae(P, N), mulher(A). |
Raciocínio: O avô/avó é pai/mãe de um dos pais da criança. Usamos o gênero para diferenciar avô de avó.
📊 6. Visualizando as Relações com UML
Abaixo está a representação UML das principais relações que definimos, usando o formato PlantUML:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
[plantuml] @startuml !define parent_arrow <|-- !define sibling_relation ..> class Joao { + pai(Carlos) + pai(Beatriz) } class Maria { + mae(Carlos) + mae(Beatriz) } class Carlos { + pai(Pedro) + pai(Clara) + pai(Lucas) } class Ana { + mae(Pedro) + mae(Clara) + mae(Lucas) } class Beatriz { + mae(Joao_Jr) + mae(Sofia) } class Roberto { + pai(Joao_Jr) + pai(Sofia) } Joao parent_arrow Carlos Joao parent_arrow Beatriz Maria parent_arrow Carlos Maria parent_arrow Beatriz Carlos parent_arrow Pedro Carlos parent_arrow Clara Carlos parent_arrow Lucas Ana parent_arrow Pedro Ana parent_arrow Clara Ana parent_arrow Lucas Beatriz parent_arrow Joao_Jr Beatriz parent_arrow Sofia Roberto parent_arrow Joao_Jr Roberto parent_arrow Sofia Carlos ..> Beatriz : irmãos Joao_Jr ..> Pedro : primos Carlos ..> Pedro : pai/filho @enduml [/plantuml] |
Diagrama UML mostrando as relações pai/mãe e algumas relações derivadas (irmão, primo).
7. Por que praticar com regras?
- Pensamento lógico: Cada regra é uma pequena prova lógica que você constrói.
- Reuso: Regras como
irmao/2etio/2podem ser combinadas para construir outras mais complexas. - Validação constante: Testar cada regra com consultas ajuda a garantir que a lógica está correta antes de avançar.
- Base para IA: Sistemas especialistas e bases de conhecimento são construídos exatamente assim.
Dica final: Sempre comece com um grafo ou diagrama antes de codificar. Isso ajuda a visualizar as conexões e evita erros de lógica. Depois, codifique e teste exaustivamente.
Conclusão
Neste exercício, construímos uma árvore genealógica completa e definimos 8 relações derivadas usando apenas fatos básicos e regras. A prática de desenhar o grafo antes de codificar e validar com consultas é fundamental para dominar o Prolog.
Próximos passos: Tente adicionar mais pessoas na árvore, ou definir relações como bisavo/2, sobrinho/2 ou cunhado/2. Quanto mais você praticar, mais natural se torna o raciocínio lógico!
“A lógica é a anatomia do pensamento.” — John Locke