Control 版 (精华区)
发信人: dagam (断情), 信区: Control
标 题: [转载]专家系统[2]
发信站: 哈工大紫丁香 (2001年07月01日11:48:29 星期天), 站内信件
更加复杂的规则
要识别加拿大鹅就需要比较复杂的规则。因为加拿大鹅夏天在加拿大度过,而冬天在美
国度过。
我们在识别的时候需要知道是在什么地方,什么时候看到这种鸟的。在此我们仅需要加
入两个规则来描述它就行了。
bird(canada_goose):-
family(goose),
season(winter),
country(united_states),
head(black),
cheek(white).
bird(canada_goose):-
family(goose),
season(summer),
country(canada),
head(black),
cheek(white).
我们再加入一些关于地方的谓词:
country(united_states):-
region(mid_west).
country(united_states):-
region(south_west).
country(united_states):-
region(north_west).
country(united_states):-
region(mid_atlantic).
country(canada):- province(ontario).
country(canada):- province(quebec).
region(new_england):-
state(X), member(X, [massachusetts, vermont, ....]).
region(south_east):- state(X), member(X, [florida, mississippi, ....]).
还有许多需要多个规则的鸟类。例如雄野鸭的头是绿色的,而 埔把际 杂褐色的。
bird(mallard):- family(duck), voice(quack), head(green). bird(mallard):- fam
ily(duck), voice(quack), color(mottled_brown).
好了,作为一个例子,我们的关于鸟类的知识够多的了。只要你手上有一本这方面的专
业书籍,你应该很容易的把书上的知识翻译成prolog的规则吧。
用户界面
前面我们一直是使用prolog的事实来储存有关用户掌握的信息,作为一个真正的专家系
统,系统应该主动的向用户提问以收集信息,
而不是让用户自己把所有的信息手工输入。
所以这里当我们遇到需要向用户收集信息的时候,就应该向用户提出问题。
前面的有关鸟的属性都是需要从用户那里获得的信息。所以我们就把他们改写成下面这
种规则:
eats(X):- ask(eats, X).
feet(X):- ask(feet, X).
wings(X):- ask(wings, X).
neck(X):- ask(neck, X).
color(X):- ask(color, X).
ask(Attr, Val):- write(Attr:Val), write('? '), read(yes).
有了上面的这些规则,当系统需要寻找color(white)这个目标的时候,他就会调用ask规
则,如果ask(color,white)目标成立的话,那么color(white)就成功了。
ask/2中的最后一个目标read(yes),只有当用户输入yes的时候才成功,而用户输入别的
东西都会是失败。
现在我们不需要事先添加用户信息就可以运行了,系统会在需要的时候对用户进行询问
。下面是一次对话的例子:
?- bird(X).
nostrils : external_tubular? yes.
live : at_sea? yes.
bill : hooked? yes.
size : large? yes.
wings : long_narrow? yes.
color : white? yes.
X = laysan_albatross
这里还有一个问题,如果用户最后一个问题回答no的话,那么bird(laysan_albatross)
规则就会失败,然后回溯,将会测试下一个规则bird(black_footed_albatross),
它的第一个子目标又会引起系统询问一些以前曾经询问过的问题。这的确是个比较笨的
系统,下面我们将介绍如何保存询问的信息,以免重复询问。
记住答案
我们使用新的谓词known/3来记住用户对问题的回答。这个谓词的子句不是直接写在程序
中的,而是通过assert动态的加入到系统中的,这也就是专家系统的工作空间working
storage。
每次调用ask谓词要做的第一件事情,就是检查known谓词是否已经保存了这个问题的信
息。
如果还没有保存过这样的问题的信息,就会在用户回答以后,把回答的答案加入到系统
中。known/3的三个参数分别是yes/no,属性,属性值。 新版本的ask谓词如下:
ask(A, V):-
known(yes, A, V), % 如果这个问题已经有答案yes,那么ask目标就成功。
!. % 不需要考察其它的ask子句。
ask(A, V):-
known(_, A, V), % 如果答案是no,ask目标就失败。
!, fail.
ask(A, V):-
write(A:V), % 询问用户
write('? : '),
read(Y), % 得到答案
asserta(known(Y, A, V)), % 把答案记录下来。
Y == yes. % 判断用户的回答。
具有多值的回答
我们还可以对known谓词进行改进。到目前为止,ask谓词所询问的问题都是是非问题。
这意味着用户可能会对color-white和color-black这样的问题同时回答yes,这显然是不
合理的,
当系统知道color-white是真的时候,就应该同时知道color-black是假。这就是说colo
r属性只
能是单值的,不过对于voice这样的属性就可以多值的。所以我们在专家系统中应该对这
些属性进行说明。
我们使用最简单的方法来解决这个问题---加一个用来描述属性的谓词。
multivalued(voice).
multivalued(feed).
这两个句子说明voice和feed属性可以是多值的。
同时我们需要对ask谓词进行修改:
ask(A, V):-
not multivalued(A),
known(yes, A, V2),
V \== V2, !, fail.
我们添加上面一条ask子句,它应该放在其他ask子句之前。这个子句首先检查属性A是否
同时我们需要对ask谓词进行修改: 从不喜欢光光一个,可惜偏偏光光一个
ask(A, V):-
not multivalued(A),
known(yes, A, V2),
V \== V2, !, fail.
我们添加上面一条ask子句,它应该放在其他ask子句之前。这个子句首先检查属性A是否
为多值属性,
如果不是,就在已知的属性值中查找是否已经有其他的值, 如果有的话,就不需要询问
用户,而直接失败了。
例如,如果用户已经对size-large这个问题回答了yes,系统就不会询问size-small这样
的问题了。
(原文转自“垂钓听竹轩”)
--
--
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: heart.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:4.002毫秒