好,接下来我们看一下, 如何利用logic
programming的方式,来解决问题, 那在logic programming里面,所谓的演算法呢,基本上就分成了,
基本上就分成了,所谓的逻辑演练部分,还有最后的control,这个control就- 是让使用者能够,
比较好控制,等一下我们会看到trace,还有listing,还有看它程式 跑的过程,ok,在一般的programming里面,首先我们第一步就是
先了解问题,然后收集资讯,然后接下来想办法找出solution,那在logic programming这一部分呢,
一开始,所谓了解问题以及搜集资讯,这边是没有很多差别,但是在logic programming里面,一般而言,我们是不需要去
解决,就是不要去找solution,那logic本身,我们上次讲的forward chaining,backward
chaining,和resolution,其实都是logic本身 其实都是logic本身非常正规的解决问题的方法,那这一部分,其实就,ok,不需要-
去做,那 那在ordinary
programming这个部分呢,你就是开始要,这一次就开始写program,那在- 相对于logic programming这边, 在第四步骤,其实是logic
programming最heavy的部分,就是你要设法把information,把- 它写进knowledge base,
那这部分其实就是,也就是说你在了解你的问题之后,利用逻辑的方法, 不管first order或是propositional
logic,然后把它转成知识库,那这部分 非常的有些难度,转成一部分是rule,那一部分是facts,就已知的,
已知的部分,好,那接下来的话,在ordinary programming也是把程式就直接 把程式装在资料上面,那在logic
programming这里要问的是,你想问的一些query,然后接下来 在ordinary programming,你最后就是debunk,那在logic
programming里面,你要找的事所谓的false facts, 就是你的程式如果有什么问题的话,其实它可能会演绎出,推导出一些不正确的事实,
就是因为你可能在,在把问题转化成knowledge,转进knowledge base的时候,有些失真的关系,
好,那我们接下来介绍,整个prolog system,那整个prolog system它跟我们一般所使用的,
我们在这几讲所使用的symbol有点不太一样,刚好反过来,那它这种lower case 用小写来代表constant,那用upper
case来代表未知的变数,只要是大写开头的 都是一个未知的一个variable,那整个program呢,其实就是
整个在prolog里面就是一个definite clause,那definite clause我们有提过,就是你只有一个 one
positive的literal,那你也可以,这是在CNF的讲法,那你也可以把它写- 成imply的情况,
那用implication的写法,就是这些symbol都全是正的,就是这是已知这个- ,而且这个,然后
implies C,好,那这样的话,是一个definite
clause,那在prolog里面的语法呢,所使用的是 写成这个样,我们是习惯上,在prolog里面习惯上是把结论写在前面,
然后把前提写在后面,那这个概念,这边写的是一个,其实是它特有symbol,就是冒号,
冒号,然后再一个减,那这个意思,你如果要翻成英文的话,意思大概你知道是如果,就- 是,ok
得到C这个结论,如果A和B都成立,那A和B的 连接方式就是使用逗点,逗点分别就是它的前提,
之间就是and,那如果我们回想一下,我们之前提的那个western criminal,我们要证明criminal
west 是criminal的,这个knowledge base里面,这整句话讲的就是说,任何人,
任何一个x,它这边因为x是变数嘛,然后我们讲过变数,在这个情况下,是for all, 只要你看到变数,所谓所有的
existence,我们都会用EI把它用scrolling constant去取代掉,所以我们这里看到 全都是for
all,也就是说,任何一个人,他只要是,任何一个人是criminal,只要他是am- erican,
ok,只要他是american,然后某个weapon是west weapon, 然后x把y这个weapon卖给z,而且z跟
美国是敌对的状态,那这边是我的xyz,全都是for all。
好,那这样就成立,那下面这一个就是prolog的写法,这个就是prolog的写法,- 好,那prolog还有一些
常用的一些资料结构,譬如说list,那list来说,我们可以把它拆开,就是你可以说,
这个东西,那中间用一个直线来代替的话,就会把 把一个list拆解成,第一个element和它剩下的东西,
好,那在如果对prolog没有写过的同学,那你们可以试试看
试试看,就是网络上也可以download到几个免费的,一个是gnu prolog,另外一个是swi的prolog,
那这两个其实都可以,那在gnu prolog里面,你可以用的几个指令,包含常用的几个指令,一个是
等一下我们会看到trace,notrace,好,trace和notrace,这两个- 指令是用来
就是debunk的过程,那你如果下trace指令,之后你问的每一个query,它所- 有的步骤,都会一步一步的显现,那notrace
就是把它这个功能关掉,那你也可以打user,那这边需要两边需要中括弧,然后再一个句- 点,那这样的话,它会进入
当场编辑的模式,你可以直接在它的互动状态下, 直接写入程式,那这边还有一个,这边没有列出来,就是包含listing,
好,listing这个指令的话,会把读进来的,就现在 有的程式,把它写出来,现在在这个状况的程式,把它列出来,
好,那prolog的写法有满多种,那我们看一下,像上面这一个的话,是一个一般的- DFS,
一般的DFS,我们如果用prolog,这是概念性的写法,我还没把事实整个写出来,那- 整个概念性的话,
那基本上就是DFSx,那x本身如果是够的话,那当然你第二个phrase就结束,那否- 则的话,
你就去找successor,然后把successor展开,那这两行其实在prolo- g里面,就会把它整个展开,
我们为了,在下面有个例子append,是把两个list粘在一起,
那我们先看一下prolog的一些例子。我们来试着写一个factorial,就是
算阶层的例子好了,好不好,就是我要算n阶是多少,那如果1阶是1,
0阶是1,然后2阶是2,3阶是6,这个程式,因为prolog除了问relation- 以外,我们就看似
怎么用逻辑的方式来写这个程式,那你如果要进入的,进入直接当场写的状态,你是打u- ser,
好,这样,然后一个句点,接下来就进入这个模式, 好,那接下来你可以写程式,那我们就是要定一些东西,因为在prolog的写法,
你就是要定一些predicate,那我们先定什么东西为true,那我们假设,譬如说- 前面的变数
是我想query的,那譬如说,我用f来当作factorial这个概念,那我可以说- ,ok, 0阶好了,是1,
好,那如果是fact或, 不管是fact或rule,你结束都是一个句号,那就代表说,ok,我知道,这个代表说,
f(0,1)为true,它知道这个事是true,这个写法说, 对我们来说,就f反正是一个function,小写都是function,那对prol-
og这个写法来说, 就是等于说我们顶一个proposition,那说p为true, ok,这是一样的事情,那接下来我们要写一般项,就是我们要想的是说,
你如果叫电脑算阶层,好不好,就是你的重点是,你要定义
什么是阶层,对不对,你比如说,那阶层怎么定义呢?你当然可以说从1一直连乘到n, 可这个定义其实并不完备,什么叫连乘,这其实
听起来是很混乱的,那在prolog的写法,通常你要比较 比较用递回定义的方向来思考,也就是说我们定义的0阶为1,
之后呢,n阶怎么算,n阶我不会算,但我知道,n阶的定义就是n乘上n-1阶,
好,概念就是这个样,也就是说,如果我问一个N, 然后F,我就要这个为true的情况下呢,
好,这就是我们的前面先把结论写出来,前面这个为true,那它的前提呢就是,好,因为- 我前面已经写了,
0阶嘛,那我这边先要求n必须大于1, 大于0阶,就可以了,大于0,N大于0,那接下来它有一个
它可以做简单的运算 和unification,它可以去计算,譬如说我要需要N1,它用的key
word是is, 然后N减1,那这个N减1部分它会去做运算,然后设法去找
然后is要求它做unification,使得左边等于右边。
好,这个其实,那看一般在programming很像跟assignment一样,就有- 点像,有点像是assign,但是在 logic
programming的时候,我们不用assignment这个概念,相对的,我们是- 用unification,
右边这边N-1,我们算出来,然后之后is这个东西会要求它去真的运算, 在prolog里面,
就是2-1,它就是2-1,它不会真的把它算成1,但你is,这个kew word
会要求它去真的去做运算,然后之后左右两边会要求做unification,使得2-- 1变1, 那左边那N1就变1,
好,那我把N1算出来以后,接下来就是,N1就是N-1,那接下来我要找一个,我要求p- rolog找一个
f(N1)为true的,那我把它称为F1好了, 是让这个为true,要求它设法去找出这个东西,
那也就是到这一步,我们想像说F1是拿到的结果,
那已经有了F1的情况下,那F呢就是is F1乘上
F1是N-1嘛,所以乘上N,好,这样 那这整个程式其实就是一个factorial的程式,
ok,那我们结束的时候,你要跳出这个模式,让control,如果在windows的- 话就control加d,
就会结束,好,那你如果要知道你刚刚打了些什么呢,你这时候可以用个指令,叫list- ing,
好,listing的时候,就会,prolog就把现在在这个记忆区内所有的
把程式给列出来,那你各位可以看到,就是,其实prolog里面的,它就做一个stan- dardization过程,
我们大家都有听过,就是如果你有两个变数,名字是一样的,那它会做standardiz- ation,用个流水号,前面一个是x1,后面x2,x3等等等。
那它作为一个,我们刚才打的,不管是n还是f,大写的它都是变数,它都把它变数置换成- abcd
这样子往下下去,那这个情况下,可以问,我们接下来可以问prolog的一些,譬如说,
我们问f(0,1),那这就是我们给的事实,那这个东西prolog一定会回答true- ,没有问题,
那接下来你还可以做类似的事,比如说你可以问,比如说,5节是不是120, 好,那如果我们整个程式写的是正确的话,那prolog也会跟立项,
5节是120,那我们当然更希望的就是5节是多少, 那是可以的,prolog所有你只要是大写,你全都是query,
譬如说5,你用个,譬如说W,那只要是大写开头,它就是一个变数,那这个prolog会用 利用其实是backward
chaining的方式,然后做这个东西,120 好,那如果我们要看整个backward
chaining的过程,我们有提过的,那我们就 可以下这个指令trace,就是你下完指令trace以后,之后它会启动trace的机-
制,那之后所有的 你做的动作,它都会一步一步的show出来,那我们再看一次,5节可能跑的有点久,我们-
看一下3街好了, 好,如果我们query (3,W),那答案应该式6嘛,w等于是6,那它会做事情呢,其实就是回去呼叫,
这边可以,大家可以看到,其实就是给一个变数,就是变那底线就等于说 是3号,那里面有它自己的一个work,就会呼叫3,
然后W就换成一个standardization,之后的变数。
然后接下来,因为你的,它会从上,我们做的KB里面由上而下match,它当然这个f3 问好嘛,那当然不match
f,我们第一个是f(0,1) 对不对,当然不match,它就接下来所以它会走第二条路,第二条路它会用,ok,
那第二个式子是n>0,ok,那这边的n就是3,所以它会看,它会呼叫3有没有大于0,
那它里面有inbedding的程式,会跟你说,会回答return 这是true,所以就exit, 那之后呢,就会呼叫,这边就是n1 is
n-1那一行,那n1是n-1,就是120号 也是变数is 3-1,那它会evaluate出2是3-1,
好,这是它inbedding的东西,接下来我们,就是问f这一行就相对应的就是f n1,f1,ok,那会问
2,但是对我们来说,人类来说,赋予的意义就是2节是多少,好了,它接下来要设的
设法去解释,解出145号变数是多少,好,接下来就一样递回的,它就不断的呼叫,那2有- 大于0,然后
然后c是2-1,那是1,好,接下来又问,1是多少,就1节是多少, 那这边我们还没结束,就是继续1>0,然后谁是1-1,
好,0是1-1,接下来它会问你,就是f0节是多少,那这个时候,这KB
还是由上而下match,由上而下match,它会match到给它第一个事实,也就是- 01为初,
我们到0节是1,所以之后,它就会,它这两个就会做unification,那它就会可- 以做出来,
299号变数就是1,好,就是unification,那这时候return回去,ca- ll回去,那接下来就会我们到,我们下面的,
就是f is f1, 乘上n,这一行。
好,那它都记得刚刚那东西,然后就会解出这个,这一号变数,那它就知道了1节也是1,
ok,这是f1,它知道为初,然后之后它会 设法去,就一样,一直return回去,那就1乘2,就是2,那就要2节0,2
直到2乘3,3除5,3节is6,好,那它就知道W是6。
好,那这整个过程中,你只要会trace下文,它就会一直这样做,那你不希望 这个功能继续,你就打no
trace,好,记得要句号。这就是我们讲的 logic
programming里面的control,我这边是我的listing,trac- e和no trace都是这些东西。
所以我们可以看到,就是,可以了解嘛,就是在logic programming里面,
其实我并没有真的去写个演算法,来算出 教电脑怎么算factorial,那我做的事情是跟它讲
factorial定义是什么,那只要你定义定的清楚,那它自然 一个logic
programming,应该里面inbedding的universal的tool,- 其实就是一个backward chaining的,它应该会自然把你的答案拿给你。
好,那它还有很多,有些例子,那我们可以看一下append这个例子,append其实是
prolog又inbedding进去,那我要做的就是把两个例子的连在一起,看一下这- 个例子好了,
那我这边已经有写好的,好,那我这样load进来以后,你可以打listing,然后把- load进来的等式看一下,
我少打一个,listing,好,我们可以看到,那我这边定义,因为a append这个是已经
有定义说,我就用app,那我做的事情就是把前面,就是把前面这个变数跟后面这个变数- 连起来,
那两个括弧当然就是一个空的 空的list,那也就是说,任何一个A,对所有的A来说,你跟空的连在一起,它就是A,
就是把前面两个粘到第三个,那下面第二个就是递回定义了,
就是,如果有个list,它第一个admin是A,然后剩下是B,然后粘上C的话,
那第二个,后面的结果,list也是第一个是A,然后后面是D,那很明显的就是
你这个要为true,那就必须是B和C粘在一起,必须是D嘛。
B和C如果粘起来是D的话,那我前面这个argument的AB粘在一起,跟C粘在一起- ,结果就是
AD的结果。好,大家可以check一下这件事,好, 那如果这样的话,我就可以问一些问题,最基本的query,我还是可以问这样,
1、2、3,譬如说跟 4、5、6,那它是不是1、2、3、4、5、6,
好,那这当然难以选择,然后就会回答yes,然后我们真正想知道的,可能要做的事情- 是这样,
1、2、3、4、5、6你粘起来是什么,那它会,可以跟我讲,粘出来是1、2、3、4、- 5、6, 那我们还是可以看一下,trace一下,让大家熟悉一下,整个backward
chaining做法是怎么样, 好,那我在问这个query的时候,它其实做的就是,
好,它一样,就是把x换成一个standardized变数,然后之后呢,它会 问第二个,就是,因为我不match第一个嘛,第一个rule,我们knowledge
base的话,第一个argument, 比如说是空的,空的list,那它没有嘛,所以我就是match第二个,第二个的话
我把第一个元素拿掉,它问就是2、3跟4、5、6粘是什么样,它还是不知道,所以它会- 继续问,
3跟4、5、6粘是怎么样,这递回的呼叫过程,然后接下来,还是不知道,你就会问空跟4- 、5、6粘的结果是什么,
那这个空跟4、5、6粘的结果,这时候我们match第一个rule,所以结果1是1号- 变数,就是结果就是4、5、6,
这个它是知道的,这就是直接unification,unify处理出来的,那接下来,- 你就可以倒回去,所以3它就知道
递回后3跟4、5、6,结果就3、4、5、6,然后2、3跟4、5、6粘,结果就2、3- 、4、5、6,然后一直回到 最前面为止。