Скачиваний:
52
Добавлен:
01.05.2014
Размер:
346.11 Кб
Скачать

Глава 11 Отсечения и отрицание

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

Отсечение может быть также использовано умышленно или по недосмотру для изъятия путей вычислений, которые должны содержать решения. Таким образом можно реализовать слабую форму отрицания.

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

11.1. Зеленые отсечения: выражение детерминизма

Рассмотрим программу merge (Xs.Ys.Zs) (программа 11.1), сливающую два упорядоченных числовых списка Xs и Ys в единый упорядоченный список Zs.

merge (Xs, Ys, Zs)-

упорядоченый список целых чисел Zs получен слиянием упорядоченых списков целых чисел Xs и Ys.

merge([X | Xs],[Y | Ys],[X | Zs])

X < Y, merge(Xs, Y | Ys],Zs).

merge([X | Xs],[Y | Ys],[X,Y | Zs])

Х = Y, merge (Xs,Ys,Zs).

merge([X | Xs], [Y | Ys],[Y, Zs]

X > Y,merge([X | Xs], Ys , Zs).

merge(Xs,[ ],Xs).

merge([ ],Ys,Ys).

Программа 11.1.Слияние упорядоченных списков.

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

Отсечение, обозначаемое символом “!”, может быть использовано для выражения взаимоисключающего характера проверок. В таких случаях символ отсечения записывается после арифметических проверок. Например, первое предложение программы merge может быть записано в виде

merge([X | Xs], [Y | Ys], [Z, | Zs]) X < Y,!, merge(Xs,[Y | Ys],Zs).

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

Хотя данное определение является полным и точным, его частные случаи и следствия не всегда являются интуитивно ясными и очевидными.

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

Перечисленные следствия могут помочь понять приведенное выше определение:

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

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

• С другой стороны, отсечение не влияет на цели, расположенные правее его. В случае возврата они могут порождать более одного решения. Однако если эта конъюнкция не выполнится, то поиск переходит к последнему выбору, сделанному перед выбором предложения, содержащего отсечение. Рассмотрим фрагмент дерева поиска решений вопроса merge([1,2,3],[2,3],Xs)? относительно программы 11.2 -полной версии программы merge с добавлением отсечений. Этот фрагмент приведен на рис. 11.1. Сначала исходный вопрос сводится к конъюнктивному вопросу 1 < 2 ,!, merge-([3,5], [2,3],Xs1)?, цель 1 < 2 решается успешно, что приводит к вершине дерева поиска, помеченной символом “*”. В результате применения отсечения отбрасываются ветви с метками (а) и (b).

merge (X.YS.Zs)

упорядоченный список целых чисел Zs получен слиянием упорядоченных списков целых чисел Xs и Ys.

merge([X | Xs],[Y | Ys],[X | Zs])-

X<Y,! merge (Xs,[Y | Ys], Zs). merge([X | Xs].[Y | Ys],[X,Y | Zs])

X = Y, !, merge (Xs,Ys,Zs). merge([XjXs],[Y|Ys],[Y Zs])

X > Y,!, merge ([X | Xs],Ys.Zs).

merge([ ].[X | Xs],[X | Xs]) !.

merge(Xs,[ ],Xs) !.

Программа 11.2 Слияние упорядоченых списков с использованием отсечения.

Рис. 11.1. Результат отсечения.

Приступим к обсуждению программы 11.2. В трех рекурсивных правилах программы merge отсечение помещено после проверок1). Два исходных случая программы также детерминированы. Подходящее предложение определяется в них при унификации, поэтому отсечение размещается как первая (а в действительности и единственная) цель в теле такого правила. Заметим, что отсечение устраняет лишнее решение цели merge[ ],[ ],Xs). Раньше мы добивались этого более сложным способом, указывая, что список Xs (или Ys) должен содержать хотя бы один элемент.

Опишем еще раз эффект применения отсечения в общем предложении С = =АB,...,B,!,B,...,B процедуры, определяющей А. Если текущая цель G унифицируется с заголовком предложения С и цели B,...,Bвыполняются, то отсечение приводит к следующему результату. В программе фиксируется выбор предложения С для редуцирования цели G, и любые другие предложения процедуры А, которые могут быть унифицированы с целью G, игнорируются. Кроме того, если некоторое Bпри i> k не выполняется, то возврат происходит не далее чем к моменту отсечения. Все другие выборы в дереве поиска, относящиеся к вычислению целей B, при ik, отбрасываются. Если процесс возврата фактически привел к моменту отсечения, то отсечение становится невыполненным и процесс поиска возвращается к последнему выбору, сделанному перед сопоставлением цели G предложения С.

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

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

