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

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

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

R7

= B2

: горизонтальная_грань,

Здесь значение каж-

R8

=

B2

: правая_грань,

дой из 10 переменных –

R9

=

B2

: левая_грань,

это структура с функ-

R10 = B2

: горизонтальная_грань

тором «:». 1-й аргумент

этой структуры – переменная Bk, обозначающая k-е «распознанное» тело, 2-й аргумент – тип грани.

С указанной задачей успешно справляется следующая программа (код 10.2):

 

Код 10.2

patrec :-

 

patrecdata(A, C),

% Подготовить список

assert((solution(A) :- C)),

% подцелей С для

goal.

% распознавания изображения.

% Выполнить распознавание.

goal :- solution(X), write(X).

 

К этой программе должны быть присоединены так называемые правила распознавания, содержащие семантику (свойства) рёбер:

Код 10.3

vr(левая_грань:B, правая_грань:B, выпуклое_ребро).

vr(правая_грань:B1, левая_грань:B2, вогнутое_ребро). vr(правая_грань:B, X, down_ребро).

vr(X, левая_грань:B, up_ребро).

pr(горизонт_грань:B, правая_грань:B, выпуклое_ребро).

pr(правая_грань:B1, горизонт_грань:B2, вогнутое_ребро). pr(X, горизонт_грань:B, up_ребро).

pr(правая_грань:B, X, down_ребро).

nr(левая_грань:B, горизонт_грань:B, выпуклое_ребро).

nr(горизонт_грань:B1, левая_грань:B2, вогнутое_ребро). nr(горизонт_грань:B, X, down_ребро).

nr(X, левая_грань:B, up_ребро).

141

Распознавание реализуется путём сопоставления образцов,

представленных кодом 10.3, с целями C, находящимися в правой части правила: solution(A) :- C.

На первом шаге распознавания цель pr(фон, R2, E1) успешно сопоставляется с образцом pr(X, горизонт_грань:B, up_ребро). Результат сопоставления:

R2 = горизонт_грань:B,

X = фон,

E1 = up_ребро.

На втором шаге цель nr(горизонт_грань:B, фон, E2) успешно сопоставляется с образцом nr(горизонт_грань:B, X, down_ребро). Результат сопоставления:

X = фон,

E2 = down_ребро.

И так далее.

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

Довольно быстро (так как дедукция реализуется только «на уровне сопоставления образцов») указанный процесс приводит к

результату, который был представлен ранее: R1 = B1 : левая_грань,

R2 = B1 : горизонт_грань,

R10 = B2 : горизонт_грань.

Для большей привлекательности ввода и вывода данных код 10.2 можно модернизировать:

 

 

Код 10.4

:-op(50, xfy, ;).

%

Файл ai_patrec1.pl

:-op(30, xfy, :).

%

Николай Волченков, 2003 г. ©

patrec :-

write('Введите имя файла с правилами для распознавания'), nl, write(' (ai_patrec2): '), read(G), reconsult(G), write('Введите имя файла с данными об изображении'),

142

nl, write(' (ai_patrec3): '), read(D), reconsult(D), patrecdata(A, B),

assert((solution(A) :- B)), % Подготовить список целей.

goal.

% Выполнить распознавание.

goal :-

 

patrecdata(A, C),

 

side_list(97, A),

% Создать список граней.

edge_list(1, C),

% Создать список рёбер.

write(A), nl,

% Напечатать список граней.

write_list(C), nl,

% Напечатать список рёбер.

solution(X), nl,

% Выполнить распознавание.

outp(A, 1, X), nl.

% Выдать результат.

side_list(A, X) :- var(X), !, name(X, [A]).

% Присвоение граням имён: a, b, … side_list(A, X;Y) :- !, name(X, [A]), inc(A, A1),

side_list(A1, Y).

edge_list(N, (X, Y)) :- arg(3, X, N), inc(N, N1),

% Присвоение рёбрам номеров: 1, 2, … edge_list(N1,Y).

edge_list(N, X) :- arg(3, X, N).

outp(A;B, N, X:V; Y) :- var(V), !,

% Выдача результатов распознавания

V=N, outp1(A, X:N), nl, inc(N, N1), outp(B, N1, Y).

outp(A;B, N, X:V;Y) :- !, outp1(A, X:V), nl, outp(B, N, Y).

outp(A, N, X:V) :- var(V), !, V=N, outp1(A, X:N).

outp(A, N, X:V) :- !, outp1(A, X:V).

143

outp1(A, X:Y) :- % Печать результата для одной грани write(' У тела '), write(Y),

write(' грань '), write(A), write(' – '), write(X).

write_list((X, Y)) :-

write(X), write(' '), write_list(Y). % Печать списка рёбер write_list(X) :- write(X), nl.

inc(N, N1) :- N1 is N+1. dec(N, N1) :- N1 is N-1.

В этом случае «фотография» консоли после запуска программы будет иметь следующий вид:

| ?- patrec.

Введите имя файла с правилами для распознавания

(ai_patrec2): |: ai_patrec2.

Введите имя файла с данными об изображении

(ai_patrec3): |: ai_patrec3.

