热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Eresye制作的专家系统(玩具演示用)

Erlang麾下有一群“大将”,其中一员便是Eresye,专司“专家系统引擎”。Eresye统帅一支轻骑兵,装备精良,武艺高强。Eresye导出的内建函数,仅仅10个左右,能以极快速

Erlang麾下有一群“大将”,其中一员便是Eresye,专司“专家系统引擎”。

Eresye统帅一支轻骑兵,装备精良,武艺高强。

Eresye导出的内建函数,仅仅10个左右,能以极快速度搭建起专家系统的框架,并凭借Rete算法的优势,使系统高速运行。

最近,领教了Eresye的强大威力,得把感受记下来。一来作个总结,二来想看看是不是真弄明白了。一直以为,明白的标志,一是能把复杂的问题简单说清,二是要白纸黑字用笔来说。

用Eresye做了个专家系统模型,虽然十分简陋,属于玩具演示类,没有实用价值,但从中可见Eresye的工作原理和强大功能。

这个系统模拟著作权专家,对作品是否享有著作权,给出咨询判断。系统由推理机、知识库、推理规则构成。推理机是Eresye内建的,拿来用便可;知识库是断言式的事实集合,源自中国《著作权法》的条文规定;推理规则,用以根据事实知识和用户的回答,得出结论。

这里说的,没有学术理论。编程这事儿,其实无需太多理论,除非要唬人吓已。说编程的事儿,最好直接用程序代码。下面是玩具源码。

%

% c_f_2.erl

%

-module (c_f_2).

-export ([start/0,

determine_legal/2,

        determine_applicable1/4,

determine_applicable2/4,

determine_applicable3/4,

        determine_works1/4,

determine_works2/4,

determine_works3/4,

determine_works4/4,

determine_works5/4,

determine_works6/4,

no_copyright/2

]).

ask_yn (Prompt) ->

  P = Prompt ++"( y / n ): ",

  [Response | _] = io:get_line (P),

  case Response of

    $y -> true;

    _ -> false

  end.

%%%%%%% 知识(事实)库

add_works(Engine) ->

  eresye:assert(Engine,{works,1,"音乐、戏剧、曲艺、舞蹈、杂技艺术作品"}),

  eresye:assert(Engine,{works,2,"美术、建筑作品"}),

  eresye:assert(Engine,{works,3,"摄影作品"}),

  eresye:assert(Engine,{works,4,"电影作品和以类似摄制电影的方法创作的作品"}),

  eresye:assert(Engine,{works,5,"工程设计图、产品设计图、地图、示意图等图形作品和模型作品"}),

  eresye:assert(Engine,{works,6,"计算机软件"}).

add_not_applicable(Engine) ->

  eresye:assert(Engine,{not_applicable,1,"法律、法规,国家机关的决议、决定、命令和其他具有立法、行政、司法性质的文件,及其官方正式译文"}),

  eresye:assert(Engine,{not_applicable,2,"时事新闻"}),

  eresye:assert(Engine,{not_applicable,3,"历法、通用数表、通用表格和公式"}).

%%%%%% 推理规则

