動物產生式識別系統

  摘要構造知識型系統和建立認知模型時常用的知識表示形式系統。1943年E.波斯特首先將他提出的一種計算形式體系命名爲產生式系統。50年代末期,A.紐厄爾和H.A.西蒙在研究人類問題求解的認知模型時也使用了產生式系統這一術語。產生式系統現代已成爲研製人工智能系統時採用的最典型的體系結構之一。本文主要論述計算機科學與技術專業大三下專業課《人工智能》第三個實驗算法。

關鍵字:人工智能,專家系統,產生式系統

Production system

Abstract: Constructs the knowledge system and cognitive model often used in the form of knowledge representation system. E. 1943 post first will he come up with a form of computing system named production system. The late 50 s, a. Newell and H.A. Simon in the study of human cognitive model of problem solving when the term is also used by the production system. Production system has become an artificial intelligence system in modern times, with one of the most typical architecture. This paper mainly discusses the computer science and technology under the junior in professional class "artificial intelligence" third experiment algorithm.

Keywords: Artificial intelligence, expert system, production system

1,問題重述 

  通過理解並體會知識庫與控制系統相互獨立的智能產生式系統與一般程序的區別,爲以後設計並實現複雜的專家系統奠定基礎。

知識表示爲產生式知識表示方法,設計並實現具有15條規則能自動識別7種動物的產生式系統。知識庫與控制系統相互獨立,系統完成後除了能識別已有的7種動物外,按產生式知識表示方法向知識庫中添加、修改新的知識後,系統能在不修改控制系統程序的情況下仍然能正確識別。
 圖片


2,問題分析

2.1.事實的表示:

事實可看成是斷言一個語言變量的值或是多個語言變量間的關係的陳述句,語言變量的值或語言變量間的關係可以是一個詞。不一定是數字。一般使用三元組(對象,屬性,值)或(關係,對象1,對象2)來表示事實,其中對象就是語言變量,若考慮不確定性就成了四元組表示(增加可信度)。這種表示的機器內部實現就是一個表

2.2.規則的表示:

規則用於表示事物間的因果關係,以if conditionthen action 的單一形式來描述,將規則作爲知識的單位。其中的condition 部分稱爲條件式前件或模式,而action部分稱作動作、後件或結論。

產生式一般形式爲:前件     後件。前件和後件也可以是有“與”、“或”、“非”等邏輯運算符的組合的表達式。條件部分常是一些事實的合取或析取,而結論常是某一事實B。如果不考慮不確定性,需另附可信度度量值。

產生式過則的含義是:如果前件滿足,則可得到後件的結論或者執行後件的相應動作,即後件由前件來觸發。一個產生式生成的結論可以作爲另一個產生式的前提或語言變量使用,進一步可構成產生式系統。

蘊涵式表示的知識只能是精確的,產生式表示的知識可以是不確定的,原因是蘊涵式是一個邏輯表達式,其邏輯值只有真和假。蘊含式的匹配一定要求是精確的,而產生式的匹配可以是不確定的,原因是產生式的前提條件和結論都可以是不確定的,因此其匹配也可以是不確定的。 

3,設計文檔 

<知識庫>

<事實>

<條件>

1:有毛髮     2:產奶         3:有羽毛      4:會飛 

5:會下蛋     6:吃肉         7:有犬齒      8:有爪

9:眼盯前方   10:有蹄        11:反芻       12:黃褐色

13:有斑點    14:有黑色條紋  15:長脖       16:長腿

17:不會飛    18:會游泳      19:黑白二色   20:善飛

</條件>

<中間結論>

21:哺乳類     22:鳥類     23:食肉類      24:蹄類  

</中間結論>

<結論>

25:金錢豹   26:虎     27:長頸鹿      28:斑馬      29:鴕鳥

30:企鵝     31:信天翁

</結論>

</事實>

<規則>

有毛->哺乳類

產奶->哺乳類

有羽毛->鳥類

會飛,會下蛋->鳥類

哺乳類,吃肉->食肉類

有犬齒,有爪,眼盯前方->食肉類

哺乳類,有蹄->蹄類

