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