Представление структурного графа и реализация алгоритма унификации его вершин и термов

УДК 519.68

ПРЕДСТАВЛЕНИЕ СТРУКТУРНОГО ГРАФА И РЕАЛИЗАЦИЯ АЛГОРИТМА УНИФИКАЦИИ ЕГО ВЕРШИН И ТЕРМОВ

© 2006 г. Б.Ю. Тапкинов

The representation of the structural graph in the manner of a references structure which is stored in a Prolog database is described. One of the basic assignments of this graph is the intermediate representation of the program. The implementation of unification algorithm which is used for construction and analysis of the structural graph is also considered.

Центральной задачей трансляции алгоритмических языков является построение в результате синтаксического и семантического анализа программы её промежуточной структуры, удобной для дальнейшей трансляции. Для решения этой задачи в [1] были предложены структурные предикативные грамматики, основой является понятие структурного графа и процедура унификации, с помощью которой осуществляется построение и анализ этого графа. Одно из основных назначений структурного графа -промежуточное представление программы.

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

Во многих Пролог-системах реализованы DC-грамматики (Definite Clause Grammars) Ф. Перейры и Д. Уоррена [2, 3], а также существуют средства работы с собственной индексированной базой данных, что позволяет на базе этих систем реализовать представление графа и алгоритм унификации его вершин с термами. Одной из таких Пролог-систем является Arity Prolog [4].

Представление структурного графа

Представление структурного графа подбиралось таким образом, чтобы было возможно реализовать описанный в [1] алгоритм унификации.

Вершина графа, помеченная конструктором или объектом первичного сорта (атомом), представлена ссылкой на запись в базе данных. В самой записи хранится метка вершины. Вершина-переменная представлена одноместным конструктором r(X), где X - ссылка на промежуточную запись в БД, содержащую ссылку X1 на основную запись, в которой уже будет храниться будущая метка вершины. Для краткости далее будем записывать r(X) ^ X1. Обоснование выбора такого представления приводится дальше.

Пример 1. Рассмотрим граф, изображенный на рис. 1, и его представление.

В этом графе вершина (1) помечена конструктором bl(_,_), у которого аргументами являются две другие вершины:

1) вершина (2), помеченная одноместным конструктором v(_), аргументом которого является вершина (4), помеченная объектом первичного сорта - атомом a;

2) вершина (3), помеченная переменной A. Отметим, что на рис. 1 промежуточная запись не обозначена.

A

Рис. 1

Представление вершин графа в базе данных приведем в виде табл. 1.

Таблица 1

Представление вершин графа в базе данных

Номер вершины Ссылка на запись в БД Запись в БД Сорт вершины

1 ~ref 1 bl(~ref_2, r(~ref_3)) Конструктор

2 ~ref_2 v(~ref_4) Конструктор

3 ~ref_3 A Переменная

4 ~ref_4 a Объект первичного сорта

Реализация алгоритма унификации Пример 2. Рассмотрим поэтапно унификацию вершины (1) структурного графа из примера 1 и терма bl(v(Z), comp(let(Z, n(5)), skip)). Этапы унификации приводятся в табл. 2.

В результате унификации получится граф, изображенный на рис. 2. В случаях, когда унифицируются: 1) вершина любого сорта и обычная переменная; 2) конкретизированная вершина (не переменная) и терм, не являющийся вершиной, применяется стандартная унификация Пролога. Основная сложность реализации алгоритма унификации заключается в отождествлении вершин-переменных с другими вершинами структурного графа, которое ведет к его перестроению. К примеру, если нужно унифицировать две вершины-переменные, то они должны быть отождествлены в графе, т.е. ссылки, которыми представлены эти вершины, после унификации должны указывать на одну запись в БД. Однако в Arity Prolog разные ссылки не могут указывать на одну и ту же запись. Поэтому было принято

решение: для представления вершины-переменной использовать промежуточную запись.

Таблица 2

Унификация вершины структурного графа и терма

Этап Вершина Терм (подтерм) Результат

Номер Метка Сорт

1 1 bl Конструктор bl(_,_) Успешно

2 2 v Конструктор v(_) Успешно

3 4 a Атом Z В терме все вхождения переменной Z заменяются ссылкой на вершину

Вершина помечается конструкто-

4 3 A Переменная comp

5 5 Переменная let

6 7 Переменная Z(конкретизирована ссылкой Вершина отождествляется с вершиной (4), помеченной атомом a

на вершину

Вершина помечается конструкто-

7 8 Переменная n ром n, создается дочерняя вершина-переменная

8 9 Переменная 5 Вершина помечается атомом 5

9 6 Переменная skip Вершина помечается атомом skip

Рис. 2

Таким образом, чтобы отождествить две вершины-переменные г(Х) ^ X! и г(У) ^ У1, достаточно для любой из вершин, например, г(Х), в

—>

промежуточной записи по ссылке X заменить ссылку XI на У1. В результате получится: г(Х) ^ У1, г(У) ^ У1.

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

Таблица 3

Реализация алгоритма унифкации

Вершина Терм (подтерм) Действие

Представление Сорт Представление Сорт

r(Y) ^ Y1 Переменная, атом или терм Заменяем запись по X на запись по У, т.е. теперь по ссылке X будет находиться ссылка У1, а не Х1

Переменная Y Переменная, атом или терм Заменяем запись по X на У

Переменная Переменная = г^)

Атом Заменяем запись по X! на атом

Терм f2(ti, t2, tN) Строим дерево терма А^х, 12, и заменяем запись по X на ссылку, указывающую на корень построенного дерева.

Переменная Заменяем запись по У на запись по X

r(Y) ^ Y1 Атом Если X1 и У1 совпадают, то унификация ЗАВЕРШЕНА УСПЕШНО, в противном случае - унификация НЕВОЗМОЖНА

Терм Унификация НЕВОЗМОЖНА

Переменная Находим в базе данных все термы г(2), у которых по Z находится У, и делаем замену: У на X1

r(X) ^ X1 Атом Y Атом Если X1 и У совпадают, то унификация ЗАВЕРШЕНА УСПЕШНО, в противном случае - НЕВОЗМОЖНА

Терм Унификация НЕВОЗМОЖНА

Переменная Переменная = г^)

Атом Если атомы совпадают, то унификация ЗАВЕРШЕНА УСПЕШНО, в противном случае - НЕВОЗМОЖНА

Терм f2(ti, t2, tN) Унификация НЕВОЗМОЖНА

Переменная Заменяем запись по У на запись по X

r(Y) ^ Y1 Атом Унификация НЕВОЗМОЖНА

Терм f2(ti, t2, ..., IN) Если £1 и £2 совпадают, то переходим к последовательной унификации Х1 и 11, Х2 и 12, ..., хк и 1к.

Терм fi(xi, Х2, ..., Xn) Переменная Находим в базе данных все термы r(Z), у которых по Z находится У, и делаем замену: У на X1

Y Атом Унификация НЕВОЗМОЖНА

Терм f2(ti, t2, tN) Если £1 и £2 совпадают, то переходим к последовательной унификации Х1 и 11, Х2 и 12, ..., хк и 1к.

Переменная Переменная = г^)

Атом Унификация НЕВОЗМОЖНА

Окончание табл. 3

Вершина Терм (подтерм) Действие

Представление Сорт Представление Сорт

Терм f2(ti, t2, tN) Если £1 и £2 совпадают, то переходим к последовательной унификации Х1 и 11, Х2 и 12, ..., хк и 1к.

X Переменная r(Y) ^ Y1 Переменная, атом или терм Заменяем запись по У на X

Y Переменная, атом или терм Находим в базе данных все термы г(2), у которых по Z находится X, и делаем замену: X на У

Переменная Переменная = X

Атом Заменяем запись по X на атом

Терм f2(ti, t2, tN) Строим дерево терма ^х, 12, с корнем в вершине по X

Атом r(Y) ^ Y1 Переменная Заменяем запись по У на X

Атом Если X и У1 совпадают, то унификация ЗАВЕРШЕНА УСПЕШНО, в противном случае - НЕВОЗМОЖНА

Терм Унификация НЕВОЗМОЖНА

Y Переменная Находим в базе данных все термы r(Z), у которых по Z находится У, и делаем замену: У на X

Атом Если X и У совпадают, то унификация ЗАВЕРШЕНА УСПЕШНО, в противном случае - НЕВОЗМОЖНА

Терм Унификация НЕВОЗМОЖНА

Переменная Переменная = X

Атом Если атомы совпадают, то унификация ЗАВЕРШЕНА УСПЕШНО, в противном случае - НЕВОЗМОЖНА

Терм f2(ti, t2, tN) Унификация НЕВОЗМОЖНА

Терм fi(xi, Х2, ..., XN) r(Y) ^ Y1 Переменная Заменяем запись по У на X

Атом Унификация НЕВОЗМОЖНА

Терм f2(ti, t2, ..., In) Если £1 и £2 совпадают, то переходим к последовательной унификации Х1 и 11, Х2 и 12, ..., хк и 1к.

Y Переменная Находим в базе данных все термы r(Z), у которых по Z находится У, и делаем замену: У на X

Атом Унификация НЕВОЗМОЖНА

Y Терм f2(ti, t2, ..., tN) Если £1 и £2 совпадают, то переходим к последовательной унификации Х1 и 11, Х2 и 12, ..., хк и 1к.

Переменная Переменная = X

Атом Унификация НЕВОЗМОЖНА

Терм f2(ti, t2, tN) Если £1 и £2 совпадают, то переходим к последовательной унификации Х1 и 11, Х2 и 12, ..., Хк и 1к.

Так как процедура унификации рекурсивная, и на каждом этапе возможно перестроение графа, то должен быть реализован откат изменений в графе в случае неудачной унификации. Для этого каждый раз перед вызо-

вом процедуры унификации мы должны запоминать информацию об унифицируемых параметрах (предикат зауе_ге£), а при неудаче восстанавливать эту информацию (предикат ге81оге_ге£).

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

Реализация отката на Прологе:

'=@='(X, Y) :-

),

save_ref(X, X1), save_ref(Y, Y1),!, ( unify(X, Y) ; restore_ref(X, X1),

restore_ref(Y, Y1), !, fail

)

; unify(X, Y).

save_ref(X, s(X3, X5)) :-nonvar(X), ( X = r(X1), instance(X1, X2), recordz_g(stack, X2, X3), instance(X2, X4), recordz_g(stack, X4, X5) ; instance(X, X1),

X3 = null,

recordz_g(stack, X1, X5) ; X3 = null, X5 = null

),!

; X3 = null, X5 = null.

restore_ref(X, s(null, null)) :- !.

restore_ref(X, s(null, X1)) :-

!, instance(X1, X2), erase_g(X1),

% в программе символ унификации = обозначается как =@=.

% проверка, является ли X - переменной % проверка, является ли У - переменной % если X или У - переменные, то % сохраняем в стек информацию о X % сохраняем в стек информацию о У % унифицируем X и У

% в противном случае, если X и У не унифицируемы, то

% восстанавливаем из стека информацию о X и У

% если ни X, ни У не являются переменными, то происходит унификация % без отката

% X - сохраняемая переменная, % X3 - ссылка на вершину, X5 - метка вершины % если вершина X представлена с помощью % промежуточной записи, то % сохраняем ссылку на вершину и

% сохраняем метку вершины

% если промежуточная запись не использовалась, то

% сохраняем только метку вершины % если X - не вершина, то ничего не сохраняем

% если X - не вершина, то ничего не сохраняем

% восстанавливать нечего

% восстанавливаем только метку вершины и удаляем

% запись из стека

replace(X, X2).

restore_ref(X, s(X1, X2)) :- % восстанавливаем ссылку на вершину и метку

вершины и

X = r(X3), % удаляем запись из стека

instance(X1, X4),

erase_g(X1),

replace(X3, X4),

instance(X2, X5),

erase_g(X2),

replace(X4, X5).

Литература

1. Крицкий С.П. // Компьютерное моделирование. Вычислительные технологии. Ростов н/Д, 2003. С. 67-90.

2. PereiraF., Warren D. // Artificial Intelligence. 1980. Vol. 13. P. 231-278.

3. Стерлинг Л., Шапиро Э. Искусство программирования на языке Пролог. М., 1990.

4. The Arity/Prolog Language reference manual. Concord; Massachusetts, 1988.

Ростовский государственный университет 14 октября 2005 г.