Press "Enter" to skip to content

用prolog推理家族关系

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

Prolog语言知识推理系列文章 ,不同编程语言有着不同编程视角,JAVA是面向对象,Nodejs是异步回调,R语言是统计算法,Prolog就是知识推理。每种语言都是独特的,如果想把一门语言学好用好,关键是利用语言的特点,做对的事情。

 

本系列文章主要介绍Prolog语言,从入门安装到知识推理。Prolog是完全不一样的,他没有复杂的程序结构,也不是为了解决算法问题,而是专注于逻辑推理,擅长解决抽象的问题。

 

关于作者:

张丹,分析师/程序员/Quant: R,Java,Nodejs
blog: http://fens.me
email: [email protected]

转载请注明出处:

http://blog.fens.me/prolog-family/

 

前言

 

最近在研究逻辑推理的一些问题,无意中发现了一门编程语言prolog就是解决推理问题的。家族关系是社会生活中一个重要的组成元素,每个人都有自己的家族关系网,这种关系结构并不是很容易地表达,而且人物关系一旦多了,会非常地复杂。

 

试试prolog的在推理上的强大之处,能否帮我们解决复杂的社会问题的推理计算过程。

 

目录

 

 

    1. 家族关系定义

 

    1. 用prolog表达家族关系

 

    1. 推理计算

 

 

1. 家族关系定义

 

我们虚拟一个家族关系,共16个人,8男8女,包括几个不同的维度关系,性别,,孩子,结婚,兄弟,姐妹等,如下图所示。

 

 

上图注释:

性别特征:男为蓝色方形,女为橙色圆形。
家长关系:用蓝色箭头表示,箭头的开始为家长,箭头的指向为孩子。
婚姻关系:用红色连线表示,两端为结婚的男性和女性。

2. 用prolog表达家族关系

 

我们首先建立一个prolog的文件叫family.pl,在family.pl中定义关系的定义,如果直接在prolog的运行环境中运行代码代码,则会出现DWIM could not correct goal的错误,错误解决请参考文章prolog语言安装

 

新建文件family.pl。在window中可以直接在任何文本编辑器中,新建一个文件。

 

~ notepad c:/work/prolog/02 family/family.pl

 

根据prolog语言的语法结构,我们需要在编程时,分别定义事实(Fact)、(Rule)和问题(Question)。

事实,就是把具体的对象进行语言表达和描述。
规则,就是建立对象之间的关系。
问题,就是用prolog来找答案。

事实:建立对象的性别特征,女性和男性。

 

% female: a,c,i,k,m,e,g,o
% male:   b,d,j,l,n,f,h,p
female(a).
female(c).
female(i).
female(k).
female(m).
female(e).
female(g).
female(o).
male(b).
male(d).
male(j).
male(l).
male(n).
male(f).
male(h).
male(p).

 

规则:建立家长关系

 

% parent
parent(a,d).
parent(a,j).
parent(b,d).
parent(c,m).
parent(c,n).
parent(d,m).
parent(d,n).
parent(d,g).
parent(e,g).
parent(e,h).
parent(f,h).
parent(g,o).
parent(i,k).
parent(i,l).
parent(j,k).
parent(j,l).

 

规则:建立婚姻关系

 

% married
married(a,b).
married(c,d).
married(i,j).
married(e,f).
married(o,p).

 

通过上面的代码,我们就让这个家族关系的事实和基本规则建立完成了。

 

3. 推理计算

 

接下来,我们就可以进行关系的计算了。我们只需要提出问题,让程序自动实现推理计算的过程。

 

首先需要打开prolog运行环境,然后加载刚写的family.pl脚本文件。

 

# 启动 prolog运行环境
~ swipl
# 设置工作路径
?- cd("c:/work/prolog/02 family/").
true.
# 加载脚本
?- [family].
true.

 

问题1:a是谁的家长

 

?- parent(a,Who).
Who = d ;
Who = j.

 

a是我们之前定义好的常量,Who是变量,用Who表达结果。得出a是d和j的家长。

 

问题2:d是谁的孩子

 

?- parent(Who,d).
Who = a ;
Who = b.

 

