Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Волченков Логическое программирование язык пролог 2015

.pdf
Скачиваний:
11
Добавлен:
12.11.2022
Размер:
4.14 Mб
Скачать

Лекция 9 Пролог и системы искусственного интеллекта

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

1. Интерпретация редукционной модели на Прологе

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

Для наглядной интерпретации редукции в теории ИИ используется понятие И/ИЛИ-графа. Это ориентированный граф. Вершины графа обозначают задачи (в общем случае, структуры данных) и подзадачи (подструктуры). Дуги графа соединяют родительские вершины с дочерними вершинами (задачи – с их подзадачами, структуры – с их подструктурами).

Все дочерние вершины одной родительской вершины должны быть либо только конъюнктивными, либо только дизъюнктивными

121

вершинами. В первом случае (рис. 9.1, а) это означает, что решение задачи может быть заменено последовательностью (грубо – конъюнкцией) решений более простых подзадач. Иными словами – структура данных может быть заменена совокупностью более простых структур. Во втором случае (рис. 9.1, б) это означает, что решение задачи может быть заменено решением одной из альтернативных подзадач. Иными словами – структура данных может быть заменена одной из альтернативных структур.

 

a

 

 

b

 

b1

b2

bn

c1

c2 …

cm

 

а)

 

 

б)

 

Рис 9.1. Конъюнктивные и дизъюнктивные вершины И/ИЛИ-графа

Дочерние вершины могут, в свою очередь, являться родительскими вершинами для других вершин. Если у вершины нет дочерних вершин, то это элементарная подзадача (подструктура). Она принадлежит к одному из двух классов: заведомо разрешимых и заведомо неразрешимых подзадач (допустимых и недопустимых

подструктур).

Родительская вершина называется разрешимой (допустимой), если все её конъюнктивные дочерние вершины разрешимы (допустимы) или если хотя бы одна из её дизъюнктивных дочерних вершин разрешима (допустима).

Интерпретация редукционной модели обычно заключается в доказательстве разрешимости (допустимости) корневой вершины И/ИЛИ-графа, а также в выделении решающего подграфа, состоящего только из разрешимых (допустимых) вершин.

Связь между представленной редукционной моделью и Прологом достаточно очевидна. Действительно, легко заметить, что факты и правила любой базы данных Пролога представляют не что иное, как иную форму записи некоторого И/ИЛИ-графа.

122

В частности, «кусту» на рис. 9.1,а соответствует единственное правило Пролога:

a :- b1, b2, …, bn.

А «кусту» на рис. 9.1,б соответствуют несколько правил с одинаковыми левыми частями:

b :- c1. b :- c2.

b :- cm.

Пример 9.1. На рис. 9.2,а показан И/ИЛИ-граф, у которого «висячие» вершины f3, f4, f6 заведомо разрешимые, а вершины f1, f2, f5 – заведомо неразрешимые. На рис. 9.2,б показан решающий подграф этого графа.

 

a

 

 

a

 

 

 

 

 

 

 

b

c

f1

c

 

d

f2

e

f3

e

f3

 

 

 

 

 

f4

f5

f6

 

f6

 

 

а)

 

 

б)

 

Рис. 9.2. Пример И/ИЛИ-графа и решающий подграф этого графа

Заведомо разрешимым подзадачам соответствуют факты, заведомо неразрешимым – отсутствие фактов в базе данных.

Так, И/ИЛИ-графу примера 9.1 соответствует следующая база данных (код 9.1):

123

Код 9.1

Для доказательства разрешимости исходной задачи интерпретатору Пролога достаточно задать целевое утверждение ?- a.

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

(код 9.2).

a:- b.

a:- c.

a:- f1.

b:- d, f2,

c:- e, f3.

d:- f4.

d:- f5.

e:- f6, f3. f3.

f4.

Код 9.2

a(a(X)) :- b(X). a(a(X)) :- c(X). a(a(X)) :- f1(X).

b(b(X, Y, Z)) :- d(X), f2(Y), e(Z). c(c(X, Y)) :- e(X), f3(Y). d(d(X)) :- f4(X).

d(d(X)) :- f5(X).

e(e(X, Y)) :- f6(X), f3(Y). f3(f3).

f4(f4). f6(f6).

Целевое утверждение ?- a(X). возвратит следующее значение:

X = a(c(e(f6, f3), f3)).

2.Анализ игры двух лиц с полной информацией исчерпывающим перебором

К сожалению, в реальности И/ИЛИ-граф бывает изначально не задан: его приходится строить в процессе решения задачи. Другими словами, чаще всего приходится располагать не самими «кустами», показанными на рис. 9.1, а только правилами построения таких «кустов».

124

Рассмотрим так называемую игру двух лиц с полной информаци-

ей, когда противники ходят по очереди, меняя каждым своим ходом позицию игры. Эта позиция всегда «видна» каждому игроку. (В этом смысле игра и является «информационно полной».)

Для простоты будем считать, что:

