В данном проекте предметную область составляют наиболее часто встречающиеся заболевания, а именно: ларингит, фарингит, грипп, орви, бронхит, менингит, гастрит, язва, отравление, мигрень, краснуха, корь, анемия.
У каждой болезни имеется набор признаков или, выражаясь медицинскими терминами, симптомов. Одни и те же симптомы могут являться признаками одной и той же болезни.
Система состоит из пяти компонентов, которые отвечают за решение проблемы. К ним относятся:
- Рабочая память
- База знаний
- Машина логического вывода
- Консультирующая программа (система объяснения и пользовательский интерфейс)
- Система приобретения знаний
Рабочая память системы состоит из фактов – симптомов. Эти факты мы определяем с помощью шаблона, который имеет 4 слота – название симптома, перечень болезней, для которых этот симптом характерен, вопрос о наличии данного симптома, и ответ на вопрос.
Фрагмент рабочей памяти:
(sympthom (name pain_in_muscles) (type flu poisoning meningitis) (question "Is there pain in muscles? - yes - 1) no - 2) why - 3)") (answer unknown))
(sympthom (name cought) (type flu ORVI laringitis pharingitis bronchitis measles meningitis) (question "Is there cought? - yes - 1) no - 2) why - 3)") (answer unknown))
(sympthom (name weaknesses) (type flu ORVI migraine bronchitis measles meningitis anemia) (question "Is there weaknesses? - yes - 1) no - 2) why - 3)") (answer unknown))
(sympthom (name paleness) (type anemia) (question "Is there paleness? - yes - 1) no - 2) why - 3)") (answer unknown))
(sympthom (name faint) (type anemia) (question "Is there faint? - yes - 1) no - 2) why - 3)") (answer unknown))
База знаний состоит из набора правил, и когда пользователь отвечает на поставленный вопрос, изменяются факты, соответствующие ответам, в частности, меняется слот answer в факте symptom. Фрагмент базы знаний (знания об анемии):
(defrule ask_anemia ; спрашиваем о симптоме
(declare (salience 120)) ; объявляем приоритет правила
(not (suggest ?)) ; спрашиваем, когда еще нет решения
(not(no $? anemia $?)) ; и нет решения, что точно не анемия
; f1 нужно для изменения значений слотов
?f1 <- (sympthom (name ?name) (type $?x anemia $?z) (question ?question) (answer unknown))
=>
(bind ?response (ask-allowed ?question 1 2 3)) ; записываем ответ на вопрос в response
(if (eq ?response 1) ; если ответ на вопрос 1), т.е. yes
then
(modify ?f1 (answer yes)) ;тогда меняем в слоте unknown на yes
(assert( name ?name )) ;принимаем симптом как факт
else (if (eq ?response 2) ;если ответ 2), т.е. нет
then
(modify ?f1 (answer no)) ;то меняем в слоте answer ответ на no
(assert(no $?x anemia $?z)) ;принимаем факт, что это точно не
;те болезни, у которых есть этот симптом
else
(if (eq ?response 3) ;если пользователю интересно почему ему задают такой вопрос,
then
(modify ?f1 (answer unknown)) ;перепишем факт, чтобы продукция его не отбросила, т.к. ответ по-прежнему неизвестен
(printout t "There is suggest that you have anemia" crlf)) ;выводим наше предположение
(defrule anemia ; это правило определяет болезнь
(declare (salience 115)) ;приоритет правила
(not(suggest ?))
(name headache) ;левая часть правила - симптомы
(name weaknesses)
(name paleness)
(name faint)
=>
;правая часть – предположение о диагнозе
(assert(suggest "This is anemia, because you have headache, weaknesses, paleness and faint"))
Программа перебирает правила, и ищет то правило, которое выполняется при имеющихся фактах. Для того чтобы избежать возможных конфликтов, используется свойство salience. Результат работы программы – предположение о диагнозе, или вывод сообщения о том, что предположений нет.
Эта программа ведет диалог с пользователем.
Она спрашивает его о наличии диагноза, и он может выбрать один из трех вариантов ответа – да, нет, или спросить у системы, зачем ей это знание.
Примеры диалогов с пользователем:
Пользователь отвечает на вопросы, а также сам спрашивает, зачем система задает такой вопрос.
Пример определения диагноза – анемия.
Для того чтобы добавить какую-либо болезнь, необходимо в рабочей памяти, в фактах-симптомах, в мультислоте type, в котором перечислены релевантные симптому болезни, приписать эту болезнь для каждого симптома, характерного этой болезни, и аналогично добавляем два таких же правила – которые спрашивают, и выводят решение, приписав для правил отличные от всех остальных приоритеты. Таким образом, с добавлением правил не возникает никаких сложностей, поскольку нет необходимости изменять какие-то данные по всему коду. Достаточно просто добавить 2 правила для болезни, и добавить название этой болезни к имеющимся симптомам, или создать новый симптом.