a ; b ; c ; d ; e ; f ; g ; h ; i ; j

pr(фон,b,1) nr(b,фон,2) vr(фон,e,3) pr(фон,g,4) nr(g,фон,5) vr(h,фон,6) pr(h,фон,7) nr(фон,e,8) vr(f,фон,9) pr(f,фон,10) nr(фон,d,11) pr(c,фон,12) nr(фон,a,13) vr(фон,a,14) nr(a,b,15) pr(b,c,16) vr(a,c,17) vr(c,d,18) nr(d,b,19) pr(b,f,20) nr(j,i,28) pr(j,h,29)

Утела 1 грань a – левая

Утела 1 грань b – горизонтальная

Утела 1 грань c – правая

Утела 1 грань d – левая

Утела 2 грань e – левая

Утела 1 грань f – правая

Утела 2 грань g – горизонтальная

Утела 2 грань h – правая

Утела 2 грань i – левая

Утела 2 грань j – горизонтальная yes

144

Авторское право на постановку данной задачи и коды 10.2 –

10.3принадлежат Д.Уоррену (D.H.D.Warren, 1975).

2.Задача о коммивояжёре

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

Приведем решение этой задачи, «скаченное» автором из Интернета (вместе с бесплатной версией Пролога LPA 4.200) без какихлибо комментариев. Единственное, что сделал автор – это убрал большую часть (90 %) кода, посвящённую графическому интерфейсу (рисованию карты Британии и отображению на ней результатов работы программы), а также сократил (с 25 до 6) список городов Британии.

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

телей (слушателей).

Код 10.5

/* The Travelling Salesman – (c) 1998-2001 LP Associates Ltd Rewritten with new algorithms by:

Brian D Steel, 17 Jun 98 / 19 Sep 01 Original version by:

Nicky Johns, Frank McCabe, Rebecca Shalfield,

Brian D Steel, Phil Vasey, Alan Westwood, Dave Westwood

This program displays a map of the mainland UK, showing a number of towns. These can be selected using the mouse, and then the shortest route found between them. Two algorithms are defined: the "exhaustive" one finds

every possible route and returns the shortest; the "heuristic" one takes each selected town in turn, and inserts it into the optimal location in the route as it grows. The former routine is combinatorial in nature, and takes far too long to compute complex routes; the latter is an n-square algorithm,

and works reasonably well even with large numbers of towns, however, it does not always return the very best route.

145

To run this example, compile this program and then run the goal:

?- salesman.\

*/

Два алгоритма решения задачи о коммивояжёре:

exhaustive( [Home|Towns], Route, Dist ) :-

best_route( exhaustive_route(Towns,Home,Route), Route ), measure_route( Route, 0, Dist ).

exhaustive_route( [], Home, [Home,Home] ).

exhaustive_route( [Town|Towns], Home, NewRoute ) :- exhaustive_route( Towns, Home, IntRoute ), insert_route( Town, IntRoute, NewRoute ).

heuristic( [Home|Towns], Route, Dist ) :- heuristic_route( Towns, [Home,Home], Route ), measure_route( Route, 0, Dist ).

heuristic_route( [], Route, Route ).

heuristic_route( [Town|Towns], OldRoute, NewRoute ) :- best_route( insert_route(Town,OldRoute,IntRoute), IntRoute ), heuristic_route( Towns, IntRoute, NewRoute ).

best_route( Test, Route ) :- abolish( temp_store/2 ),

assert( temp_store([], 99999999) ), ( Test,

measure_route( Route, 0, NewDist ), temp_store( _, OldDist ),

NewDist < OldDist, abolish( temp_store/2 ),

assert( temp_store(Route,NewDist) ), fail

; % Логическое «ИЛИ» (пояснение Н.Г. Волченкова)

146

temp_store( Route, _ ), abolish( temp_store/2 ) ).

measure_route( [Town], Dist, Dist ) :- !.

measure_route( [Town1,Town2|Towns], OldDist, NewDist ) :- distance( Town1, Town2, Dist ),

IntDist is Dist + OldDist,

measure_route( [Town2|Towns], IntDist, NewDist ).

insert_route( Town, [Town1,Town2|R], [Town1,Town, Town2|R] ).

insert_route( Town, [Town1|OldRoute], [Town1|NewRoute] ) :- insert_route( Town, OldRoute, NewRoute ).

distance( Town1, Town2, Dist ) :- dist( Town1, Town2, Dist ), !.

distance( Town1, Town2, Dist ) :- dist( Town2, Town1, Dist ), !.

Рассмотрим, для примера, только 15 фактов, в которых зафиксированы расстояния между шестью городами Британии:

dist( b, e, 291).

% Бирмингем – Эдинбург.

dist( b, g, 292).

% Бирмингем – Глазго.

dist( b, l, 99).

% Бирмингем – Ливерпуль.

dist( b, m, 80).

% Бирмингем – Манчестер.

dist( b, n, 48).

% Бирмингем – Ноттингем.

dist( e, g, 44).

% Эдинбург – Глазго.

dist( e, l, 211).

% Эдинбург – Ливерпуль.

dist( e, m, 213).

% Эдинбург – Манчестер.

dist( e, n, 258).

% Эдинбург – Ноттингем.

dist( g, l, 212).

% Глазго – Ливерпуль.

dist( g, m, 214).

% Глазго – Манчестер.

dist( g, n, 281).

% Глазго – Ноттингем.

dist( l, m, 35).

% Ливерпуль – Манчестер.

dist( l, n, 100).

% Ливерпуль – Ноттингем.

dist( m, n, 71).

% Манчестер – Ноттингем.

 

 

 

147

Аэто – проведённый запуск программы («фотография» консоли

срезультатами её работы):

| ?-

# 0.000 seconds to consult sales-new.pl [d:\prolog\lpa2002\fb998f02\examples\] | ?- heuristic( [b,e,g,l,m,n], Route, Dist ). Route = [b,l,g,e,m,n,b] ,

Dist = 687

| ?- exhaustive( [b,e,g,l,m,n], Route, Dist ). Route = [b,m,l,g,e,n,b] ,

Dist = 677

| ?-

Графическая иллюстрация полученного результата представлена на рис. 10.5.

Глазго

Глазго

Эдинбург

Эдинбург

Ливерпуль

Ливерпуль

Манчестер

Манчестер

 

Бирмингем

Бирмингем

Ноттингем

Ноттингем

а)

б)

Рис. 10.5. Решение задачи о коммивояжере для шести городов Британии

Данный пример показывает, что не всегда эвристический алгоритм (рис. 10.5,а) даёт тот же результат, что и алгоритм полного перебора (рис. 10.5,б). Очевидно, что в случае их несовпадения первый результат несколько хуже второго – здесь: 687 > 677.

3. Задача об обитателях пяти домов

Это типичная задача, решение которой требует дедуктивного дарования известного сыщика Шерлока Холмса. Автор нашел её

148

решение в одном из архивов многочисленных хранящихся у него Пролог-систем, слегка модернизировал это решение и получил результат.

Приведем программу целиком (код 10.6) «в оригинале». Автор надеется, что английский язык этого примера (как и в представле-

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

Код 10.6

%PROLOG program to solve the "5 houses" problem using

%a "verify and choose" method.

%

© Lewis Baxter, LPA Co, UK, London

:- op(200, xfx, ':').

 

:- assert(bag(n, 0)).

:- write('There are five houses, each of a different color and '),nl, write(' inhabited by men of different nationalities, '),nl, write(' with different pets, drinks and cigarettes.'),nl,nl, write('1. The Englishman lives in the red house.'),nl,

write('2. The Spaniard owns the dog.'),nl, write('3. Coffee is drunk in the green house.'),nl, write('4. The Ukrainian drinks tea.'),nl,

write('5. The green house is immediately to the right'), write(' of the ivory house.'),nl,

write('6. The Winston smoker owns snails.'),nl, write('7. Kools are smoked in the yellow house.'),nl, write('8. Milk is drunk in the middle house.'),nl,

write('9. The Norwegian lives in the first house on the left.'),nl, write('10. The Chesterfields smoker lives next to the man'), write(' with the fox.'),nl,

write('11. Kools are smoked next to the house where'), write(' the horse is kept.'),nl,

write('12. The Lucky Strike smoker drinks orange juice.'),nl, write('13. The Japanese smokes Parliaments.'),nl,

write('14. The Norwegian lives next to the blue house.'),nl, write(''),nl,

write('THE PROBLEM: Who owns the Zebra? '),nl, write(' Who drinks water?),nl,

write('Type: ?-zebra(N).'),nl.

149

zebra(N) :- write('Wait...'), nl, solve(N).

zebra(N) :- retract(bag(n,N)),!.

solve(New) :- candidate(Colours,Drinks,Nationalities,Cigarettes,Pets),

!, % Это «отсечение» в программу включил автор

% (Н. Волченков) – догадайтесь, зачем? constraints(Colours,Drinks,Nationalities,Cigarettes,Pets), member(water:Nw, Drinks), member(zebra:Nz, Pets), write(water:Nw),nl, write(zebra:Nz),nl, write(Colours),nl,

write(Drinks),nl,

write(Nationalities),nl,

write(Cigarettes),nl,

write(Pets),nl, step_number(New).

step_number(New):-

retract(bag(n,Old)), New is Old+1, assert(bag(n,New)),!.

%A candidate solution is any of the (5!)**5 ways of

%distributing 5 colours (C), 5 drinks (D), 5 nationalities (N),

%5 cigarettes (S), and 5 pets (P) amongst 5 houses.

candidate(L1, L2, L3, L4, L5) :-

perm(L1), perm(L2), perm(L3), perm(L4), perm(L5).

perm([_:A,_:B,_:C,_:D,_:E]) :- permutation([A,B,C,D,E], [1,2,3,4,5]).

%The following constraints are placed on colours (C),

%drinks (D), nationalities (N), cigarettes (S) and pets (P).

constraints(C, D, N, S, P) :-

% The Englishman lives in the red house. member(englishman:H1, N), member(red:H1, C),

150

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