通过家长的反向规则,可计算出孩子。

 

我们可以新建一个规则:建立孩子关系,家长关系的反向关系。

 

child(X,Y) :- parent(Y,X).

 

重新加载family.pl文件再运行。

 

?- child(d,Who).
Who = a ;
Who = b.

 

问题3:g的爸爸是谁?

 

需要满足2个条件,是g的家长,同时是男性。

 

?- parent(X,g),male(X).
X = d .

 

我们可以新建一个规则:建立父子关系和母子关系。

 

% mother, father
mother(X,Y) :- parent(X,Y),female(X).
father(X,Y) :- parent(X,Y),male(X).

 

g的爸爸和g的妈妈。

 

% g的爸爸
?- father(Who,g).
Who = d .
% g的妈妈
?- mother(Who,g).
Who = e.

 

问题4:e和f结婚了吗?

 

结婚是一个双方关系,需要计算e和f是否结婚,同时还需要判断f和e是否结婚。

 

?- married(e,f).
true.
?-  married(f,e).
false.

 

我们需要建立f和e的新规则:建立双向的婚姻关系。

 

% 建立双向的婚姻关系
married(X,Y) :-  married(Y,X).

 

重新加载后,计算f和e的婚姻规则。

 

?- married(f,e).
true .

 

问题5:谁是亲姐妹,谁是亲兄弟

 

谁是亲姐妹,设X和Y是亲姐妹,Z是X和Y的家长,X和Y都是女性,X不是Y。

 

?- parent(Z,X),parent(Z,Y),female(X),female(Y), \+ X=Y.
Z = d,
X = m,
Y = g ;
Z = d,
X = g,
Y = m ;
false.

 

计算得出X=m和Y=g是亲姐妹,她们的家长是Z=d。

 

那幺,谁是亲兄弟?设X和Y是亲兄弟,Z是X和Y的家长,X和Y都是男性,X不是Y。

 

?- parent(Z,X),parent(Z,Y),male(X),male(Y), \+ X=Y.
Z = a,
X = d,
Y = j ;
Z = a,
X = j,
Y = d ;
false.

 

计算得出X=d和Y=j是亲兄弟,她们的家长是Z=a。

 

新加新规则:建立兄弟和姐妹的关心。

 

sister(X,Y) :- parent(Z,X),parent(Z,Y),female(X),female(Y), \+ X=Y.
brother(X,Y) :- parent(Z,X),parent(Z,Y),male(X),male(Y), \+ X=Y.

 

问题6:祖父母,姥姥姥爷,爷爷奶奶

 

在英语里祖父母似乎是不分的,都叫grandparent,而在汉语里妈妈的父母是姥姥和姥爷,爸爸的父母是爷爷和奶奶,规则有所不同。

 

直接新规则:

 

% grandparent
grandparent(X,Y) :- parent(X,Z),parent(Z,Y).
% yeye,nainai
yeye_nainai(Y,X) :- father(Z,X),parent(Y,Z).
% laolao,laoye
laolao_laoye(Y,X) :- mother(Z,X),parent(Y,Z).

 

重新加载程序:o的祖父母是谁?

 

?- grandparent(Y,o).
Y = d ;
Y = e ;
false.

 

o的姥姥和姥爷是谁?

 

?- laolao_laoye(Y,o). 
Y = d ;
Y = e.

 

n的爷爷和奶奶是谁?

 

?- yeye_nainai(Y,n).
Y = a ;
Y = b.

 

其实,可以找的关系还有很多,比如表兄妹,姑姑,婶婶,舅舅,姨夫等,同时我们也可以增加其他维度的内容,比如同在一所大学,谁与谁曾经结婚又离婚了,孩子谁在抚养等多种逻辑上复杂的问题。

 

本文的完整代码,可以在github上找到: https://github.com/bsspirit/prolog-learning/tree/main/02 family

 

同样,本文还是对于prolog的初探,进行逻辑推理,从浅入入深的过程,希望本文能让所有的prolog新手快速上手。

Be First to Comment

发表评论

邮箱地址不会被公开。 必填项已用*标注