油克小学期(七)规则树搜索

1.实验目的

(1)用搜索思路描述基于产生式规则(决策规则)的问题求解

(2)认识产生式系统、人机交互、知识库维护

(3)完成基于规则树的正向搜索问题的求解

2.实验内容

1. 知识和知识库搜索

2. 动物识别专家系统的实现

3.算法设计

持续搜索流程

 

单步搜索流程

规则树搜索总结

 

4.程序实现

【1】在记事本中建立规则库 

如果动物有毛发
那么该动物是哺乳动物
如果动物能下奶
那么该动物是哺乳动物
如果动物有羽毛
那么该动物是鸟类
如果动物能飞/动物能下蛋
那么该动物是鸟类
如果动物吃肉
那么该动物是食肉动物
如果动物有锋利的牙齿/动物有爪/动物有前向眼
那么该动物是食肉动物
如果动物是哺乳功物动/物有蹄子
那么该动物是有蹄类动物
如果动物是哺乳动物/动物是咀嚼反刍的
那么该动物是有蹄类动物/有偶数个脚趾物
如果动物是哺乳动物/动物是食肉动物/动物有黄褐色毛发/动物有黑斑
那么该动物是非洲猎豹
如果动物是哺乳动物/动物是食肉动物/动物有黄褐色毛发/动物有黑条纹
那么该动物是老虎

 

 

【2】在记事本中建立事实库

动物有毛发/动物是食肉动物/动物有黄褐色毛发/动物有黑斑

 

 

【3】程序代码-动物识别专家

