这次的人工智能实验是产生式系统——动物分类
规则:R1:动物有毛→ 哺乳类
R2:动物产奶 → 哺乳类
R3:动物有羽毛 → 鸟类
R4:动物会飞 ∧会下蛋 → 鸟类
R5:哺乳类∧动物吃肉→ 食肉类
R6:动物有犬齿 ∧有爪 ∧眼盯前方→肉食类
R7:哺乳类 ∧有蹄 →蹄类动物
R8:哺乳类 ∧反刍 → 蹄类
R9:食肉类 ∧ 黄褐色 ∧ 有斑点→ 金钱豹
R10:食肉类 ∧ 黄褐色 ∧ 有黑色条纹→虎
R11:蹄类 ∧ 长脖 ∧ 长腿 ∧ 有斑点→ 长颈鹿
R12:蹄类 ∧ 有黑色条纹→ 斑马
R13:鸟类 ∧长脖 ∧ 长腿 ∧ 不会飞 →鸵鸟
R14:鸟类 ∧会游泳 ∧黑白二色 ∧ 不会飞 →企鹅
R15:鸟类 ∧善飞 →信天翁
产生式系统的问题求解过程即为对解空间的搜索过程,也就是推理过程。按照搜索的方向可把产生式系统分为正向推理、逆向推理和双向推理。
正向推理:从一组表示事实的谓词或命题出发,使用一组产生式规则,用以证明该谓词公式或命题是否成立。
逆向推理:从表示目标的谓词或命题出发,使用一组产生式规则证明事实谓词或命题成立,即首先提出一批假设目标,然后逐一验证这些假设。
双向推理:双向推理的推理策略是同时从目标向事实推理和从事实向目标推理,并在推理过程中的某个步骤,实现事实与目标的匹配。
这里,我们采用双向推理。通俗来说,双向推理就是先采用正向推理,如果已经是无法进行下去的情况,采用逆向推理,这个时候就需要询问用户是否能观察到某
些逆向推理出来的特征,然后讲这些特征加入到已知的条件特征中,再次进行正向推理,如此反复,知道得到最后的结果。需要注意的是,上面给定的规则库中的
名词可以分为三类:1.已知类,即用户能实际观察到的动物特征,这些只会出现在每个条件的前半段;2.概念类,即对动物进行的抽象的概念概括,也算是推理的
中间产物,会出现在条件的前端或后端;3.结果类,即最后推理出来的结果,真实的动物,只会出现在条件的后端。
有了这些概念之后,下面就是具体的推理过程了,我所采用的方式是读取规则库txt文件,将所有名词编号,然后用编号来组织成一条条件,遍历这些条件,根据
用户给出的名词,进行比较,同时计算每个条件的符合程度,推理出的名词加入到已知的名词队列中,重新遍历条件,更新符合度,如果没有100%符合的条件,则
寻找符合度最高的条件,进行逆向推理,询问可能的且没有在已知名词队列中的名词,进行判断,加入名词队列,重新遍历,更新符合度,直至找到属于结果类的
名词,即是结果。
代码中,只要是按照这种格式编写的规则的txt文件,都可以进行推理,实现了更便捷的应用。
下面是实现代码:
首先是主处理流程类,Project:
import java.util.ArrayList;
import java.util.Scanner;
/**
* 主函数,处理
* @author 41571
*
*/
public class Project {
public static ArrayList word = new ArrayList(); //存放所有的词汇,用下标来编号
public static ArrayList sentenceList = new ArrayList(); //存放句子
private ArrayList now = new ArrayList(); //存放用户输入的条件
public static ArrayList know = new ArrayList();
public static void main(String args[]){
new Project();
}
public Project(){
new ReadFile();
System.out.println("请输入你已知的信息(空格间隔):");
Scanner in = new Scanner(System.in);
dealKnow(in.nextLine());
/* for(int i = 0;i < word.size();i ++){
System.out.print(i+": ");
word.get(i).show();
}*/
domain();
}
private void dealKnow(String nextLine) { //处理输入的已知信息
// TODO Auto-generated method stub
char[] temp = nextLine.toCharArray();
int a = temp.length -1 ;
for(int i = temp.length - 1;i >= 0;i --){
if(temp[i] == ' '){
toString(temp,i+1,a);
a = i -1;
}
if(i == 0){
toString(temp,0,a);
}
}
addKnow();
}
private void toString(char[] temp, int j, int i) { //转化为字符串,开始位置,结束位置
// TODO Auto-generated method stub
String str = "";
for(int m = j;m <= i;m ++){
str = str+temp[m];
}
now.add(new Condition(str));
}
private void addKnow() {
// TODO Auto-generated method stub
for(int i = 0;i < now.size();i ++){
know.add(find(now.get(i).getStr()));
}
//sortKnow();
}
/*private void sortKnow(){
int a;
for(int i = 0;i < know.size();i ++){
for(int j = i+1;j < know.size();j ++){
if(know.get(i) > know.get(j)){
a = know.get(j);
know.set(j, know.get(i));
know.set(i, a);
}
}
}
}*/
private int find(String str) {
// TODO Auto-generated method stub
for(int i = 0;i < Project.word.size();i ++){
if(str.equals(Project.word.get(i).getStr())){
return i;
}
}
return -1;
}
public void domain(){ //主进程
int a,z = 0;
boolean out = true;
while(out){
a = 0;z = 0;
for(int i = 0;i < sentenceList.size();i ++){
if(sentenceList.get(i).isLook()){ //isLook==true时,表示这个还没有完全匹配
sentenceList.get(i).compare();
if(sentenceList.get(i).getMay() == 1.0){
know.add(sentenceList.get(i).getResult());
sentenceList.get(i).setLook(false); //不再遍历
sentenceList.get(i).setNeglect(false); //忽视这个语句
a = 1;z = 1;
if(word.get(sentenceList.get(i).getResult()).isBaceOK()){
System.out.println("你所描述的对象是"+word.get(sentenceList.get(i).getResult())
.getStr()+"。");
out = false;
break;
}
}
}
}
/*for(int i = 0;i < sentenceList.size();i ++){
if(!sentenceList.get(i).isNeed()){
sentenceList.get(i).setNeglect(false);
}
}*/
if(a == 0){
/*for(int i = 0;i < know.size();i ++){
System.out.println(word.get(know.get(i)).getStr());
}*/
float max = 0;int tag = 0; //找出最有可能的句子,询问用户
for(int i = 0;i < sentenceList.size();i ++){
if(sentenceList.get(i).isLook()&&sentenceList.get(i).isNeglect()&&
sentenceList.get(i).isNeed()){
//isLook == true时,说明当前语句没有完全匹配,isNeglect == true 说明这个句子在询问查询时不能忽略
sentenceList.get(i).compare();
if(sentenceList.get(i).getMay()>max){
max = sentenceList.get(i).getMay();
tag = i;
}
}
}
for(int k = 0;k < sentenceList.get(tag).getNotExist().length;k ++){
if(word.get(sentenceList.get(tag).getNotExist()[k]).isFrontOK()){
System.out.println("请问你是否发现该对象有 “"+word.get(sentenceList
.get(tag).getNotExist()[k]).getStr()
+"” 特征吗?(是的回答“y”,否或不知道回答“n”)");
Scanner in = new Scanner(System.in);
String input = in.nextLine();
char[] inputs = input.toCharArray();
z = 1;
if(inputs[0] == 'y'){
know.add(sentenceList.get(tag).getNotExist()[k]);
break;
}else{
sentenceList.get(tag).setNeglect(false); //忽略这个句子
break;
}
}
else{
sentenceList.get(tag).setNeglect(false);
}
}
}
if(z == 0){
System.out.println("抱歉!系统暂时未包含该对象!");
out = false;
}
/*if(a == 0){ //如果没有匹配的了,就要询问用户可能的情况了
int m = 0;
while(m == 0){
for(int j = 0;j < sentenceList.size();j ++){
if(sentenceList.get(j).isLook()){
if(sentenceList.get(j).getNotExist()!=null)
for(int k = 0;k < sentenceList.get(j).getNotExist().length;k ++){
if(word.get(sentenceList.get(j).getNotExist()[k]).getBack()&& //即出现在前端又
word.get(sentenceList.get(j).getNotExist()[k]).getFront()); //出现在后端
else{
System.out.println("请问你是否发现该对象有 “"+word.get(sentenceList
.get(j).getNotExist()[k]).getStr()
+"” 特征吗?(是的回答“y”,否回答“n”)");
Scanner in = new Scanner(System.in);
String input = in.nextLine();
char[] inputs = input.toCharArray();
if(inputs[0] == 'y'){
know.add(sentenceList.get(j).getNotExist()[k]);
m = 1;
}else{
if(k+1==sentenceList.get(j).getNotExist().length){
sentenceList.get(j).setNeglect(false);
break;
}
}
}
}
}
}
}
}*/
}
}
}
接下来是条件句子类Sentence:
/**
* 经过处理的一个句子
* 包括条件
* 还有结果
* @author 41571
*
*/
public class Sentence {
private int[] begin;
private int result;
private int[] notExist;
private float may;
private boolean isLook = true; //是否完全匹配
private boolean neglect = true; //询问用户时是否忽略
public boolean isNeglect() {
return neglect;
}
public void setNeglect(boolean neglect) {
this.neglect = neglect;
}
public Sentence(){
}
public boolean isLook() {
return isLook;
}
public void setLook(boolean isLook) {
this.isLook = isLook;
}
public void compare(){
int[] temp = new int[10];
int a,m = 0;
for(int i = 0;i < begin.length;i ++){
a = 0;
for(int j = 0;j < Project.know.size();j ++){
if(Project.know.get(j) == begin[i]){
a = 0;
break;
}
a = 1;
}
if(a == 1){
temp[m++] = begin[i];
}
}
notExist = new int[m];
for(int i = 0;i < m;i ++){
notExist[i] = temp[i];
}
may = ((float)(begin.length-notExist.length))/begin.length;
}
public int[] getNotExist() {
return notExist;
}
public void setNotExist(int[] notExist) {
this.notExist = notExist;
}
public float getMay() {
return may;
}
public int[] getBegin() {
return begin;
}
public void setBegin(int[] begin) {
this.begin = sort(begin);
}
private int[] sort(int[] begin) {
// TODO Auto-generated method stub
int a;
for(int i = 0;i < begin.length;i ++){
for(int j = i+1;j < begin.length;j ++){
if(begin[i] > begin[j]){
a = begin[j];
begin[j] = begin[i];
begin[i] = a;
}
}
}
return begin;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
public boolean isNeed() {
// TODO Auto-generated method stub
for(int i = 0;i < Project.know.size();i ++){
if(this.result == Project.know.get(i)){
return false;
}
}
return true;
}
}
/**
* 名词条件类,属性包括两个boolean型变量
* @author 41571
*
*/
public class Condition {
private String str;
private boolean front; //是前端的
private boolean back; //是后端的
//如果既是前端的,也是后端的,那就是中间属性
public Condition(String str){
this.str = str;
}
public String getStr(){
return this.str;
}
public void setFront(boolean front){
this.front = front;
}
public void setBack(boolean back){
this.back = back;
}
public boolean getFront(){
return this.front;
}
public void show(){
System.out.println("字符串:"+this.str+" Front:"+this.front+" Back:"+this.back);
}
public boolean getBack(){
return this.back;
}
public boolean isFrontOK(){ //是否是前端
if(this.front&&!this.back){
return true;
}
return false;
}
public boolean isBaceOK(){ //是否是后端
if(!this.front&&this.back){
return true;
}
return false;
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Scanner;
import java.io.OutputStreamWriter;
/**
* 读取文件类,将文件内容加工成
* @author 41571
*
*/
public class ReadFile {
private final String filePath = "file\\knowledge.txt";
private ArrayList content = new ArrayList(); //存放读取到的所有数据
//public ArrayList word = new ArrayList(); //存放所有的词汇,用下标来编号
public ReadFile(){
getData();
}
private void getData() {
// TODO Auto-generated method stub
/*try{ //写入文件
File file = new File(filePath);
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(file),"gbk");
BufferedWriter writer = new BufferedWriter(write);
writer.write(content);
writer.close();
}catch(Exception e){
e.printStackTrace();
}*/
try{ //读取文件
File file = new File(filePath);
if(file.isFile()&&file.exists()){
InputStreamReader read = new InputStreamReader(new FileInputStream(file),"gbk");
BufferedReader reader = new BufferedReader(read);
String line;
while((line = reader.readLine())!=null){
content.add(line);
}
read.close();
}
}catch(Exception e){
e.printStackTrace();
}
collectWord(); //收集所有关键词
collectSentence(); //收集所有的句子
}
private void collectSentence() {
// TODO Auto-generated method stub
for(int i = 0;i < content.size();i ++){
char[] temp = content.get(i).toCharArray();
for(int j = (temp.length-1);j > 0;j --){
if(temp[j] == '>'){
String str = toString(temp,j+1,temp.length-1);
Sentence sen = new Sentence();
sen.setResult(find(str));
setBegin(temp,j,sen);
}
}
}
}
private void setBegin(char[] temp, int j, Sentence sen) {
// TODO Auto-generated method stub
int a = j-1;
int[] test = new int[10];
int total = 0;
int[] begin;
for(int i = j-1;i >= 0;i --){
if(temp[i] == '^'){
String str = toString(temp,i+1,a); //数组,开始位置,结束位置
test[total++] = find(str);
a = i-1;
}
if(i == 0){
String str = toString(temp,0,a);
test[total++] = find(str);
}
}
begin = new int[total];
for(int i = 0;i < total;i ++){
begin[i] = test[i];
}
sen.setBegin(begin);
Project.sentenceList.add(sen);
/* for(int i = 0;i < sen.getBegin().length;i ++){
System.out.print(sen.getBegin()[i]+" ");
}
System.out.println("result:"+sen.getResult());*/
}
private int find(String str) {
// TODO Auto-generated method stub
for(int i = 0;i < Project.word.size();i ++){
if(str.equals(Project.word.get(i).getStr())){
return i;
}
}
return 0;
}
private void collectWord() {
// TODO Auto-generated method stub
for(int i = 0;i < content.size();i ++){
char[] temp = content.get(i).toCharArray();
for(int j = (temp.length-1);j > 0;j --){
if(temp[j] == '>'){
String str = toString(temp,j+1,temp.length-1);
addStr(str,1,1); //position = 1表示后条件,a = 1 表示在后面遇到
precondition(temp,j); //前提
}
}
}
}
private void precondition(char[] temp, int j) {
// TODO Auto-generated method stub
int a = j-1;
for(int i = j-1;i >= 0;i --){
if(temp[i] == '^'){
String str = toString(temp,i+1,a); //数组,开始位置,结束位置
addStr(str,-1,-1); //position = -1表示前条件,a = -1 表示在前面遇到
a = i-1;
}
if(i == 0){
String str = toString(temp,0,a);
addStr(str,-1,-1);
}
}
}
private void addStr(String str,int position,int a) {
// TODO Auto-generated method stub
boolean is = true;
for(int i = 0;i < Project.word.size();i ++){
if(str.equals(Project.word.get(i).getStr())){
is = false;
Project.word.get(i).setFront(true);
}
}
if(is){
Condition con = new Condition(str);
if(position == 1){
con.setBack(true);
}else if(position == -1){
con.setFront(true);
}
Project.word.add(con);
}
}
private String toString(char[] temp, int j, int i) {
// TODO Auto-generated method stub
String str = "";
for(int m = j;m <= i;m ++){
str = str+temp[m];
}
return str;
}
}