исход игры двузначен: выигрыш или проигрыш каждого игрока;

каждому игроку известен алгоритм построения всех ходов (порождения всех позиций Q1, Q2, …, Qn из любой позиции

P);

позиция для данного игрока является проигрышной, если данный игрок не может сделать из неё ни одного хода.

Покажем, что для анализа игры указанного типа естественно использовать И/ИЛИ-граф, если под анализом понимать доказательство того факта, что игрок, начинающий игру из некоторой позиции, выигрывает (или, что он проигрывает).

Вершина И/ИЛИ-графа – это позиция игры. Заметим, что если доказывается выигрыш игрока, то своими возможными ходами он порождает дизъюнктивные вершины графа (хотя бы один ход должен быть выигрывающим). Если же доказывается проигрыш игрока, то он порождает конъюнктивные вершины (все возможные ходы проигрывающие).

Игрока, выигрыш которого мы пытаемся доказать, будем называть игроком ПЛЮС, а игрока, проигрыш которого мы пытаемся доказать, – игроком МИНУС. Очевидно, что если из данной позиции нет хода для игрока ПЛЮС, то это заведомо неразрешимая вершина графа, а если нет хода для игрока МИНУС, то это заведомо разрешимая вершина.

Пример 9.2. Рассмотрим игру Гранди, которую также называют «игрой английских моряков».

Имеется кучка предметов (чаще всего, монет), которые выставлены «на кон» двумя игроками. Число монет N «видно» каждому игроку.

Ходят по очереди. Первый ход – разделение исходной кучки на две так, чтобы число монет в новых кучках (N1 и N2) было различ-

ным:

N1 + N2 = N, N1 N2.

125

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

Пусть, например, исходная кучка состоит из 7 монет. Нетрудно построить И/ИЛИ-граф, который демонстрирует проигрыш игрока, начинающего игру (рис. 9.3,а). На рис. 9.3,б показан решающий подграф этого графа. (Отметим, что единицы и двойки в описаниях позиций отсутствуют, такие кучки монет можно сразу удалять со стола, ссыпая их в особую коробку, предназначенную для того, кто выиграет игру.)

 

 

7

 

 

7

 

3,4

 

5

6

3,4

5

6

 

 

 

 

3,3

4

3

5

3,3

4

 

 

 

 

 

 

 

3

 

4

 

3

 

 

 

 

 

 

 

 

 

 

3

 

 

 

 

а)

 

 

 

б)

 

Рис. 9.3. Пример И/ИЛИ-графа и решающего подграфа игры Гранди для исходного числа предметов N=7

Приведённый ниже код на Прологе (код 9.3) демонстрирует интерпретацию рассмотренной редукционной модели для произвольной (любой!) игры двух лиц с полной информацией.

 

Код 9.3

%

Игра двух лиц с полной информацией.

%

© Н.Г. Волченков.

igra(win, P, p(P, m(Q))) :- igrokp(P, p(P, m(Q))), !, assert_new_fact(p(P, m(Q))).

igra(los, P, Sp) :- igrokm(P, Sp), !, assert_new_fact(m(P)).

126

igrokp(P, _) :- nohod(P), !, fail.

igrokp(P, p(P, m(Q))) :- call(p(P, m(Q))), !. igrokp(P, p(P, Tree)) :- hod(P, Q),

igrokm(Q, Tree).

igrokm(P, m(P)) :- nohod(P), !. igrokm(P, m(P)) :- call(m(P)), !.

igrokm(P, m(P, Tree)) :- setof(Q, hod(P, Q), M), ansp(M, Tree).

ansp([], []) :- !.

ansp([P | M], [Tree1 | Tree]) :- igrokp(P, Tree1), ansp(M, Tree).

assert_new_fact(F) :- call(F), !. assert_new_fact(F) :- !, assert(F).

С помощью этой программы в базу данных Пролога вносятся новые факты вида p(P, m(Q)), если позиция P приводит к выигрышу, и факты вида m(P), если позиция P приводит к проигрышу. В первом случае разумно указывать выигрывающий ход P → Q. Во втором случае ходы не указываются, так как ни один из них не уберегает игрока от проигрыша. В первом случае позицию P будем называть «выигрышной», во втором случае – «проигрышной».

Чтобы представленную выше программную структуру применить к конкретной игре, например к описанной выше игре Гранди, к этой программе необходимо добавить определения предикатов hod/2 и nohod/1 для данной игры. Первый из них должен строить все дочерние вершины данной вершины И/ИЛИ-графа, а второй предикат должен доказывать, что данная вершина «висячая».

В качестве примера рассмотрим определения этих предикатов для игры Гранди (код 9.4).

127

Код 9.4

% Ход для игры Гранди (а также отсутствие хода). :- assert(m([])), assert(m([4])).

:- assert(p([3], m([]))).

hod(P, Q) :- setof(Q1, hodizb(P, Q1), L), member(Q, L).

