Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Библиотека / ЛЕКЦИИ / POSIBNIK / ПРОГР НА ПРОЛОГЕ.doc
Скачиваний:
42
Добавлен:
23.03.2015
Размер:
669.7 Кб
Скачать

Симетричність і транзитивність

Розглянемо особливості реалізації відношень, що є одночасно симетричними й транзитивними. Прикладом такго відношення може служити відношення “можна-проїхати”. Попередньо ми навчилися ці властивості забезпечувати окремо. Особлива складність при одночасному їх забезпеченні – можливість зациклення.

Спроба 1

Розглянемо реалізацію відношення “тснр_подорожувати1” (транзитивне, симетричне, нерефлексивне 1-а версія):

% при подорожі одним видом транспорту

тснр_подорожувати1(А, Б, м(Вид_транспорту, Б)):-

А <> Б,

сим_подорож(А, Б, Вид_транспорту).

% при подорожі більш, ніж одним видом транспорту

тснр_подорожувати1(А, Б, м(Вид_транспорту1, У, Вид_транспорту2)):-

А <> Б,

сим_подорож(А, У, Вид_транспорту1),

тснр_подорожувати1(У, Б, Вид_транспорту2).

Задамо приклад бази даних для транспортної мережі:

подорож(київ, кременчук, автобус).

подорож(київ, дніпропетровськ, зал_дорога).

Для забезпечення властивості симетричності додамо правило сим_подорож.

сим_подорож(А, Б, Вид_транспорту):-

подорож(А, Б, Вид_транспорту).

сим_подорож(А, Б, Вид_транспорту):-

подорож(Б, А, Вид_транспорту).

Тут “подорож” – це фактуальна база даних, що описує конкретні маршрути й види транспорту. Для спрощення в цій версії відсутні операнди з назвою транспортної компанії. Якщо ми введемо запит “тснр_подорожувати1(кременчук, дніпропетровськ, М)”, тобто захочемо довідатися, як можна проїхати від Кременчука до Дніпропетровська, то перша відповідь буде вірною:

М = м(автобус, київ, м(зал_дорога, дніпропетровськ))

Однак, виявиться, що існує нескінченна кількість відповідей, цінність яких дуже сумнівна:

М = м(автобус, київ, м(автобус, кременчук),

м(автобус, київ, м(зал_дорога, дніпропетровськ))

М = м(автобус, київ, м(автобус, кременчук),

м(автобус, київ, м(автобус, кременчук),

м(автобус, київ, м(зал_дорога, дніпропетровськ))

М = м(автобус, київ, м(автобус, кременчук),

м(автобус, київ, м(автобус, кременчук),

м(автобус, київ, м(автобус, кременчук),

м(автобус, київ, м(зал_дорога, дніпропетровськ)) та ін.

Тобто щоразу, коли ми запитуємо іншу відповідь, процедура робить ще один цикл між Києвом і Кременчуком, перш ніж дістанеться Дніпропетровська.

Спроба 2.

Можна уникнути циклічних переміщень між Києвом і Кременчуком, якщо зазначивши, що якщо існує прямий маршрут між пунктами А и Б, то не слід шукати які-небудь додаткові відповіді. Іншими словами, якщо перше правило процедури “тснр_подорожувати1” виявиться успішним, то необхідно заборонити застосовувати друге правило. Для цього можна застосовувати предикат “відсікання” (“!”). Перевіримо, чи усуне це виникнення циклічних переміщень:

% при подорожі одним видом транспорту

тснр_подорожувати2(А, Б, м(Вид_транспорту, Б)):-

А <> Б,

сим_подорож(А, Б, Вид_транспорту), !.

% при подорожі більш, ніж одним видом транспорту

тснр_подорожувати1(А, Б, м(Вид_транспорту1, У, Вид_транспорту2)):-

А <> Б,

сим_подорож(А, У, Вид_транспорту1),

тснр_подорожувати1(У, Б, Вид_транспорту2).

Якщо база даних про маршрути має той же вид, що й у попередній програмі, то відповідь на запит “тснр_подорожувати2 (кременчук, дніпропетровськ, М)” буде цілком достовірною

М = м(автобус, київ, м(жел_дорога, дніпропетровськ)).

Інтуїтивно ми уявляємо, що на цей запит повинна бути тільки одна відповідь, і програма її знаходить.

Але уявимо собі, що транспортна система має трохи трохи складний вигляд, наприклад, (рис. 11).

літак

зал_дорога

автобус автобус

автобус

автомобіль

автомобіль

Рис. 11. Схема транспортної мережі деякої компанії

Описати цю транспортну мережу мовою ПРОЛОГ можна в такий спосіб:

подорож(київ, кременчук, автобус).

подорож(київ, дніпропетровськ, зал_дорога).

подорож(кременчук, полтава, автомобіль).

подорож(полтава, дніпропетровськ, автобус).

подорож(київ, полтава, літак).

подорож(кременчук, черкаси, автомобіль).

подорож(київ, черкаси, автобус).

Результати виконання запиту “тснр_подорожувати2(кременчук, дніпропетровськ, М)” знову збентежують:

М = м(автобус, київ, м(зал_дорога, дніпропетровськ))

М = м(автобус, київ, м(літак, полтава), м(автомобіль, кременчук),

м(автобус, київ),м(зал_дорога, дніпропетровськ))

М = м(автобус, київ, м(літак, полтава), м(автомобіль, кременчук),

м(автобус, київ, м(літак, полтава), м(автомобіль, кременчук),

м(автобус, київ),м(зал_дорога, дніпропетровськ))

та ін.

Таким чином, додавання предиката “відсікання” дозволило усунути циклічні переміщення тільки для випадку, коли в базі даних “подорож” було всього два факти. Крім того, предикат “відсікання” небезпечний тим, що при його застосуванні можуть бути відкинуті й правильні відповіді. Якщо між двома пунктами курсує більше ніж один вид транспорту, то процедура “тснр_подорожувати2” стане циклічно переміщуватися між Кременчуком і Полтавою і ніколи не дійде до більш зручного маршруту з Кременчука на Дніпропетровськ через Київ.

Причиною цього є циклічність бази даних і запит “грузне” в одному з циклів. Існує два способи боротьби з таким поводженням програми:

1) необхідно ретельно перевіряти дані на відсутність циклів;

2) зробити програму нечуттєвою до циклічності даних.

Другий спосіб здається привабливішим. Можна зробити так, щоб процедура “тснр_подорожувати2” не поверталася в ті місця де вона вже побувала.