доказательству ведет применение лишь одного правила программы. Отсечение фиксирует выбор такого правила, как только вычисление достигло стадии, на которой это можно определить.

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

Рассмотрим некоторые другие примеры. Отсечение можно добавить к программе, вычисляющей минимум двух чисел (программа 3.7) точно таким же образом, как и в случае программы merge. При выполнении одной арифметической проверки оказывается невозможным выполнение другой проверки. Программа 11.3 является соответствующей модификацией программы minimum.

minimum (X.Y.M in)

Min - минимум чисел X и Y

minimum(X,Y,X)  XY,!. minimum(X,Y,Y)  X >Y,!.

Программа 11.3 Нахождение минимума с помощью отсечения.

Более содержательным примером, в котором добавление отсечений используется для указания детерминированности программы, служит программа 3.28. Програм­ма определяет отношение polynomial (Term, X), которое истинно, если терм Term -многочлен от переменной X. Типичным правилом является

polynomial (Term 1 +Term2,X)

polynomial(Terml ,X), polynomial (Term2,X).

Как только выяснено (унификацией с заголовком правила), что терм является суммой, никакое другое правило программы polynomial не будет применено. Программа 11.4 является полной программой распознавания многочленов с добав­лением отсечений. Это - детерминированная программа, в которой используются как отсечения после условий, так и отсечения после унификации.

polynomial (Term, X)

терм Term является многочленом от X.

polynomial(X,X)  !. polynomial(Term,X)

constant(Term),!.

polynomial(Term1 + Term2,X)

!,polynomial(Terml , X), polynominal(Term2,X). polynomial(Terml -Term2,X) 

!, polynomial (Term 1,X), polynomial(Term2,X). polynomial (Term1 * Term2,X) 

!, polynomial (Term1,X), polynomial(Term2,X), polynomial (Term l/Term2,X)

!, polynomial (Term 1,X), constant (Term2). polynomial (TermN,X) 

!, natural _ number(N), polynomial(Term, X).

Программа 11.4. Распознавание многочленов.

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

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

Sort(Xs,Ys)

append (As, [X, Y | Bs],Xs), X>Y,

append(As,[Y,X | Bs],Xs1),

sort(Xsl , Ys).

В программе отыскивается пара соседних элементов, расположенных с наруше­нием порядка. Эти два элемента переставляются, и процесс продолжается, пока список не будет упорядочен. Исходное предложение –

Sort(Xs, Xs)ordered (Xs).

Рассмотрим цель Sort([3,2,l]},Xs?}. Упорядочение происходит путем перестанов­ки 3 и 2, далее 3 и 1 и, наконец, 2 и 1, что приводит к упорядоченному списку [1,2,3]. То же решение можно получить, переставив сначала 2 и 1, затем 3 и 1 и, наконец, 3 и 2. Мы знаем, что может получиться лишь один упорядоченный список. Таким образом, если некоторая перестановка выполнена, то нет никакого смысла рас­сматривать другие варианты. Это можно указать с помощью отсечения, по­мещаемого после проверки Х > У. Отсечение производится, как только выяснено, что перестановка необходима. Программа 11.5 является программой сортировки перестановками с отсечениями.

sort(Xs,Ys)

список Ys упорядоченная перестановка списка Xs

sort(Xs,Ys)

append (As, [X,Y | Bs],Xs), X>Y,

t

append(As,[Y,X Bs],Xs1), sort(Xsl,Xs). sort(Xs,Xs)

ordered (Xs),

!.

ordered(Xs) См. программу 3.20

Программа 11 5. Сортировка перестановками.

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

Упражнения к разд. 11.1

1. Добавьте отсечения к процедуре partition в программе quiksort (программа 3.22).

2. Добавьте отсечения к программе дифференцирования (программа 3.29).

3. Добавьте отсечения к программе сортировки вставкой (программа 3.21).

Соседние файлы в папке 1-13