hodizb(P, Q) :- % По возврату будут избыточные решения. memdel(X, P, P1), % Удаление элемента из списка.

razb(X, Y, Z),

% Разбиение числа на два неравных.

upr([Y, Z | P1], Q1), % Удаление единиц и двоек.

mysort(Q1, Q).

% Сортировка без удаления

 

% дубликатов.

nohod([]) :- !.

memdel(X, [X | T], T).

memdel(X, [Y | T], [Y | T1]) :- memdel(X, T, T1).

razb(X, Y, Z) :- V is X // 2, genint(Y, 1, V), Z is X – Y, Z \= Y.

genint(L, L, R).

genint(X, L, R) :- L < R, L1 is L + 1, genint(X, L1, R).

upr([N | P], Q) :- (N = 1; N = 2), !, upr(P, Q). upr([N | P], [N | Q]) :- !, upr(P, Q).

upr([], []) :- !.

mysort([], []) :- !.

mysort([A | L], S) :- mysort(L, S1), insort(A, S1, S). insort(A, [], [A]) :- !.

insort(A, [B | S], [A, B | S]) :- A @=< B, !. insort(A, [B | S1], [B | S]) :- !, insort(A, S1, S).

Взаключение, несколько слов о реализации эксперимента с данной игрой (Гранди).

Всилу того, что представленный выше алгоритм является пере-

борным, даже небольшое увеличение размерности задачи (значения N) резко увеличивает время доказательства выигрыша или

128

проигрыша игрока, начинающего игру (типичный пример «комбинаторного взрыва»). Для борьбы с ним автор предложил приём, который можно назвать накоплением опыта. Он заключается в том, что вместо трёх «известных» позиций, которые вносятся в память играющих на этапе загрузки кода 9.4:

:- assert(m([])), assert(m([4])).

% Две проигрышные позиции.

:- assert(p([3], m([]))).

% Одна выигрышная позиция.

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

няется в ходе очередного запуска данной программы (код 9.5):

Код 9.5

izvp :- see(ppos), read(T), cys(T), seen.

%Извлечь позиции, приводящие к выигрышу. izvm :- see(mpos), read(T), cys(T), seen.

%Извлечь позиции, приводящие к проигрышу. cys(end_of_file) :- !.

cys(T) :- assert(T), read(TN), cys(TN).

% Создание новых файлов. zapp :- tell(ppos), setof(p(X, Y), p(X, Y), L), cyt(L), told. zapm :- tell(mpos), setof(m(X), m(X), L), cyt(L), told.

cyt([]):-!.

cyt([H|T]):-write(H), write('.'),nl, cyt(T).

Более того, можно существенно сократить время, которое компьютер будет затрачивать на накопление опыта, если для любого заданного числа (например, 21) генерировать все возможные позиции, которые могут возникнуть из этого числа (например, [3, 18], …, [3, 3, 3, 4, 4, 4], …), и выяснять, «выигрышны» или «проигрышны» эти позиции (код 9.6):

129

Код 9.6

%Генерация всех позиций из данного числа.

%(Сумма элементов списка равна данному числу.) genpos(N, L) :- N1 is N + 1, gp(N, N1, [], L).

gp(N, N, L, L) :- !.

gp(I, N, B, L) :- setof(L0, raz(I, L0), L1),

append(B, L1, B1), I1 is I + 1, gp(I1, N, B1, L).

raz(N, L) :- K is N // 3, raz(N, K, L1), reverse(L1, L). raz(N, K, L) :- genint(X, 1, K), raz(N, N, X, 3, [], L). raz(_, 0, 0, _, L, L).

raz(P, N, X, Y, B, L) :- genint(Z, Y, P), N1 is N – Z, N1 >= 0, X1 is X – 1, X1 >= 0, raz(P, N1, X1, Z, [Z | B], L).

% Исследование результатов игры для каждой позиции. igry(N,L) :- genpos(N, L), genigr(L).

genigr([]) :- !.

genigr([P|Ps]) :- igra(R, P, T), write(T), nl, genigr(Ps).

С помощью представленного подхода автору удалось построить решающие подграфы для всех позиций [N], где N < 23. При этом файл mpos содержит 76, а файл ppos – 169 позиций.

Скептики и ниспровергатели Пролога! Попробуйте создать указанные файлы с помощью таких языков как бейсик или паскаль – автор не уверен, что это удастся осуществить такими же «минимальными» средствами, как это сделано на Прологе. Тем же из слушателей или читателей, которые заинтересовались приведенным примером, автор может выслать эти файлы по электронной почте: сыпьте деньги на стол, играйте и выигрывайте, если у Вашего противника таких данных нет…

3. Эвристический поиск на игровых деревьях

Игра Гранди – это тот редкий пример игры двух лиц с полной информацией, когда вручную или на компьютере можно перебрать все возможные варианты ходов за сравнительно небольшое время. Ведь если в исходной кучке N предметов, максимальное число ходов одного игрока не может превысить числа k = (N – 1) / 2. Боль-

130

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