Опубликован: 12.02.2014 | Уровень: для всех | Доступ: платный
Лекция 3:

Управление перебором. Отсечение

< Лекция 2 || Лекция 3: 1234 || Лекция 4 >
Аннотация: Основными средствами управления перебором являются предикаты отсечения, fail и отрицания. В данной лекции вводится отсечение. Определяются режимы детерминизма предикатов и потоки параметров. Обсуждается предикат findall, собирающий решения в список, и его обобщение — конструкция […||…]. Рассматриваются примеры решения логических задач. Для решения задач обычно используется метод "образовать и проверить": сначала генерируются возможные значения переменных, а потом проверяется удовлетворение их условиям задачи. В целях сокращения перебора отбрасывание ненужных значений должно производиться как можно раньше. В данном случае перебором управляет порядок следования вычисляемых подцелей.

Для того чтобы сделать поиск решений более эффективным, в язык Пролог были добавлены внелогические средства управления процессом вычислений. Внелогическими называют предикаты, процедурная семантика которых лежит вне рамок SLD-резолютивного вывода. Такими предикатами являются, например, предикаты ввода и вывода. Предикат отрицания также внелогический (см. п. 2.8).

Основными средствами управления перебором являются предикаты отсечения, fail и отрицания. В настоящей главе вводится отсечение. Определяются режимы детерминизма предикатов и потоки параметров. Обсуждается предикат findall, собирающий решения в список, и его обобщение — конструкция […||…].

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

3.1. Статическое отсечение

Отсечение обозначается знаком "!". Правило с отсечением в общем случае имеет вид:

A_0:- A_1, A_2, \dots, A_k, !, A_{k + 1}, \dots, A_n.

Отсечение используется для предотвращения отката после достижения цели. Пусть цель имеет вид: ?- A_0. Если в правиле достигнуто отсечение, то вычисления не выходят за пределы этого правила, при этом

  • откат для подцелей A_1, A_2, \dots, A_k не производится;
  • для подцелей A_{k + 1}, \dots, A_n откат возможен.

Например, пусть программа имеет вид:

цифра(0).
цифра(1):- !.
цифра(2).

Частная цель

цифра(2).

является успешной. Но общая цель

цифра(X).

имеет всего два решения, так как во втором правиле стоит отсечение:

X = 0
X = 1.

Поэтому третье правило игнорируется. Далее, цель

цифра(X), !, цифра(Y)

также имеет два решения, так как для первой подцели откат невозможен:

X = 0, Y = 0
X = 0, Y = 1

Если в последней цели убрать отсечение, то решений будет четыре. А если его убрать и из программы, то решений будет девять.

Отсечение используется:

  • для предотвращения ненужных вычислений;
  • для моделирования ветвления "Q: если A, то B, иначе C":

    Q:- A, !, B.
     Q:- C.
    
  • для выражения отрицания. Например, правило "P:- not(A)." равносильно совокупности правил:

    P:- A, !, fail. 
    P.
    

Если удаление отсечения не изменяет множество решений, то оно называется зеленым, а если изменяет, то красным (см. листинг 3.4).

3.2. Динамическое отсечение

Отсечение "!" является статическим. В языке Visual Prolog имеется динамическое отсечение, которое предотвращает откат только для некоторых подцелей. Такие подцели помещаются между предикатами programControl::getBackTrack и programControl::cutBackTrack/1. Например, найти мужчин, которые являются родителями, можно следующим образом:

run():-
    male(X),
        B = programControl::getBackTrack(),
            parent(X, _),
        programControl::cutBackTrack(B),
        write(X), nl,
    fail;
    _ = readLine().

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

Динамическое отсечение всегда можно заменить статическим, с помощью определения дополнительного предиката или предикатов. Например, в данном случае можно ввести предикат проверки, является ли некто родителем:

class predicates
    isParent: (string) determ.
clauses
    isParent(X):-
        parent(X, _),
        !.
    
    run():-
        male(X),
            isParent(X),
            write(X), nl,
        fail;
        _ = readLine().
< Лекция 2 || Лекция 3: 1234 || Лекция 4 >
Жаныл Айкын
Жаныл Айкын
Rustam Inatov
Rustam Inatov

Доброго времени суток, подскажите пожалуйста, visual prolog examples, pie, vip7.5 - это все, где я могу скачать? (в смысле) может быть на сайте есть какой-то архив? Увы я не нашел его.

Подскажите, пожалуйста.

С уважением, Рустам.

Айдана Ахметова
Айдана Ахметова
Россия
Дмитрий Куянов
Дмитрий Куянов
Россия, Омск, ОмГТУ