Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
LP_3.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
110.59 Кб
Скачать

3. Механизм автоматического поиска решений на Прологе

При попытке согласования целевого утверждения Пролог выби­рает первое из тех утверждений, голова которых сопоставима с целе­вым утверждением.

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

3.1 Рассмотрим поиск решений на примерах

3.1.1 Решим на Прологе такую задачу.

Боря любит любую еду с хорошим вкусом.

Пусть у нас есть две еды – пиво и пирожок. И пусть, также у пирожка будет вкус хороший, а у пива – так называемый, bad.

Программа получается такой.

еда(пиво).

еда(пирожок).

имеет_вкус(пирожок,хороший).

имеет_вкус(пиво,bad).

любит(боря,X):-

еда(X),

имеет_вкус(X,хороший).

Сделаем запрос, чего же съест Боря?

?- любит(боря,What).

What = пирожок

Yes

Чтобы разобрать работу Пролога по нахождению решения, воспользуемся встроенным предикатом trace

?- trace.

true.

Снова поставим перед Прологом ту же цель и посмотрим, как он ищет решение.

[trace] ?- любит(боря,What).

Call: (6) любит(боря, _G284) ? creep

Call: (7) еда(_G284) ? creep

Exit: (7) еда(пиво) ? creep

Call: (7) имеет_вкус(пиво, хороший) ? creep

Fail: (7) имеет_вкус(пиво, хороший) ? creep

Поскольку предикат имеет_вкус(пиво, хороший) оказался Fail, происходит возврат к предикату еда и выбор нового факта, что в режиме [trace] указывается словом Redo

Redo: (7) еда(_G284) ? creep

Exit: (7) еда(пирожок) ? creep

Call: (7) имеет_вкус(пирожок, хороший) ? creep

Exit: (7) имеет_вкус(пирожок, хороший) ? creep

Exit: (6) любит(боря, пирожок) ? creep

What = пирожок ;

Fail: (7) имеет_вкус(пирожок, хороший) ? creep

Fail: (7) еда(_G284) ? creep

Fail: (6) любит(боря, _G284) ? creep

No

Теперь можно этот режим отладки отключить

[trace] ?- notrace.

true.

Процесс согласования целевого утверждения путем прямого продвижения по программе называется прямой трассировкой (forward tracking).

Пролог производит доказательство конъюнкции целевых утверж­дений слева направо.

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

Если слева нет таких утверждений, то конъюнкцию целевых утверждений согласовать нельзя и цель будет неуспешной.

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

Описанный процесс смещения вле­во для повторного согласования целевого утверждения и возвраще­ния вправо носит название поиск с возвратом (backtracking).

3.1.2 Пример на сложный запрос цели.

Наша задача узнать, какие игроки будут играть друг с другом в детском шахматном турнире.

Дополнительное условие – играют только девятилетки, а захотели играть четверо: Петя (9 лет), Паша(10), Даша(9) и Саша(9).

Поступим так. Зададим простую «фактическую» БД, а целевой запрос напишем с конкретным условием поиска.

игрок_в_шахматы(петя,9).

игрок_в_шахматы(паша,10).

игрок_в_шахматы(даша,9).

игрок_в_шахматы(саша,9).

Запрос будет состоять из нескольких предикатов, каждый из которых мы будем вводить на новой строке, разделяя их запятой и Enter’ом

?- игрок_в_шахматы(Person1,9),

| игрок_в_шахматы(Person2,9),

| Person1 \= Person2.

Person1 = петя

P erson2 = даша ;

P erson1 = петя

Person2 = саша ;

Person1 = даша

Person2 = петя ;

P erson1 = даша

Person2 = саша ;

Person1 = саша

Person2 = петя ;

Person1 = саша

Person2 = даша ;

No

?-

Чтобы заставить Пролог искать следующее решение, надо вводить символ «;».

В SWI-Prolog-Editorе для продолжения можно просто нажать Enter

Последнее No означает, что больше решений нет.

Обратите внимание, что решения повторяются. Это происходит потому, что в нашей программе не запрограммировано запоминание уже найденных решений, а сам Пролог этого не делает.

3.1.3 Вот задача, где встречаются факт и правило одинакового имени и арности.

Что она решает - придумайте сами.

любит(федя,живопись).

любит(федя,книги).

любит(федя,петь).

любит(ваня,петь).

покупает_книги(ваня).

читает_книги(ваня).

любит(Z,книги):-

покупает_книги(Z),

читает_книги(Z).

При компиляции этой программы (consult) возможно получить warning о том, что Пролог находит некую раздвоенность в использовании предиката любит, что не влияет на правильность компиляции тела программы.

Задеём цель.

?- любит(X,петь),любит(X,книги).

X = федя ;

X = ваня ;

No

Теперь посмотрим действие этой «неопределённости» в работе с помощью trace

[trace] 35 ?- любит(X,петь),любит(X,книги).

Call: (8) любит(_G513, петь) ? creep

Exit: (8) любит(федя, петь) ? creep

Call: (8) любит(федя, книги) ? creep

Exit: (8) любит(федя, книги) ? creep

X = федя ;

Redo: (8) любит(федя, книги) ? creep

Все факты отработали. Теперь происходит переход к правилу, совпадающему с заголовком цели.

Call: (9) покупает_книги(федя) ? creep

Fail: (9) покупает_книги(федя) ? creep

Fail: (8) любит(федя, книги) ? creep !!!!!!!!!

Получается, что правило не подходит. Надо снова подбирать факты.

Redo: (8) любит(_G513, петь) ? creep

Exit: (8) любит(ваня, петь) ? creep

Call: (8) любит(ваня, книги) ? creep

Call: (9) покупает_книги(ваня) ? creep

Exit: (9) покупает_книги(ваня) ? creep

Call: (9) читает_книги(ваня) ? creep

Exit: (9) читает_книги(ваня) ? creep

Exit: (8) любит(ваня, книги) ? creep

X = ваня ;

Redo: (8) любит(_G513, петь) ? creep

No

Итак. Первое решение берется только из фактов, второе – одного факта и выполнения правила.

3.2 Рассмотрим задачи с использованием отрицания

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]