首先提一下。 FeatherskyExpertSystem.DLL是网络上一个不知名的程序。我是用来学习借鉴。所以把它从IL 修改成C#版。然后搞明白方法后,自己又开发自己的版本的。
而且此推理程序1.不是基于数据库,2.前提条件只能2个,结论只能1个。3.多数操作都是在定长的数组中。
并不能解决我要的问题。 不过其借鉴意义和我的搭建和实现思路指导意义功不可没。
连续两天解读,已经搞定。这里发上来,给大家借鉴一下。
原作者如果有意见,请联系我。
下面的代码是最初理解的时候做的注释,不一定正确,新的在我的工作项目中。不再整理了。大家凑活看吧。
规则库实例:
if 市电中断 ^ 停电 then 检查市电;
if 市电正常 then ~ 检查市电;
if 逆变器不工作 then 检测电池电压;
if 停电 ^ 逆变器不工作 then 红色指示灯长亮;
if 电源变压器噪声大 then 市电正常;
if 市电正常 ^ 电源变压器噪声大 then 负载过重;
if 负载过重 then 检查变压器的次级并未发现碰线短路、匝间短路、元器件损坏故障;
这里只是把规则库加载部分的代码贴上来, 推理的模块有点长,影响页面美观
public class ExpertSystem
{
//字段 a,b,c,d,e,f,g,h,i.
public List<string> ET_ap = new List<string>();
public SortedList<string, int> ET_bp = new SortedList<string, int>();
private int ET_cp;//ET_cp 计数, 当前(规则切割得到)关键字索引 走到的位置。
private string[] ET_dp;//当前(规则切割得到)关键字 数组。 存放if,~,then,A1等全部字符。
private d ET_ep = new d();//D类的对象
private string ET_fp;//分析后的关键字字符串 ---当前
private string ET_gp;//分析前(规则切割得到)的字符串 ---当前
//通过ET_cp计数 与 ET_fp ET_gp 做多个方法的共同参数的使用。
private List<int> ET_hp = new List<int>();//Hp 存入 关键字的在AP的位置。 AP中是关键字,通过BP【‘关键字’】也可以定位到AP中的索引。
private List<int> ET_ip = new List<int>();//IP 存入对应关键字是否反义。 与Hp 是一一对应的关系。
#region 定义函数
/// <summary>
/// 通过此方法,对end之前的 规则的全部切割字符进行判断 ,非if的关键字,纳入分析。 这样每个关键字都分析到。
/// </summary>
public void ET_af()
{
int i = 0;
while (true)//循环全部规则字符。
{
i++;
if (!(this.ET_fp == "if"))
{
break;
}
else
{
this.ET_cf();//非IF 纳入分析。
}
}
}
/// <summary>
/// 关键字 与在 DP数组中的位置 存入 BP数组(关键字(条件与结论 非~ 关键字:索引)与 AP数组(条件与结论 关键字))。
/// 形式BP【‘冬天’:8】 AP 【‘冬天’】
/// 存入,返回 在数组中的索引位置。
/// 返回8-1。 因为从0开始。 得到真正的 关键字对应BP与AP的索引。
/// </summary>
/// <param name="A_0"></param>
/// <returns></returns>
private int ET_af(string A_0)
{
if (this.ET_bp.ContainsKey(A_0))
{
return this.ET_bp[A_0];
}
else
{
this.ET_bp.Add(A_0, this.ET_ap.Count);
this.ET_ap.Add(A_0);
return (this.ET_ap.Count - 1);
}
}
/// <summary>
/// 非~关键字,执行af ~关键字执行 下一个的af,然后都指向 下一个
/// 主要是对关键字做this.ET_af(this.ET_gp);调用
/// </summary>
/// <param name="A_0"></param>
/// <param name="A_1"></param>
public void ET_af(ref int A_0, ref int A_1)
{
A_1 = 1;
int num = 0;
Label_0002:
switch (num)
{
case 0:
if (!(this.ET_fp == "~"))
{
A_0 = this.ET_af(this.ET_gp);
this.ET_ef();
break;
}
else
{
num = 1;
}
goto Label_0002;
case 1:
A_1 = -1;
this.ET_ef();
num = 2;
goto Label_0002;
case 2:
A_0 = this.ET_af(this.ET_gp);
this.ET_ef();
break;
}
}
/// <summary>
/// 只执行一次,做规则加载时。 启动规则分析。
/// </summary>
public void ET_bf()
{
this.ET_ef();//ET_ef()对索引进行走动。
this.ET_af();//启动 规则关键字分析。 此方法,自动对完成全部索引的分析循环。
}
/// <summary>
/// 对每个关键字都进行循环时调用。 每次都是非IF关键字调用此。
/// </summary>
public void ET_cf()
{
this.ET_hp.Clear();
this.ET_ip.Clear();
this.ET_ef();//站到if关键字 去非if关键字, 索引已经++了。 得到下一条。
this.ET_df();//做关键字存入与^与下一个关键字存入(调用存入方法)
this.ET_ef();//下一个。
int num = 0;
int num2 = 0;
this.ET_af(ref num, ref num2);
this.ET_ef();
this.ET_ep.d_af(this.ET_hp, this.ET_ip, num, num2);
}
/// <summary>
/// 可以对非^符号关键字
/// 把所有的非if的关键字存入到 BP与AP中,利用HP与IP记录是否反义与AP中的位置。
/// ^符号关键字,存入到之后, 再走一步,对下一个关键字进行存入。
/// </summary>
public void ET_df()
{
int num = 0;
int num2 = 0;
this.ET_af(ref num, ref num2);
this.ET_hp.Add(num);
this.ET_ip.Add(num2);
int num3 = 3;
Label_0002:
switch (num3)
{
case 0:
if (this.ET_fp == "^")
{
this.ET_ef();
this.ET_af(ref num, ref num2);
this.ET_hp.Add(num);
this.ET_ip.Add(num2);
num3 = 1;
}
else
{
num3 = 2;
}
goto Label_0002;
case 1:
case 3:
num3 = 0;
goto Label_0002;
case 2:
return;
}
}
public void ET_ef()
{
if (this.ET_dp[this.ET_cp] != null)
{
this.ET_fp = f.f_af(this.ET_dp[this.ET_cp]);
this.ET_gp = this.ET_dp[this.ET_cp];
this.ET_cp++;
return;
}
else
{
return;
}
}
#endregion /// <summary>
/// 导入规则库
/// </summary>
/// <param name="file"></param>
public void LoadRule(string file)
{
string str = "";
StreamReader reader = new StreamReader(file, Encoding.Default);
string[] strArray = null;
string str2 = string.Empty;
char[] chArray = new char[]{' '};
string[] strArray2 = null;
int num = 0;
int num2 = 0;
int num3 = 6;
Label_0002:
switch (num3)
{
case 0:
if (num < strArray2.Length)
{
str2 = strArray2[num];
num3 = 2;
}
else
{
num3 = 8;
}
goto Label_0002;
case 1:
this.ET_dp[this.ET_cp++] = str2;
num3 = 4;
goto Label_0002;
case 2:
if (str2.Length <= 0)
{
num++;
num3 = 5;
}
else
{
num3 = 1;
}
goto Label_0002;
case 3:
case 5:
num3 = 0;
goto Label_0002;
case 4:
num++;
num3 = 5;
goto Label_0002;
case 6:
try
{
str = reader.ReadToEnd();
reader.Close();
//strArray = str.Replace("\r\n", " ").Replace("^~", " ~ ").Replace("^", " ^ ").Replace("if", " if ").Replace("then", " then ").Replace(";", " ; ").Split(chArray);
strArray = str.Replace("\r\n", " ").Split(chArray);
this.ET_dp = new string[0x1388];
strArray2 = strArray;
num3 = 3;
goto Label_0002;
}
catch(Exception ext)
{
return;
}
case 7:
return;
case 8:
this.ET_dp[this.ET_cp] = "end";
this.ET_cp = 0;
this.ET_bf();
num3 = 7;
goto Label_0002;
}
}
}
本人声明:沐海(http://my.oschina.net/mahaisong) 以上文章是经过本人设计实践和阅读其他文档得出。如果需要探讨或指教可以留言!欢迎交流!