哺乳類,反芻->蹄類

食肉類,黃褐色,有斑點->金錢豹

食肉類,黃褐色,有黑色條紋->虎

蹄類,長脖,長腿,有斑點->長頸鹿

蹄類,有黑色條紋->斑馬

鳥類,長脖,長腿,會飛->鴕鳥

鳥類,會游泳,黑白二色,會飛->企鵝

鳥類,善飛->信天翁

</規則>

</知識庫>


**規則符號化

1->21                  //有毛->哺乳類

2->21                  //產奶->哺乳類

3->22                  //有羽毛->鳥類

4,5->22                //會飛,會下蛋->鳥類

21,6->23               //哺乳類,吃肉->食肉類

7,8,9->23              //有犬齒,有爪,眼盯前方->食肉類

21,10->24              //哺乳類,有蹄->蹄類

21,11->24              //哺乳類,反芻->蹄類

23,12,13->25           //食肉類,黃褐色,有斑點->金錢豹

23,12,14->26           //食肉類,黃褐色,有黑色條紋->虎

24,15,16,13->27        //蹄類,長脖,長腿,有斑點->長頸鹿

24,14->28              //蹄類,有黑色條紋->斑馬

22,15,16,4->29         //鳥類,長脖,長腿,會飛->鴕鳥

22,18,19,4->30         //鳥類,會游泳,黑白二色,會飛->企鵝

22,20->31              //鳥類,善飛->信天翁


**

**測試用例


2,10,13,15,16 -> 27

產奶,有蹄,有斑點,長脖,長腿 -> 長頸鹿


*/

4,程序設計

圖片


圖片



#include<iostream>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<list>

using namespace std;

const int fact_num = 31;      //知識庫中的知識:31種知識
const int rule_num = 15;      //知識庫中的規則:15條規則
const int rule_volume = 4;    //規則中每個結果最多有4個前提條件
const int object_range_begin = 25;  //從第25個知識開始
const int object_range_end = 31;    //到第31個知識爲目標結論
const int object_middle_begin = 21;     //中間結果起始位置 

string fact[fact_num] =               
{
	"有毛髮","產奶","有羽毛","會飛","會下蛋",
	"吃肉","有犬齒","有爪","眼盯前方","有蹄",
	"反芻","黃褐色","有斑點","有黑色條紋","長脖",
	"長腿","不會飛","會游泳","黑白二色","善飛",
	"哺乳類","鳥類","食肉類","蹄類","金錢豹",
	"虎","長頸鹿","斑馬","鴕鳥","企鵝","信天翁"
};

int rule_prerequisite[rule_num][rule_volume] =      
{
	{1,0,0,0},
	{2,0,0,0},
	{3,0,0,0},
	{4,5,0,0},
	{21,6,0,0},
	{7,8,9,0},
	{21,10,0,0},
	{21,11,0,0},
	{23,12,13,0},
	{23,12,14,0},
	{24,15,16,13},
	{24,14,0,0},
	{22,15,16,4},
	{22,18,19,4},
	{22,20,0,0}
};

int rule_result[rule_num] =
{
	21,
	21,
	22,
	22,
	23,
	23,
	24,
	24,
	25,
	26,
	27,
	28,
	29,
	30,
	31
};

