laba 1
.docxМИНИСТЕРСТВО ЦИФРОВОГО РАЗВИТИЯ, СВЯЗИ И МАССОВЫХ КОММУНИКАЦИЙ РОССИЙСКОЙ ФЕДЕРАЦИИ
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ
«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ.ПРОФ.М.А.БОНЧ-БРУЕВИЧА»
(СПбГУТ)
Факультет: «Институт магистратуры»
Кафедра: «Систем автоматизации и робототехники»
Направление подготовки: |
Автоматизация технологических процессов и производств |
Направленность (профиль): |
Интеллектуальные технологии в автоматизации |
ЛАБОРАТОРНАЯ РАБОТА № 1
по дисциплине:
Методы и модели искусственного интеллекта в управлении техническими системами
|
на тему:
Разработка и экспериментальное исследование формальной логической модели
Вариант: 10
-
Выполнили студенты группы:
дата, подпись
Фамилия И. О.
Принял к.т.н., доцент
Верхова Г.В.
дата, подпись
Фамилия И. О.
Цель работы: приобретение навыков создания формальных логических моделей на языке логического программирования Prolog.
Ход работы
Эксперимент 1
Задание:
Разработать программу на языке Prolog, реализующую формальную логическую модель согласно заданному варианту. База знаний, определяющая генеалогическое древо, представленное на рис.1. Также определит все пары «правнук – правнучка», определить всех потомков Нестора и определить, сколько потомков у Ивана.
Рис. 1 Генеалогическое древо
Код программы на языке Prolog, реализующей формальную логическую модель:
implement main
open core, console
domains
gender = male; female.
name = symbol.
class facts
person : (name, gender).
parent : (name, name).
class predicates
% Базовые предикаты родства
father : (name, name) nondeterm anyflow.
brother : (name, name) nondeterm anyflow.
uncestor : (name, name) nondeterm anyflow.
% Основной предикат для запуска
run : () procedure.
clauses
% Факты person/2: люди и их пол
person("Нестор", male()).
person("Просковия", female()).
person("Ксения", female()).
person("Иван", male()).
person("Пётр", male()).
person("Ирина", female()).
person("Николай", male()).
person("Дмитрий", male()).
person("Фёдор", male()).
person("Наталья", female()).
person("Владислав", male()).
person("Елена", female()).
person("Вячеслав", male()).
person("Ольга", female()).
person("Ростислав", male()).
person("Макар", male()).
person("Игнат", male()).
person("Юлия", female()).
% Факты parent/2: родитель → ребёнок
% Старшее поколение
parent("Нестор", "Ксения").
parent("Просковия", "Ксения").
parent("Нестор", "Пётр").
parent("Просковия", "Пётр").
% Второе поколение
parent("Ксения", "Николай").
parent("Иван", "Николай").
parent("Ксения", "Дмитрий").
parent("Иван", "Дмитрий").
parent("Пётр", "Фёдор").
parent("Ирина", "Фёдор").
parent("Пётр", "Наталья").
parent("Ирина", "Наталья").
% Третье поколение
parent("Дмитрий", "Елена").
parent("Наталья", "Ольга").
% Четвёртое поколение
parent("Владислав", "Ростислав").
parent("Елена", "Ростислав").
parent("Елена", "Макар").
parent("Вячеслав", "Игнат").
parent("Ольга", "Игнат").
parent("Вячеслав", "Юлия").
parent("Ольга", "Юлия").
parent("Вячеслав", "Макар").
% Определение базовых предикатов родства
% father(X, Y): X — отец Y, если X — родитель Y и X — мужчина
father(X, Y) :-
parent(X, Y),
person(X, male()).
% brother(X, Y): X — брат Y, если у них общий родитель, X — мужчина и X ≠ Y
brother(X, Y) :-
parent(Z, X),
parent(Z, Y),
person(X, male()),
not(X = Y).
% uncestor(X, Y): X — предок Y, если X — родитель Y
% или X — родитель Z, который предок Y
uncestor(X, Y) :-
parent(X, Y).
uncestor(X, Y) :-
parent(X, Z),
uncestor(Z, Y).
run() :-
nl,
write("Males"),
nl,
person(X, male()),
write(X),
nl,
fail.
run() :-
nl,
write("Females"),
nl,
person(X, female()),
write(X),
nl,
fail.
run() :-
nl,
write("Fathers"),
nl,
father(X, Y),
write(X, " is the father of ", Y),
nl,
fail.
run() :-
nl,
write("Brothers"),
nl,
brother(X, Y),
write(X, " is the brother of ", Y),
nl,
fail.
run() :-
nl,
write("Пётр's brothers"),
nl,
brother(X, "Пётр"),
write(X, " is Пётр's brother"),
nl,
fail.
run() :-
nl,
write("Иван's children"),
nl,
father("Иван", Y),
write(Y, " is Иван's child"),
nl,
fail.
run() :-
nl,
write("Is Наталья Иван's child?"),
nl,
father("Иван", "Наталья"),
write("Yes, Наталья is Иван's child"),
nl,
fail.
run() :-
nl,
write("Female count"),
ResultFem = [ X || person(X, female()) ],
CountFem = list::length(ResultFem),
write("Female count = ", CountFem),
nl,
fail.
run() :-
nl,
write("Male count"),
ResultMale = [ X || person(X, male()) ],
CountMale = list::length(ResultMale),
write("Male count = ", CountMale),
nl,
fail.
run() :-
nl,
write("Пётр's uncestors"),
nl,
uncestor(X, "Пётр"),
write(X, " is Пётр's uncestor"),
nl,
fail.
run() :-
nl,
write("Иван's uncestors"),
nl,
uncestor(X, "Иван"),
write(X, " is Иван's uncestor"),
nl,
fail.
run() :-
stdio::write("\nEnd").
end implement main
goal
% Запуск с UTF-8 для корректного отображения русских символов:
console::runUtf8(main::run).
Результаты выполнения программы:
Мужчины:
Нестор
Иван
Пётр
Николай
Дмитрий
Фёдор
Владислав
Вячеслав
Ростислав
Макар
Игнат
Женщины:
Просковия
Ксения
Ирина
Наталья
Елена
Ольга
Юлия
Отцы:
Нестор является отцом Ксения
Нестор является отцом Пётр
Иван является отцом Николай
Иван является отцом Дмитрий
Пётр является отцом Фёдор
Пётр является отцом Наталья
Дмитрий является отцом Елена
Владислав является отцом Ростислав
Вячеслав является отцом Игнат
Вячеслав является отцом Юлия
Вячеслав является отцом Макар
Братья:
Пётр является братом Ксения
Пётр является братом Ксения
Николай является братом Дмитрий
Николай является братом Дмитрий
Дмитрий является братом Николай
Дмитрий является братом Николай
Фёдор является братом Наталья
Фёдор является братом Наталья
Ростислав является братом Макар
Макар является братом Ростислав
Игнат является братом Юлия
Игнат является братом Макар
Игнат является братом Юлия
Макар является братом Игнат
Макар является братом Юлия
Правнуки и правнучки:
Ростислав является правнуком Ксения
Ростислав является правнуком Иван
Макар является правнуком Ксения
Макар является правнуком Иван
Игнат является правнуком Пётр
Игнат является правнуком Ирина
Елена является правнучкой Нестор
Елена является правнучкой Просковия
Ольга является правнучкой Нестор
Ольга является правнучкой Просковия
Юлия является правнучкой Пётр
Юлия является правнучкой Ирина
Потомки Нестора:
Ксения является потомком Нестора
Пётр является потомком Нестора
Николай является потомком Нестора
Дмитрий является потомком Нестора
Елена является потомком Нестора
Ростислав является потомком Нестора
Макар является потомком Нестора
Фёдор является потомком Нестора
Наталья является потомком Нестора
Ольга является потомком Нестора
Игнат является потомком Нестора
Юлия является потомком Нестора
Количество потомков у Ивана:
У Ивана всего потомков: 5
Конец
Вывод: В результате выполнения задания была разработана программа на языке Prolog, которая успешно реализует формальную логическую модель генеалогического древа согласно 10 варианту. База знаний корректно описывает родственные связи, что позволило:
Определить все пары «правнук – правнучка»;
Вывести список всех потомков Нестора;
Вычислить количество потомков Ивана.
Эксперимент 2
Задание:
Задача о ходе коня. Создать формальную логическую модель для решения задачи о нахождении маршрута шахматного коня, проходящего через все поля доски по одному разу для классической шахматной доски (8x8). Вывести последовательность всех ходов.
Отобразить последовательность ходов на изображении шахматной доски.
Формальная логическая модель:
Существуют замкнутые решения (последний ход коня заканчивается в одном ходе от начала) и незамкнутые решения.
Для шахматной доски размером 8 х 8 существует:
- 26,534,728,821,064 вариантов замкнутых решений
- 19,591,828,170,979,904 вариантов незамкнутых решений
Для квадратных досок N x N решение существует для всех N>=5
Ставим цифры ходом коня, пока не заполним все поле.
Найти одно из решений можно по правилу Варнсдорфа. Звучит оно так:
При обходе доски конь следует на то поле, с которого можно пойти на минимальное число ещё не пройденных полей. Если таких полей несколько, то можно пойти на любое из них.
Код программы на языке Prolog, реализующей формальную логическую модель: implement main
open core, console
class predicates
knight_move : (pair, pair) nondeterm.
degree : (list(pair), pair, integer [out]) nondeterm.
next_moves : (pair, list(pair), list(pair) [out]) nondeterm.
knight_tour : (list(pair) [out]) nondeterm.
knight_tour_helper : (list(pair), list(pair) [out]) nondeterm.
build_board : (list(pair), list(list(integer)) [out]) nondeterm.
fill_board : (list(pair), integer, list(list(integer)), list(list(integer)) [out]) nondeterm.
update_board: (list(list(integer)), integer, integer, integer, list(list(integer)) [out]) nondeterm.
replace_nth : (list(integer), integer, integer, list(integer) [out]) nondeterm.
print_board : (list(list(integer))) nondeterm.
print_row : (list(integer)) nondeterm.
run : () nondeterm.
clauses
% Определение возможных ходов коня
knight_move(X/Y, NX/NY) :-
member((DX, DY), [(2,1), (1,2), (-1,2), (-2,1),
(-2,-1), (-1,-2), (1,-2), (2,-1)]),
NX is X + DX,
NY is Y + DY,
NX >= 1, NX =< 8,
NY >= 1, NY =< 8.
% Эвристика Варнсдорфа: вычисление степени клетки
degree(Visited, X/Y, Degree) :-
findall(Next, (knight_move(X/Y, Next), \+ member(Next, Visited)), Moves),
length(Moves, Degree).
% Получение списка возможных ходов с сортировкой по возрастанию степени
next_moves(Current, Visited, SortedMoves) :-
findall(Next, (knight_move(Current, Next), \+ member(Next, Visited)), Moves),
map_list_to_pairs(degree(Visited), Moves, Pairs),
keysort(Pairs, SortedPairs),
pairs_values(SortedPairs, SortedMoves).
% Поиск тура коня: начинаем с клетки 5/1
knight_tour(Tour) :-
knight_tour_helper([5/1], RevTour),
reverse(RevTour, Tour).
% Если посещено 64 клетки, тур найден
knight_tour_helper(Visited, Visited) :-
length(Visited, 64).
knight_tour_helper(Visited, Tour) :-
Visited = [Current|_],
next_moves(Current, Visited, SortedMoves),
member(Next, SortedMoves),
knight_tour_helper([Next|Visited], Tour).
% Построение шахматной доски с номерами ходов
build_board(Tour, Board) :-
findall(Row, (between(1,8,_), findall(0, between(1,8,_), Row)), EmptyBoard),
fill_board(Tour, 1, EmptyBoard, Board).
% Заполнение доски ходами
fill_board([], _, Board, Board).
fill_board([Col/Row|Rest], N, BoardIn, BoardOut) :-
update_board(BoardIn, Row, Col, N, BoardNext),
N1 is N + 1,
fill_board(Rest, N1, BoardNext, BoardOut).
% Обновление клетки доски: в позиции (Row, Col) записывается значение Value
update_board(Board, Row, Col, Value, NewBoard) :-
nth1(Row, Board, OldRow),
replace_nth(OldRow, Col, Value, NewRow),
replace_nth(Board, Row, NewRow, NewBoard).
% Замена N-го элемента списка на заданное значение
replace_nth([_|T], 1, X, [X|T]).
replace_nth([H|T], N, X, [H|R]) :-
N > 1,
N1 is N - 1,
replace_nth(T, N1, X, R).
% Вывод доски в консоль
print_board([]).
print_board([Row|Rest]) :-
print_row(Row),
nl,
print_board(Rest).
print_row([]).
print_row([Elem|Rest]) :-
write(Elem), write('\t'),
print_row(Rest).
% Главная процедура: поиск тура коня и вывод результата
run() :-
knight_tour(Tour),
writeln('Последовательность ходов (Столбец/Строка):'),
writeln(Tour),
build_board(Tour, Board),
writeln('Шахматная доска с номерами ходов:'),
print_board(Board),
halt.
end implement main
goal
console::runUtf8(main::run).
Результаты выполнения:
Последовательность ходов (Столбец/Строка):
[5/1,7/2,8/4,7/6,8/8,6/7,4/8,2/7,1/5,2/3,1/1,3/2,1/3,2/1,4/2,6/1,8/2,6/3,7/1,8/3,7/5,8/7,6/8,4/7,2/8,1/6,2/4,1/2,3/1,5/2,7/3,8/1,6/2,4/1,2/2,4/3,6/4,8/5,7/7,5/8,3/7,1/8,2/6,1/4,3/5,5/6,4/4,3/6,1/7,3/8,5/7,7/8,8/6,6/5,4/6,2/5,3/3,5/4,6/6,4/5,5/3,7/4,5/5,3/4]
Шахматная доска с номерами ходов:
11 14 29 34 1 16 19 32
28 35 12 15 30 33 2 17
13 10 57 36 61 18 31 20
44 27 64 47 58 37 62 3
9 56 45 60 63 54 21 38
26 43 48 55 46 59 4 53
49 8 41 24 51 6 39 22
42 25 50 7 40 23 52 5
Вывод: В результате выполнения задания была разработана программа на языке Prolog, которая успешно реализует формальную логическую модель о ходе коня согласно 10 варианту.
Заключение:
В ходе выполнения задания были разработаны две формальные логические модели, демонстрирующие возможности языка Prolog в решении задач из различных областей.
Первая модель решает классическую задачу о ходе коня. Суть задачи заключалась в нахождении маршрута шахматного коня по доске 8×8 таким образом, чтобы каждая клетка посещалась ровно один раз. Реализован алгоритм, который не только выводит последовательность всех ходов, но и отображает её на изображении шахматной доски, что позволяет наглядно проверить корректность найденного решения.
Вторая модель представляет собой генеалогическое древо, реализованное согласно заданному варианту. База знаний корректно описывает родственные связи, что дало возможность:
Определить все пары «правнук – правнучка»;
Вывести список всех потомков Нестора;
Вычислить количество потомков Ивана.
Таким образом, выполнение задания подтвердило, что формальные логические модели на языке Prolog эффективно справляются с решением как комбинаторных задач (на примере задачи о ходе коня), так и задач анализа сложных родственных связей.
Санкт Петербург
2025
