Пример 9.11. Правило no-repairs
(defrule no-repairs ""
(declare (salience -10) )
(not (repair ?) )
= >
(assert (repair "Take your car to a mechanic."))
)
Обратите внимание на использование приоритета при определении этого правила. Все правила, приведенные в предыдущем разделе, определялись с приоритетом, по умолчанию равным нулю. Использование для правила no-repairs приоритета, равного —10, гарантирует, что правило не будет выполнено, пока в плане решения задачи находится, по крайней мере, одно из диагностических правил. Если все активированные диагностические правила отработали и ни одно из них не смогло подобрать подходящую рекомендацию по устранению неисправности, то CLIPS запустит правило no-repairs, которое просто порекомендует пользователю обратиться к более опытному механику.
Реализация правил 2 и 3 приведена ниже.
Пример 9.12. Правила normal-engine-state-conclusions и unsatisfactory-engine-state-conclusions
(defrule normal-engine-state-conclusions ""
(declare (salience 10) )
(working-state engine normal)
=>
(assert (repair "No repair needed."))
(assert (spark-state engine normal))
(assert (charge-state battery charged))
(assert (rotation-state engine rotates))
)
(defrule unsatisfactory-engine-state-conclusions ""
(declare (salience 10))
(working-state engine unsatisfactory)
=>
(assert (charge-state battery charged))
(assert (rotation-state engine rotates))
)
В этих правилах, наоборот, используется более высокий приоритет, что гарантирует их выполнение до выполнения любого диагностического правила (естественно, только в случае удовлетворения условий, заданных в левой части правил). Это избавит нашу систему от лишних проверок, а пользователя от лишних вопросов.
Наша экспертная система фактически готова к работе. Единственное, чего ей не хватает, — это метода вывода итоговой информации и правила, сообщающего пользователю о начале работы. Ниже приведена реализация этих правил.
Пример 9.13. Правила system-banner и print-repair
(defrule system-banner ""
(declare (salience 10))
=>
(printout t crlf crlf)
(printout t "**********************************" crlf)
(printout t "* The Engine Diagnosis Expert System *" crlf)
(printout t "**********************************" crlf)
(printout t crlf crlf)
)
(defrule print-repair ""
(declare (salience 10))
(repair ?item)
=>
(printout t crlf crlf)
(printout t "Suggested Repair:")
(printout t crlf crlf)
(format t " %s%n%n%n" ?item)
)
Листинг программы
В данном разделе приведен полный листинг программы с подробными комментариями. Если у вас еще не сложилась целостная картина о том, как работает наша экспертная система, из каких частей она состоит, внимательно изучите приведенный ниже код.
Пример 9.14. Полный листинг программы
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
; Пример экспертной системы на языке CLIPS
;
; Приведенная ниже экспертная система способна
; диагностировать некоторые неисправности автомобиля и
; предоставлять пользователю рекомендации по устранению
; неисправности.
;
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
; Вспомогательные функции
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - -
; Функция ask-question задает пользователю вопрос, полученный
; в переменной ?question, и получает от пользователя ответ,
; принадлежащий списку допустимых ответов, заданному в $?allowed-values
(deffunction ask-question (?question $?allowed-values)
(printout t ?question)
(bind ?answer (read))
(if (lexemep ?answer)
then
(bind ?answer (lowcase ?answer)))
(while (not (member ?answer ?allowed-values)) do
(printout t ?question)
(bind ?answer (read))
(if (lexemep ?answer)
then
(bind ?answer (lowcase ?answer))))
?answer
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Функция yes-or-no-p задает пользователю вопрос, полученный
; в переменной ?question, и получает от пользователя ответ yes(у) или
; по(n). В случае положительного ответа функция возвращает значение TRUE,
; иначе — FALSE
(deffunction yes-or-no-p (?question)
(bind ?response (ask-question ?question yes no у n))
(if (or (eq ?response yes) (eq ?response y))
then
TRUE
else
FALSE)
)
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
; Диагностические правила
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-engine-state определяет текущее состояние двигателя
; машины по ответам, получаемым от пользователя. Двигатель может
; находиться в одном из трех состояний: работать нормально
; (working-state engine normal) , работать неудовлетворительно
; (working-state engine unsatisfactory) и не заводиться
; (working-state engine ;does-not-start) (см. правило 1).
(defrule determine-engine-state ""
(not (working-state engine ?) )
(not (repair ?) )
=>
(if (yes-or-no-p "Does the engine start (yes/no) ? ")
then
(if (yes-or-no-p "Does the engine run normally (yes/no)? ")
then
(assert (working-state engine normal) )
else
(assert (working-state engine unsatisfactory) ) )
else
(assert (working-state engine does-not-start) ) )
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-rotation-state определяет состояние вращения двигателя по ответу,
; получаемому от пользователя. Двигатель может вращаться (rotation-state engine rotates)
; или не вращаться (spark-state engine does-not-spark) (см. правило 4).
; Кроме того, правило делает предположение о наличии плохой искры
; или ее отсутствии в системе зажигания
(defrule determine-rotation-state ""
(working-state engine does-not-start)
(not (rotation-state engine ?))
(not (repair ?))
=>
(if (yes-or-no-p "Does the engine rotate (yes/no)? ")
then
; Двигатель вращается
(assert (rotation-state engine rotates))
; Плохая искра
(assert (spark-state engine irregular-spark))
else
; Двигатель не вращается
(assert (rotation-state engine does-not-rotate))
; Нет искры
(assert (spark-state engine does-not-spark)))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-gas-level по ответу пользователя определяет
; наличие топлива в баке. В случае если топлива нет, пользователю
; выдается рекомендация по ремонту — машину необходимо заправить
; (repair "Add gas.") (см. правило 5) . При появлении соответствующей
; рекомендации выполнение диагностических правил прекращается.
(defrule determine-gas-level ""
(working-state engine does-not-start)
(rotation-state engine rotates)
(not (repair ?) )
=>
(if (not (yes-or-no-p "Does the tank have any gas in it (yes/no) ? ") )
then
; Машину необходимо заправить
(assert (repair "Add gas.")))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-battery-state по ответу пользователя определяет,
; заряжен ли аккумулятор. В случае если это не так, пользователю
; выдается рекомендация по ремонту — Зарядите аккумулятор (repair
; "Charge the battery.") (см. правило 6) .
; Кроме того, правило добавляет факт, описывающий состояние аккумулятора.
; Выполнение диагностических правил прекращается
(defrule determine-battery-state ""
(rotation-state engine does-not-rotate}
; Состояние аккумулятора еще не определено
(not (charge-state battery ?))
(not (repair ?))
=>
(if (yes-or-no-p "Is the battery charged (yes/no)? ")
then
; Аккумулятор заряжен
(assert (charge-state battery charged))
else
; Зарядите аккумулятор
(assert (repair "Charge the battery."))
; Аккумулятор разряжен
(assert (charge-state battery dead)))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-low-output определяет, развивает ли двигатель
; нормальную выходную мощность или нет и добавляет в систему факт,
; описывающий эту характеристику (см. правило 12).
(defrule determine-low-output ""
(working-state engine unsatisfactory)
; Мощность работы двигателя еще не определена
(not (symptom engine low-output | not-low-output))
(not (repair ?))
=>
(if (yes-or-no-p "Is the output of the engine low (yes/no)? ")
then
; Низкая выходная мощность двигателя
(assert (symptom engine low-output))
else
; Нормальная выходная мощность двигателя
(assert (symptom engine not-low-output)))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-point-surface-state определяет по ответу
; пользователя состояние контактов (см. правила 7, 12). Контакты могут
; находиться в одном из трех состояний: чистые, опаленные и
; загрязненные. В двух последних случаях пользователю выдаются
; соответствующие рекомендации.
; Выполнение диагностических правил прекращается.
(defrule determine-point-surfасе-state ""
(or (and (working-state engine does-not-start);не заводится
(spark-state engine irregular-spark));и плохая искра
(symptom engine low-output));или низкая мощность
(not (repair ?))
=>
(bind ?response (ask-question "What is the surface state of the
points (normal /burned /contaminated)?"
normal burned contaminated))
(if (eq ?response burned)
then
; Контакты опалены — замените контакты
(assert (repair "Replace the points."))
else
(if (eq ?response contaminated)
then
; Контакты загрязнены - почистите их
(assert (repair "Clean the points."))))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-conductivity-test по ответу пользователя определяет,
; пропускает ли ток катушка зажигания. Если нет, то ее следует заменить.
; Если пропускает, то причина неисправности — распределительные провода.
; Для нормальной работы правила необходимо убедиться, что аккумулятор
; заряжен и искры нет (см. правило 8)
; Выполнение диагностических правил прекращается.
(defrule determine-conductivity-test ""
(working-state engine does-not-start)
(spark-state engine does-not-spark) ;нет искры
(charge-state battery charged) ;аккумулятор заряжен
(not (repair ?) )
=>
(if (yes-or-no-p "Is the conductivity test for the ignition coil positive (yes/no) ? ")
then
; Замените распределительные провода
(assert (repair "Repair the distributor lead wire."))
else
; Замените катушку зажигания
(assert (repair "Replace the ignition coil.")))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-sluggishness спрашивает пользователя, не ведет ли
; себя машина инертно (не сразу реагирует на подачу топлива) .
; Если такой факт обнаружен, то необходимо прочистить
; топливную систему (см. правило 9) и выполнение диагностических правил
; прекращается.
(defrule determine-sluggishness ""
(working-state engine unsatisfactory)
(not (repair ?))
=>
(if (yes-or-no-p "Is the engine sluggish (yes/no)? ")
then
; Прочистите систему подачи топлива
(assert (repair "Clean the fuel line.")))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-misfiring узнает — нет ли перебоев с зажиганием.
; Если это так, то необходимо отрегулировать зазоры между контактами
; (см. правило 10).
; Выполнение диагностических правил прекращается.
(defrule determine-misfiring ""
(working-state engine unsatisfactory)
(not (repair ?))
=>
(if (yes-or-no-p "Does the engine misfire (yes/no)? ")
then
; Отрегулируйте зазоры между контактами
(assert (repair "Point gap adjustment."))
; Плохая искра
(assert (spark-state engine irregular-spark)))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило determine-knocking узнает — не стучит ли двигатель.
; Если это так, то необходимо отрегулировать зажигание (см. правило 11).
; Выполнение диагностических правил прекращается.
(defrule determine-knocking ""
(working-state engine unsatisfactory)
(not (repair ?))
=>
(if (yes-or-no-p "Does the engine knock (yes/no)? ")
then
; Отрегулируйте положение зажигания
(assert (repair "Timing adjustment.")))
)
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
; Правила, определяющие состояние некоторых подсистем автомобиля
; по характерным состояниям двигателя
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило normal-engine-state-conclusions реализует правило 2
(defrule normal-engine-state-conclusions ""
(declare (salience 10))
; Если двигатель работает неудовлетворительно
(working-state engine normal)
=>
; то
(assert (repair "No repair needed.")) ; ремонт не нужен
(assert (spark-state engine normal)) ; зажигание в норме
(assert (charge-state battery charged)) ; аккумулятор заряжен
(assert (rotation-state engine rotates)) ; двигатель вращается
)
; Правило unsatisfactory-engine-state-conclusions реализует правило 3
(defrule unsatisfactory-engine-state-conclusions ""
(declare (salience 10))
; Если двигатель работает нормально
(working-state engine unsatisfactory)
=>
; то
(assert (charge-state battery charged)) ; аккумулятор заряжен
(assert (rotation-state engine rotates)) ; двигатель вращается
)
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; Запуск и завершение
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило no-repairs запускается в случае, если ни одно
; из диагностических правил не способно определить неисправность.
; Правило корректно прерывает выполнение экспертной системы и предлагает
; пройти более тщательную проверку (см. правило 13).
(defrule no-repairs ""
(declare (salience -10))
(not (repair ?))
=>
(assert (repair "Take your car to a mechanic."))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило print-repair выводит на экран диагностическое сообщение
; по устранению найденной неисправности,
(defrule print-repair ""
(declare (salience 10))
(repair ?item)
=>
(printout t crlf crlf)
(printout t "Suggested Repair:")
(printout t crlf crlf)
(format t " %s%n%n%n" ?item)
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Правило system-banner выводит на экран название экспертной системы
; при каждом новом запуске.
(defrule system-banner " каждом новом запуске."
(declare (salience 10) )
=>; каждом новом запуске.
(printout t crlf crlf)
(printout t "********************************************" crlf)
(printout t "* The Engine Diagnosis Expert System *" crlf)
(printout t "**********************************" crlf)
(printout t crlf crlf)
)
Помните, что среда CLIPS (по крайней мере, последняя версия 6.20) воспринимает только символы английского алфавита. Все комментарии в приведенном листинге даны на русском языке для наглядности, однако при вводе программы в таком виде CLIPS выведет сообщение об ошибке.
Запуск программы
Для запуска программы наберите приведенный в примере 9.14 листинг в каком-нибудь текстовом редакторе (лучше использовать встроенный редактор CLIPS по причинам, упоминавшимся в гл. 6). Сохраните набранный файл, например, с именем auto.CLP.
После этого запустите CLIPS или, если он уже был у вас запущен, очистите его командой (clear). Загрузите созданный вами файл с помощью команды (load "auto.CLP"). Если файл был набран без ошибок, то вы должны увидеть сообщения, представленные на рис. 9.1.
Рис. 9.1 демонстрирует успешную попытку загрузки файла конструкторов. Обратите внимание, что функция load вернула значение true. Если это нетак, значит, в синтаксисе определений функций или правил была допущена ошибка. Для загрузки вы также могли бы воспользоваться функцией load*. В этом случае на экран не выводилась бы информация, отражающая процесс загрузки.
Рис. 9.1.Загрузка экспертной системы
После удачной загрузки файла убедитесь, что все правила присутствуют в списке правил CLIPS, а функции — в списке функций. Легче всего это выполнить с помощью менеджеров правил и функций соответственно. Внешний вид этих менеджеров показан на рис. 9.2 и 9.3.
Для того чтобы запустить нашу экспертную систему, достаточно выполнить команду reset, которая добавит факт initial-fact, необходимый для правила system-banner, и команду run. После этого вы сразу увидите сообщение "The Engine Diagnosis Expert system", которое означает, что система начала работать, и получите серию вопросов, ответы на которые помогут экспертной системе оценить текущее состояние вашей машины и подобрать соответствующую рекомендацию по ремонту. Пример работы системы показан на рис. 9.4.
Обратите внимание, что если после завершения работы нашей экспертной системы в списке фактов CLIPS остаются факты, описывающие состояние автомобиля, их легко просмотреть с помощью команды Fact Windowиз меню Window.Факты для нашего примера изображены на рис. 9.5.
Рис. 9.2. Правила экспертной системы
Рис. 9.3.Функции экспертной системы
Для повторного запуска экспертной системы необходимо еще раз выполнить команды reset и run. Протестируйте экспертную систему, по-разному отвечая на ее вопросы. Чтобы лучше понять механизмы ее работы и логический механизм вывода CLIPS, перед запуском системы сделайте видимым окно фактов (Fact Window)и окно плана решения задачи (Agenda Window).
Приведенный в этой главе пример доступен в Интернете по адресу: www.ghg.net/clips/download/executables/examples/auto.clp.
Рис. 9.4.Диалог с экспертной системой
Рис. 9.5.Результаты работы экспертной системы
В данной главе был рассмотрен достаточно реальный пример построения экспертной системы в CLIPS. Он является наглядным подтверждением того, что с помощью фактов, функций и правил CLIPS можно построить вполне работоспособную систему. Однако CLIPS содержит и более сложные конструкции, такие как родовые функции, объекты и модули. С их помощью вы сможете строить еще более гибкие и мощные экспертные системы. Изучением этих конструкций мы и займемся в следующей главе.
Дата добавления: 2021-12-14; просмотров: 330;