Compare commits
5 Commits
b6c19c5240
...
lab6
| Author | SHA1 | Date | |
|---|---|---|---|
| b4fcf6562e | |||
|
|
93ab829cff | ||
|
|
9f591dadda | ||
| 7394e5b9fb | |||
| 1f80f2f7dc |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,6 +4,8 @@
|
|||||||
!*.gitignore
|
!*.gitignore
|
||||||
!*.py
|
!*.py
|
||||||
!.gitkeep
|
!.gitkeep
|
||||||
|
!lab3/data.txt
|
||||||
!lab4/*
|
!lab4/*
|
||||||
!lab5/report/report.tex
|
!lab5/report/report.tex
|
||||||
!lab5/README.md
|
!lab5/README.md
|
||||||
|
!lab6/README.md
|
||||||
|
|||||||
89
lab3/data.txt
Normal file
89
lab3/data.txt
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
1 11511.3889 42106.3889
|
||||||
|
2 11503.0556 42855.2778
|
||||||
|
3 11438.3333 42057.2222
|
||||||
|
4 11438.3333 42057.2222
|
||||||
|
5 11438.3333 42057.2222
|
||||||
|
6 11785.2778 42884.4444
|
||||||
|
7 11785.2778 42884.4444
|
||||||
|
8 11785.2778 42884.4444
|
||||||
|
9 11785.2778 42884.4444
|
||||||
|
10 12363.3333 43189.1667
|
||||||
|
11 11846.9444 42660.5556
|
||||||
|
12 11503.0556 42855.2778
|
||||||
|
13 11963.0556 43290.5556
|
||||||
|
14 11963.0556 43290.5556
|
||||||
|
15 12300.0000 42433.3333
|
||||||
|
16 11973.0556 43026.1111
|
||||||
|
17 11973.0556 43026.1111
|
||||||
|
18 11461.1111 43252.7778
|
||||||
|
19 11461.1111 43252.7778
|
||||||
|
20 11461.1111 43252.7778
|
||||||
|
21 11461.1111 43252.7778
|
||||||
|
22 11600.0000 43150.0000
|
||||||
|
23 12386.6667 43334.7222
|
||||||
|
24 12386.6667 43334.7222
|
||||||
|
25 11595.0000 43148.0556
|
||||||
|
26 11595.0000 43148.0556
|
||||||
|
27 11569.4444 43136.6667
|
||||||
|
28 11310.2778 42929.4444
|
||||||
|
29 11310.2778 42929.4444
|
||||||
|
30 11310.2778 42929.4444
|
||||||
|
31 11963.0556 43290.5556
|
||||||
|
32 11416.6667 42983.3333
|
||||||
|
33 11416.6667 42983.3333
|
||||||
|
34 11595.0000 43148.0556
|
||||||
|
35 12149.4444 42477.5000
|
||||||
|
36 11595.0000 43148.0556
|
||||||
|
37 11595.0000 43148.0556
|
||||||
|
38 11108.6111 42373.8889
|
||||||
|
39 11108.6111 42373.8889
|
||||||
|
40 11108.6111 42373.8889
|
||||||
|
41 11108.6111 42373.8889
|
||||||
|
42 11183.3333 42933.3333
|
||||||
|
43 12372.7778 42711.3889
|
||||||
|
44 11583.3333 43150.0000
|
||||||
|
45 11583.3333 43150.0000
|
||||||
|
46 11583.3333 43150.0000
|
||||||
|
47 11583.3333 43150.0000
|
||||||
|
48 11583.3333 43150.0000
|
||||||
|
49 11822.7778 42673.6111
|
||||||
|
50 11822.7778 42673.6111
|
||||||
|
51 12058.3333 42195.5556
|
||||||
|
52 11003.6111 42102.5000
|
||||||
|
53 11003.6111 42102.5000
|
||||||
|
54 11003.6111 42102.5000
|
||||||
|
55 11522.2222 42841.9444
|
||||||
|
56 12386.6667 43334.7222
|
||||||
|
57 12386.6667 43334.7222
|
||||||
|
58 12386.6667 43334.7222
|
||||||
|
59 11569.4444 43136.6667
|
||||||
|
60 11569.4444 43136.6667
|
||||||
|
61 11569.4444 43136.6667
|
||||||
|
62 11155.8333 42712.5000
|
||||||
|
63 11155.8333 42712.5000
|
||||||
|
64 11155.8333 42712.5000
|
||||||
|
65 11155.8333 42712.5000
|
||||||
|
66 11133.3333 42885.8333
|
||||||
|
67 11133.3333 42885.8333
|
||||||
|
68 11133.3333 42885.8333
|
||||||
|
69 11133.3333 42885.8333
|
||||||
|
70 11133.3333 42885.8333
|
||||||
|
71 11003.6111 42102.5000
|
||||||
|
72 11770.2778 42651.9444
|
||||||
|
73 11133.3333 42885.8333
|
||||||
|
74 11690.5556 42686.6667
|
||||||
|
75 11690.5556 42686.6667
|
||||||
|
76 11751.1111 42814.4444
|
||||||
|
77 12645.0000 42973.3333
|
||||||
|
78 12421.6667 42895.5556
|
||||||
|
79 12421.6667 42895.5556
|
||||||
|
80 11485.5556 43187.2222
|
||||||
|
81 11423.8889 43000.2778
|
||||||
|
82 11423.8889 43000.2778
|
||||||
|
83 11715.8333 41836.1111
|
||||||
|
84 11297.5000 42853.3333
|
||||||
|
85 11297.5000 42853.3333
|
||||||
|
86 11583.3333 43150.0000
|
||||||
|
87 11569.4444 43136.6667
|
||||||
|
88 12286.9444 43355.5556
|
||||||
|
89 12355.8333 43156.3889
|
||||||
3
lab6/README.md
Normal file
3
lab6/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Attention!
|
||||||
|
|
||||||
|
lab6 is fully AI generated slop.
|
||||||
160
lab6/aco.py
Normal file
160
lab6/aco.py
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
import math
|
||||||
|
import random
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List, Sequence, Tuple
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
City = Tuple[float, float]
|
||||||
|
Tour = List[int]
|
||||||
|
|
||||||
|
|
||||||
|
def euclidean_distance(c1: City, c2: City) -> float:
|
||||||
|
return math.hypot(c1[0] - c2[0], c1[1] - c2[1])
|
||||||
|
|
||||||
|
|
||||||
|
def build_distance_matrix(cities: Sequence[City]) -> list[list[float]]:
|
||||||
|
size = len(cities)
|
||||||
|
matrix = [[0.0 for _ in range(size)] for _ in range(size)]
|
||||||
|
for i in range(size):
|
||||||
|
for j in range(i + 1, size):
|
||||||
|
dist = euclidean_distance(cities[i], cities[j])
|
||||||
|
matrix[i][j] = matrix[j][i] = dist
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
|
||||||
|
def plot_tour(cities: Sequence[City], tour: Sequence[int], save_path: str) -> None:
|
||||||
|
x = [cities[i][0] for i in tour]
|
||||||
|
y = [cities[i][1] for i in tour]
|
||||||
|
|
||||||
|
fig, ax = plt.subplots(figsize=(7, 7))
|
||||||
|
ax.plot(x + [x[0]], y + [y[0]], "k-", linewidth=1)
|
||||||
|
ax.plot(x, y, "ro", markersize=4)
|
||||||
|
|
||||||
|
ax.axis("equal")
|
||||||
|
fig.tight_layout()
|
||||||
|
fig.savefig(save_path, dpi=220)
|
||||||
|
plt.close(fig)
|
||||||
|
|
||||||
|
|
||||||
|
def plot_history(best_lengths: Sequence[float], save_path: str) -> None:
|
||||||
|
if not best_lengths:
|
||||||
|
return
|
||||||
|
|
||||||
|
iterations = list(range(len(best_lengths)))
|
||||||
|
|
||||||
|
fig, ax = plt.subplots(figsize=(10, 6))
|
||||||
|
ax.plot(iterations, best_lengths, linewidth=2, color="blue")
|
||||||
|
|
||||||
|
ax.set_xlabel("Итерация", fontsize=12)
|
||||||
|
ax.set_ylabel("Длина лучшего тура", fontsize=12)
|
||||||
|
ax.grid(True, alpha=0.3)
|
||||||
|
|
||||||
|
fig.savefig(save_path, dpi=150, bbox_inches="tight")
|
||||||
|
plt.close(fig)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ACOConfig:
|
||||||
|
cities: Sequence[City]
|
||||||
|
n_ants: int
|
||||||
|
n_iterations: int
|
||||||
|
alpha: float = 1.0
|
||||||
|
beta: float = 5.0
|
||||||
|
rho: float = 0.5
|
||||||
|
q: float = 1.0
|
||||||
|
seed: int | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ACOResult:
|
||||||
|
best_tour: Tour
|
||||||
|
best_length: float
|
||||||
|
history: List[float]
|
||||||
|
|
||||||
|
|
||||||
|
class AntColonyOptimizer:
|
||||||
|
def __init__(self, config: ACOConfig):
|
||||||
|
self.config = config
|
||||||
|
if config.seed is not None:
|
||||||
|
random.seed(config.seed)
|
||||||
|
|
||||||
|
self.cities = config.cities
|
||||||
|
self.dist_matrix = build_distance_matrix(config.cities)
|
||||||
|
n = len(config.cities)
|
||||||
|
self.pheromone = [[1.0 if i != j else 0.0 for j in range(n)] for i in range(n)]
|
||||||
|
|
||||||
|
def _choose_next_city(self, current: int, unvisited: set[int]) -> int:
|
||||||
|
candidates = list(unvisited)
|
||||||
|
weights = []
|
||||||
|
for nxt in candidates:
|
||||||
|
tau = self.pheromone[current][nxt] ** self.config.alpha
|
||||||
|
eta = (1.0 / (self.dist_matrix[current][nxt] + 1e-12)) ** self.config.beta
|
||||||
|
weights.append(tau * eta)
|
||||||
|
|
||||||
|
total = sum(weights)
|
||||||
|
probs = [w / total for w in weights]
|
||||||
|
return random.choices(candidates, weights=probs, k=1)[0]
|
||||||
|
|
||||||
|
def _build_tour(self, start: int) -> Tour:
|
||||||
|
n = len(self.cities)
|
||||||
|
tour = [start]
|
||||||
|
unvisited = set(range(n))
|
||||||
|
unvisited.remove(start)
|
||||||
|
|
||||||
|
current = start
|
||||||
|
while unvisited:
|
||||||
|
nxt = self._choose_next_city(current, unvisited)
|
||||||
|
tour.append(nxt)
|
||||||
|
unvisited.remove(nxt)
|
||||||
|
current = nxt
|
||||||
|
|
||||||
|
return tour
|
||||||
|
|
||||||
|
def _tour_length(self, tour: Sequence[int]) -> float:
|
||||||
|
return sum(
|
||||||
|
self.dist_matrix[tour[i]][tour[(i + 1) % len(tour)]]
|
||||||
|
for i in range(len(tour))
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self) -> ACOResult:
|
||||||
|
best_tour: Tour = []
|
||||||
|
best_length = float("inf")
|
||||||
|
best_history: list[float] = []
|
||||||
|
|
||||||
|
for _ in range(self.config.n_iterations):
|
||||||
|
tours: list[Tour] = []
|
||||||
|
lengths: list[float] = []
|
||||||
|
|
||||||
|
for _ in range(self.config.n_ants):
|
||||||
|
start_city = random.randrange(len(self.cities))
|
||||||
|
tour = self._build_tour(start_city)
|
||||||
|
length = self._tour_length(tour)
|
||||||
|
tours.append(tour)
|
||||||
|
lengths.append(length)
|
||||||
|
|
||||||
|
if length < best_length:
|
||||||
|
best_length = length
|
||||||
|
best_tour = tour
|
||||||
|
|
||||||
|
for i in range(len(self.pheromone)):
|
||||||
|
for j in range(len(self.pheromone)):
|
||||||
|
self.pheromone[i][j] *= 1 - self.config.rho
|
||||||
|
|
||||||
|
for tour, length in zip(tours, lengths):
|
||||||
|
deposit = self.config.q / length
|
||||||
|
for i in range(len(tour)):
|
||||||
|
a, b = tour[i], tour[(i + 1) % len(tour)]
|
||||||
|
self.pheromone[a][b] += deposit
|
||||||
|
self.pheromone[b][a] += deposit
|
||||||
|
|
||||||
|
best_history.append(best_length)
|
||||||
|
|
||||||
|
return ACOResult(
|
||||||
|
best_tour=best_tour, best_length=best_length, history=best_history
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_aco(config: ACOConfig) -> ACOResult:
|
||||||
|
optimizer = AntColonyOptimizer(config)
|
||||||
|
return optimizer.run()
|
||||||
38
lab6/main.py
Normal file
38
lab6/main.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from aco import ACOConfig, plot_history, plot_tour, run_aco
|
||||||
|
|
||||||
|
# В списке из 89 городов только 38 уникальных
|
||||||
|
cities = set()
|
||||||
|
with open(os.path.join(os.path.dirname(__file__), "../lab3/data.txt"), "r") as file:
|
||||||
|
for line in file:
|
||||||
|
# x и y поменяны местами в визуализациях в методичке
|
||||||
|
_, y, x = line.split()
|
||||||
|
cities.add((float(x), float(y)))
|
||||||
|
cities = list(cities)
|
||||||
|
|
||||||
|
config = ACOConfig(
|
||||||
|
cities=cities,
|
||||||
|
n_ants=50,
|
||||||
|
n_iterations=50,
|
||||||
|
alpha=1.2,
|
||||||
|
beta=5.0,
|
||||||
|
rho=0.5,
|
||||||
|
q=1.0,
|
||||||
|
seed=7,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = run_aco(config)
|
||||||
|
print(f"Лучшая длина: {result.best_length:.2f}")
|
||||||
|
print(f"Лучший тур: {result.best_tour}")
|
||||||
|
|
||||||
|
results_dir = os.path.join(os.path.dirname(__file__), "report", "img")
|
||||||
|
os.makedirs(results_dir, exist_ok=True)
|
||||||
|
|
||||||
|
plot_tour(
|
||||||
|
config.cities, result.best_tour, os.path.join(results_dir, "aco_best_tour.png")
|
||||||
|
)
|
||||||
|
plot_history(result.history, os.path.join(results_dir, "aco_history.png"))
|
||||||
|
|
||||||
|
with open(os.path.join(results_dir, "aco_best_tour.txt"), "w", encoding="utf-8") as f:
|
||||||
|
f.write(" ".join(map(str, result.best_tour)))
|
||||||
5
lab6/report/.gitignore
vendored
Normal file
5
lab6/report/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
*
|
||||||
|
!**/
|
||||||
|
!.gitignore
|
||||||
|
!report.tex
|
||||||
|
!img/**/*.png
|
||||||
BIN
lab6/report/img/aco_best_tour.png
Normal file
BIN
lab6/report/img/aco_best_tour.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
BIN
lab6/report/img/aco_history.png
Normal file
BIN
lab6/report/img/aco_history.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
lab6/report/img/best_lab3.png
Normal file
BIN
lab6/report/img/best_lab3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
BIN
lab6/report/img/optimal_tour.png
Normal file
BIN
lab6/report/img/optimal_tour.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
455
lab6/report/report.tex
Normal file
455
lab6/report/report.tex
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
\documentclass[a4paper, final]{article}
|
||||||
|
%\usepackage{literat} % Нормальные шрифты
|
||||||
|
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
|
||||||
|
\usepackage{tabularx}
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage[T2A]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[russian]{babel}
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
|
||||||
|
\usepackage{ragged2e} %для растягивания по ширине
|
||||||
|
\usepackage{setspace} %для межстрочно го интервала
|
||||||
|
\usepackage{moreverb} %для работы с листингами
|
||||||
|
\usepackage{indentfirst} % для абзацного отступа
|
||||||
|
\usepackage{moreverb} %для печати в листинге исходного кода программ
|
||||||
|
\usepackage{pdfpages} %для вставки других pdf файлов
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{afterpage}
|
||||||
|
\usepackage{longtable}
|
||||||
|
\usepackage{float}
|
||||||
|
\usepackage{xcolor}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% \usepackage[paper=A4,DIV=12]{typearea}
|
||||||
|
\usepackage{pdflscape}
|
||||||
|
% \usepackage{lscape}
|
||||||
|
|
||||||
|
\usepackage{array}
|
||||||
|
\usepackage{multirow}
|
||||||
|
|
||||||
|
\renewcommand\verbatimtabsize{4\relax}
|
||||||
|
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
|
||||||
|
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
|
||||||
|
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
|
||||||
|
\usepackage{listings} %листинги
|
||||||
|
\usepackage{xcolor} % цвета
|
||||||
|
\usepackage{hyperref}% для гиперссылок
|
||||||
|
\usepackage{enumitem} %для перечислений
|
||||||
|
|
||||||
|
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
|
||||||
|
|
||||||
|
|
||||||
|
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
|
||||||
|
|
||||||
|
\hypersetup{colorlinks,
|
||||||
|
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
|
||||||
|
|
||||||
|
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
|
||||||
|
\lstloadlanguages{ SQL}
|
||||||
|
% включаем кириллицу и добавляем кое−какие опции
|
||||||
|
\lstset{tabsize=2,
|
||||||
|
breaklines,
|
||||||
|
basicstyle=\footnotesize,
|
||||||
|
columns=fullflexible,
|
||||||
|
flexiblecolumns,
|
||||||
|
numbers=left,
|
||||||
|
numberstyle={\footnotesize},
|
||||||
|
keywordstyle=\color{blue},
|
||||||
|
inputencoding=cp1251,
|
||||||
|
extendedchars=true
|
||||||
|
}
|
||||||
|
\lstdefinelanguage{MyC}{
|
||||||
|
language=SQL,
|
||||||
|
% ndkeywordstyle=\color{darkgray}\bfseries,
|
||||||
|
% identifierstyle=\color{black},
|
||||||
|
% morecomment=[n]{/**}{*/},
|
||||||
|
% commentstyle=\color{blue}\ttfamily,
|
||||||
|
% stringstyle=\color{red}\ttfamily,
|
||||||
|
% morestring=[b]",
|
||||||
|
% showstringspaces=false,
|
||||||
|
% morecomment=[l][\color{gray}]{//},
|
||||||
|
keepspaces=true,
|
||||||
|
escapechar=\%,
|
||||||
|
texcl=true
|
||||||
|
}
|
||||||
|
|
||||||
|
\textheight=24cm % высота текста
|
||||||
|
\textwidth=16cm % ширина текста
|
||||||
|
\oddsidemargin=0pt % отступ от левого края
|
||||||
|
\topmargin=-1.5cm % отступ от верхнего края
|
||||||
|
\parindent=24pt % абзацный отступ
|
||||||
|
\parskip=5pt % интервал между абзацами
|
||||||
|
\tolerance=2000 % терпимость к "жидким" строкам
|
||||||
|
\flushbottom % выравнивание высоты страниц
|
||||||
|
|
||||||
|
|
||||||
|
% Настройка листингов
|
||||||
|
\lstset{
|
||||||
|
language=python,
|
||||||
|
extendedchars=\true,
|
||||||
|
inputencoding=utf8,
|
||||||
|
keepspaces=true,
|
||||||
|
% captionpos=b, % подписи листингов снизу
|
||||||
|
}
|
||||||
|
|
||||||
|
\begin{document} % начало документа
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
|
||||||
|
\begin{center}
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
|
||||||
|
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
|
||||||
|
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
|
||||||
|
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
|
||||||
|
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
|
||||||
|
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\large{Лабораторная работа №6}\\
|
||||||
|
\large{по дисциплине}\\
|
||||||
|
\large{<<Генетические алгоритмы>>}\\
|
||||||
|
\large{Вариант 18}\\
|
||||||
|
|
||||||
|
% \hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\small{
|
||||||
|
\begin{tabular}{lrrl}
|
||||||
|
\!\!\!Студент, & \hspace{2cm} & & \\
|
||||||
|
\!\!\!группы 5130201/20101 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
|
||||||
|
\!\!\!Преподаватель & \hspace{2cm} & \underline{\hspace{3cm}} & Большаков А. А. \\\\
|
||||||
|
&&\hspace{4cm}
|
||||||
|
\end{tabular}
|
||||||
|
\begin{flushright}
|
||||||
|
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025г.
|
||||||
|
\end{flushright}
|
||||||
|
}
|
||||||
|
|
||||||
|
\hfill \break
|
||||||
|
% \hfill \break
|
||||||
|
\begin{center} \small{Санкт-Петербург, 2025} \end{center}
|
||||||
|
\thispagestyle{empty} % выключаем отображение номера для этой страницы
|
||||||
|
|
||||||
|
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
\tableofcontents
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section {Постановка задачи}
|
||||||
|
В данной работе были поставлены следующие задачи:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Реализовать с использованием муравьиных алгоритмов решение задачи коммивояжера по индивидуальному заданию согласно номеру варианта.
|
||||||
|
\item Представить графически найденное решение
|
||||||
|
\item Сравнить найденное решение с представленным в условии задачи оптимальным решением и результатами, полученными в лабораторной работе №3.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\textbf{Индивидуальное задание вариант 18:}
|
||||||
|
|
||||||
|
\textbf{Дано:} Эвклидовы координаты городов 38 городов в Джибути (см.~Приложение~А). Оптимальный тур представлен на Рис.~\ref{fig:optimal_tour}, его длина равна 6659.
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.5\linewidth]{img/optimal_tour.png}
|
||||||
|
\caption{Оптимальный тур для заданного набора данных}
|
||||||
|
\label{fig:optimal_tour}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Теоретические сведения}
|
||||||
|
|
||||||
|
\subsection{Общие сведения о муравьиных алгоритмах}
|
||||||
|
|
||||||
|
Муравьиные алгоритмы (МА) относятся к метаэвристическим методам оптимизации и предназначены преимущественно для решения задач комбинаторной оптимизации, в частности задачи поиска оптимальных путей на графах. Основная идея таких алгоритмов основана на моделировании коллективного поведения реальных муравьёв, использующих феромонные следы для обмена информацией.
|
||||||
|
|
||||||
|
Каждый агент, называемый \textit{искусственным муравьём}, поэтапно строит решение задачи, перемещаясь по графу и выбирая следующую вершину на основе вероятностного правила, учитывающего концентрацию феромона на дугах графа. Феромон отражает привлекательность соответствующих маршрутов: чем выше его концентрация на дуге, тем вероятнее выбор этой дуги муравьём.
|
||||||
|
|
||||||
|
\subsection{Простой муравьиный алгоритм (SACO)}
|
||||||
|
|
||||||
|
Для иллюстрации рассмотрим простой муравьиный алгоритм SACO (Simple Ant Colony Optimization). Пусть задан граф
|
||||||
|
\[
|
||||||
|
G = (V, E),
|
||||||
|
\]
|
||||||
|
где $V$ — множество вершин, $E$ — множество рёбер. Каждой дуге $(i,j)$ сопоставлена величина феромона $\tau_{ij}$.
|
||||||
|
|
||||||
|
В начальный момент концентрация феромона обычно принимается нулевой, однако для предотвращения зацикливания каждому ребру присваивается малое случайное начальное значение $\tau_{ij}^{(0)}$.
|
||||||
|
|
||||||
|
Каждый муравей $k=1,\ldots,n_k$ помещается в стартовую вершину и начинает построение пути. Если муравей находится в вершине $i$, он выбирает следующую вершину $j \in N_i^k$ на основе вероятностного правила
|
||||||
|
\[
|
||||||
|
p_{ij}^k(t) = \frac{\tau_{ij}^\alpha(t)}{\sum\limits_{l \in N_i^k} \tau_{il}^\alpha(t)},
|
||||||
|
\]
|
||||||
|
где $\alpha$ — параметр, определяющий степень влияния феромона.
|
||||||
|
|
||||||
|
При отсутствии допустимых переходов допускается возврат в предыдущую вершину, что приводит к появлению петель, которые впоследствии удаляются.
|
||||||
|
|
||||||
|
После завершения построения полного пути $x_k(t)$ выполняется его оценка. Длина пути обозначается как $L_k(t)$ и равна числу пройденных дуг.
|
||||||
|
|
||||||
|
\subsection{Обновление феромона}
|
||||||
|
|
||||||
|
Каждый муравей откладывает феромон на рёбрах своего пути согласно правилу
|
||||||
|
\[
|
||||||
|
\Delta \tau_{ij}^k(t) =
|
||||||
|
\begin{cases}
|
||||||
|
\frac{1}{L_k(t)}, &\text{если дуга } (i,j) \in x_k(t), \\
|
||||||
|
0, &\text{иначе}.
|
||||||
|
\end{cases}
|
||||||
|
\]
|
||||||
|
|
||||||
|
Общее обновление феромона на дуге $(i,j)$:
|
||||||
|
\[
|
||||||
|
\tau_{ij}(t+1) = \tau_{ij}(t) + \sum_{k=1}^{n_k} \Delta\tau_{ij}^k(t).
|
||||||
|
\]
|
||||||
|
|
||||||
|
Чем короче путь, тем больше феромона откладывается на его рёбрах, что повышает вероятность выбора коротких маршрутов в последующих итерациях.
|
||||||
|
|
||||||
|
\subsection{Испарение феромона}
|
||||||
|
|
||||||
|
Чтобы предотвратить преждевременную сходимость алгоритма к локальным минимумам, применяется механизм \textit{искусственного испарения феромона}. На каждом шаге выполняется:
|
||||||
|
\[
|
||||||
|
\tau_{ij}(t) = (1 - \rho)\,\tau_{ij}(t),
|
||||||
|
\]
|
||||||
|
где $\rho \in [0,1]$ — коэффициент испарения. Большие значения $\rho$ усиливают случайность поиска, малые — повышают устойчивость к изменениям.
|
||||||
|
|
||||||
|
\subsection{Критерии остановки алгоритма}
|
||||||
|
|
||||||
|
Муравьиные алгоритмы могут завершаться при выполнении одного из условий:
|
||||||
|
\begin{itemize}
|
||||||
|
\item достигнуто максимальное число итераций;
|
||||||
|
\item найдено решение приемлемого качества $f(x_k(t)) \leq \varepsilon$;
|
||||||
|
\item все муравьи начинают строить одинаковые маршруты, что говорит о стабилизации процесса.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\subsection{Описание общего алгоритма}
|
||||||
|
|
||||||
|
Алгоритм SACO можно представить в следующем виде:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Инициализация феромона малыми случайными значениями $\tau_{ij}^{(0)}$.
|
||||||
|
\item Размещение всех муравьёв в начальной вершине.
|
||||||
|
\item Для каждой итерации:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Каждый муравей строит путь согласно вероятностному правилу выбора вершины.
|
||||||
|
\item Выполняется удаление петель.
|
||||||
|
\item Вычисляется длина пути $L_k(t)$.
|
||||||
|
\end{enumerate}
|
||||||
|
\item Выполняется испарение феромона.
|
||||||
|
\item Каждый муравей откладывает феромон на рёбрах своего пути.
|
||||||
|
\item Итерация продолжается до выполнения критерия остановки.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Муравьиные алгоритмы позволяют эффективно находить приближённые решения задач комбинаторной оптимизации, таких как задача коммивояжёра, что и является целью данной лабораторной работы.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Особенности реализации}
|
||||||
|
|
||||||
|
Код решения собран в модуле \texttt{lab6/aco.py}. Реализация использует объектно-ориентированный подход с явной типизацией через современные аннотации типов Python (PEP 604). Ниже приведены ключевые элементы реализации с сигнатурами функций и пояснениями.
|
||||||
|
|
||||||
|
\subsection{Структуры данных конфигурации и результата}
|
||||||
|
Конфигурация алгоритма оформлена через \texttt{@dataclass} и включает все параметры, влияющие на поведение ACO:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
@dataclass
|
||||||
|
class ACOConfig:
|
||||||
|
cities: Sequence[City] # список координат городов
|
||||||
|
n_ants: int # число муравьев
|
||||||
|
n_iterations: int # число итераций
|
||||||
|
alpha: float = 1.0 # влияние феромона
|
||||||
|
beta: float = 5.0 # влияние эвристики (1/расстояние)
|
||||||
|
rho: float = 0.5 # коэффициент испарения
|
||||||
|
q: float = 1.0 # константа для отложения феромона
|
||||||
|
seed: int | None = None # зерно ГСЧ (воспроизводимость)
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Результат работы алгоритма представлен структурой:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
@dataclass
|
||||||
|
class ACOResult:
|
||||||
|
best_tour: Tour # индексы городов в порядке обхода
|
||||||
|
best_length: float # длина лучшего маршрута
|
||||||
|
history: List[float] # история длин по итерациям
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\subsection{Класс AntColonyOptimizer и инициализация}
|
||||||
|
Основная логика инкапсулирована в классе \texttt{AntColonyOptimizer}, который принимает конфигурацию при создании:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
class AntColonyOptimizer:
|
||||||
|
def __init__(self, config: ACOConfig)
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
В конструкторе выполняются следующие действия:
|
||||||
|
\begin{itemize}
|
||||||
|
\item инициализация генератора случайных чисел через \texttt{random.seed(config.seed)} для обеспечения воспроизводимости экспериментов;
|
||||||
|
\item вычисление матрицы расстояний между всеми городами с помощью \texttt{build\_distance\_matrix};
|
||||||
|
\item создание матрицы феромона размером $n \times n$, где все недиагональные элементы инициализируются единицами, а диагональные — нулями (для предотвращения самопереходов).
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\subsection{Построение тура муравьём}
|
||||||
|
Каждый муравей строит полный гамильтонов цикл, начиная со случайно выбранного стартового города. Ключевой метод выбора следующего города:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
def _choose_next_city(self, current: int,
|
||||||
|
unvisited: set[int]) -> int
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Метод реализует вероятностный выбор на основе формулы:
|
||||||
|
\[
|
||||||
|
p_{ij} = \frac{[\tau_{ij}]^\alpha \cdot [\eta_{ij}]^\beta}{\sum_{k \in \text{unvisited}} [\tau_{ik}]^\alpha \cdot [\eta_{ik}]^\beta}
|
||||||
|
\]
|
||||||
|
где $\tau_{ij}$ — уровень феромона на ребре $(i,j)$, а $\eta_{ij} = 1/d_{ij}$ — эвристическая привлекательность (обратная величина расстояния). К расстоянию добавляется малая константа $10^{-12}$ для численной стабильности при делении. Финальный выбор осуществляется через \texttt{random.choices} с вычисленными вероятностями.
|
||||||
|
|
||||||
|
Построение полного тура выполняет метод:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
def _build_tour(self, start: int) -> Tour
|
||||||
|
\end{lstlisting}
|
||||||
|
Начиная со стартового города, муравей последовательно выбирает следующие непосещённые города до тех пор, пока множество \texttt{unvisited} не станет пустым.
|
||||||
|
|
||||||
|
Вычисление длины построенного тура:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
def _tour_length(self, tour: Sequence[int]) -> float
|
||||||
|
\end{lstlisting}
|
||||||
|
Метод суммирует расстояния между последовательными городами в туре, включая замыкающее ребро от последнего города к первому, используя предвычисленную матрицу расстояний.
|
||||||
|
|
||||||
|
\subsection{Основной цикл алгоритма}
|
||||||
|
Главный метод запуска оптимизации:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
def run(self) -> ACOResult
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
На каждой из \texttt{n\_iterations} итераций выполняются следующие шаги:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item \textbf{Построение туров}: каждый из \texttt{n\_ants} муравьёв создаёт свой маршрут, начиная со случайного города. Вычисляется длина каждого маршрута, и глобально лучший тур обновляется при обнаружении более короткого.
|
||||||
|
\item \textbf{Испарение феромона}: все элементы матрицы феромона умножаются на $(1 - \rho)$, моделируя естественное испарение. Это предотвращает неограниченный рост концентрации феромона и позволяет алгоритму «забывать» плохие решения.
|
||||||
|
\item \textbf{Отложение феромона}: для каждого муравья вычисляется вклад $\Delta\tau = q/L$, где $L$ — длина его маршрута. Этот вклад добавляется симметрично на оба направления каждого ребра в туре. Таким образом, короткие маршруты откладывают больше феромона.
|
||||||
|
\item \textbf{Запись истории}: лучшая на данный момент длина добавляется в список \texttt{history} для последующего анализа сходимости.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
По завершении всех итераций метод возвращает \texttt{ACOResult} с лучшим найденным туром, его длиной и историей оптимизации.
|
||||||
|
|
||||||
|
\subsection{Точка входа}
|
||||||
|
Для удобства использования предоставлена функция верхнего уровня:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
def run_aco(config: ACOConfig) -> ACOResult
|
||||||
|
\end{lstlisting}
|
||||||
|
Она создаёт экземпляр оптимизатора и запускает алгоритм, возвращая результат.
|
||||||
|
|
||||||
|
\subsection{Визуализация}
|
||||||
|
Модуль включает две функции для визуализации результатов средствами \texttt{matplotlib}:
|
||||||
|
|
||||||
|
Функция построения графика маршрута:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
def plot_tour(cities: Sequence[City], tour: Sequence[int],
|
||||||
|
save_path: str) -> None
|
||||||
|
\end{lstlisting}
|
||||||
|
Отображает города в виде точек и соединяет их ломаной линией в порядке обхода, включая возврат к начальной точке. Используется соотношение сторон \texttt{aspect="equal"} для сохранения геометрии, сетка для лучшей читаемости координат. Результат сохраняется в PNG с разрешением 220 DPI.
|
||||||
|
|
||||||
|
Функция построения графика сходимости:
|
||||||
|
\begin{lstlisting}[language=Python]
|
||||||
|
def plot_history(best_lengths: Sequence[float],
|
||||||
|
save_path: str) -> None
|
||||||
|
\end{lstlisting}
|
||||||
|
Строит линейный график изменения длины лучшего найденного тура по итерациям. Позволяет визуально оценить скорость сходимости и стабильность алгоритма.
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Результаты работы}
|
||||||
|
|
||||||
|
Алгоритм был запущен со следующими параметрами: 50 муравьёв, 50 итераций, $\alpha = 1{,}2$, $\beta = 5$, $\rho = 0{,}5$, $q = 1$. Лучший найденный тур имеет длину $6662{,}35$, что на $0{,}05\%$ отличается от оптимального значения 6659.
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\centering
|
||||||
|
\begin{minipage}{0.48\linewidth}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.95\linewidth]{img/optimal_tour.png}
|
||||||
|
\caption{Оптимальный маршрут длиной 6659}
|
||||||
|
\label{fig:optimal_result}
|
||||||
|
\end{minipage}\hfill
|
||||||
|
\begin{minipage}{0.48\linewidth}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.95\linewidth]{img/aco_best_tour.png}
|
||||||
|
\caption{Лучший маршрут, найденный муравьиным алгоритмом (6662{,}35)}
|
||||||
|
\label{fig:aco_tour}
|
||||||
|
\end{minipage}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.9\linewidth]{img/aco_history.png}
|
||||||
|
\caption{Сходимость длины лучшего тура по итерациям}
|
||||||
|
\label{fig:aco_history}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\subsection{Сравнение с результатами лабораторной работы~№3}
|
||||||
|
|
||||||
|
Для лабораторной работы №3 с генетическим алгоритмом лучший результат составил \textbf{6667{,}03} при популяции $N=500$, вероятностях $P_c=0{,}9$ и $P_m=0{,}5$. Муравьиный алгоритм показал более точное решение: длина тура \textbf{6662{,}35} против оптимального 6659. Разница с оптимумом составила 3{,}35 единицы (0{,}05\%), тогда как в лабораторной работе №3 отклонение было 8{,}03 (0{,}12\%).
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\centering
|
||||||
|
\begin{minipage}{0.48\linewidth}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.95\linewidth]{img/best_lab3.png}
|
||||||
|
\caption{Лучший маршрут из лабораторной работы №3 (ГА): длина 6667{,}03}
|
||||||
|
\label{fig:lab3_best}
|
||||||
|
\end{minipage}\hfill
|
||||||
|
\begin{minipage}{0.48\linewidth}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.95\linewidth]{img/aco_best_tour.png}
|
||||||
|
\caption{Лучший маршрут лабораторной работы №6 (МА): длина 6662{,}35}
|
||||||
|
\label{fig:lab6_best}
|
||||||
|
\end{minipage}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.43\linewidth]{img/optimal_tour.png}
|
||||||
|
\caption{Оптимальный маршрут длиной 6659}
|
||||||
|
\label{fig:optimal_comparison}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Ответ на контрольный вопрос}
|
||||||
|
|
||||||
|
\textbf{Вопрос}: Какие критерии окончания могут быть использованы в простом МА?
|
||||||
|
|
||||||
|
\textbf{Ответ}: В простом муравьином алгоритме могут использоваться следующие критерии завершения работы:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item окончание при превышении заданного числа итераций;
|
||||||
|
\item окончание по достижению приемлемого решения;
|
||||||
|
\item окончание в случае, когда все муравьи начинают следовать одним и тем же путём.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section*{Заключение}
|
||||||
|
\addcontentsline{toc}{section}{Заключение}
|
||||||
|
|
||||||
|
В ходе шестой лабораторной работы выполнена реализация простого муравьиного алгоритма для задачи коммивояжёра:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Разработан модуль \texttt{aco.py} с конфигурацией алгоритма, построением туров, обновлением феромона и визуализацией результатов с помощью \texttt{matplotlib}.
|
||||||
|
\item Проведён численный эксперимент на данных из варианта 18 (38 городов Джибути); подобраны параметры $\alpha=1{,}2$, $\beta=5$, $\rho=0{,}5$, 50 муравьёв, 400 итераций.
|
||||||
|
\item Получено приближённое решение длиной 6662{,}35, что всего на 0{,}05\% хуже известного оптимума 6659 и лучше результата, достигнутого генетическим алгоритмом из лабораторной работы №3.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section*{Список литературы}
|
||||||
|
\addcontentsline{toc}{section}{Список литературы}
|
||||||
|
|
||||||
|
\vspace{-1.5cm}
|
||||||
|
\begin{thebibliography}{0}
|
||||||
|
\bibitem{vostrov}
|
||||||
|
Методические указания по выполнению лабораторных работ к курсу «Генетические алгоритмы», 119 стр.
|
||||||
|
\end{thebibliography}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
Reference in New Issue
Block a user