Родственные отношения на Prolog
Используя предикаты parent(symbol,symbol) , man(symbol) , woman(symbol) , married(symbol,symbol) , записать факты, описывающие вашу семью. Записать 8 правил вывода для любых родственных отношений в вашей семье (например: мать, отец, сестра, брат, племянница, племянник, тетя, дядя, внучка, внук, бабушка, дедушка, двоюродная сестра, двоюродный брат и т.д.).
parent("Alexandr","Olya"). parent("Masha","Olya"). parent("Alexandr","Alina"). parent("Masha","Alina"). parent("Alexandr","Leha"). parent("Masha","Leha"). parent("Leha","Gleb"). parent("Dasha","Gleb"). parent("Alina","Maks"). parent("Leha","Maks"). man("Alexandr"). man("Leha"). man("Pavel"). man("Dima"). woman("Olya"). woman("Alina"). woman("Masha"). married("Masha","Pavel"). married("Alina","Dima"). check_married(X, Y):- married(X, Y); married(Y, X). father(X,Y):- parent(X,Y),man(X). mother(X,Y):- parent(X,Y),woman(X). sister(X,Y):- parent(Z,X), parent(Z,Y), woman(X), X\=Y. brother(X,Y):- parent(Z,Y),parent(Z,X),man(X), X\=Y. son(X,Y):- parent(Y,X),man(X). daughter(X,Y):- parent(Y,X),woman(X). wife(X,Y):- check_married(X,Y), woman(X). husband(X,Y):- check_married(X,Y), man(X). brother_in_law(X, Y):- wife(Y, Wife), brother(X, Wife). mother_in_law(X,Y):- wife(Y, Wife), mother(X, Wife). uncle(X, Y):- parent(Parent, Y), brother(X, Parent). ?-father(X,"Olya"),write(X),write(" "). ?-mother(X,"Alina"),write(X),write(" "). ?-married("Alina","Dima"),write(" "). ?-husband("Masha",Y),write(Y),write(" "). ?-wife(X,"Pavel"),write(X),write(" "). ?-sister("Olya","Alina"),write(" "). ?-brother_in_law(X,"Dima"),write(X),write(" "). ?-mother_in_law(X,"Dima"),write(X),write(" "). ?-uncle(X,"Maks"),write(X),write(" ").
вы говорите, что X отец Y если он является родителем и при этом мужчиной. Очень похоже работает правило mother . Функция
sister(X,Y):- parent(Z,X), parent(Z,Y), woman(X), X\=Y.
значит, что X является сестрой для Y если у них есть общий родитель ( Z ), X является женщиной и X не равен Y (человек не является сестрой сам себе). Аналогично построено правило brother , но в нем X является мужчиной. Предикат
проверяет, что X является сыном для Y тогда и только тогда, когда Y является родителем X и X является мужчиной. Почти также работает предикат daughter . Функции проверки жены и мужа используют не предикат married , а check_married , который проверяет что люди ( X и Y ) женаты если в базе если запись married(X, Y) или married(Y, X) .
wife(X,Y):- check_married(X,Y), woman(X).
тут говорится, что X является женой Y если они женаты и X — женщина. Аналогично выполняется проверка мужа (но он мужчина). Шурин — это брат жены, поэтому для его проверки можно использовать предикаты wife и brother :
brother_in_law(X, Y):- wife(Y, Wife), brother(X, Wife).
Тут мы говорим, что X является шурином для Y если у Y есть жена ( Wife ), братом которой является X . Теща — это мать жены:
mother_in_law(X,Y):- wife(Y, Wife), mother(X, Wife).
Таким образом, X — теща для Y если у Y есть такая жена ( Wife ), что ее матерью является X . Если дядю понимать как брата отца или матери (в более общем случае — это муж тетки, т.е. он может быть не родным), то:
uncle(X, Y):- parent(Parent, Y), brother(X, Parent).
тут говорится, что X является дядей для Y если у Y есть такой родитель ( Parent ), что X является его братом. Дед — это отец одного из родителей.
grandfather(X, Y):- parent(Parent, Y), father(X, Parent). grandmother(X, Y):- parent(Parent, Y), mother(X, Parent).
X является дедом для Y если существует Parent, который является родителем для Y и при этом X является отцом Y. Аналогично с бабушкой.
parent(иван, георгий). parent(иван, софья). parent(иван, галина). parent(дарья, георгий). parent(дарья, софья). parent(дарья, галина). parent(генадий, николай). parent(генадий, сергей). parent(галина, николай). parent(галина, сергей). parent(ирина, елена). parent(николай, елена). parent(татьяна, александр). parent(сергей, александр). man(георгий). man(генадий). man(николай). man(сергей). man(александр). woman(софья). woman(галина). woman(дарья). woman(ирина). woman(елена). woman(татьяна). married(иван, дарья). married(генадий, галина). married(николай, ирина). married(татьяна, сергей).
На рисунке показан граф родственных отношений, соответствующий базе данных:
Пусть, наша задача: «Найти племянницу сына зятя Дарьи». Зять — муж дочери или сестры:
son_in_low(X, Y):- daughter(Z, Y), husband(X, Z); sister(Z, Y), husband(X, Z).
X является зятем (муж дочери) для Y если у Y есть дочь Z такая, что X является мужем для Z.
Аналогично описывается зять, являющийся мужем сестры. В нашем случае, зять Дарьи — это Генадий, проверим:
?- son_in_low(X, дарья). X = генадий ;
?- son_in_low(X, дарья), son(Z, X). X = генадий, Z = николай ; X = генадий, Z = сергей ; false.
niece(X, Y):- brother(Z, Y), daughter(X, Z); sister(Z, Y), daughter(X, Z).
nephew(X, Y):- brother(Z, Y), son(X, Z); sister(Z, Y), son(X, Z).
X является племянницей Y если Z является братом или сестрой Y, при этом, у Z есть дочь X. В нашем примере искомой племянницей сына зятя Дарьи является Елена:
?- son_in_low(X, дарья), son(Z, X), niece(Niece, Z). X = генадий, Z = сергей, Niece = елена ;
Следующее дерево родственных отношений:
Задано семантической сетью, использующей отношения father/mother вместо parent:
predicates nondeterm mother(string, string) nondeterm father(string, string) nondeterm male(string) nondeterm female(string) nondeterm son(string, string) nondeterm daughter(string, string) nondeterm grandfather(string, string) nondeterm grandmother(string, string) nondeterm granddaughter(string, string) nondeterm grandson(string, string) goal grandson(Vnuk, "Пётр_III"), write(Vnuk), nl, fail; true. clauses mother("Екатерина_II", "Павел_I"). mother("Мария_Фёдоровна", "Александр_I"). mother("Мария_Фёдоровна", "Константин"). mother("Мария_Фёдоровна", "Николай_I"). mother("Александра_Фёдоровна", "Александр_II"). mother("Мария_Александровна", "Александр_III"). mother("Дагмара_Датская", "Николай_II"). mother("Алиса_Гессенская", "Алексей"). mother("Алиса_Гессенская", "Анастасия"). father("Пётр_III", "Павел_I"). father("Павел_I", "Александр_I"). father("Павел_I", "Николай_I"). father("Александр_II", "Александр_III"). father("Николай_II", "Алексей"). father("Павел_I", "Константин"). father("Николай_I", "Александр_II"). father("Александр_III", "Николай_II"). father("Николай_II", "Анастасия"). female("Екатерина_II"). female("Мария_Фёдоровна"). female("Александра_Фёдоровна"). female("Мария_Александровна"). female("Дагмара_Датская"). female("Алиса_Гессенская"). female("Анастасия"). male("Павел_I"). male("Александр_I"). male("Константин"). male("Николай_I"). male("Александр_II"). male("Николай_II"). male("Алексей"). male("Александр_III"). male("Пётр_III"). son(Who, X):- male(Who), father(X, Who); male(Who), mother(X, Who). daughter(Who, X):- female(Who), father(X, Who); female(Who), mother(X, Who). grandfather(Who, X):- father(Who, Y), father(Y, X); father(Who, Y), mother(Y, X). grandmother(Who, X):- mother(Who, Y), father(Y, X); mother(Who, Y), mother(Y, X). grandson(Who, X):- male(Who), grandfather(X, Who); male(Who), grandmother(X, Who). granddaughter(Who, X):- female(Who), grandfather(X, Who); female(Who), grandmother(X, Who).
Источник
Дерево родственных отношений пролог
В этой главе на примере конкретной программы рассматриваются основные механизмы Пролога. Несмотря на то, что материал излагается в основном неформально, здесь вводятся многие важные понятия.
1. 1. Пример программы: родственные отношения
Пролог — это язык программирования, предназначенный для обработки символьной нечисловой информации. Особенно хорошо он приспособлен для решения задач, в которых фигурируют объекты и отношения между ними. На рис. 1.1 представлен пример — родственные отношения. Тот факт, что Том является родителем Боба, можно записать на Прологе так:
родитель( том, боб).
Здесь мы выбрали родитель в качестве имени отношения, том и боб — в качестве аргументов этого отношения. По причинам, которые станут понятны позднее, мы записываем такие имена, как том, начиная со строчной буквы. Все дерево родственных отношений рис. 1.1 описывается следующей пролог-программой:
родитель( пам, боб).
родитель( том, боб).
родитель( том, лиз).
родитель( боб, энн).
родитель( боб, пат).
родитель( пам, джим).
Эта программа содержит шесть предложений . Каждое предложение объявляет об одном факте наличия отношения родитель.
После ввода такой программы в пролог-систему последней можно будет задавать вопросы, касающиеся отношения родитель. Например, является ли Боб родителем Пат? Этот вопрос можно передать пролог-системе, набрав на клавиатуре терминала:
?- родитель( боб, пат).
Найдя этот факт в программе, система ответит
Другим вопросом мог бы быть такой:
?- родитель( лиз, пат).
поскольку в программе ничего не говорится о том, является ли Лиз родителем Пат. Программа ответит «нет» и на вопрос
?- родитель( том, бен).
потому, что имя Бен в программе даже не упоминается.
Можно задавать и более интересные вопросы. Например:»Кто является родителем Лиз?»
?- родитель( X, лиз).
На этот раз система ответит не просто «да» или «нет». Она скажет нам, каким должно быть значение X (ранее неизвестное), чтобы вышеприведенное утверждение было истинным. Поэтому мы получим ответ:
Вопрос «Кто дети Боба?» можно передать пролог-системе в такой форме:
?- родитель( боб, X).
В этом случае возможно несколько ответов. Сначала система сообщит первое решение:
Возможно, мы захотим увидеть и другие решения. О нашем желании мы можем сообщить системе (во многих реализациях для этого надо набрать точку с запятой), и она найдет другой ответ:
Если мы потребуем дальнейших решений, система ответит «нет», поскольку все решения исчерпаны.
Нашей программе можно задавать и более общие вопросы: «Кто чей родитель?» Приведем другую формулировку этого вопроса:
Найти X и Y такие, что X — родитель Y.
На Прологе это записывается так:
?- родитель( X, Y).
Система будет по очереди находить все пары вида «родитель-ребенок». По мере того, как мы будем требовать от системы новых решений, они будут выводиться на экран одно за другим до тех пор, пока все они не будут найдены. Ответы выводятся следующим образом:
X = пам
Y = боб;
X = том
Y = боб;
X = том
Y = лиз;
Мы можем остановить поток решений, набрав, например, точку вместо точки с запятой (выбор конкретного символа зависит от реализации).
Нашей программе можно задавать и еще более сложные вопросы, скажем, кто является родителем родителя Джима? Поскольку в нашей программе прямо не сказано, что представляет собой отношение родительродителя, такой вопрос следует задавать в два этапа, как это показано на рис. 1.2.
(1) Кто родитель Джима? Предположим, что это некоторый Y.
(2) Кто родитель Y? Предположим, что это некоторый X.
Такой составной вопрос на Прологе записывается в виде последовательности двух простых вопросов:
?- родитель( Y, джим), родитель( X, Y).
X = боб
Y = пат
Рис. 1. 2. Отношение родительродителя, выраженное через композицию двух отношений родитель.
Наш составной вопрос можно интерпретировать и так: «Найти X и Y, удовлетворяющие следующим двум требованиям»:
родитель ( Y, джим) и родитель( X, У)
Если мы поменяем порядок этих двух требований, то логический смысл останется прежним:
родитель ( X, Y) и родитель ( Y, джим)
Этот вопрос можно задать нашей пролог-системе и в такой форме:
?- родитель( X, Y), родитель( Y, джим).
При этом результат будет тем же. Таким же образом можно спросить: «Кто внуки Тома?»
?- родитель( том, X), родитель( X, Y).
X = боб
Y = энн;
X = боб
Y = пат
Следующим вопросом мог бы быть такой: «Есть ли у Энн и Пат общий родитель?» Его тоже можно выразить в два этапа:
(1) Какой X является родителем Энн?
(2) Является ли (тот же) X родителем Пат?
Соответствующий запрос к пролог-системе будет тогда выглядеть так:
?- родитель( X, энн), родитель( X, пат).
родитель( X, энн), родитель( X, пат)
означает конъюнкцию этих целевых утверждений:
X — родитель Энн и
X — родитель Пат.
Упражнения
1. 1. Считая, что отношение родитель определено так же, как и раньше в данном разделе (см. рис. 1.1), найдите, какими будут ответы пролог-системы на следующие вопросы:
(a) ? — родитель ( джим, X).
(b) ? — родитель( X, джим).
(c) ? — родитель( пам,Х), родитель( Х, пат).
1. 2. Сформулируйте на Прологе следующие вопросы об отношении родитель:
(c) Кто является родителем родителя Пат?
Источник