11

用prolog推理家族关系

 3 years ago
source link: http://blog.fens.me/prolog-family/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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

关于作者:

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

转载请注明出处:

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

FNRNJzm.png!mobile

前言

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

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

目录

  1. 家族关系定义
  2. 用prolog表达家族关系
  3. 推理计算

1. 家族关系定义

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

V3UVBvM.png!mobile

上图注释:

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

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新手快速上手。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK