МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
Інститут комп’ютерних наук та інформаційних технологій
Кафедра автоматизованих систем управління
Лабораторна робота №1
з курсу
«Логічне програмування»
Львів – 2010
Лабораторна робота №1
Тема: Загальна структура програм на мові TURBO-PROLOG
Мета: Зрозуміти принципи логічного програмування
Завдання: Написати програму, яка складає таблицю істинності деякої логічної функції, заданої схемою з елементів “І-НЕ”
Теоретичні відомості
Програма на мові логічного програмування не задає алгоритм обробки даних. Вона декларує логічні зв'язки між деякими подіями, властивостями, об'єктами, діями. Зв'язок представляється як предикат, який містить вказані логічні поняття: події властивості, об'єкти, дії у вигляді своїх змінних. Наприклад, X=Y+Z можна розглядати як предикат, в якому права частина відома, а ліва - не відома. Тоді, для істинності предиката необхідно прирівняти праву і ліву частини рівняння. Якщо відомі обидві частини рівняння, то цей предикат можна трактувати як логічну умову, яка може бути істиною. Сам предикат також має чітке логічне визначення в абстрактних поняттях тих змінних, з якими він оперує. В даному прикладі, цей предикат можна назвати “додавання двох змінних”.
Логічні умови, які накладаються на змінні в тілі предикату визначають його істинність. Програма є просто множиною предикатів, які посилаються один на одний і всі вони закінчуються крапкою. Кожен з них в залежності від того, які змінні визначені, а які - ні, можна трактувати так:
Якщо відомі X, Y, Z,... то чи виникне подія f(X,Y,Z,...)? (або чи збережеться властивість f(X,Y,Z,...)?, або чи існуватиме об'єкт f(X,Y,Z,...)? і т.д.)
Якщо відомо, що подія f(X,Y,Z,...) відбулася (або є властивість f(X,Y,Z,...), або якщо об'єкт f(X,Y,Z,...) існує), то якими повинні бути X, Y, Z,... ?
Звичайно, розв'язок системи предикатних рівнянь може існувати, і вбудований механізм інтерпретації логічних програм його знайде, але під час програмування краще про нього не думати.
Фактично, програма складається з множини розділів, а кожний розділ складається з множини визначень, характерних для даного розділу. Якщо програма немає інших розділів крім “goal”, то її виконання не відрізняється від звичайного лінійного алгоритму, наприклад:
goal X=5, Y=6, Z=X+Y, write(“ Z=“,Z).
Отже, в “goal” задається мета програми - обчислити деякий предикат. В розділі “clauses” задається логічна модель задачі, яка складається з фактів і правил. Кожний факт має відповідну логічну інтерпретацію в поняттях, на яких базується модель задачі. Правило фактично задає опис алгоритму вирішення задачі у вигляді переліку інших простіших задач, які необхідно розв'язати.
При складанні програми на декларативній мові, такій як PROLOG, існує два шляхи. Перший - це взагалі забороняється конкретне алгоритмічне мислення, яке заважає помітити логічні зв'язки і сформулювати визначення у вигляді правил. Коректність програми повинна повністю забезпечуватись правильними визначеннями логічних понять та предикатів, з якими працює програма. Наведемо приклад програми для знаходження кращого ходу для гри в “сірники” (подивіться текст програми).
Умова гри: на столі знаходиться N сірників. Кожен з гравців може брати 1, 2 чи 4 сірника з загальної купи. Програє той, хто бере останнім, і на столі більше не буде сірників. Для складання логічних рівнянь необхідно сформулювати такі поняття у вигляді предикатів, як можливий хід “can_take_matches( кількість сірників, що можна брати)” і умова виграшу “win( скільки необхідно взяти щоб виграти, загальна кількість сірників)”.
Як можна бачити з програми, розділ domains містить визначення типів даних; розділ “predicates” - опис форми предикатів (які виражають поняття, події, зв'язки, тощо) та типів даних, які в предикатах зустрічаються. Розділ clauses являє собою тіло програми, тому що в ньому визначаються самі логічні умови і зв’язки, які складають логічну модель задачі. Як можна бачити з цього розділу, кожний логічний вираз закінчюється крапкою. Можливі два типи виразів:
P(X1,X2,...,Xn). - “факти”
P(X1,X2,...,Xn):-Q1,Q2,...,Qm. - “правила”
При виконанні предикатів цих типів кожний раз утворюється покоління змінних, яке зникає після того, як програма зустріла крапку кінця предикату. Отже, змінні в предикатах розрізняються лише на протязі виконання даного предикату.
Перший тип предикатів називається фактом. Факт задає жорсткі зв'язки між значеннями своїх змінних. Одноіменні факти групуються один біля одного і розглядаються як альтернативи (з умовою “або”): якщо є два факта з одним іменем та різними значеннями змінних, то комбінації значень при уточненні змінних можуть братись повністю з одного, або повністю з другого факту. Наприклад, в поданій нижче програмі факти “can_take_matches” вказують на можливість взяти 1, 2 або 4 сірників.
Вирази другого типу, які містять підстроку “:-” називаються правилами. Позначення “:-” між головою і тілом правила використовується як зв'язка “якщо”, “тоді, коли”, “необхідно” і т.д. Зміст правила виражається в наступному. Для того, щоб предикат P був істиним, необхідно, щоби були істиними всі предикати, які перелічені в правій частині правила. В нашому прикладі - це правило win(X,N), яке визначає умову виграшу. Прочитати це правило можна так: для того, щоб виграти в ситуації з N сірниками, необхідно взяти X сірників, після чого на столі залишиться Z=N-X сірників, яке більше нуля і при даному Z виграш неможливий, що виражено вбудованою функцією not( ). Знак підкреслення в предикаті win(_,Z) означає довільне значення пропущеної змінної, тобто: 1, 2 або 4.
Як не дивно, формулювання понять, які використовуються в алгоритмічних мовах, найбільш важке для декларативних мов програмування. Розглянемо предикат утворення циклу: cycle( змінна циклу, початкове значення, кінцеве значення), який наведений у програмі. Він складається з двох альтернативних правил: присвоїти значення змінній циклу або спробувати перейти до нового значення. Шаблон cycle(N,Y,N) означає, що якщо 1-й параметр не відомий, а 2-й і 3-й відомі, то першому параметру буде присвоєно значення третього параметра, оскільки вони позначені одною змінною N.
Розділ goal вказує кінцеву мету - знайти всі розв’язки задачі від 1 до 12 сірників.
Хід роботи
Вводжу запропоновану програму про сірники в середовищі Turbo Prolog:
DOMAINS
m = integer
PREDICATES
can_take_matches(m).
win(m,m).
cycle(m,m,m).
CLAUSES
cycle(N,Begin_value,N) :- N >= Begin_value.
cycle(N,X,Y) :- Y > X,
N2 = Y - 1,
cycle(N,X,N2).
can_take_matches(1).
can_take_matches(2).
can_take_matches(4).
win(X,N) :- can_take_matches(X),
Z = N - X,
Z > 0,
not(win(_,Z)).
GOAL
cycle(N,1,12),
win(X,N),nl,
write("If there are ",N,"matches, you need "),
write(X,"matches."),fail.
Запускаю і отримую результати:
Вводжу наступну програму, запропоновану викладачем, яка показує стани RS-тригера:
PREDICATES
and_not(integer,integer,integer)
schema(integer,integer,integer,integer)
CLAUSES
and_not(0,0,1).
and_not(0,1,1).
and_not(1,0,1).
and_not(1,1,0).
schema(A,B,C,D):-and_not(A,B,E),and_not(C,B,F),
and_not (F,D,G),and_not (E,G,D).
Запускаю і отримую результати:
Вводжу власну програму, яка показує більш складний тригер:
PREDICATES
and_not(integer,integer,integer,integer)
schema(integer,integer,integer,integer,integer,integer)
CLAUSES
and_not(0,0,0,1).
and_not(0,0,1,1).
and_not(0,1,0,1).
and_not(0,1,1,1).
and_not(1,0,0,1).
and_not(1,0,1,1).
and_not(1,1,0,1).
and_not(1,1,1,0).
schema(A,B,C,D,E,F):-and_not(A,E,F,D), and_not(D,B,F,E), and_not(E,C,D,F).
Вводжу ціль:
Goal: schema(A,B,C,D,E,F)
І отримую розв’язок з загальними станами системи:
Задаю інші цілі, щоб отримати:
Тригер з двома станами, який утворюється при вхідних значеннях 1, 1, 0 чи в будь-якій іншій послідовності.
Тригер з трьома станами.
Висновок: На цій лабораторній роботі я підтвердив можливості мови програмування Prolog визначати стани логічних елементів.