Программирование на языке ПРОЛОГ для искуственного интеллекта

       

Цели с отрицанием


Использование знака отрицания в левых частях правил, а следовательно, и в вопросах, обрабатываемых процедурой рассмотреть, представляется естественным и его следует разрешить. В качестве первой попытки можно предложить следующий способ работы с отрицанием целей:

line();

% Процедура-драйвер верхнего уровня

        эксперт :-
                принять_вопрос( Вопрос),

                                            % Ввести вопрос пользователя
                ( ответ_да( Вопрос);
                                            % Попытка найти положительный ответ
                ответ_нет( Вопрос) ).
            % Если нет положительного ответа, то найти отрицательный

        ответ_да( Вопрос) :-
                                            % Искать положительный ответ на Вопрос
                статус( отрицательный),


                                            % Пока еще нет положительного ответа


                рассмотреть( Вопрос, [ ], Ответ),             % Трасса пуста
                положительный( Ответ),            % Искать положительный ответ
                статус( положительный),
                                                           % Найден положительный ответ
                выдать( Ответ), nl,
                write( 'Нужны еще решения?' ),
                принять( Ответ1),
          % Прочесть ответ пользователя
                Ответ1 = нет.
                                % В противном случае возврат к "рассмотреть"

        ответ_нет( Вопрос):-
                                % Искать отрицательный ответ на Вопрос
                retract( пока_нет_положительного_решения),  !,


                                                           % Не было положительного решения?
                рассмотреть( Вопрос, [ ], Ответ),
                отрицательный( Ответ),
                выдать( Ответ), nl,
                write( 'Нужны еще решения?' ),
                принять( Ответ1),
                Ответ1 = нет.

                                % В противном случае - возврат к "рассмотреть"
        статус( отрицательный) :-
                assert( пока_нет_положительного_решения).


        статус( положительный) :-
                retract( пока_нет_положительного_решения),  !;  true.


        принять_вопрос( Вопрос) :-
                nl, write( 'Пожалуйста, спрашивайте:'), nl,
                read( Вопрос).




line(); Рис. 14. 13.  Оболочка экспертной системы: драйвер. Обращение
к оболочке из Пролога при помощи процедуры эксперт.

        рассмотреть( не Цель, Трасса, Ответ) :-  !,
                рассмотреть( Цель, Трасса, Ответ1),
                обратить( Ответ1, Ответ).

                                % Получить обратное истинностное значение

        обратить( Цель это правда было Найдено,
                          ( не Цель) это ложь было Найдено).


        обратить( Цель это ложь было Найдено,
                          ( не Цель) это правда было Найдено).


Если Цель конкретизирована, то все в порядке, если же нет, то возникают трудности. Рассмотрим, например, такой диалог:

        ?-  эксперт.

        Пожалуйста, спрашивайте:
        не ( X ест мясо).

        Есть (еще) решения для   :  Животное
        да.
        Животное = тигр.

В этот момент система даст ответ:

        не ( тигр ест мясо) это ложь

Такой ответ нас не может удовлетворить. Источник затруднения следует искать в том, какой смысл мы вкладываем в вопросы типа

        не ( X ест мясо)



В действительности мы хотим спросить: "Существует ли такой X, что X не ест мяса?" Однако процедура рассмотреть (так как мы ее определили) проинтерпретирует этот вопрос следующим образом:

    (1)        Существует ли такой X, что X ест мясо?
    (2)        Да, тигр ест мясо.

    Итак,

    (3)        не (тигр ест мясо) это ложь.

Короче говоря, интерпретация такова - "Правда ли, что никакой X не ест мясо?" Положительный ответ мы получим, только если никто не ест мяса. Можно также сказать, что процедура рассмотреть отвечает на вопрос так, как будто X находится под знаком квантора всеобщности:

        для всех X: не (X ест мясо)?

а не квантора существования, в чем и состояло наше намерение:

        для некоторого X: не (X ест мясо)?

Если рассматриваемый вопрос конкретизирован, то проблемы исчезают. В противном случае правильный способ работы с отрицаниями становится более сложным. Например, вот некоторые из возможных правил:

Для того, чтобы рассмотреть (не Цель), рассмотрите Цель, а затем:
  • если Цель это ложь, то (не Цель) это правда;
  • если Цель' - это некоторое решение для Цель, и Цель' - утверждение той же степени общности, что и Цель, то (не Цель) это ложь;
  • если Цель' - это некоторое решение для Цель, и Цель' - более конкретное утверждение, чем Цель, то об утверждении (не Цель) нельзя сказать ничего определенного.
Можно избежать всех этих осложнений, если потребовать, чтобы отрицания стояли только перед конкретизированными целями. Если правила базы знаний формулировать должным образом, то часто удается удовлетворить этому условию. Нам это удалось в "правиле поломки" (рис. 14.7):

        правило_поломки:
                            если


                                    вкл( Прибор) и
                                    прибор( Прибор) и
                % Конкретизация
                                    не работает( Прибор) и
                                    соед( Прибор, Предохр) и
                                    доказано( цел( Предохр) )
                            то
                                    доказано( неиспр( Прибор) ).


Здесь условие

        прибор( Прибор)

"защищает" следующее за ним условие

        не работает( Прибор)

от неконкретизированной переменной.


Содержание раздела