determine_legal(Engine,{start,Pid}) ->

  add_not_applicable(Engine),

  add_works(Engine),

  case ask_yn ("/n作品属于:依法禁止出版、传播的作品吗?") of

    true ->

      io:format("~n结论:非法作品,没有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    false ->

      eresye:assert(Engine,{legal,ok})

  end.

determine_applicable1(Engine,{start,Pid},{legal,ok},{not_applicable,1,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品没有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

  end.

determine_applicable2(Engine,{start,Pid},{legal,ok},{not_applicable,2,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品没有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

determine_applicable3(Engine,{start,Pid},{legal,ok},{not_applicable,3,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品没有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

determine_works1(Engine,{start,Pid},{legal,ok},{works,1,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

determine_works2(Engine,{start,Pid},{legal,ok},{works,2,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

determine_works3(Engine,{start,Pid},{legal,ok},{works,3,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

determine_works4(Engine,{start,Pid},{legal,ok},{works,4,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

determine_works5(Engine,{start,Pid},{legal,ok},{works,5,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

determine_works6(Engine,{start,Pid},{legal,ok},{works,6,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

no_copyright(Engine,{start,Pid}) ->

  eresye:retract(Engine,{start,Pid}),

  io:format("~n结论:作品没有著作权~n"),

  Pid ! ok.

%%%% 程序启动和停止

start () ->

  io:format("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%~n"),

  io:format("%%                                    %%~n"),

  io:format("%%        判断作品是否有著作权        %%~n"),

  io:format("%%                                    %%~n"),

  io:format("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%~n~n"),

  eresye:start (c_f_2),

  [eresye:add_rule (c_f_2, {?MODULE, X},10) ||

    X <- [

determine_legal,

        determine_applicable1,

determine_applicable2,

determine_applicable3

]],

  [eresye:add_rule (c_f_2, {?MODULE, X},0) ||

    X <- [

determine_works1,

determine_works2,

determine_works3,

determine_works4,

determine_works5,

determine_works6

]],

  eresye:add_rule (c_f_2, {?MODULE, no_copyright},-10),

  eresye:assert (c_f_2, {start, self ()}),

  receive

    _ -> ok

  end,

  io:format("~n~n…… 咨询结束 ……~n"),

  eresye:stop (c_f_2).

下面,做些解说。

一、模块名字c_f_2是指:copyright_forward_chaing_version_2,意思是著作权专家系统,使用前向推理方式的第2版。

二、导出模块:-export ([start/0,……]). 必须写全推理规则函数,否则编译时通不过。

三、知识库和推理规则函数的第一个参数,必须是变量,代表推理机名称,否则运行时出错,如:

add_not_applicable(Engine) ->

  eresye:assert(Engine,{not_applicable,1,"法律、法规,国家机关的决议、决定、命令和其他具有立法、行政、司法性质的文件,及其官方正式译文"}),

……

四、系统的启动和停止

1、eresye:start (c_f_2),进程开启,参数是模块名字;

2、eresye:add_rule(……),把规则加入推理机中;

3、eresye:assert(……),把知识(事实)加入推理机中;

4、receive

    _ -> ok

   end, 相当于可终止的loop,终止的条件是进程发来信号;

5、eresye:stop (c_f_2).进程停止,参数是模块名字;

五、推理机运行机制

专家系统操作任务,在规则体中进行;运行规则首先需要将其激活,激活的条件是规则首部的模式全部匹配。例如:

determine_works6(Engine,{start,Pid},{legal,ok},{works,6,A}) ->

  case ask_yn(A) of

    true ->

      io:format("~n结论:作品有著作权~n"),

      eresye:retract(Engine,{start,Pid}),

      Pid ! ok;

    _ -> ok

    end.

要激活这条规则,使其执行,必须先给出三个事实断言{start,Pid},{legal,ok},{works,6,A}。

也就是说,当程序eresye:assert了这三个事实后,它们就进入知识库,推理机便自动激活这条规则。

eresye:assert(……)的任务目的,就是为了激活规则。

本系统规则激活的首要条件,是函数start()中的eresye:assert (c_f_2, {start, self ()}),在此断言之后,推理机开始运行,第一个激活的规则是determine_legal(Engine,{start,Pid})。

在激活的规则执行过程中,又有新的事实断言出现,于是,会有其他规则激活执行。

这种以事实数据(前提)导向的推理方式,叫做“前向链推理”、“正向推理”等。

六、对规则激活顺序的控制

如果事实断言同时激活多个规则,而规则执行必须先后有序时,可以预设规则执行的优先级,以作控制。如函数start()中的:

eresye:add_rule (c_f_2, {?MODULE, X},10),规定规则X的优先级为10。优先级高的规则先激活执行。

七、eresye:retract(……)的重要作用

本系统终止运行,要在规则中执行语句 Pid ! ok 

在本例中,这样做了以后,程序并未正常终止,出现一些规则继续激活的异常。这个问题,并非本例程编写有误,而是eresye特点所致。

本例用eresye:retract(Engine,{start,Pid}),消除了各规则激活所需的首要条件,解决了问题。

八、如何做实用化改造

我觉得,正向推理方式不如反向推理,后者是Prolog内建的,其实用性、控制性、扩展性、应用领域、代码规模等优于前者。

其实,在Eresye上我实现的第一个专家系统模型,就是反向推理的。它是对Prolog推理机的模拟。

 


推荐阅读
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
author-avatar
U友48805799
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有