• 2009-04-24

    CLIPS中文用户手册(19) - [日志纪事]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://penning.blogbus.com/logs/38444182.html

    效率问题

    CLIPS是基于规则的语言,使用了高效的模式匹配算法,即Rete算法,该算法是由卡内基-梅隆大学的Charles Forgy和他的OPS团队设计出来的。Rete在拉丁语中是网(net)的意思,用来描述模式匹配过程中的软件结构。

    很难给出一个精确的规则能够总是促进在Rete算法下程序运行的效率。然而,下面的几点可以作为有所帮助的一般指南:

    1.将最明确的模式放在规则首位。无界变量和通配符的模式应该放在规则模式的后面。一个控制事实应该放在模式的最前面。

    2.较少匹配事实的模式应该先行以减小部分匹配。

    3.经常被撤销和声明的模式,不稳定模式(volatile patterns),应该放在模式列表的最后。

    如你所见,这个指南有潜在的对立。一个非明确的模式可能只有少数的匹配(参见12),那么它应该怎么归类?以上的指南都是以减少一个推理引擎循环内部分匹配的变化为目的的。这也许要求程序员花更多的心思在监视部分匹配上。一个简单易行的办法是买一台更快的电脑,或更换一个加速主板。这在电脑硬件的价格一路下滑,人力价值一路飙升的今天,听起来很具吸引力。因为CLIPS具有可移植性,那么在一台机器上能运行的代码应该同样能在另一台机器上运行无恙。

    其他特性

    条件检验元素(test conditional element)通过比较LHS中的数字,变量和字符串提供了一个非常有用的方法。(test)被作为一个模式用在LHS中。只有当(test)与其他模式一起满足时,规则才能被触发。

    CLIPS提供了许多预定义函数,如下表所示:

     

    Predefined Functions

        逻辑                             算术

    not         Boolean not                      /  除法

    and         Boolean and                      *  乘法

    or          Boolean or                       +  加法

               

                比较

    eq          等于(任何类型)。比较类型和大小

    neq         不等于(任何类型)

    =           等于(数字类型)。比较大小

    <>          不等于(数字类型)

    >=          大于等于

    >           大于

    <=          小于等于

    <           小于

     

    以上所有的比较函数除了“eq”和“neq”,在被用于比较一个数字与一个非数字的时候都会提示错误信息。如果类型不能预知,那么就可以用“eq”和“neq”了。eq函数检查比较参数的大小和类型,而“=”函数仅检查比较数值型参数的大小,而与数字是否为整型还是浮点型无关。

    CLIPS的逻辑函数(logical functions)and,ornot。他们可以被当作布尔型函数使用在表达式中。CLIPS中,真和假由符号TRUEFALSE表示。注意在CLIPS中,必须用大写来表示逻辑值。

    除了以上预定义的函数外,你还可以在CAda或其他程序语言中写外部函数(external functions)或用户自定义函数(userdefine functions),然后链接到CLIPS中来。这些外部函数被用来作为任意的预定义函数使用。

    CLIPS同时还有在LHS中指定确定的与条件元素(and conditional element),或条件元素(or conditional element)和非条件元素(not conditional element)。使用“not”条件元素指定LHS中缺损的事实。

    改变信息以符合实际,被称之为正确性保持(truth maintenance)。也就是说,我们试图保持我们的心情以包容真实的信息,为的是减少与真实世界的冲突。

    当人类能相当简单的做这些的时候(熟能生巧),对电脑来说却很难,这是因为计算机不能正常的得知哪个模式实体逻辑依赖(logically dependent)另一个模式实体。CLIPS还支持正确性保持特性,该特性将在内部标记出哪些模式实体是依赖与另一些模式实体的。如果那些模式实体被撤销了,CLIPS会自动撤销这种逻辑依存。逻辑条件元素(logical conditional element)使用关键字logical包含模式,表明模式匹配实体提供RHS中声明以逻辑支持(logical support)

    虽然逻辑支持为声明服务,但是它不能重新声明撤销事实。按道理讲,如果由于错误的信息而使你丢失了某些东西,你将不能再找回来了(就像是在你的股票经纪人劝说下损失钱财一样)

    CLIPS有两个函数用来协助逻辑支持。一是相关函数(dependencies function),该函数列出了所有的部分匹配,这些匹配来自模式实体接收到逻辑支持,或根本没有支持。第二个逻辑函数是从属函数(dependents),该函数列出了所有的模式实体,这些模式实体从另一模式实体中接收逻辑支持。

    连接约束为“&”,“|”和“~”。另一种字段约束被称之为谓词约束(predicate constraint),它通常被用在对复杂字段的模式匹配当中。谓词约束的目的是依据布尔表达式的结果来约束字段。如果布尔返回值为FALSE,那么约束不被满足且模式匹配失败。你将会发现谓词约束在数字模式中非常有用。

    谓词函数(predicate function)用来返回FALSE或一个非假值(non-FALSE)。谓词函数后面跟着冒号“:”被称之为谓词约束。“:”的优先级高于“&”,“|”或“~”,如写在一起的模式(fact : > 2 1))。与“与约束&”的典型使用为“&:”。

     

    谓词函数              核查参数

    (evenp <arg>)         正好是数字

    (float <arg>)         浮点型数字

    (integerp <arg>)      整型

    (lexemep <arg>)       字符或字符串

    (numberp <arg>)       浮点型或整型

    (oddp <arg>)          奇数

    (pointerp <arg>)      外部地址

    (sequencep <arg>)     多字段值

    (stringp <arg>)       字符串

    (symbolp <arg>)       字符

     

    专家系统中非常方便的获取全局值,有多种情形。举例而言,重新定义通用常量如π是不必要的。CLIPS提供自定义全局常量(defglobal construct),这样这些值就会被所有规则广泛知道。

    另一个非常有用的函数是随机数字。CLIPS有随机函数(random function),用来返回随机整型值。CLIPS的随机数字函数实际上返回的是伪随机(pseudorandom)数字,这意味着实际上并不是真正的随机,而是由一个数学公式产生出来的。伪随机数字能满足多数目的,CLIPS的随机函数使用的是ANSI Crand库函数,该函数可能在不支持它的电脑系统上无效。关于更多的信息,可参看CLIPS参考指南。

    除了控制事实以控制程序的执行外,CLIPS提供了一个更直接的控制事实的方式,那就是显式的声明规则的权值。使用权值进行显式声明的一个问题是当你从一开始用CLIPS时就在连续程序中过度使用权值,过度的使用将会达不到使用基于规则语言的目的,基于规则的语言提供的是通过规则应用最好表达的自然手段。同样的道理,对于强导向应用,程序语言是最好的,对于描述对象来说,对象导向语言是最好的。CLIPS有一个关键词为声明权值(declare salience),被用在声明规则的优先级别上。

    权值被设置在一个数字范围,最低为-10000,最高为10000。如果一个规则没有被程序员显式的声明权值,CLIPS自动设置其值为0。权值0介于最大与最小值之间。权值为0并不意味着规则没有权值,相反,它有一个中间的优先级。

    CLIPS提供一些过程程序设计结构,这些结构可以用在RHS中。这些结构是whileif then els,这些同样可以在其他语言如AdaCJava中找到。

    另一个与(while)有关的有用函数是break,它结束(while)循环的当前执行。return函数立即结束当前执行的自定义函数,类属函数,方法或消息句柄。

    任何函数都可以从RHS中调用,这大大增强了CLIPS的功能。另一些CLIPS函数在返回数字,字符或字符串中很有效。这些函数可以用在它们的返回值或他们的副作用(side-effects)中。一个仅使用副作用的例子是(printout),由它返回的值都是没有意义的。(printout)的重要性在它的输出的副作用上。通常情况下,如果要到达你期望的效果,函数都会有嵌套的参数的。

    文件的读写访问之前,必须使用open函数来打开它。一次打开文件的个数取决于你的操作系统和硬件情况。当你不再访问一个文件的时候,你应该使用close函数去关闭它。除非文件是关闭的,不能保证写入它的文件将会被保存。

    CLIPS通过逻辑名(logical name)来识别一个文件。逻辑名是一个全局名,可以被CLIPS在所有的规则中访问。尽管逻辑名可以与文件名是相同的,但你最好使用不同的。逻辑名的另一个好处是你将很方便的替代一个不同的文件名,而不需要做主程序的修改。

    从文件中读取数据的函数是前面介绍的(read)(readline)。唯一你需要做的是必须制定文件名,作为这两个函数的参数。

    使用(read)读取多个字段,必须使用循环(loop)。即使是使用(readline),在读取多行字段的时候也是必需的。使用while-loop循环可以通过一个规则而连续触发。循环不能用来读文件或操作系统的末端,会出现错误信息。为了防止这个问题,在如果你尝试读入文件的末端时,CLIPS会返回一个EOF字符字段。

    评价函数(evaluation)---eval,被用来评估任意的字符串或字符,除了自定义类型结构,如defruledeffacts等,像在顶端输入一样。build函数用于自定义类型结构,是eval函数的补充。build函数评估字符串和字符就像被在顶端输入一样,如果参数符合自定义类型结构如deffruledeffacts等,则返回TRUE


    历史上的今天:

    花床 2007-04-24

    收藏到:Del.icio.us