基于Java和Amzi! Prolog混合编程的辅助训练专家系统
2019-03-21张鹏海旺堆次仁
张鹏海, 毕 璐, 刘 斌, 旺堆次仁
(1.西藏民族大学院体育学院, 陕西 咸阳 712082; 2.陕西科技大学电气与信息工程学院, 陕西 西安 710021; 3.拉萨市北京中学, 拉萨 850000)
0 引 言
运动员的比赛成绩受多方面的因素影响,比如赛场的情况、天气环境、比赛期间的饮食、运动员赛前的心理状态等[1],如果遇到这类不确定的问题,除了需要运动员有良好的适应力和应变力,能迅速给运动员提供教练员的知识经验和处理方法则是首要选项。运动员训练专家系统就是把教练员的处理方案和涉及运动员选拔和训练的知识经验在计算机上建立一个知识经验数据库,使用Java语言进行系统前端用户界面的开发,使用Prolog逻辑编程语言构建辅助训练专家系统,该系统在给定环境模式进过简洁准确推理,即可得到待解决问题的专家建议或者训练计划安排[2]。
1 知识库的建立
专家系统知识库的建立首先需要大量收集运动员教练时的比赛和训练经验,然后把这类文字性知识经验进行分类整理,按照逻辑总体分为三个模块,每个模块根据教练的经验知识划分为3-6个不同方面的考察点[3],最后得到一个树状逻辑结构图(如图1),为了保证知识结构化的细化和深入,以及知识经验的充实性,要能判断每个模块的子模块是否可以再分。最后将总结好的知识经验存入到计算机的数据库中以备调用[4-5]。
运动员选拔模块主要根据身体形态和生理机能的各种指标对运动员进行择优培养,达到最初运动员就占有一定身体优势的目的。运动员训练计划安排模块是知识介绍性的模块,根据运动员的生理机能指标,专家系统就会给出详细而准确的训练计划安排,将运动员的身体机能指标训练到最佳状态。训练和比赛中的故障排除的主要任务是根据训练和比赛过程中可能出现的特殊状况给出解决方案,比如赛场的情况、天气环境、比赛期间的饮食、运动员赛前的心理状态等[6]。
以知识库的第三个模块-训练和比赛中的故障排除为例,使用判断树来描述这个功能模块的处理过程,其基本思路是:从问题出发,列出所有可能影响训练和比赛的因素,主要通过用户来选择产生问题的原因,然后显示出专家给出的解决方案。这种方法直观、方便的表现出了知识库的逻辑[7]。
图1 运动员训练专家系统树状逻辑结构图
2 判断树的实现
判断树是一种自顶向下的判断方法。通常判断树这种树形结构有三种不同的树枝节:①决策结点:主要作用就是判断决策的走向,本系统在运动员选拔模块所用的是二叉判断树,因此只有两种决策分支。②状态结点:每个结点代表一种解决方案,通过对各个状态结点的对比选择出所属问题的最佳解决方案。③结果结点:也就是决策树从根结点延伸到最后的叶子结点,也叫决策结果,这个结点可以清楚的看出该模型有多少个类别[8],存储的内容是专家提供的解决方案或运动员训练计划。按照判断树的这种层次结构模型建立了如图2所示的“运动员选拔”判断树。
通常使用判断树进行推理时,主要是通过用户交互界面向用户提问来收集信息,然后根据用户点击的答案按钮确定判断树的分支,这样随着分支的深入,直到叶子结点止,也就是专家系统给出的最终解决方案或建议。在用户界面中,使用单选按钮为用户选择答案提供显示,并用文本框控件来显示最后的解决方案或运动员训练计划。充分使用Prolog程序的搜索和匹配功能,对所建立的知识库进行动态加载,结合Java语言生成选择按钮和显示最后的解决方案或运动员训练计划[9]。
图2 判断树的一个分支
在判断树中,不但要记录每个结点所存储的数据内容,而且还要记录结点之间的关系和结点之间转移的条件。在结点中所存储的数据内容一般是中文字符串的形式,但是系统使用的Amzi! Prolog编程环境不支持中文,改进方式为使用MySQL数据库来存储这些结点中需要显示的中文字符串和结点名,需要注意的是每个结点命名也必须是英文字符串,将结点名当做事实语句的参数和查询条件来查询结点中所存储的中文字符串[10]。
以下为系统定义的三个基本事实:
Contain事实:定义为父结点和子结点之间的关系,包含两种参数,一个代表父结点,另一个表示父结点下的所有子结点,是一个列表类型。列表中的数据具体表现为运动员的选拔标准:“体重超重或不足、身高超高或不足、体重/身高×1000、下肢长/身高×100”择优录取这四种情况。用Prolog的事实表示就是:“contain(不达标的原因是什么,[体重超重或不足、身高超高或不足、体重/身高×1000、下肢长/身高×100择优录取])。”。
connect事实:定义父结点与其子结点间的动态联系,包含三个参数,参数一表示父结点本身,参数二代表用户的选择,是用户自己输入关键词或点击按钮,参数三表示在用户的输入下会由父结点转到的子结点,用Prolog的事实表示就是:“connect(不达标的原因是什么,ans1,体重超重或不足)。”,具体在运动员选拔模块实现的流程是:如果运动员的身体形态不达标,系统会提问“不达标的原因是什么?”,此时用户输入ans1或点击解决方案按钮,当前结点会转到“体重超重或不足”结点。
end事实:表示最终的叶子结点,用Prolog的事实表示就是:“end(解决方案1)。”,也就是代表:“解决方案1”是一个叶子结点。
3 Java与Prolog混合编程
该运动员训练专家系统的程序设计使用的是Java语言和Prolog逻辑编程语言混合编程,充分利用了各自语言的优点。因Java语言特有的代码简单、平台无关性、解释性等优点,所以选择使用Java语言进行前端的用户交互界面程序设计[11]。Prolog语言在逻辑推理上具有代码可读性强、实现的推理功能丰富、易移植等优点,近乎用自然语言的方式描述了各种逻辑推理运算,使得程序更简单,占用内存更小,是开发专家系统这一人工智能程序的最常用工具,选择使用Prolog程序设计语言进行专家系统推理机制的程序设计。将Java和Prolog这两大开发语言的优势充分结合起来,各显其能,使程序更严谨整洁,缩短开发周期,可实现运动员训练专家系统的开发[12]。
3.1 Java与Amzi! Prolog的编程接口
Amzi! Prolog不仅为Java(通过Java Servlets)和许多其他工具提供了插件,而且提供了基于规则的服务。Amzi! Prolog+逻辑服务器(Logic Server)可以将基于规则的组件与Windows和其他应用程序集成在一起[13]。集成是通过“逻辑服务器API(Logic Server API)”实现的,它可以像访问数据库一样轻松地访问规则的逻辑库。其结果是一个可管理且行为良好的接口,使得在需要的任何地方都可以运用基于规则的编程。
Amzi!Prolog提供了Java与Prolog程序的编程接口。它包含一个封装了Prolog引擎及其API的主要LogicServer类和一个用于错误处理的LSException类[14]。它们都包含在一个Java包中,'amzi.ls',如图3所示。
图3 Java package包封装图
3.2 专家系统用户交互界面的生成
专家系统给出的内容都是判断树的结点中包含的信息,通过Prolog设计的基于规则和事实的推理程序进行搜索匹配,当匹配到对应结点中的内容,会将结点所包含的内容动态加载到Java的窗体中[15]。在专家系统的用户交互界面中显示专家提问、解决方案、运动员训练计划等内容即是采用了这种模式匹配和动态加载,在充分利用了各自语言的优点的基础上,Prolog程序采用自然语言表达那些适用于计算机规则的复杂的不精确的语言,应用于基于事实和推论的知识库,用Java程序直接控制用户界面的显示(见图4)。
(1)Java的程序设计。
① 新建一个Java工程。
② 在主窗体中放入JRadioButton控件,用来显示根结点内容;设置文本框控件,其内容为接收专家知识提问内容;为窗体增加控制进程的按钮,提供进行“下一步”的选项。
③ 初始化Prolog程序,加载Prolog生成的.xpl文件,调用特定的对象方法初始化Logic Server,初始化逻辑服务器的函数是:lsInit,它的定义形式如下:RC lsInit(ENGid cureng, STRptr ininame)。
④ 根据用户已经选择的结点按钮,获得当前的结点的名字,使用Java程序进行访问,通过“下一步”、“上一步”或者“返回”按钮控制程序的进程。其中下一步选项的部分代码及伪代码如下。
//或者所选的结点的内容
Component[] components = choice.getComponents();
next_node_name = jr.getText();
try {
pro_next_node_name = ls.CallStr(“node(Node,Type,”+next_node_name+“,Answer,_)”);
java_next_node_name = ls.GetStrArg(pro_next_node_name, 1);
node_type = ls.GetStrArg(pro_next_node_name, 2);
//ls.AssertzStr(“current_node(”+current_node_name+“)”);
}
//判断结点类型伪代码
if(node_type == 答案结点)
获取答案结点名字,将当前结点设为答案结点;
答案显示区域生成;
从数据库中调取相应答案结点的内容;
else(node_type == 判断结点)
调用next规则,将当前结点设置为所选结点;
获取当前结点的子结点内容;
动态生成当前结点选项内容;
继续选取下一结点。
图4 训练知识节点界面显示
(2)Prolog程序设计。
Prolog程序主要是动态加载当前结点以及当前结点子结点的所包含的内容,通过两种Prolog功能可以完成对列表list的访问。其中list是变量通过模式匹配得到当前list的内容,允许引用列表的第一个元素和剩余的元素列表符号,其中X被绑定成为列表的第一个元素,称为头部,T被绑定到剩余元素的列表中,称为尾部。之后通过show_radiolist()递归获得每个子结点的内容,为之后动态加载选项提供基础内容,具体代码如下。
list_question(X,[H|T]):-%获取列表中的内容
list_question(X,T). %访问列表头部和尾部元素
show_radiolist:- %动态获得每个子结点内容模块
current_node(Node), %加载当前结点
node(Node,_,_,_,List),%访问当前结点列表中的内容
list_question(X,List),%加载当前结点子结点
node(X,decision,Question,_,_),%获取子结点中的内容
write(Question), %写入问题
asserta(store_radio(Question)), %加载列表中第一个子句到数据库
nl,
fail.
3.3 推理机制设计
以图2所示的运动员选拔模块为例,详细介绍使用判断树方法进行推理的过程:设定一个当前结点的位置,我们选择s结点为当前结点,此时专家系统的界面上会显示专家提问:“运动员身体形态是否达标?”和备选答案“不达标的原因是什么?”、“身体机能测评”,若用户选择了“不达标的原因是什么?”,则进入下一个结点s1。用户界面又会显示结点s1所对应的信息备选答案“体重超重或不足”、“身高超高或不足”“体重/身高×1000、下肢长/身高×100择优录取”,这时s1成为新当前结点。在这个推理过程中,专家系统扫描到的当前结点信息需要被记住,并且结点的信息在更新时需要释放之前结点的数据内容。
Prolog程序在运行时的动态控制表现为:解释器会把程序的所有子句存入到系统内存中,但是专家系统扫描到的当前结点信息需要被记录,结点的信息在更新时需要释放之前结点的数据内容。本文中会使用一些谓词来对内存中的子句进行动态控制,主要有:①asserta(X),把第一个子句载入到动态数据库中;②retract(X),从动态数据库中删除子句X,此过程完全不可逆。专家系统对父结点访问结束后需要访问其子结点时,将执行如下代码:
next:-
retract(current_node(_)),%删除当前结点内容
next_node(Node),%获得用户输入的结点
asserta(current_node(Node)),%将下一结点变为当前结点
clear_radio,%删除上一结点子结点内容
if_leaf. %判断是否为答案结点
专家系统显示的内容存储在分支结点和叶子结点中,next谓词可使专家系统对父结点访问结束后转移访问其子结点,实现访问状态的改变。如果当前结点到达了叶子结点,需要进行回溯时,需要判断是否到达了叶子结点,使用cut谓词来判断不同情况,cut谓词的用法和其他程序开发语言中if语句的用法一样。在程序中用“!”来表示。
Prolog语言的查询依赖与模式匹配,查询的模板为目标,如果有某个事实与目标相匹配,查询即为成功,否则为查询失败,使用截断谓词cut,如果系统的事实成功匹配到目标进行回溯时,前面的选择就会被释放,不需要重新考虑,查询就成功了。如图5(A)所示带有cut谓词的程序对查询控制流的影响,每一个方块代表一个目标,目标就是需要查询的内容。当目标进行回溯遇到cut时,控制权发生转移,迅速转移给上一级的目标,而不是其他目标,这样其他目标就会被自动筛选掉,缩短查询时间。图5(B)是对单个目标的端口和控制流程的说明,具体工作流程为:从调用端口(call)进入目标,如果经过目标匹配成功,就进入退出端口(exit),反之进入失败端口(fail),如果用户需要重新查询或者引起回溯,则控制进入重试端口(redo),来重新进入目标。
图5 (A)cut对控制流的影响,(B)goal(目标)的4个端口及控制流程
If_leaf的第一个子句表示获取当前的结点位置,接下来判断是否到达了叶子结点,如果到达叶子结点,则专家系统界面会显示解决方案或运动员的训练计划等内容。下一步就需要使用cut谓词执行截断搜索,阻止回溯。如果第一个子句不满足目标条件,则说明未到达叶子结点,程序会进入到第二个子句,使用了cut后,还需要满足第一个子句在cut之前就被目标排除了这一条件,这种情况下Prolog程序才会考虑第二个子句是否满足目标,从而进行搜索匹配流程。具体程序如下:
if_leaf:-
current_node(Node), %获取当前结点
node(Node,answer,Question,Answer,_), %判断当前结点是否为叶子结点
retract(store_answer(_)), %清空答案列表的内容
asserta(store_answer(Answer)), %插入答案结点
!,
fail.
if_leaf:-
current_node(Node), %获取当前结点
node(Node,decision,Question,_,_), %判断当前结点是否为分支结点
nl,
show_radiolist, % 列出子结点
!,
fail.
4 结 语
本专家系统在大量收集了运动员教练的知识经验的基础上构建专家系统知识库。同时在辅助训练专家系统中引入判断树方案,并采用Prolog和Java混合编程技术来具体实现,用Prolog语言实现判断树的推理机制,Java平台实现动态用户界面的生成,充分发挥了各自程序设计语言的优点,建立的专家系统占用内存小,程序便于修改和扩展,结构整洁灵活,经试验,本系统可以对提出的问题给出专家建议,达到了辅助训练运动员,帮助运动员在比赛中取得优异的成绩的目的,收到了满意的效果。