Пример 14.17. Правило print-result

(defrule print-result

(print-results)

?f <- (result $?input?response)

(not (result $?input-2?response-2&:

(< (str-compare?response-2?response) 0)))

=>

(retract?f)

(while (neq?input (create$)) do

(printout t " " (nth 1?input) " ")

(bind?input (rest$?input)))

(printout t " | ")

(bind?response (str-explode?response))

(while (neq?response (create$)) do

(printout t " " (nth 1?response) " ")

(bind?response (rest$?response)))

(printout t crlf)

)

Правило print-result выводит на экран оптимизированную таблицу истинности, сортируя при этом ее строки.

Листинг программы

Разработку экспертной системы CIOS можно считать завершенной. Данный раздел содержит полный листинг программы с подробными комментариями. Если у вас еще не сложилась целостная картина, как работает эксперт­ная система CIOS, из каких частей она состоит, внимательно изучите приведенный код.

Пример 14.18. Полный листинг программы

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

; Пример экспертной системы на языке CLIPS

;

; Приведенная ниже экспертная система способна находить

; и оптимизировать таблицы истинности заданных логических схем.

;

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

; Необходимые классы

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс COMPONENT является суперклассом для всех классов логических элементов

(defclass COMPONENT

(is-a USER)

(slot ID# (create-accessor write))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс NO-OUTPUT реализует логику работы элемента без логических выходов

(defclass NO-OUTPUT

(is-a USER)

(slot number-of-outputs (access read-only)

(default 0)

(create-accessor read))

)

; Предварительное объявление обработчика, осуществляющего обработку полученного сигнала

(defmessage-handler NO-OUTPUT compute-output ())

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс ONE-OUTPUT реализует логику работы элемента с одним логическим выходом

(defclass ONE-OUTPUT

(is-a NO-OUTPUT)

(slot number-of-outputs (access read-only)

(default 1)

(create-accessor read))

; значение выхода

(slot output-1 (default UNDEFINED)

(create-accessor write))

; название элемента, с которым связан выход

(slot output-1-link (default GROUND)

(create-accessor write))

; номер входа, с которым связан выход

(slot output-1-link-pin (default 1)

(create-accessor write))

)

; Обработчик для передачи обработанного сигнала на вход следующего элемента

(defmessage-handler ONE-OUTPUT put-output-1 after (?value)

(send?self:output-1-link

(sym-cat put-input-?self:output-l-link-pin)

?value)

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс TWO-OUTPUT реализует логику работы элемента с двумя логическими выходами

(defclass TWO-OUTPUT

(is-a ONE-OUTPUT)

(slot number-of-outputs (access read-only)

(default 2)

(create-accessor read))

; значение выхода

(slot output-2 (default UNDEFINED)

(create-accessor write))

; название элемента, с которым связан выход

(slot output-2-link (default GROUND)

(create-accessor write))

; номер входа, с которым связан выход

(slot output-2-link-pin (default 1)

(create-accessor write))

)

; Обработчик для передачи обработанного сигнала на вход следующего элемента

(defmessage-handler TWO-OUTPUT put-output-2 after (?value)

(send?self: output-2-link

(sym-cat put-input-?self: output-2-link-pin)

?value)

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс NO-INPUT реализует логику работы элемента без логических входов

(defclass NO-INPUT

(is-a USER)

(slot number-of-inputs (access read-only)

(default 0)

(create-accessor read))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс ONE-INPUT реализует логику работы элемента с одним логическим входом

(defclass ONE-INPUT

(is-a NO- INPUT)

(slot number-of-inputs (access read-only)

(default 1 )

(create-accessor read))

; значение входа

(slot input-1 (default UNDEFINED)

(visibility public)

(create-accessor read-write))

; название элемента, с которым связан вход

(slot input-1-link (default GROUND)

(create-accessor write))

;номер выхода, с которым связан вход

(slot input-1-link-pin (default 1)

(create-accessor write)))

; Обработчик, активизирующий процесс вычисления результата работы схемы

; после изменения данного входа

(defmessage-handler ONE-INPUT put-input-1 after (?value)

(send?self compute-output)

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс TWO-INPUT реализует логику работы элемента с двумя логическими входами

(defclass TWO-INPUT

(is-a ONE-INPUT)

(slot number-of-inputs (access read-only)

(default 2}

(create-accessor read))

; значение входа

(slot input-2 (default UNDEFINED)

(visibility public)

(create-accessor write))

; название элемента, с которым связан вход

(slot input-2-link (default GROUND)

(create-accessor write))

; номер выхода, с которым связан вход

(slot input-2-link-pin (default 1)

(create-accessor write))

)

; Обработчик, активизирующий процесс вычисления результата работы схемы

; после изменения данного входа

(defmessage-handler TWO-INPUT put-input-2 after (?value)

(send?self compute-output)

)

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

; Классы, реализующие логические элементы

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс, реализующий логику работы элемента SOURCE, имеет один выход и не имеет входов

(defclass SOURCE

(is-a NO-INPUT ONE-OUTPUT COMPONENT)

(role concrete)

(slot output-1 (default UNDEFINED)

(create-accessor write))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс, реализующий логику работы элемента LED, имеет один вход и не имеет выходов

(defclass LED

(is-a ONE-INPUT NO-OUTPUT COMPONENT)

(role concrete)

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс, реализующий логику работы элемента NOT, имеет один вход и один выход

(defclass NOT-GATE

(is-a ONE-INPUT ONE-OUTPUT COMPONENT)

(role concrete)

)

; Функция, вычисляющая значение элемента NOT в зависимости от полученного аргумента

(deffunctiori not# (?x) (- 1?х))

; Обработчик, выполняющий вычисления элемента NOT при изменении входных сигналов

(defmessage-handler NOT-GATE compute-output ()

(if (integerp?self:input-1) then

(send?self put-output-1 (not#?self:input-1)))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс, реализующий логику работы элемента AND, имеет два входа и один выход

(defclass AND-GATE

(is-a TWO-INPUT ONE-OUTPUT COMPONENT)

(role concrete)

)

; Функция, вычисляющая значение элемента AND в зависимости от полученного аргумента (deffunction and! (?x?y)

(if (and (! =?х 0) (!=?у 0)) then 1 else 0))

; Обработчик, выполняющий вычисления элемента AND при изменении входных сигналов (defmessage-handler AND-GATE compute-output ()

(if (and (integerp?self:input-1)

(integerp?self:input-2)) then

(send?self put-output-1

(and#?self:input-1?self:input-2)))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс, реализующий логику работы элемента OR, имеет два входа и один выход

(defclass OR-GATE

(is-a TWO- INPUT ONE-OUTPUT COMPONENT)

(role concrete)

)

; Функция, вычисляющая значение элемента OR в зависимости от полученного аргумента

(deffunction or# (?x?y)

(if (or (!=?х 0) (I-?y 0)) then 1 else 0))

; Обработчик, выполняющий вычисления элемента OR при изменении входных сигналов

(defmessage-handler OR-GATE compute-output ()

(if (and (integerp?self: input-1)

(integerp?self: input-2)) then

(send?self put-output-1

(or#?self: input-1?self: input-2)))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс, реализующий логику работы элемента NAND, имеет два входа и один выход

(defclass NAND-GATE

(is-a TWO-INPUT ONE-OUTPUT COMPONENT)

(role concrete)

)

; Функция, вычисляющая значение элемента NAND в зависимости от полученного аргумента

(deffunction nand# (?x?y)

(if (not (and (!=?x 0) (!=?y 0») then 1 else 0))

; Обработчик, выполняющий вычисления элемента NAND при изменении входных сигналов

(defmessage-handler NAND-GATE compute-output ()

(if (and (integerp?self: input-1)

(integerp?self: input-2)) then

(send?self put-output-1

(nand#?self: input-1?self: input-2)))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс,реализующий логику работы элемента XOR, имеет два входа и один выход

(defclass XOR-GATE

(is-a TWO- INPUT ONE-OUTPUT COMPONENT)

(role concrete)

)

; Функция, вычисляющая значение элемента XOR в зависимости от полученного аргумента

(deffunction xor# (?x?y)

(if (or (and (=?x 1) (=?y 0))

(and (=?x 0} (=?y 1))) then 1 else 0))

; Обработчик, выполняющий вычисления элемента XOR при изменении входных сигналов

(defmessage-handler XOR-GATE compute-output (}

(if (and (integerp?self: input-1)

(integerp?self: input-2)) then

(send?self put-output-1

(xor#?self: input-1?self: input-2)))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Класс, реализующий логику работы элемента SPLITTER, имеет один вход и два выхода

(defclass SPLITTER

(is-a ONE-INPUT TWO-OUTPUT COMPONENT)

(role concrete)

)

; Обработчик, выполняющий вычисления элемента SPLITTER при изменении входных сигналов

(defmessage-handler SPLITTER compute-output ()

(if (integerp?self: input-1) then

(send?self put-output-1?self: input-1)

(send?self put-output-2?self: input-1))

)

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

; Методы родовой функции

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Предварительное объявление родовой функции

(defgeneric connect)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Соединение элемента, имеющего один выход, с элементом, имеющим один вход

(defmethod connect ((?out ONE-OUTPUT) (?in ONE-INPUT))

(send?out put-output-1-link?in)

(send?out put-output-1-link-pin 1)

(send?in put-input-1-link?out)

(send?in put-input-1-link-pin 1)

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Соединение элемента, имеющего один выход, с элементом, имеющим два входа

(defmethod connect ((?out ONE-OUTPUT) (?in TWO- INPUT) (?in-pin INTEGER))

(send?out put-output-1-link?in)

(send?out put-output-1-link-pin?in-pin)

(send?in (sym-cat put-input-?in-pin -link)?out)

(send?in (sym-cat put-input-?in-pin -link-pin) 1)

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Соединение элемента, имеющего два выхода, с элементом, имеющим один вход

(defmethod connect ((?out TWO-OUTPUT) (?out-pin INTEGER) (?in ONE-INPUT)

(send?out (sym-cat put-output-?out-pin -link)?in)

(send?out (sym-cat put-output-?out-pin -link-pin) 1)

(send?in put-input-1-link?out)

(send?in put-input-1-link-pin?out-pin)

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Соединение элемента, имеющего два выхода, с элементом, имеющим два входа

(defmethod connect ((?out TWO-OUTPUT) (?out-pin INTEGER)(?in TWO- INPUT) (?in-pin INTEGER))

(send?out (sym-cat put-output-?out-pin -link)?in)

(send?out (sym-cat put-output-?out-pin -link-pin)?in-pin)

(send?in (sym-cat put-input-?in-pin -link)?out)

(send?in (sym-cat put-input-?in-pin -link-pin)?out-pin)

)

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = == = = = = = = = = = = = = = = = =

; Глобальные переменные

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = == = = = = = = = = = = = = = = = =

(defglobal?*gray-code* = (create$); Переменная для хранения текущего кода Грея

?*sources* = (create$); Список источников текущей логической схемы

?*max-iterations* = 0); Максимальное число итераций для текущей логической схемы

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = == = = = = = = = = = = = = = = = =

; Вспомогательные функции

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = == = = = = = = = = = = = = = = = =

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Определяет номер сигнала, который необходимо изменить для получения

; следующего кода Грея

(deffunction change-which-bit (?x)

(bind?i 1)

(while (and (evenp?x) (!=?x 0)) do

(bind?x (div?x 2))

(bind?i (+?i 1))

)

?i

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; С помощью функции do-for-all-instances определяет обработанный сигнал с индикаторов

; логической схемы

(def function LED- response ()

(bind? response (create$))

(do-for-all-instances ((?led LED)) TRUE

(bind?response (create$?response

(send?led get-input-1))))

?response

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Предварительное объявление функции, необходимой для объединения элементов

; логической схемы

deffunction connect-circuit ())

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = == = = = = = = = = = = = = = = = =

; Правила

;= = = = = = = = = = = = = = = = = = = = = = = = = = = = == = = = = = = = = = = = = = = = =

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Инициализация логической схемы и запуск системы

(defrule startup

=>

; инициализация текущей логической схемы

(connect-circuit)

; получение имен всех источников текущей логической схемы

(bind?*sources* (find-all-instances ((?х SOURCE)) TRUE))

; создает нулевой код Грея

(do-for-all-instances ((?x SOURCE)) TRUE

(bind?*gray-code* (create$?*gray-code* 0)))

; определение максимального числа итераций

(bind?*max-iterations* (round (** 2 (length?*sources*))

; обнуление количества сделанных итераций

(assert (current-iteration 0))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Запуск процесса перебора всевозможных входных сигналов текущей логической системы

(defrule compute-response-1st-time

; если это первая итерация, то

?f <- (current-iteration 0)

=>

; помещение во все источники нулевого сигнала

(do-for-all-instances ((?source SOURCE)) TRUE

(send?source put-output-1 0))

; получение результата работы логической схемы

(assert (result?*gray-code* =(str-implode (LED-response))))

; увеличение количества итераций на 1

(retract?f)

(assert (current-iteration 1))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Перебор всевозможных входных сигналов текущей логической системы

(defrule compute-response-other-times

; если это не первая итерация и количество итераций еще не превышено

?f <- (current-iteration?n&~0&:(<?n?*max-iterations*))

=>

; вычисление номера источника, сигнал которого нужно менять

(bind?pos (change-which-bit?n))

; получение следующего кода Грея

(bind?nv (- 1 (nth?pos?*gray-code*)))

(bind?*gray-code* (replace$?*gray-code*?pos?pos?nv))

; изменение сигнала на заданном источнике на противоположный

(send (nth?pos?*sources*) put-output-1?nv)

; получение результата работы логической схемы

(assert (result?*gray-code* =(str-implode (LED-response))))

; увеличение количества итераций на 1

(retract?f)

(assert (current-iteration = (+?n 1)))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Оптимизация таблицы истинности

(defrule merge-responses

; более высокий приоритет позволяет производить оптимизацию

; в процессе построения таблицы истинности

(declare (salience 10))

; если в текущей таблице есть две строки, которые можно объединить

?fl <- (result $?b?x $?e?response)

?f2 <- (result $?b ~?x $?e?response)

=>

; то удалить такие строки

(retract?fl?f2)

; и вставить обобщенную строку

(assert (result?b *?е?response))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Вывод заголовка таблицы истинности

(defrule print-header

; более низкий приоритет запрещает применение этого правила

; до окончания перебора всевозможных вариантов входных сигналов

(declare (salience -10))

=>

; вывод списка источников

(do-for-all-instances ((?x SOURCE)) TRUE

(format t " %3s " (sym-cat?x)))

; вывод разделительной линии

(printout t " | ")

; вывод списка индикаторов

(do-for-all-instances ((?x LED)) TRUE

(format t " %3s " (sym-cat?x)))

(format t "%n")

; вывод разделительной линии, отделяющей заголовок

(do-for-all-instances ((?x SOURCE)) TRUE

(printout t " ----- ")) (printout t "-+-")

(do-for-all-instances ((?x LED)) TRUE

(printout t " ----- "))

(format t "%n")

; запрос на печать таблицы истинности

(assert (print-results))

)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Вывод таблицы истинности

(defrule print-result

; если заголовок уже напечатан

(print-results)

; еще остались не выведенные строки

?f <- (result $?input?response)

; выбор наименьшей по порядку строки

(not (result $?input-2?response-2&:

(< (str-compare?response-2?response) 0)))

=>

; удаление выбранной строки

(retract?f)

; вывод выбранной строки

(while (neq?input (create$)) do

(printout t " " (nth 1? input) "

(bind?input (rest$? input)))

(printout t " | ")

(bind?response (str-explode?response))

(while (neq?response (create$)) do

(printout t " " (nth 1?response)

(bind?response (rest$?response)))

(printout t crlf)

)

Создайте файл cios.CLP, содержащий текст переведенной выше программы. Как уже не раз упоминалось, среда CLIPS воспринимает только символы английского алфавита, поэтому комментарии, приведенные в листинге, необходимо опустить.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: