Конспект лекций по дисциплине "Программное обеспечение интеллектуальных систем". Для магистров специальности 5А521902

Вид материалаКонспект

Содержание


2Рекурсивные операции. Методы организации
3Методы обобщенного правила рекурсии – ОПР
File = datafile
File = datafile1; datafile2; datafile3
Чтение из файла прямого доступа
Отметим особенности дружественного интерфейса программ.
Подобный материал:
1   2   3

2Рекурсивные операции. Методы организации


Простая рекурсия


Правило, содержащее само себя в качестве компоненты, называется рекурсией. Рекурсия используется в арифметических операциях, при формировании запросов к базе данных и при обработке списков.

Общий вид:

голова:

<предикаты и правила>

голова.

Этот процесс может повторяться бесконечно, но при этом число элементов данных непрерывно растет и стек, где хранятся значения переменных, может переполниться. При этом на экране появляется сообщение об ошибке. Увеличить размер стека можно в меню “Setup” опция Miscellaneous setting. Но чтобы избегать бесконечной рекурсии нужно ввести предикат завершения, содержащий условия выхода.

Например:

1)write_st:-

write(“Вводим символы”),nl,

readchar(X),write(X),nl,

write_st.

Процесс продолжается бесконечно, пока не переполнится стек. Чтобы избежать этого, вводим правило, например:


read_a:-

readchar(X),

X<>’#’,

write(X),nl,

read_a.

Это простое правило рекурсии.


3Методы обобщенного правила рекурсии – ОПР


Общий вид ОПР имеет структуру:

<имя правила рекурсии>:-

<список предикатов>, (1)

<предикат выхода>, (2)

<список предикатов>, (3)

<имя правила рекурсии>, (4)

<список предикатов>. (5)

Данное правило рекурсии имеет 5 компонент.

Первая из них – группа предикатов. Успех или неудача любого из них не влияют на рекурсию.

Вторая компонента – определяет ход рекурсии, или останавливает ее, или продолжает.

Третья компонента – список других предикатов. Они не влияют на рекурсию.

Четвертая компонента – само правило рекурсии.

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

Обычно, рекурсивная процедура должна состоять из 2 фраз:

1. нерекурсив., определяющий вид процедуры в момент прекращения рекурсии

2. рекурсивное правило


Например: Генерация всех целых чисел, начиная с 1 и заканчивая Э.

Построим правило

write_n(N):-

N<8,

write(N),nl,

Next_N = N + 1,

write_n(Next_n).

Вся программа имеет вид:

domains

number = integer

predicates

write_n(number)

goal

write(“Ряд чисел_”),nl

write_n(1),

write(“Ряд закончен”).

clauses

write_n(N):-

N<8,

write(N),nl,

Next_n = N + 1,

write_n(Next_n).


Важным свойством правила является его расширяемость.

Рассмотрим 2 пример: Вычисление суммы ряда от 1 до 7.


domains

n,sum = integer

predicates

sum_ser(N,Sum)

goal

sum_ser(7,sum),write (“Summa = ”,sum).

clauses

sum_ser(1,1).

sum_ser(N,Sum):-

N>0,

Next_n = N – 1,

sum_ser(Next_n,Part_s),

Sum = N + Part_s.


Вычислим цель (7, Sum). Она сопоставляется с 1 фактом (1,1) – неуспешно. Затем берется правило: sum_ser(N,Sum) оно выполняется так N>0, высчитывается Next_n = 7 – 1 = 6 и вызывается правило с N=6. Part_s – свободная переменная.

До правила Sum = N + Part_s дело не доходит пока работает рекурсия, т.е. пока sum_ser(1,Part_s). Эта позиция сопоставляется с 1 фактом sum_ser(1,1) и Part_s приравнивается 1.

Далее проверяется 2 правило: и Sum получает значение 1. Next_n = 0 и по условию N>0 это правило становится неуспешным. Таким образом процесс прыгает к подцели Sum = N + Part_s.

В стеке были заполнены все значения N от «7 до 1», поэтому Sum последовательно присваивается: Sum: 1,3,6,10,15,21,28.


Рассмотрим программу ФАКТОРИАЛ.

N! = N * (N-1) * (N-2) … * 2 * 1


domains

number, product = integer

predicates

factorial(number, product)

goal

factorial(7,Result),

write(“7! = ”, Result), nl.

clauses

factorial(1,1):- !.

factorial(Number, Result):-

Next_n = Number – 1,

factorial(Next_n, Part_fac),

Result = Number * Part_fac).


Лекция №5.

Работа со статическими файлами

План Лекции
  1. Запись в файл
  2. Чтение из файла
  3. Модификация существующего файла
  4. Дозапись в конец уже существующего файла
  5. .Предикаты по общей работе с файлом

Ключевые слова

Запись в файл.Чтение из файла .Модификация существующего файла.

Дозапись в конец уже существующего файла..Предикаты по общей работе с файлом.

правило создания и записи файла прямого доступа.


Для использования в программе файла, необходимо снабдить его описанием файлового домена.

File = datafile

Символическое имя datafile есть идентификатор, который может быть логически отождествлен с DOS-ким именем файла. Это символическое имя называют логическим именем.

В описании file может быть указано несколько символических имен, но само описание должно быть существенным.

File = datafile1; datafile2; datafile3


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

OPENWrite(datafile1,”имя файла”)

Например:

OPENWrite(datafile1,”FILE1.Dat”)

Затем, что этим предикатом осуществляется открытие файла. Если с таким именем файл уже есть, то его содержимое пропадет. Поэтому сначала надо проверить наличие файла при помощи предиката

Existfile (”имя файла”)
  1. Назначить файл для записи в него можно при помощи предиката

Writedevice(datafile1)
  1. Сама запись в файл осуществляется предикатами

Write, writef
  1. Закрытие файла осуществляется предикатом

Closefile(datafile)

Когда файл закрыт, операции чтения или записи для него недопустимы, он защищен от потери информации, а указатель переведен на начало файла автоматически.


2.Чтение из файла


Для этого требуется:
  1. Открытие файла openread(datafile1,”file.dat”)
  2. Назначить файл устройством чтения readdevice(datafile1)
  3. Само чтение из файла осуществляется при помощи соответствующего предиката или правила
  4. Закрытие файла closefile(datafile1)


3.Модификация существующего файла


Последовательность действий, требуемых для модификации уже существующего файла, несколько отличается от предыдущих действий.

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

Предикат openmodify(datafile1,”имя файла”) успешен, если файл существует на диске, т.е. до этого он должен был быть создан предикатом openwrite


Модификация файла осуществляется посредством следующих шагов:
  1. Открытие файла. Openmodify (datafile1,”имя”)
  2. Переадресация вывода в файл. Writedevice (datafile1)
  3. Запись в файл новых данных
  4. Использование произвольных предикатов по работе с данными файлами
  5. Закрытие файла closefile(datafile1)


4.Дозапись в конец уже существующего файла


  1. Когда файл открывается для дозаписи, то указатель сразу смещается в конец предикатом openappend(datafile1,”имя”)
  2. Переадресация вывода в файл. Writedevice(datafile)
  3. Дозапись при помощи предикатов и правил
  4. Закрытие файла closefile(datafile1)


5.Предикаты по общей работе с файлом


В системе Турбо Пролог имеются следующие предикаты для работы с файлами в целом:
  1. сохранение файла – Save(DOS_name)
  2. уничтожение файла – deletefile(DOS_name)
  3. переименование файла – renamefile(DOS_name)
  4. проверка наличия файла – existfile(DOS_name)
  5. сброс данных из внутреннего буфера – flush(file_domain)
  6. выбор дисковода и пути доступа – disk(path)
  7. выдача каталога директории – dir(path,file_spec,file_name)


file_spec – группа файлов

file_name – имя найденного файла


Рассмотрим примеры:

Пример 1. Вывод информации в файл, содержащейся в фактах.

Domains

str = string

file = datafile

Predicates

data(str)

write_l

Goal

openwrite(datafile1,”имя”),

write_l :- data(Line),

write_l,

closefile(datafile1).

Clauses

data(“Первое предложение”).

data(“Второе предложение”),

……………………………….

write(Line),nl, /*вывод на экран*/

writedevice(datafile), /*переадресация из файла*/

write(Line),nl,

writedevice(screen), /*переадресация на экран*/

write(Line),

file.

write_l.

Последний write_l позволяет удовлетворить цель, когда правило дало неуспех из-за конца данных о data.

Пример 2. Чтение данных из существующего файла.


Domains

str = string

file = datafile

Predicates

read_l

Goal

openread(datafile1,”имя”),

read_l,

closefile(datafile).

Clauses

read_l :- readdevice(datafile),

not(eof(datafile)),

readln(Line),

writedevice(screen),

write(Line),nl,

read_l, /*рекурсия на чтение*/

read_l.


Пример 3. Запись в файл данных с клавиатуры.


Рассмотрим правило

create_a_file :-

readln(Filename), /*чтение переменной из экрана, которая определяет имя файла*/

openwrite(datafile1,filename), /*открытие файла с именем переменной*/

writedevice(datafile),

readline(Dstring), /*назначение файла данным*/

concat(Dstring,”\13\10”,Cstring), /*добавляет к строке спец. символ конца строки, чтобы readln различал конец строки*/

readin(Dstring,Cstring)

closefile(datafile).

readin(“done”,_):-!

readin(_,Cstring):- /*рекурсивное правило … записи в файл*/

write(Cstring) /*запись в файл …строки*/

readln(Dstring 1), /*чтение след. строки из клавиатуры*/

concat( Dstring 1,”\13\10”,Cstring 1),

writedevice(datafile), /*необязательный т.к. файл уже назначен*/

readin(Dstring 1,Cstring 1).


Пример 4. Дозапись данных в файл.


append_file :-

openappend(datafile,”имя”),

writedevice(datafile),

readln(Dstring) /*чтение данных _ строки*/

concat(Dstring,”\13\10”,Cstring),

readin(Dstring,Cstring),

closefile(datafile).


readin – правило, списанное выше


Лекция №6.

Использование файлов прямого доступа

План Лекции
  1. файлом прямого доступа
  2. создания и записи файла прямого доступа
  3. Чтение из файла прямого доступа
  4. особенности дружественного интерфейса программ



Ключевые слова

Чтение из файла прямого доступа. Особенности дружественного интерфейса программ.

Openmodify

1Файл прямого доступа


Каждая запись файла занимает определенную позицию, которая характеризуется смещением указателя от первого символа файла. Указатель может быть помещен в любое место. Файл с такой организацией называется файлом прямого доступа.

Если надо модифицировать файл, то следует использовать следующие шаги:
  1. openmodify(datafile,”имя”).
  2. сместить указатель файла filepos(datafile,File_position,Mode).

Параметру File_position – присвоено действительное число, обозначающее позицию в файле.

Параметру Mode присвоено одно из 3-х значений: 0,1,2.

0 – смещение относительно начала файла

1 – смещение относительно текущей позиии

2 – смещение берется относительно конца файла

Например:

File_pos(players,100,0)

В этом предикате players – имя логического файла.

«100» - означает, что указатель сместиться к 100 символу или 100 позиции.

«0» - показывает, что 100 отсчитывается от начала файла.

Если «1» - то отсчет будет вестись от текущей позиции указателя и указатель сместиться на 100 позиций от текущей.


Рассмотрим пример использования файлов прямого доступа.


Имеются записи о футболистах

Иванов, 7, Динамо …

Петров, 6, Спартак …

Сидоров, 11, ЦСКА …

Воробьев, 12, Зенит …

Вся информация состоит из 4 строк, каждая содержит 38 символов.

Данные хотим извлекать выборочно, а не подряд. Чтобы добиться этого, необходимо в конец каждой строки добавить комбинацию символов «\10\13» . Длина строки станет 40 – (LF-CR). Все строки одинаковые, так как мы их дополнили дефисами до 38.


Рассмотрим правило создания и записи файла прямого доступа.

create_file:

write(“Введите имя файла:”),nl

readln(fileName),

openwrite(datafile,FileName), /*Создают пустой файл*/

closefile(datafile)

openmodify(datdfile,FileName), /*Открытие для модификации*/

write(“Введите строку данных”),nl

readln(Dstring),

write_read(0,Dstring), /*рекурсивная процедура …. данные в файл, 0 – первоначальная позиция в файле*/

closefile(datdfile).

write_read(“done”):- /*правило при окончании «done»-слова конца*/

nl,write(“Конец данных”),

readchar(_),exit. /*модуль ожидания полезен в диалоговых программах*/

/*exit-выход из программы Турбо Пролог*/


write_read(Index,Dstring):-

writedevice(datafile),

filepos(datafile,Index,0), /*вывод на 0- позицию*/

1) pad_string(Dstring, Padstring,38), /*правило дополнения строки дефисами*/

2) concat(Padstring,”\10\13\”,Cstring)

write(Cstring), /*писать в файл*/

writedevice(screen),

readln(Dstring 1) /*считывание очередной строки*/

Index 1 = Index + 40, /*выбор следующей записи*/

write_read(Index 1, Dstring 1).

pad_string(Inst,Inst,Len):- /*Len – длина требуемая = 38*/

str_len(Inst,Test), /*встр. предикат длины строки*/

Test >= Len,!. /*если строка = или длиннее требуемого (38), то программа завершается*/

pad_string(Inst,Padstr,Len):- /*программа заполнения строки дефисами до длины Len(38)*/

concat(Inst,”-”, New),

pad_string(New, Padstr, Len).


Чтение из файла прямого доступа


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

Правило для чтения имеет вид:


read_file :-

openread(datafile,FileName),

readreal(record), /*чтение номера записи*/

filepos(datafile,index,0) Index = (Record-1)*40,

readln(Cstring), readdevice(datafile)

write(Cstring),nl,nl

readdevice(keyboard) /*готовность диалога через клавиатуру*/

readchar(-)

closefile(datafile).

exit.


Проследим, как вычисляется значение переменной Index. Введенный номер записи уменьшается на 1 и умножается на 40. Например, 2 запись (2-1)*40. Значит, с 40 позиции будет прочитана запись длиной 40 и помещена в переменную cstring.


Отметим особенности дружественного интерфейса программ.


readdevice (keyboard) /*предназначено для ведения диалога с пользователем-ожидание, пока не будет нажата какая-нибудь клавиша */

readchar(_)


Заметим, что существует 2 способа считывания данных с клавиатуры:

readln-для чтения данных symbol и string

readchar – для чтения данных посимвольно

в одном и другом случае нужно сцеплять с комбинацией CR-LF, для того, чтобы предикат readln мог читать каждую строку отдельно, а не потоком.

Особенность readchar является то, что при считывании не высвечивается вводимые данные, поэтому их нужно распечатывать write. При этом нужно учесть, когда заканчивается последний символ записи, нужно поставить символ возврата коретки (код ASCII-13), при этом комбинация CR-LF выводиться на экран и в файл и далее ………. следующий символ, пока не будет введен символ конца всех записей.

Ниже приведено правило ввода данных посимвольно.


