Пример экспертной системы на Prolog

      Комментарии к записи Пример экспертной системы на Prolog отключены

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 1 неделя, 1 день назад.

  • Автор
    Сообщения
  • #3559

    Создадим простую экспертную систему «Кто чем увлекается?». Нам нужна система, которая отвечала бы на вопросы, сформулированные на русском языке, на тему увлечений (hobby) действующих лиц. Пример начала диалога с этой экспертной системой приведен ниже:

    Начнем с простейшего варианта. Нам следует создать элементарную базу фактов типа увлечение(Кто,Что). Все вербальные варианты запросов система проинтерпретирует так:

    1. если в тексте вопроса присутствует значение «Кто» (Петров, Сидоров,…), следует выдать все значения «Что»;
    2. если в тексте вопроса присутствует значение «Что», следует выдать все значения «Кто»;
    3. если в тексте запроса присутствуют «Что» и «Кто», то система интерпретирует запрос, как «Увлекается ли Кто Что?».

    Ответ: «Да» или «Нет» в зависимости от содержания элементарной базы знаний.

    В таком простейшем варианте экспертной системы (с единственным видом отношения между субъектом и объектом) можно не утруждать пользователя формулированием запроса в полном виде, играя в понимание, а предоставить ему возможность выбрать тип запроса и заполнить соответствующие поля.

    Алгоритм обработки запросов очень прост. В самом сложном случае, когда их типы заранее не определены (через меню выбора типа), каждое слово запроса проверяется на принадлежность типам «Кто» или «Что» и, в зависимости от результата, формулируется ответ. «Закодируем» алгоритм обработки строки-запроса Запрос, полагая, что база знаний содержится в файле «hobbyNew.dbs».

    Программа завершает работу, если в ответ на ее вопрос write("Есть вопросы? (Д|Н|д|н)"), пользователь ответит 'Н' или 'н'. Предикат repeat используется в разделе goal для организации цикла по обработке вопросов.

    domains
      кто=symbol
      что=symbol
    facts - f1
      увлечение(кто,что)
      кто(кто)
      что(что)
    predicates
      nondeterm repeat
      nondeterm ответить(symbol)
      ответить_что(кто)
      ответить_кто(что)
      анализ_КтоЧто(symbol)
      спросить
    clauses
      repeat.
      repeat:-
        repeat.
    
      ответить(""):-
        кто(Кто), что(Что), увлечение(Кто,Что),!,write("Да");
        кто(Кто), что(Что), not(увлечение(Кто,Что)),!, write("Нет");
        кто(Кто), not(что(_)),!, write(Кто,".Хобби:"),nl, ответить_что(Кто);
        что(Что), not(кто(_)),!, write(Что," является увлечением для:"),nl, ответить_кто(Что);
        !,write("Не понял"),nl.
    
      ответить(Запрос):-
        fronttoken(Запрос,Лексема,Остаток),!,
        анализ_КтоЧто(Лексема),
        ответить(Остаток).
    
      анализ_КтоЧто(Лексема):-
        увлечение(Лексема,_),!, assert(кто(Лексема));
        увлечение(_,Лексема),!, assert(что(Лексема));
        !.
    
      ответить_кто(Что):-
        увлечение(Кто,Что),
        write(Кто),nl,
        fail.
      ответить_кто(_).
    
      ответить_что(Кто):-
        увлечение(Кто,Что),
        write(Что),nl,
        fail.
    
      ответить_что(_).
    
      спросить:-
        write("Введите Ваш вопрос:"),nl,
        readln(Вопрос),
        ответить(Вопрос),!;
        !.
    goal
      consult("hobbyNew.dbs",f1),
      repeat,
      спросить,
      retractall(кто(_)),
      retractall(что(_)),
      write("Есть вопросы? (Д|Н)"),
      readchar(ДаНет),
      ДаНет='Н',exit().

    Теперь усложним задачу с целью дать возможность пользователю формулировать вопрос грамматически правильно, а также для того, чтобы вводить любые виды отношений. Факты мы приведем к универсальному виду f(объект1,отношение,объект2), а также введем синонимы для имен объектов и отношений. В данном случае под термином синоним будем понимать как грамматическое видоизменение слова, так и другое слово, которое мы считаем семантически эквивалентным исходному.

    При данной организации БЗ и приведенном ниже алгоритме обработки запроса, имена объектов и отношений,множества синонимов различных отношений и множество синонимов различных объектов не должны пересекаться. Например, если есть факты:

    ф("кирилл","хобби","шахматы")},
    ф("кирилл","любить","татьяна")},
    соб("татьяна",["татьяну",...])
    сот("хобби",["нравится","увлекается","любит","любить"])
    сот("любить",["любит"])

    то на вопрос: "кирилл любит татьяну" Вы получите ответ "Нет!", поскольку в качестве имени отношения будет выбрано "хобби".

    Состав базы знаний:

    ф("кирилл","хобби","хоккей")
    ф("петров","хобби","лыжи")
    ф("ирина","хобби","кино")
    ф("татьяна","хобби","гимнастика")
    ф("кирилл","хобби","гимнастика")
    ф("петров","любить","ирина")
    ф("ирина","любить","кирилл")
    ф("кирилл","любить","татьяна")
    соб("кирилл",["кириллу","кириллом","кирилла","кирилле"])
    соб("петров",["петрову","петровым","петрова","петрове"])
    соб("ирина",["ирине","ириной","ирины","ирину"])
    соб("гимнастика",["гимнастикой","гимнастики","гимнастикой",
    "гимнастике","гимнастику"])
    соб("татьяна",["татьяне","татьяной","татьяны","татьяну"])
    сот("хобби",["нравится","увлекается"])
    сот("любить",["любит"])

    Текст программы:

    domains
      список=symbol*
    facts - f1
      ф(symbol,symbol,symbol)
      соб(symbol,список)
      сот(symbol,список)
      кто(symbol)
      что(symbol)
      отн(symbol)
      временно(symbol)
    predicates
      nondeterm repeat
      nondeterm ответить(symbol)
      ответ1(symbol,symbol,symbol)
      ответ2(symbol,symbol)
      ответ3(symbol,symbol)
      ответ4(symbol)
      ответ5(symbol,symbol)
      ответ6(symbol)
      ответ7(symbol)
      анализ_КтоОтношениеЧто(symbol)
      nondeterm поиск_кто(symbol)
      nondeterm поиск_что(symbol)
      nondeterm поиск_отношения(symbol)
      искать_синоним_кто(symbol)
      искать_синоним_отношения(symbol)
      искать_синоним_что(symbol)
      загрузить_список(список)
      спросить
    clauses
      repeat.
      repeat:-
        repeat.
    
      ответить(""):-
        кто(Кто), что(Что), отн(Отношение),!, ответ1(Кто,Отношение,Что);
        кто(Кто), что(Что), not(отн(_)),ф(Кто,_,Что),!, ответ2(Кто,Что);
        кто(Кто), отн(Отношение), not(что(_)),!, ответ3(Кто,Отношение);
        кто(Кто), not(отн(_)), not(что(_)),!, ответ4(Кто);
        not(кто(_)), отн(Отношение), что(Что),!, ответ5(Отношение,Что);
        not(кто(_)), отн(Отношение), not(что(_)),!, ответ6(Отношение);
        not(кто(_)), not(отн(_)), что(Что),!, ответ7(Что);
        !,write("Не понял"),nl.
    
      ответить(Запрос):-
        fronttoken(Запрос,Лексема,Остаток),
        анализ_КтоОтношениеЧто(Лексема),
        ответить(Остаток).
    
      анализ_КтоОтношениеЧто(Лексема):-
        поиск_кто(Лексема),!;
        поиск_отношения(Лексема),!;
        поиск_что(Лексема),!;
        !.
    
      поиск_кто(Лексема):-
        not(кто(_)),
        ф(Лексема,_,_),!,assert(кто(Лексема));
        not(кто(_)),искать_синоним_кто(Лексема),!;!,fail.
    
      поиск_отношения(Лексема):-
        not(отн(_)),
        ф(_,Лексема,_),!,assert(отн(Лексема));
        not(отн(_)),искать_синоним_отношения(Лексема),!;!,fail.
    
      поиск_что(Лексема):-
        not(что(_)),
        ф(_,_,Лексема),!,assert(что(Лексема));
        not(что(_)),искать_синоним_что(Лексема),!;!,fail.
    
      искать_синоним_кто(Лексема):-
        соб(Кто,СписокКто),
        загрузить_список(СписокКто),
        временно(Лексема),!,
        retractall(временно(_)),assert(кто(Кто));
        fail.
      искать_синоним_кто(_):-
        retractall(временно(_)),!,fail.
    
      искать_синоним_отношения(Лексема):-
        сот(Отн,СписокОтн),
        загрузить_список(СписокОтн),
        временно(Лексема),!,
        retractall(временно(_)),assert(отн(Отн));
        fail.
      искать_синоним_отношения(_):-
        retractall(временно(_)),!,fail.
    
      искать_синоним_что(Лексема):-
        соб(Что,СписокЧто),
        загрузить_список(СписокЧто),
        временно(Лексема),!,
        retractall(временно(_)),assert(что(Что));
        fail.
      искать_синоним_что(_):-
        retractall(временно(_)),!,fail.
    
      загрузить_список([]).
      загрузить_список([H|T]):-
        assert(временно(H)),загрузить_список(T).
    
      ответ1(Кто,Отношение,Что):-
        ф(Кто,Отношение,Что),!,
        write("otvet1"),nl,
        write("Да."),nl;!,write("Нет."),nl.
    
      ответ2(Кто,Что):-
        ф(Кто,Отношение,Что),
        write("otvet2"),nl,
        write(Кто," ",Отношение," ",Что),nl,
        fail.
      ответ2(_,_).
    
      ответ3(Кто,Отношение):-
        ф(Кто,Отношение,Что),
        write("otvet3"),nl,
        write(Кто," ",Отношение," ",Что),nl,
        fail.
      ответ3(_,_).
    
      ответ4(Кто):-
        ф(Кто,Отношение,Что),
        write("otvet4"),nl,
        write(Кто," ",Отношение," ",Что),nl,
        fail.
      ответ4(_).
    
      ответ5(Отношение,Что):-
        ф(Кто,Отношение,Что),
        write("otvet5"),nl,
        write(Кто," ",Отношение," ",Что),nl,
        fail.
      ответ5(_,_).
    
      ответ6(Отношение):-
        ф(Кто,Отношение,Что),
        write("otvet6"),nl,
        write(Кто," ",Отношение," ",Что),nl,
        fail.
      ответ6(_).
    
      ответ7(Что):-
        ф(Кто,Отношение,Что),
        write("otvet7"),nl,
        write(Кто," ",Отношение," ",Что),nl,
        fail.
      ответ7(_).
    
      спросить:-
        write("Введите Ваш вопрос:"),nl,
        readln(Вопрос),
        upper_lower(Вопрос,Q),
        ответить(Q),!;
        !.
    goal
      consult("hobbyNew2.dbs",f1),
      repeat,
      спросить,
      retractall(кто(_)),
      retractall(что(_)),
      retractall(отн(_)),
      write("Есть вопросы? (Д|Н)"),
      readchar(ДаНет),
      ДаНет='Н',!,exit().

    Протокол сеанса с системой (знак ‘?’ опущен, а также опущены вопросы системы в отношении продолжения диалога):

Для ответа в этой теме необходимо авторизоваться.