А.4.4. Расширение набора правил – работа с составными высказываниями
Расширим тепрь возможности программы таким образом, чтобы она могла работать с составными высказываниями. Это даст возможность охватить в ней не только вырожденный случай, рассмотренный в предыдущем разделе, но и более сложные. За основу возьмем следующую головоломку.
Р4. Встречаются два персонажа, А и В, каждый из которых либо лжец, либо прадолюбец. Персонаж А говорит: «Мы оба лжецы.» К какой категории следует отнести каждого из них?
В этой задаче нам придется иметь дело с конъюнкцией, поскольку утверждение, высказанное персонажем А, моделируется выражением F (A) ^ F (B) Эту конъюнкцию нужно разделить на выражения-компоненты и проанализировать их непротиворечивость. Очевидно, что А не может быть правдолюбцем, поскольку это противоречит утверждению, которое содержится в его реплике. Но программа должна самостоятельно «распаковать» эту конъюнкцию для того, чтобы прийти к токому выводу. Нам также понадобится снабдить программу и средствами обработки дизъюнкции, поскольку, если предположить, что А лжет, нужно будет оперировать с отрицанием этого утверждения, которое преобразует выражение F (A) ^ F (B) в F (A) v F (B) Таким образом, в программу нужно включить правило выполнения отрицания составных высказываний и правило, которое «понимало» бы, что дизъюнкции вроде Т (А) в действительности являются предположениями. Составное выражение T (A) v T (B) будем обрабатывать, предположив Т (А), и проанализируем, нет ли в нем противоречия. Если таковое не обнаружится, то можно предположить, что T (A) v T (B) совместимо с утверждением о том, что А лгун, т.е. F (A). Но если предположение Т (А) приведет к несовместимости, то нужно отказаться от него и предположить Т (В). Если и это предположение приведет к несовместимости, то это озаначает, что утверждение Т (А) v Т (В) несовместимо с предположением F (A). В противном случае Т (В) образует часть совместимоц интерпретации исходного высказывания.
В CLIPS составные высказывания проще всего представлять с помощью так называемой «польской» (или префиксной) нотации операций. Суть этого способа представления операций состоит в том, что символ операции предшествует символам операндов. Каждый оператор имеет фиксированное количество операндов, а потому всегда существует возможность однозначно установить область действия операций даже в случае, если операнды представляют собой вложенные выражения. Таким образом, выражение, представленное скобочной формой – (F (A)^T (B)), в польской записи будет иметь вид
NOT AND F A T B.
Легче всего восстановить исходный вид выражения, представленного в польской нотации, просматривая его справа налево. При этом операнды считываются до тех пор, пока не встретится объединяющий их оператор. Полученное выражение оказвается операндом следующего оператора. В представленном выше выражении В является операндом одноместного оператора Т, а пара операндов Т(В) и F(A) объединяется оператором AND. Задавшись таким способом представления составных высказываний, сформируем правило выполнения отрицания дизъюнктивной и конъюнктивной форм, в котором будет использоваться функция flip, заменяющая “T” на “F” и наоборот.
(defrule not-or ?F <- (claim (content NOT OR?P?X?Q?Y)) => (modify?F (content AND (flip?P)?X (flip?Q)?Y)) ) (defrule not-and ?F <- (claim (content NOT AND?P?X?Q?Y)) => (modify?F (content OR (flip?P)?X (flip?Q)?Y)) ) Использование функции flip упрощает преобразование и позволяет перейти от выражения
NOT AND F A T B
Прямо к OR T A F B, Минуя OR NOT F A NOT T B. Функция flip определена следующим образом:
(deffunction flip (?P) (if (eq?P T) then F else T)
) Для упрощения мы ограничимся утверждениями в виде простых дизъюнкций или конъюнкций вида T(A)vT(B) Или F(A)^T(B), Но не будем использовать более сложные утверждения в форме F(B)^(T(A)vT(B)) Или -(F(A)vF(B))^(T(A)vT(B)), поскольку для решения большинства интересных головоломок вполне достаточно простых выражений. Наибольшие сложности при модификации нашей программы связаны с обработкой дизъюнктивных выражений, поскольку вывод о наличии противоречия может быть сделан только после завершения анализа всех членов операндов дизъюнкции. Напрмер, нет противоречия между F(A) и T(A)vF(B). Противоречие, которое обнаружится при обработке первого операнда дизъюнкции Т(А) в предположении F(A), будет локальным в контексте Т(А). Но если мы вернемся к исходной дизъюнкции и попробуем проанализировать контекст F(B), то никакого противоречия обнаружено не будет, и, следовательно, интерпретация найдена. Реализовать такой анализ локальных и глобальных противоречий можно, добавив в шаблон объекта claim атрибут contest:
(deftemplate claim (multifield content (type SYMBOL)) (multifield reason (type INTEGER) (default 0)) (field scope (type SYMBOL)) (field context (type INTEGER) (default 0)) ) Значение 0 в поле context означает, что мы имеем дело с глобальным контекстом, значение 1 – с локальным контекстом левого операнда, а значение2 – с локальным контекстом правого операнда дизъюнкции. Пусть, например, анализируется дизъюнкция T(A)vF(B), Причем Т(А) будет истинным в контексте 1, а F(B) – истинным в контексте 2. В этом случае все выражение будет истинным глобально, т.е. в контексте 0. Структуру объекта world также нужно модифицировать – внести в нее поле context. Это позволит отслеживать ход вычислений. Пусть, например, объект world имеет вид
(world (tag 1) (scope truth) (context 2)).
Это означает, что данный «мир» создан следующей парой предположений: · истинно высказывание, имеющее идентификатор (tag), равный 1, и · правый операнд утверждения, которое содержится в этом высказывании, имеет значение «истина». Новый вариант шаблона объекта world приведен ниже.
;; Объект world представляет контекст, ;; сформированный определенными предположениями ;; о правдтвости или лживости персонажей. ;; Объект имеет уникальный идентификатор в поле tag, ;; а смысл допущения – истинность или лживость –
;; фиксируется в поле scope. ;; В поле context сохраняется текущий контекст ;; анализируемого операнда дизъюнкции. ;; 0 означает глобальный контекст дизъюнкции, ;; 1 означает левый операнд, ;; 2 означает правый операнд. (deftemplate world (field tag (type INTEGER) (default 1)) (field scope (type SYMBOL) (default truth)) (field context (type INTEGER) (default 0)) ) Следующий шаг – разработка правил, манипулирующих контекстом. Приведенное ниже правило формирует контекст для левого операнда дизъюнкции.
(defrule left-or ?W <- (world (tag?N) (context 0)) (claim (content OR?P?X?Q?Y) (reason?N) (scope?V)) => (modify?W (context 1)) (assert (claim (content?P?X) (reason?N) (scope?V) (context 1))) ) Это правило устанавливает значение 1 в поле context объекта world т формирует соответствующий объект claim. По этому же принципу разработаем правило для формирования контекста правого операнда дизъюнкции.
(defrule right-or ?W <- (world (tag?N) (context 1)) (claim (content OR?P?X?Q?Y) (reason?N) (scope?V)) => (modify?W (context 2)) (assert (claim (content?Q?Y) (reason?N) (scope?V) (context 2)) )
Упражнение 2 Разработайте самостоятельно правило, которое оперировало бы с объектом claim содержим утверждение в конъюнктивной форме, как показано ниже.
(claim (content AND T A F B) (reason 1) (scope truth))
Это правило должно разделить такое утверждение на два: суть первого – утверждение, что А – правдолюбец, а второго – утверждение, что В – лжец. Новяе объекты claim должны существовать в текущем контексте, определенном в объекте world. Далее разработаем правила, чувствительные к контексту, которые будут выявлять наличие противоречий в анализируемых утверждениях.
;; Выявление противоречия между предположением о ;; правдивости и следующими из него фактами ;; в разных контекстах одного и того же объекта world. (defrule contra-truth-scope (declare (salience 10)) (world (tag?N) (scope truth) (context?T)) (claim (content T?X) (reason?N) (scope truth) (context?S&: (<?S?T))) ?Q <- (claim (content P?x) (reason?N) (scope truth) (context?T)) => (printout t “Disjunct “?T “ is inconsistent with earlier truth context. “
;; “Дизъюнкт “?T ;; “ противоречит ранее установленному контексту правдивости. “ crlf) (retract?Q) ) ;; Выявление противоречия между предположением о ;; лживости и следующими из него фактами ;; в разных контекстах одного и того же объекта world. (defrule contra-falsity-scope (declare (salience 10)) ?W <- (world (tag?N) (scope falsity) (context?T)) (claim (content F?X) (reason?N) (scope falsity) (context?S&: (<?S?T))) ?Q <- (claim (content T?X) (reason?N) (scope falsity) (context?T)) => (printout t “Disjunct “?T “ is inconsistent with earlier falsity context. “ ;; “Дизъюнкт”?T ;; “ противоречит ранее установленному контексту лживости. “ crlf) retract?Q) ) Нам потребуется модифицировать и прежний вариант правила contra-truth. ;; Выявление противоречия между предположением о ;; правдивости и следующими из него фактами ;; в одном и том же контексте оджного и того же объекта world. (defrule contra-truth (declare (salience 10)) ?W <- (world (tag?N) (scope truth)) ?P <- (claim (content T?X) (reason?N) (context?S) (scope truth)) ?Q <- (claim (content F?X) (reason?N) (context?S) (scope truth)) => (printout t “Statement is inconsistent if “?X “ is a knight” ;; “Высказывание противоречиво, если “? X ;; “ правдолюбец.” crlf) (retract?Q) (retract?P) (modify?W (scope falsity) (context 0) )
;; Выявление противоречия между предположением о ;; лживости и следующими из него фактами ;; в одном и том же контексте одного и того же объекта world. (defrule contra-falsity (declare (salience 10)) ?W <- (world (tag?N) (scope falsity)) ?P <- (claim (content F?X) (reason?N) (context?S) (scope falsity)) ?Q <- (claim (content T?X) (reason?N) (context?S) (scope falsity)) => (printout t “Statement is inconsistent whether “?X “ is a knight or knave.” ;; “Высказывание противоречиво, независимо от того,” ;; “является ли “?X “ прадолюбцем или лжецом.” crlf) (modify?W (scope contra) ) Поскольку теперь постановка задачи усложнилась по сравнению с вырожденным случаем, имеет смысл включить в программу распечатку предположений о характеристиках персонажей, упомянутых в высказываниях.
(defrule consist-truth (declare (salience -10)) ?W <- (world (tag?N) (scope truth) (statement (speaker?Y) (tag?N)) => (printout t “Statement is consistent:” ;; “Высказывание непротиворечиво:” crlf) (modify?W (scope consist) )
(defrule consist-falsity (declare (salience -10)) ?W <- (world (tag?N) (scope falsity)) (statement (speaker?Y (tag?N)) => (printout t “Statement is consistent:” ;; “Высказывание непротиворечиво:” crlf) (modify?W (scope consist) ) (defrule true-knight (world (tag?N) (scope consist)) ?C <- (claim (content T?X) reason?N) => (printout t ?X “is a knight” ;;?X “ – правдолюбец” crlf) (retract?C) ) (defrule false-knave (world (tag?M) (scope consist)) ?C <- (claim (content F?X) (reason?N)) => (printout t ?X “ is a knave” ;;?X “ – лжец” crlf) (retract?C)
) Ниже приведенное правило разделения операции конюънкции, которое ранее мы предлагали вам разработать самостоятельно. Обратите внимание на то, что в нем также отслеживается контекст, хотя в данном случае без этого можно было бы и обойтись.
(defrule conj (world (tag?N) (context?S)) (claim (content AND?P?X?Q?Y) (reason?N) (scope?V)) => (assert (claim (content?P?X) (reason?N) (scope?V) (context?S))) (assert (claim (content?Q?Y) (reason?N) (scope?V) (context?S))) ) Прежде чем запустить программу на выполнение, сформируем исходные факты в соответствии с условиями задачи Р4:
(deffacts the-facts (world) (statement (speaker A) (claim AND F A F B) (tag 1)) ) После запуска программы в режиме трассировки интерпретатор сформирует распечатку процесса ее выполнения, приведенную в листинге А.2.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|