1. readin(‘#’):-!. /*правило конца всех записей*/

2. readin(‘\13’):- /*правило ввода признака конца записи*/

write(“\13\10”), /*запись в файл*/

writedevice(screen), /*запись на экран*/

write(“\13\10”),

readchar(c)

writedevice(datafile), /*считывание следующего символа с экрана*/

readin(c). /*любой другой символ*/

3. readin(c):- /*вывод в файл*/

write(c)

writedevice(screen) /*вывод на экран*/

write(c)

readchar(c1) /*ввод с клавиатуры любого символа*/

writedevice(datafile)

readin(c1).


В правило используется, сам вводимый символ – «возврат коретки»


Лекция №7.

Использование динамических баз данных.

План Лекции
  1. иерархическая модель
  2. сетевая модель
  3. реляционная модель



Ключевые слова

иерархическая модель (данные хранятся в иерархии классов), сетевая модель (данные в виде связанных агрегатов, образующих сеть) и реляционная модель (данные в виде таблиц).

Использование динамических баз данных.

Программы баз данных на Прологе есть частный случай систем управления базами данных. Можно выделить три основные модели организации базы данных это: иерархическая модель (данные хранятся в иерархии классов), сетевая модель (данные в виде связанных агрегатов, образующих сеть) и реляционная модель (данные в виде таблиц). Пролог ориентирован на создание баз данных на основе реляционной модели. Для работы с базами данных существует достаточно большой набор встроенных предикатов. Некоторые из них продемонстрированы в примерах 5 и 6.

В Примере 5 происходит загрузка файла базы данных с именем «facts.bd», далее в случае существования объекта с именем Name все факты связанные с этим объектом уничтожаются, после чего база данных на диске обновляется.

Пример 5.

Domains

i = integer s = string

Database

age(s,i)

woman(s)

man(s)

Predicates

start

conclusion(s)

Goal start.

Clauses

start:- existfile("facts.bd"),consult("facts.bd"), % если база существует, то загружаем

makewindow(1,27,57,"",0,0,25,80), % создаем окно на весь экран

/* где 1 - номер окна , 27 - атрибут экрана ( цвет символов )

57 - атрибут рамки ,заголовок окна,

0,0 -координаты верхнего левого угла окна (Y,X),

25,80 -размеры окна по осям Y и X. */

write("Введите имя: "),readln(Name),nl, % вводим искомый объект

conclusion(Name). % переходим к правилу с одноименным заголовком

start.

conclusion(Name):-

woman(Name), % проверка существования объекта с именем Name

retract(age(Name,_)), retract(woman(Name)), % удаляем данные по объекту

save("facts.bd"), % сохраняем базу на диске

write("Данные по объекту ",Name," удалены из базы !"),

readchar(_). % задержка экрана до нажатия любого символа

conclusion(Name):-

not(woman(Name)), % если объект не существует, то выводим сообщение

write("Объект ",Name," отсутствует в базе !"),readchar(_).

/* содержимое файла "facts.bd"

age("Петя",20) age("Таня",10) age("Катя",18)

woman("Таня") woman("Катя")

man("Петя")

*/

Пролог позволяет создать несколько баз данных и дает возможность работать с ними как по отдельности, так и одновременно со всеми.

В примере 6 приведен фрагмент программы, который позволяет сохранить в базе данных на диске текущую дату с подтверждением пользователя. В данном примере используется база данных с именем da1. Обобщенный алгоритм программы такой:
  1. загружается файл базы данных с именем da1;
  1. если факты в базе отсутствуют, то в память заносится факт da("",1);
  1. с помощью системных предикатов считываем текущую дату;
  1. используя встроенный редактор пролога пользователь подтверждает (вводит) текущую дату;
  1. если формат даты правильный, то база данных с именем da1 обновляется.

Пример 6.

Domains i = integer s = string

Database - da1 % описание динамической базы данных с именем da1

da(s,i) % 1-й объект дата,

% 2-й объект - номер пользователя (активно не используется)

Predicates

start % предикат целевого утверждения

dtt % для ввода новой даты

td(i,s) % для проверки правильности ввода с сохранением

Goal start.

Clauses

start:- existfile("da.bd"),consult("da.bd",da1), % загрузка базы в память

makewindow(1,0,0,"",0,0,25,80), dtt, removewindow, !.

start.

dtt:-not(da(_,_)),assert(da("",1)). % если факты отсутствуют в базе, то

% добавляем в память начальный факт

dtt:- da(H1,_), % считываем последнюю дату работы из базы

% определяем текущую дату и выводим ее в заголовке окна редактора

date(G,M,D),str_int(G1,G),str_int(M1,M),str_int(D1,D),

concat("Введите дату (Esc - отказ) [СЕГОДНЯ:",D1,S1),

concat(S1,".",S2),concat(S2,M1,S3),concat(S3,".",S4),

concat(S4,G1,S5),concat(S5," г.]",S6),

makewindow(5,48,91,S6,10,10,4,58),

% используем редактор Пролога

editmsg(H1,H2,"F10 - выход с сохpанением","","",0,"",C),

removewindow,td(C,H2),!.

dtt:-dtt. % используем рекурсию для повторного ввода в случае ошибки

% если дата введена правильно, то обновляем базу данных

td(C,H2):- C=0,str_len(H2,Ld),Ld<9,

frontstr(2,H2,H3,H4),str_int(H3,Nd),Nd>0,Nd<32,

frontstr(1,H4,K1,K2),K1=".", frontstr(2,K2,P1,P2),

str_int(P1,Nm),Nm<13,Nm>0, frontstr(1,P2,J1,J2),J1=".",

frontstr(2,J2,Q1,Q2),str_int(Q1,Ng),Ng>=0,

da(_,Bb), retractall(da(_,_)),assert(da(H2,Bb)),

save("da.bd",da1),!.

td(C,H2):- C=1,!. % если пользователь ничего не ввел, то база не обновляется.