摘要:构造知识型系统和建立认知模型时常用的知识表示的形式系统。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,程序设计
1 #include<iostream> 2 #include<string> 3 #include<cstdlib> 4 using namespace std; 5 6 const int fact_num = 31; //知识库中的知识:31种知识 7 const int rule_num = 15; //知识库中的规则:15条规则 8 const int rule_volume = 4; //规则中每个结果最多有4个前提条件 9 const int object_range_begin = 25; //从第25个知识开始 10 const int object_range_end = 31; //到第31个知识为目标结论 11 const int object_middle_begin = 21; //中间结果起始位置 12 13 int bridge_num; 14 int *bridge_message; 15 bool bridge_flag[rule_num]={false}; 16 17 string fact[fact_num] = 18 { 19 "有毛发","产奶","有羽毛","会飞","会下蛋", 20 "吃肉","有犬齿","有爪","眼盯前方","有蹄", 21 "反刍","黄褐色","有斑点","有黑色条纹","长脖", 22 "长腿","不会飞","会游泳","黑白二色","善飞", 23 "哺乳类","鸟类","食肉类","蹄类", 24 "金钱豹","虎","长颈鹿","斑马","鸵鸟","企鹅","信天翁" 25 }; 26 27 int rule_prerequisite[rule_num][rule_volume] = 28 { 29 {1,0,0,0}, 30 {2,0,0,0}, 31 {3,0,0,0}, 32 {4,5,0,0}, 33 {21,6,0,0}, 34 {7,8,9,0}, 35 {21,10,0,0}, 36 {21,11,0,0}, 37 {23,12,13,0}, 38 {23,12,14,0}, 39 {24,15,16,13}, 40 {24,14,0,0}, 41 {22,15,16,4}, 42 {22,18,19,4}, 43 {22,20,0,0} 44 }; 45 46 int rule_result[rule_num] = 47 { 48 21, 49 21, 50 22, 51 22, 52 23, 53 23, 54 24, 55 24, 56 25, 57 26, 58 27, 59 28, 60 29, 61 30, 62 31 63 }; 64 65 bool inference(int num,int message[]) //迭代推理机 66 { 67 int ii, ij, ik,im,in; 68 int hit_num = 0; //输入前提也规则前提重合数 69 int prerequisite_num; //规则前提数 70 int *message_c; //迭代前提 71 int num_c; //迭代前提数量 72 for (ik = 0; ik < num; ik++) //剪枝函数 73 { 74 if (message[ik] >= object_range_begin&&message[ik] <= object_range_end) 75 { 76 cout << "归并信息:" << fact[message[ik] - 1] << endl; 77 cout << "推理成功!" << endl<<endl; 78 return true; 79 } 80 } 81 for (ii = 0; ii < rule_num; ii++) //遍历规则匹配 82 { 83 prerequisite_num = 0; 84 hit_num = 0; 85 for (ij = 0; ij < rule_volume; ij++) //计算规则集前提数 86 { 87 if (rule_prerequisite[ii][ij] == 0) 88 { 89 break; 90 } 91 prerequisite_num++; 92 } 93 for (ij = 0; ij < prerequisite_num; ij++) 94 { 95 for (ik = 0; ik < num; ik++) 96 { 97 if (rule_prerequisite[ii][ij] == message[ik]) 98 { 99 hit_num++; 100 } 101 } 102 } 103 if (hit_num == prerequisite_num) //满足某个规则集全部前提 104 { 105 bool flag; 106 for (ik = 0; ik < num; ik++) 107 { 108 if (message[ik] == rule_result[ii]) 109 { 110 break; 111 } 112 } 113 if (ik == num) 114 { 115 num_c=num - hit_num+1; 116 flag = true; 117 } 118 else 119 { 120 num_c = num - hit_num; 121 flag = false; 122 } 123 message_c = new int[num_c]; 124 in = 0; 125 for (ik = 0; ik < num; ik++) 126 { 127 for (im = 0; im < hit_num; im++) 128 { 129 if (rule_prerequisite[ii][im] == message[ik]) 130 { 131 break; 132 } 133 } 134 if (im < hit_num) 135 { 136 continue; 137 } 138 message_c[in++] = message[ik]; 139 } 140 if (flag == true) 141 { 142 message_c[in] = rule_result[ii]; 143 } 144 cout << "推导信息:"; 145 for (int iz = 0; iz < num; iz++) 146 { 147 cout << fact[message[iz]-1] << " "; 148 } 149 cout << endl; 150 return inference(num_c,message_c); 151 } 152 } 153 cout << "归并信息:"; 154 for (int iz = 0; iz < num; iz++) 155 { 156 cout << fact[message[iz]-1] << " "; 157 } 158 cout << endl; 159 bridge_num=num; 160 if(bridge_message!=NULL) 161 { 162 delete []bridge_message; 163 } 164 bridge_message=new int[num]; 165 for(ii=0;ii<num;ii++) 166 { 167 bridge_message[ii]=message[ii]; 168 } 169 return false; 170 } 171 172 bool query_middle_result(int middle_result) 173 { 174 int ii,ij,ik; 175 for(ii=0;ii<rule_num;ii++) 176 { 177 if(rule_result[ii]==middle_result) 178 { 179 for(ij=0;rule_prerequisite[ii][ij]!=0;ij++) 180 { 181 cout<<endl<<"请问您持有的信息是否包含\""; 182 cout<<fact[rule_prerequisite[ii][ij]-1]; 183 cout<<"\"?(y or n)"<<endl; 184 char input; 185 bool flag=false; 186 while(true) 187 { 188 cin>>input; 189 if(input==‘n‘) 190 { 191 break; 192 } 193 else if(input==‘y‘) 194 { 195 flag=true; 196 break; 197 } 198 else 199 { 200 cout<<"请重新输入(y or n)!"; 201 } 202 } 203 if(flag==false) 204 { 205 break; 206 } 207 } 208 if(rule_prerequisite[ii][ij]==0) 209 { 210 return true; 211 } 212 } 213 } 214 return false; 215 } 216 217 bool backward_reasoning(int num,int message[]) //反向推理 218 { 219 int ii,ij,ik; 220 int prerequisite_num = 0; 221 int hit_num = 0; 222 int need_rule_number[rule_num]; 223 int hit_rule_number[rule_num]; 224 float hit_rule_rate[rule_num]; 225 float best_hit_rule_rate=0; 226 int best_hit_rule_number; 227 int *new_message; 228 cout<<endl<<"计算能推导出结果的规则命中率:"<<endl; 229 for (ii = 0; ii < rule_num; ii++) //遍历规则匹配 230 { 231 for (ij = 0; ij < rule_volume; ij++) //计算规则集前提数 232 { 233 if (rule_prerequisite[ii][ij] == 0) 234 { 235 break; 236 } 237 prerequisite_num++; 238 } 239 need_rule_number[ii]=prerequisite_num; 240 for (ij = 0; ij < prerequisite_num; ij++) //计算输入信息命中规则集中的前提数 241 { 242 for (ik = 0; ik < num; ik++) 243 { 244 if (rule_prerequisite[ii][ij] == message[ik]) 245 { 246 hit_num++; 247 } 248 } 249 } 250 hit_rule_number[ii]=hit_num; 251 if(rule_result[ii]>24) 252 { 253 hit_rule_rate[ii]=(float)hit_num/prerequisite_num; //命中率 254 } 255 else 256 { 257 hit_rule_rate[ii]=0; 258 } 259 cout<<"rule "<<ii<<" :"<<hit_rule_rate[ii]<<"->"<<fact[rule_result[ii]-1]; 260 cout<<" 询问过:"<<bridge_flag[ii]<<endl; 261 } 262 bool flag_check=false; 263 for(ii=0;ii<rule_num;ii++) 264 { 265 if((best_hit_rule_rate<hit_rule_rate[ii])&&bridge_flag[ii]==false) 266 { 267 best_hit_rule_rate=hit_rule_rate[ii]; 268 best_hit_rule_number=ii; 269 flag_check=true; 270 } 271 } 272 if(best_hit_rule_number==0||flag_check==false) 273 { 274 cout<<"您输入的信息对本系统无效!"<<endl<<endl; 275 system("pause"); 276 return false; 277 } 278 cout<<endl; 279 cout<<"best_hit_rule_number="<<best_hit_rule_number<<endl; 280 cout<<"best_hit_rule_rate="<<best_hit_rule_rate<<endl; 281 cout<<"最佳匹配结果="<<fact[rule_result[best_hit_rule_number]-1]<<endl; 282 for(ii=0;ii<need_rule_number[best_hit_rule_number];ii++) 283 { 284 bool flag=false; 285 for(ij=0;ij<num;ij++) 286 { 287 if(rule_prerequisite[best_hit_rule_number][ii]==message[ij]) 288 { 289 flag=true; 290 } 291 } 292 if(flag) 293 { 294 continue; 295 } 296 else 297 { 298 bridge_flag[best_hit_rule_number]=true; 299 if(rule_prerequisite[best_hit_rule_number][ii]<object_middle_begin) 300 { 301 cout<<endl<<"请问您持有的信息是否包含\""; 302 cout<<fact[rule_prerequisite[best_hit_rule_number][ii]-1]; 303 cout<<"\"?(y or n)"<<endl; 304 char input; 305 while(true) 306 { 307 cin>>input; 308 if(input==‘n‘) 309 { 310 new_message=new int[num]; 311 for(ik=0;ik<num;ik++) 312 { 313 new_message[ik]=message[ik]; 314 } 315 break; 316 } 317 else if(input==‘y‘) 318 { 319 new_message=new int[num+1]; 320 for(ik=0;ik<num;ik++) 321 { 322 new_message[ik]=message[ik]; 323 } 324 new_message[num]=rule_prerequisite[best_hit_rule_number][ii]; 325 num++; 326 break; 327 } 328 else 329 { 330 cout<<"请重新输入(y or n)!"; 331 } 332 } 333 } 334 else 335 { 336 //询问是否有中间结果rule_prerequisite[best_hit_rule_number][ii] 337 if(query_middle_result(rule_prerequisite[best_hit_rule_number][ii])) 338 { 339 new_message=new int[num+1]; 340 for(ik=0;ik<num;ik++) 341 { 342 new_message[ik]=message[ik]; 343 } 344 new_message[num]=rule_prerequisite[best_hit_rule_number][ii]; 345 num++; 346 } 347 else 348 { 349 new_message=new int[num]; 350 for(ik=0;ik<num;ik++) 351 { 352 new_message[ik]=message[ik]; 353 } 354 break; 355 } 356 } 357 if(inference(num,new_message)) 358 { 359 return true; 360 } 361 else 362 { 363 return backward_reasoning(num,new_message); 364 } 365 } 366 } 367 } 368 369 int main(int argc, char **argv) 370 { 371 bool flag; 372 int num; 373 int *message; 374 cout << "请输入已有信息数:(数字)" << endl; 375 cin >> num; 376 message = new int[num]; 377 cout << "请输入已有信息:(不重复的数字,以空格隔开)" << endl; 378 for (int ii = 0; ii < num; ii++) 379 { 380 cin >> message[ii]; 381 } 382 cout << endl << "初始信息:"; 383 for (int ij = 0; ij < num; ij++) 384 { 385 cout << fact[message[ij]-1] << " "; 386 } 387 cout << endl<<endl; 388 flag=inference(num,message); 389 if (flag == false) 390 { 391 backward_reasoning(bridge_num,bridge_message); 392 } 393 system("pause"); 394 return 0; 395 }