bool backward_reasoning(int num,int message[]) ;
bool inference(int num,int message[])         //迭代推理機
{
	int ii, ij, ik,im,in;
	int hit_num = 0;          //輸入前提也規則前提重合數
	int prerequisite_num;     //規則前提數
	int *message_c;           //迭代前提
	int num_c;                //迭代前提數量
	for (ik = 0; ik < num; ik++)     //剪枝函數
	{
		if (message[ik] >= object_range_begin&&message[ik] <= object_range_end)
		{
			cout << "歸併信息:" << fact[message[ik] - 1] << endl;
			cout << "推理成功!" << endl<<endl;
			system("pause");
			exit(0);
		}
	}
	for (ii = 0; ii < rule_num; ii++)   //遍歷規則匹配
	{
		prerequisite_num = 0;
		hit_num = 0;
		for (ij = 0; ij < rule_volume; ij++)   //計算規則集前提數
		{
			if (rule_prerequisite[ii][ij] == 0)
			{
				break;
			}
			prerequisite_num++;
		}
		for (ij = 0; ij < prerequisite_num; ij++)
		{
			for (ik = 0; ik < num; ik++)
			{
				if (rule_prerequisite[ii][ij] == message[ik])
				{
					hit_num++;
				}
			}
		}
		if (hit_num == prerequisite_num)  //滿足某個規則集全部前提
		{
			bool flag;
			for (ik = 0; ik < num; ik++)
			{
				if (message[ik] == rule_result[ii])
				{
					break;
				}
			}
			if (ik == num)
			{
				num_c=num - hit_num+1;
				flag = true;
			}
			else
			{
				num_c = num - hit_num;
				flag = false;
			}
			message_c = new int[num_c];
			in = 0;
			for (ik = 0; ik < num; ik++)
			{
				for (im = 0; im < hit_num; im++)
				{
					if (rule_prerequisite[ii][im] == message[ik])
					{
						break;
					}
				}
				if (im < hit_num)
				{
					continue;
				}
				message_c[in++] = message[ik];
			}
			if (flag == true)
			{
				message_c[in] = rule_result[ii];
			}
			cout << "推導信息:";
			for (int iz = 0; iz < num; iz++)
			{
				cout << fact[message[iz]-1] << " ";
			}
			cout << endl;
			return inference(num_c,message_c);
		}
	}
	cout << "歸併信息:";
	for (int iz = 0; iz < num; iz++)
	{
		cout << fact[message[iz]-1] << " ";
	}
	cout << endl;
	backward_reasoning(num,message);
	return false;
}

