Простая экспертная система на Java
В прошлой моем примере на тему экспертных систем, я рассказывал о созданной “ЭС поиска неисправностей ПК”. ЭС была выполнена с использованиям языка Prolog и C++. В данном примере я расскажу, как этаже ЭС с тем же набором правил в базе знаний, была реализована на языке Java.
База знаний представлена рекурсивной структурой данных типа бинарное дерево (binary tree). Для реализации более сложных правил можно использовать N-арное дерево, в узлах которых не только хранить правила, но и например какие-нибудь коэффициенты, или статистику. Приведу класс BinaryTree:
public class BinaryTree {
private BinaryTree parent;
private BinaryTree yes;
private BinaryTree no;
private String question;
private String answer;
private boolean isEnd;
public BinaryTree(BinaryTree parent) {
this.parent = parent;
}
public BinaryTree setQuestion(String question) {
this.question = question;
return this;
}
public String getQuestion() {
return question;
}
public BinaryTree getParent() {
return parent;
}
public BinaryTree setAnswer(String answer) {
this.answer = answer;
setEnd();
return this;
}
public String getAnswer() {
return answer;
}
public BinaryTree getYes() {
if (isEnd) return null;
if (yes == null) {
yes = new BinaryTree(this);
}
return yes;
}
public BinaryTree getNo() {
if (isEnd) return null;
if (no == null) {
no = new BinaryTree(this);
}
return no;
}
public boolean isEnd() {
return isEnd;
}
private void setEnd() {
this.isEnd = true;
}
public void setNo(BinaryTree no) {
this.no = no;
}
public void setYes(BinaryTree yes) {
this.yes = yes;
}
}Ядро экспертной системы, находиться в классе ExpertSysyem, в которой реализована рекурсивная функция обхода бинарного дерева:
public static void start(BinaryTree db)
throws IOException {
if(db.isEnd()) {
System.out.println(db.getAnswer());
System.out.println("Объяснить почему ЭС пришла к такому выводу?");
if(readBoolean()) {
stack.clear();
why(db);
for (String el : stack) {
System.out.println(el);
}
}
return;
}
System.out.println(db.getQuestion());
if(readBoolean()) start(db.getYes());
else start(db.getNo());
}Данный метод производит проход в глубину, и идет от корневого узла, до конечного листа. В узлах находатся вопросы, метод выводит вопрос и в зависимости от ответа пользователя производиться переход к следующему узлу, и так происходит до тех пор, пока не дойдет до листа, в котором хранится вывод. Также существует метод why (почему) это обратный рекрсивный метод, который идет от узла или листа, к корню дерева, и выводит на экран то, как ЭС, работала с пользователем. База знаний статическая, времени на реализацию денмаческой БД не было, но при желании вы можете добавить класс отвчеающий за загрузку/выгрузку ЭС, и добавление новых правил и выводов в ее структуру. База зананй представленна следующим образом:
BinaryTree db = new BinaryTree(null);
db.setQuestion("Работает ПК?");
db.getYes().setAnswer("Вам не нужны услуги экспертной системы");
db.getNo().setQuestion("ПК включается?");
db.getNo().getNo().setQuestion("Свет есть?");
db.getNo().getNo().getYes().setAnswer("Поломался блок питания");
db.getNo().getNo().getNo().setAnswer("Включите свет");
db.getNo().getYes().setQuestion("Изображение есть на мониторе?");
db.getNo().getYes().getNo().setQuestion("Монитор подключен к сети?");
db.getNo().getYes().getNo().getNo().setAnswer("Подключите монитор");
db.getNo().getYes().getNo().getYes()
.setQuestion("Индикатор горит на мониторе");
db.getNo().getYes().getNo().getYes().getNo()
.setAnswer("Не работает монитор");
db.getNo().getYes().getNo().getYes().getYes()
.setAnswer("Не работает видеокарта");
db.getNo().getYes().getYes().setQuestion("Писк есть?");
db.getNo().getYes().getYes().getYes()
.setAnswer("Используйте руководство по пискам BIOS");
db.getNo().getYes().getYes().getNo().setQuestion("Загружаеться ОС?");
db.getNo().getYes().getYes().getNo().getNo()
.setQuestion("Есть сообщения об ошибках?");
db.getNo().getYes().getYes().getNo().getNo().getYes()
.setAnswer("Следуйте сообщениям об ошибках");
db.getNo().getYes().getYes().getNo().getNo().getNo()
.setAnswer("Не знаю");
db.getNo().getYes().getYes().getNo().getYes()
.setQuestion("При входе в ОС есть звук?");
db.getNo().getYes().getYes().getNo().getYes().getYes()
.setQuestion("Система загрузилась без ошибок");
db.getNo().getYes().getYes().getNo().getYes().getYes().getYes()
.setAnswer("Следуйте рекомендациям ОС");
db.getNo().getYes().getYes().getNo().getYes().getYes().getNo()
.setAnswer("Приятной работы");
db.getNo().getYes().getYes().getNo().getYes().getNo()
.setQuestion("У вас есть звуковая карта?");
db.getNo().getYes().getYes().getNo().getYes().getNo().getYes()
.setAnswer("Не работает звуковая карта");
db.getNo().getYes().getYes().getNo().getYes().getNo()
.setNo(db.getNo().getYes().getYes().getNo().getYes().getYes());Прилогаю к примеру исходный код проекта (Eclipse проект), где вы можете рассмотреть все подробней, и собраный jar архив, который можно запустить при наличии jvm.
Исходный коды ЭС поиска неисправностей ПК (java) (96)
Скомпилированный пример ЭС (jar файл) (102)