```c
#define STATUS int
// 逻辑状态类型
#define TRUE 1
//逻辑真
#define FALSE 0
//逻辑假
#define Factsize 50
typedef char FACT[Factsize];
struct FACTNODE
{
	//事实节点类型
	FACT fact;
	//一个事实
	struct FACTNODE *next;
	//多个事实链接
};
typedef struct FACTNODE *FACTS;
FACTS facts;
typedef struct
{
	//规则类型
	FACTS ifs;
	//多个前提(事实集合)ifs
	FACTS thens;
	//多个结论(事实集合)thens
} RULE;
// 规则类型
struct RULENODE
{
	// /规则节点类型
	RULE rule;
	//一条规则
	struct RULENODE *next;
	// / 规则链接
};
 typedef struct RULENODE *RULES;

#include "stdio.h"
#include "stdlib.h"
#include "string.h"





// /事实库(集合)类型FACTS


// /规则库类型

FACTS AddAFact(FACTS facts, FACT newfact)
{
	struct FACTNODE *factnode, *lastnode; //事实节点指针
	factnode = (struct FACTNODE *)malloc(sizeof(struct FACTNODE));
	//分配事实空间
	strcpy(factnode->fact, newfact);
	//复制事实,形成节点
	factnode->next = NULL;
	if (facts == NULL)
		//事实库为空,创建事实库
		facts = factnode;
	else
	{
		lastnode = facts;
		while (lastnode->next != NULL)
			lastnode = lastnode->next; //指针后移
		lastnode->next = factnode;
		//插入事实节点
	}
	return facts;
}

void priFacts(FACTS facts)
{ //显示事实库所有事实,用分隔符“/”分隔多个字符
	while (facts != NULL)
	{
		//事实库存在
		printf("%s", facts->fact);
		//显示一个事实
		facts = facts->next;
		if (facts != NULL)
		{
			printf(",");
			/* code */
		}
		printf("\n");
	}
}

void CreateStr(char *factset)
{ //将字符数组转换为多个字符串
	//把字符串中的事实分隔符“/”改为“\0”,即成为多个事实字符串
	char *c = factset;
	while (*c)
	{
		if(*c == '/')
			*c = '\0'; //插入字符串结束标志
		c++;
	}
	c++;

	*c = '\0';
	//多一个结束标志
}

FACTS CreateFacts(FACTS facts, char *factset) //将若干事实加入事实库中
{
	// 将字符数组factset含有的多个事实逐一加入事实库facts中
	char *p = factset;
	//多个事实,用分隔符“/”隔开
	FACT fact;
	//事实
	CreateStr(factset);
	//将字符数组转换为多个事实
	while(*p)
	{
		strcpy(fact, p);
		//读取一个事实
		facts = AddAFact(facts, fact);
		//将事实加入事实库中
		p += strlen(fact) + 1;
		//下一个事实
	}

	return facts;
}

FACTS CreateFactBase(FACTS facts, char *filename) //从文件创建事实库
{
	//从文件f1 lename中读入多个事实,并加入事实库中,事实文件如图7,8所示
	FILE *fp;
	char factset[500];
	fp = fopen(filename, "r");
	//打开
	fscanf(fp, "%s", factset);
	//读取若干事实,用分隔符“/”隔开

	facts = CreateFacts(facts, factset);
	fclose(fp);
	return facts;
}
FACTS ClearFactBase(FACTS facts)
{
	//回收事实库空间
	//事实库是动态分配的空间,问题求解结束后需要回收该空间(每个事实空间)
	struct FACTNODE *fact = facts, *p;
	//指针变量
	while (fact)
	{
		// 非空循环
		p = fact;
		// /暂时指针
		fact = fact->next;
		// /指针前移
		free(p);
		//回收事实空间
	}

	return NULL;
	//没有空间
}

RULE *InitRule()
{
	//初始化一条规则(空规则)
	RULE *rule;
	//指向规则的指针
	rule = (RULE *)malloc(sizeof(RULE));
	// / 分配一条规则空间
			rule->ifs = NULL;
	//形成没有前提和结论的空规则
	rule->thens = NULL;
	return rule;
}

void AddAIf(RULE *rule, FACT newfact)
{
	//在规则rule中增加一个前提(事实)newfact
	rule->ifs = AddAFact(rule->ifs, newfact); //加入一个前提(事实)
}
void AddAThen(RULE *rule, FACT newfact)
{
	//在规则rule中增加个新结论(事实)newfact
	rule->thens = AddAFact(rule->thens, newfact); //加入一个结论(事实)
}

void AddIfs(RULE *rule, char *factset) //在规则中增加多个前提
{
	char *p = factset;
	//多个事实字符串
	FACT fact;
	// / 一个事实
			CreateStr(factset);
	// / 将字符串转化为多个前提(事实) 
	while (*p)
	{
		//多个字符串
		strcpy(fact, p);
		//读取一个前提(事实)
		AddAIf(rule, fact);
		//加入一个前提(事实)
		p += strlen(fact) + 1;
		//下一个前提(事实)
	}
}
void AddThens (RULE *rule,char *factset){
	//在规则中增加多个结论factset
char *p=factset;
//多个事实字符串
FACT fact;
//一个事实
CreateStr(factset);
//将字符串转化为多个结论(事实)
while(*p){
	//多个字符串
strcpy(fact,p);
//读取一个结论(事实)
AddAThen (rule,fact);
//加入一个结论(事实)》
p+=strlen(fact)+1;
//下一个结论(事实)
}

}

RULE *CreateRule(char *ifset, char *thenset)
{
	//根据字符数组ifs和thens创建一条规则
	RULE *rule;
	//规则指针
	rule = InitRule();
	//创建空规则ru1e
	AddIfs(rule, ifset);
	//在规则xule中加入若干前提ifs
	AddThens(rule, thenset);
	//在规则xule中加入若干结论thens
	return rule;
}
RULES AddARule(RULES rules, RULE rule) //将一条规则rule增加到规则库rules中
{
	struct RULENODE *rulenode, *lastnode;
	rulenode = (struct RULENODE *)malloc(sizeof(struct RULENODE));
	//  / 规则节点空间
	rulenode->rule = rule;
	//在规则节点rulenode中加入规则rule
	rulenode->next = NULL;
	if (rules == NULL)
		//创建规则库rules
		rules = rulenode;
	else
	//在已有规则库中加入新规则lastnode=rules;
	{
		lastnode = rules;
		//在规则节点rulenode中加入规则库rules的尾部
		while (lastnode->next != NULL)
			lastnode = lastnode->next; // 1 astnode指f针后移
		lastnode->next = rulenode;
		
	}
	return rules;
		//加入到规则rule后的规则库rules中
}

RULES CreateRuleBase(RULES rules, char *filename)
{
	//在文件filename中创建规则库rules
	RULE *rule;
	FILE *fp;
	//文件指针
	char ifset[5000], thenset[500];
	//前提与结论的字符数组
	fp = fopen(filename, "r");
	//打开并读入文本文件
	while (!feof(fp))
	{
		//文件是否结束
		fscanf(fp, "%s", ifset);
		//读入若干前提,注意,分隔符“/”
		fscanf(fp, "%s", thenset);
		//读入若干结论,注意,分隔符“/”
		rule = CreateRule(ifset + 4, thenset+ 6);
		// /创键条规则rule,跳过“如课”“那么”
		rules = AddARule(rules, *rule);
		//将新规则rule加入规则库rules中
	}

	fclose(fp);
	//关闭文件
	return rules;
	//获得规则库ru1es
}
void priRule(RULE *rule)
{
	//显示事实的一条规则rule
	FACTS ifs, thens;
	//规则的前提ifs和结论thens
	ifs = rule->ifs;
	thens = rule->thens;
	printf("IF");
		//显示IF
		priFacts(ifs);
	//显示所有前提1fs
	printf("THEN ");
		//显示THEN
		priFacts(thens);
	//显示所有结论thens
}
void priRules(RULES rules)
{

	//显示规则库ru1es
	while (rules)
	{
		//规则库ru1es不为空
		priRule(&(rules->rule));
		//显示一条规则rule
		rules = rules->next;
		//下一条规则
	}
}
RULES ClearRuleBase(RULES rules)
{
	//回收规则库ru1es的空间
	struct RULENODE *rule = rules, *p;
	while (rule)
	//规则库是否为空
	{
		p = rule;
		// / 临时指针p
		ClearFactBase(p->rule.ifs);  //回收所有前提ifs(事实库)
		ClearFactBase(p->rule.thens); //回收所有结论thens(事实库)
		rule = rule->next;
		//下一条规则
		free(p);
	}
	//回收p指向的数据空间
	return NULL;
}
#define STATUS int
// 逻辑状态类型
#define TRUE 1
//逻辑真
#define FALSE 0

STATUS member(FACT fact, FACTS facts)
//成员判断
{
	//若事实fact是事实库facts的成员(元素),则返回TRUE,否则返回FALSE
	STATUS flag = FALSE;
	//默认事实不是事实库成员
	struct FACTNODE *p = facts;
	//指向事实指针
	while (p)
		if (strcmp(p->fact, fact) == 0)
		{ // /事实fact是否为事实库成员
			flag = TRUE;
			//事实是事实库成员
			break;
		}

		else
			p = p->next;
	//下一个事实库成员
	return flag;
	//事实是否为事实库成员
}
STATUS match(FACTS subfacts, FACTS facts) //判断若干成员
{	//若这些若干事实subfacts均为事实库facts的成员,则返回TRUE,否则返回FALSE
	STATUS flag = TRUE;
	//默认若干事实都是事实库成员
	struct FACTNODE *p = subfacts;
	//指向若干事实
	while (p)
		if(!member(p->fact, facts)) //一个事实不是事实库成员
		{
			flag = FALSE;
			// /有一个事实不在事实库中
			break;
		}
	else p = p->next;
	return flag;
}

FACTS update(FACTS subfacts, FACTS facts, STATUS *flag) //更新事实库
{														//若干事实subfacts中只有一个事实不在事实库facts中,追加该事实
	//更新事实库facts并返回TURE,否则不更新事实库并返回FALSE
	struct FACTNODE *p = subfacts;
	// /若干实事指针
	*flag = FALSE;
	// /默认为FALSE,表示facts没有更新
	while (p)
		if (!member(p->fact, facts))
		//事实不在事实库中
		{
			*flag = TRUE;
			//返回TRUE,更新facts
			facts = AddAFact(facts, p->fact);
			//追加不在事实库中的事实
		}
		else
			p = p->next;
	//下一个事实
	return facts;
}

STATUS testIfs(FACTS ifs, FACTS facts) //判断前提集合是否在事实库中
{
	//若所有前提均在事实库中,则返回TRUE,否则返回FALSE
	return match(ifs, facts);
}
FACTS testThens(FACTS thens, FACTS facts, STATUS *flag) //判断结论集合
{														//若所有结论均在事实库中,则更新事实库,并返回TRUE,否则返回FALSE
	facts = update(thens, facts, flag);					//更新事实库
	return facts;
}

FACTS testRule(RULE *rule, FACTS facts, STATUS *flag) //判断规则是否有效
{													 //若规则rule前提均在事实库facts中,并且rule至少有一个结论不在事实库中
	//更新事实库并返回TRUE,否则不更新事实库并返回FALSE
	*flag = FALSE;
	if (testIfs(rule->ifs, facts))
		//规则有效性
		facts = testThens(rule->thens, facts, flag); //更新事实库
	return facts;
}
FACTS stepforward(RULES rules, FACTS facts, STATUS *flag) //进行一步搜索
{														  //若规则库中有一条规则满足,则执行一步搜索,更新事实库,返回TUE
	//否则没有更新事实库,返回FALSE
	do
	{
		//遍历规则库
		facts = testRule(&(rules->rule), facts, flag);
		// 若有一条规则有效,则更新事实库
		if (*flag == TRUE)
		{
			//判断更新事实库是否成功
			priRule(&(rules->rule));
			//显示用到的规则
			printf("=============\n");
			break;
			//结束搜索
		}
		rules = rules->next;
		//下一条规则部元是
	} while (rules);
	return facts;
	//得到更新的事实库或没有更新的事实库
}

FACTS deduce(RULES rules, FACTS facts, STATUS *flag)
//反复持续搜索1
{ //只要有一个事实库更新,则反复持续进行单步搜索,得到更新后的事实库并返回TUE
	//否则不更新事实库,并返回FALSE
	STATUS success = FALSE;
	//默认将反复持续搜索的状态设为失败
	while (TRUE)
	{
		// / 反复执行搜索
		facts = stepforward(rules, facts, flag);
		//单步搜索
		if (success == FALSE && *flag == TRUE)
			success = TRUE;
		//至少进行一次单步搜索
		if (*flag == FALSE)
			break;
	}
	//单步搜索失败
	*flag = success;
	//判断是否进行了一次搜索
	return facts;
}
// FACTS deduce(RULES rules, FACTS facts, STATUS *flag)
// //反复持续搜索
// { 	
// 	//只要有一个事实库更新,则反复持续进行单步搜索,得到更新后的事实库并返回TUE
// 	//否则不更新事实库,并返回FALSE
// 	static STATUS success = FALSE;
// 	//默认将反复持续搜索的状态设为失收
// 	facts = stepforward(rules, facts, flag);
// 	//单步搜索
// 	if (*flag == TRUE)
// 	{
// 		success = TRUE;
// 		//至少进行一次单步搜索
// 		facts = deduce(rules, facts, flag);
// 	}
// 	*flag = success;
// 	return facts;
// }


struct FACTNODE *deduceResult(FACTS facts)
//获得结论
{
	// / 从更新的事实库中获得最后事实指针
	while (facts->next)
		facts = facts->next;
	// / 指针后移
	return facts;
	//获得最后事实指针
}

void displayResult(struct FACTNODE *result, STATUS flag) //显示搜索结论
//若持续搜索成功,则显示最后事实,否则显示搜索不成功信息
{
	if (flag == TRUE)
		printf("DeduceResult=%s\n", result->fact);
	//搜索成功,显示结果
	else
		printf("DeduceResult-NO Result\n");
	//搜索不成功,显示不成功信息
	printf("============\n");
}
void ProductionSYS(char *rulefilename, char *factfilename) //集成完整问题求解系统
// 事实和规则分别在factf1 lename、rulefilename两个文本文件中
{
	RULES rules = NULL;
	//规则库为空
	FACTS facts = NULL;
	//事实库为空
	struct FACTNODE *result = NULL;
	//求解结果(事实)
	STATUS flag;
	//求解(搜索)是否成功
	facts = CreateFactBase(facts, factfilename); //从文件中读取事实,创建事实库
	printf("=====\nFact Base:\n");				 //显示所有事实
	priFacts(facts);
	printf("=====\nDeducing Procedure:\n");
	rules = CreateRuleBase(rules, rulefilename); //从文件中读取规则,创建规则库
	facts = deduce(rules, facts, &flag);
	//问题求解(持续搜索)
	result = deduceResult(facts);
	//获得求解(搜索)结果
	displayResult(result, flag);
	//显示求解(搜索)结果
	ClearFactBase(facts);
	//回收事实库空间
	ClearRuleBase(rules);
	//回收规则库空间
}

int  main()
{
		char *rulefilename = "规则库.txt";
		//规则文件
		char *factfilename1 = "事实库.txt";
		//事实文件
	ProductionSYS(rulefilename, factfilename1); //问题求解
//动物有黑斑/动物有黄褐色毛发/动物是食肉动物/动物吃奶/动物有毛发
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北城学神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值