bool backward_reasoning(int num,int message[])   //反向推理
{
	int ii,ij,ik;
	int prerequisite_num = 0;
	int hit_num = 0;
	int need_rule_number[rule_num];
	int hit_rule_number[rule_num];
	float hit_rule_rate[rule_num];
	float best_hit_rule_rate=0;
	int best_hit_rule_number;
	int *new_message;
	for (ii = 0; ii < rule_num; ii++)   //遍歷規則匹配
	{
		prerequisite_num=0;
		hit_num=0;
		for (ij = 0; ij < rule_volume; ij++)   //計算規則集前提數
		{
			if (rule_prerequisite[ii][ij] == 0)
			{
				break;
			}
			prerequisite_num++;
		}
		need_rule_number[ii]=prerequisite_num;
		for (ij = 0; ij < prerequisite_num; ij++)   //計算輸入信息命中規則集中的前提數
		{
			for (ik = 0; ik < num; ik++)
			{
				if (rule_prerequisite[ii][ij] == message[ik])
				{
					hit_num++;
				}
			}
		}
		hit_rule_number[ii]=hit_num;
		hit_rule_rate[ii]=(float)hit_num/prerequisite_num;  //命中率
		for(ij=0;ij<num;ij++)
		{
			if(message[ij]==rule_result[hit_rule_number[ii]])
			{
				break;
			}
		}
		if(hit_rule_rate[ii]==1&&ij==num)
		{
			new_message=new int[num+1];
			for(ik=0;ik<num;ik++)
			{
				new_message[ik]=message[ik];
			}
			new_message[num]=rule_result[hit_rule_number[ii]];
			num++;
			return inference(num,new_message);
		}
		cout<<"rule "<<setw(2)<<ii<<" -> "<<setw(8)<<fact[rule_result[ii]-1]
		<<"命中率:"<<hit_rule_rate[ii]<<endl;
	}
	best_hit_rule_number=-1;
	for(ii=0;ii<rule_num;ii++)
	{
		if(best_hit_rule_rate<hit_rule_rate[ii]&&
			rule_result[ii]>=object_middle_begin)
		{
			best_hit_rule_rate=hit_rule_rate[ii];
			best_hit_rule_number=ii;
		}
	}
	if(best_hit_rule_number==-1)
	{
		cout<<"您輸入的信息對本系統無效!按任意鍵退出..."<<endl<<endl;
		system("pause");
		exit(0);
	}
	cout<<endl;
	cout<<"best_hit_rule_number="<<best_hit_rule_number<<endl;
	cout<<"best_hit_rule_rate="<<best_hit_rule_rate<<endl;
	cout<<"最佳匹配最終結果="<<fact[rule_result[best_hit_rule_number]-1]<<endl;
	for(ii=0;ii<need_rule_number[best_hit_rule_number];ii++)
	{
		for(ij=0;ij<num;ij++)
		{
			if(rule_prerequisite[best_hit_rule_number][ii]==message[ij])
			{
				break;
			}
		}
		if(ij!=num)
		{
			continue;
		}
		else
		{
			if(rule_prerequisite[best_hit_rule_number][ii]<object_middle_begin)
			{
				cout<<endl<<"請問您持有的信息是否包含\"";
				cout<<fact[rule_prerequisite[best_hit_rule_number][ii]-1];
				cout<<"\"?(y or n)"<<endl;
				char input;
				while(true)
				{
					cin>>input;
					if(input=='n')
					{
						new_message=new int[num];
						for(ik=0;ik<num;ik++)
						{
							new_message[ik]=message[ik];
						}
						break;
					}
					else if(input=='y')
					{
						new_message=new int[num+1];
						for(ik=0;ik<num;ik++)
						{
							new_message[ik]=message[ik];
						}
						new_message[num]=rule_prerequisite[best_hit_rule_number][ii];
						num++;
						return inference(num,new_message);
					}
					else
					{
						cout<<"請重新輸入(y or n)!";
					}
				}
			}
			else      //詢問是否有中間結果rule_prerequisite[best_hit_rule_number][ii]
			{	
				int middle_result=rule_prerequisite[best_hit_rule_number][ii];
				for(ii=0;ii<rule_num;ii++)
				{
					if(rule_result[ii]==middle_result)
					{
						for(ik=0;ik<need_rule_number[ii];ik++)
						{
							if(rule_prerequisite[ii][ik]>=object_middle_begin-1)
							{
								continue;
							}
							for(ij=0;ij<num;ij++)
							{
								if(rule_prerequisite[ii][ik]==message[ij])
								{
									break;
								}
							}
							if(ij!=num)
							{
								continue;
							}
							else
							{
								cout<<endl<<"請問您持有的信息是否包含\"";
								cout<<fact[rule_prerequisite[ii][ik]-1];
								cout<<"\"?(y or n)"<<endl;
								char input;
								while(true)
								{
									cin>>input;
									if(input=='n')
									{
										break;
									}
									else if(input=='y')
									{
										new_message=new int[num+1];
										for(int iq=0;iq<num;iq++)
										{
											new_message[iq]=message[iq];
										}
										new_message[num]=rule_prerequisite[best_hit_rule_number][ii];
										num++;
										return inference(num,new_message);
									}
									else
									{
										cout<<"請重新輸入(y or n)!";
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

int main(int argc, char **argv)
{
	bool flag;
	int num;
	int *message;
	int ii,ij;
	cout<<"《知識庫》"<<endl;
	for(ii=0;ii<fact_num;ii++)
	{
		cout<<setiosflags(ios::left);
		cout<<setw(2)<<ii+1<<":"<<setw(10)<<fact[ii]<<"  ";
		if(ii%4==0)
		{
			cout<<endl;
		}
	}
	cout <<endl<<endl<< "請輸入初始信息個數:(數字)" << endl;
	cin >> num;
	message = new int[num];
	cout << "請輸入已有信息:(不重複的數字,以空格隔開)" << endl;
	for (ii = 0; ii < num; ii++)
	{
		cin >> message[ii];
	}
	cout << endl << "初始信息:";
	for (ij = 0; ij < num; ij++)
	{
		cout << fact[message[ij]-1] << " ";
	}
	cout << endl<<endl;
	if(!inference(num,message))
	{
		cout<<"通過您的輸入無法得出結果!"<<endl;
	}
	system("pause");
	return 0;
}


發佈了21 篇原創文章 · 獲贊 14 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章