Усреднил значения

This commit is contained in:
2025-09-11 22:02:59 +03:00
parent b6c9bf8e68
commit 931af08511
3 changed files with 84 additions and 57 deletions

View File

@@ -1,6 +1,7 @@
import math import math
import os import os
import shutil import shutil
import statistics
from gen import GARunConfig, genetic_algorithm from gen import GARunConfig, genetic_algorithm
from prettytable import PrettyTable from prettytable import PrettyTable
@@ -19,6 +20,9 @@ POPULATION_SIZES = [10, 25, 50, 100]
PC_VALUES = [0.3, 0.4, 0.5, 0.6, 0.7, 0.8] # вероятности кроссинговера PC_VALUES = [0.3, 0.4, 0.5, 0.6, 0.7, 0.8] # вероятности кроссинговера
PM_VALUES = [0.001, 0.01, 0.05, 0.1, 0.2] # вероятности мутации PM_VALUES = [0.001, 0.01, 0.05, 0.1, 0.2] # вероятности мутации
# Количество запусков для усреднения результатов
NUM_RUNS = 30
# Базовые параметры (как в main.py) # Базовые параметры (как в main.py)
BASE_CONFIG = { BASE_CONFIG = {
"x_min": 3.1, "x_min": 3.1,
@@ -26,7 +30,7 @@ BASE_CONFIG = {
"fitness_func": target_function, "fitness_func": target_function,
"precision_digits": 3, "precision_digits": 3,
"max_generations": 200, "max_generations": 200,
"seed": 17, "seed": None, # None для случайности, т. к. всё усредняем
"minimize": True, "minimize": True,
"fitness_avg_threshold": -0.049, # критерий остановки "fitness_avg_threshold": -0.049, # критерий остановки
# при включенном сохранении графиков на время смотреть бессмысленно # при включенном сохранении графиков на время смотреть бессмысленно
@@ -34,23 +38,42 @@ BASE_CONFIG = {
} }
def run_single_experiment(pop_size: int, pc: float, pm: float) -> tuple[float, int]: def run_single_experiment(
pop_size: int, pc: float, pm: float
) -> tuple[float, float, float, float]:
""" """
Запускает один эксперимент с заданными параметрами. Запускает несколько экспериментов с заданными параметрами и усредняет результаты.
Возвращает (время_в_мс, номер_поколения). Возвращает (среднее_время_в_мс, стд_отклонениеремени, среднее_поколений, стд_отклонение_поколений).
""" """
config = GARunConfig( times = []
**BASE_CONFIG, generations = []
pop_size=pop_size,
pc=pc,
pm=pm,
results_dir=os.path.join(
BASE_DIR, str(pop_size), f"pc_{pc:.3f}", f"pm_{pm:.3f}"
),
)
result = genetic_algorithm(config) for run_num in range(NUM_RUNS):
return result.time_ms, result.generations config = GARunConfig(
**BASE_CONFIG,
pop_size=pop_size,
pc=pc,
pm=pm,
results_dir=os.path.join(
BASE_DIR,
str(pop_size),
f"pc_{pc:.3f}",
f"pm_{pm:.3f}",
f"run_{run_num}",
),
)
result = genetic_algorithm(config)
times.append(result.time_ms)
generations.append(result.generations)
# Вычисляем средние значения и стандартные отклонения
avg_time = statistics.mean(times)
std_time = statistics.stdev(times) if len(times) > 1 else 0.0
avg_generations = statistics.mean(generations)
std_generations = statistics.stdev(generations) if len(generations) > 1 else 0.0
return avg_time, std_time, avg_generations, std_generations
def run_experiments_for_population(pop_size: int) -> PrettyTable: def run_experiments_for_population(pop_size: int) -> PrettyTable:
@@ -59,6 +82,7 @@ def run_experiments_for_population(pop_size: int) -> PrettyTable:
Возвращает таблицу результатов. Возвращает таблицу результатов.
""" """
print(f"\nЗапуск экспериментов для популяции размером {pop_size}...") print(f"\nЗапуск экспериментов для популяции размером {pop_size}...")
print(f"Количество запусков для усреднения: {NUM_RUNS}")
# Создаем таблицу # Создаем таблицу
table = PrettyTable() table = PrettyTable()
@@ -69,9 +93,13 @@ def run_experiments_for_population(pop_size: int) -> PrettyTable:
row = [f"{pc:.1f}"] row = [f"{pc:.1f}"]
for pm in PM_VALUES: for pm in PM_VALUES:
print(f" Эксперимент: pop_size={pop_size}, Pc={pc:.1f}, Pm={pm:.3f}") print(f" Эксперимент: pop_size={pop_size}, Pc={pc:.1f}, Pm={pm:.3f}")
time_ms, generations = run_single_experiment(pop_size, pc, pm) avg_time, std_time, avg_generations, std_generations = (
# Форматируем результат: время(поколение) run_single_experiment(pop_size, pc, pm)
cell_value = f"{time_ms:.1f} ({generations})" )
# Форматируем результат: среднееремя±стд_отклонение (среднее_поколения±стд_отклонение)
# cell_value = f"{avg_time:.1f}±{std_time:.1f} ({avg_generations:.1f}±{std_generations:.1f})"
cell_value = f"{avg_time:.1f} ({avg_generations:.0f})"
row.append(cell_value) row.append(cell_value)
table.add_row(row) table.add_row(row)
@@ -86,6 +114,7 @@ def main():
print(f"Размеры популяции: {POPULATION_SIZES}") print(f"Размеры популяции: {POPULATION_SIZES}")
print(f"Значения Pc: {PC_VALUES}") print(f"Значения Pc: {PC_VALUES}")
print(f"Значения Pm: {PM_VALUES}") print(f"Значения Pm: {PM_VALUES}")
print(f"Количество запусков для усреднения: {NUM_RUNS}")
print( print(
f"Критерий остановки: среднее значение > {BASE_CONFIG['fitness_avg_threshold']}" f"Критерий остановки: среднее значение > {BASE_CONFIG['fitness_avg_threshold']}"
) )
@@ -103,7 +132,10 @@ def main():
print(f"\n{'='*60}") print(f"\n{'='*60}")
print(f"РЕЗУЛЬТАТЫ ДЛЯ ПОПУЛЯЦИИ РАЗМЕРОМ {pop_size}") print(f"РЕЗУЛЬТАТЫ ДЛЯ ПОПУЛЯЦИИ РАЗМЕРОМ {pop_size}")
print(f"{'='*60}") print(f"{'='*60}")
print("Формат: время_в_мсомер_поколения)") print(
f"Формат: среднееремя±стд_отклонениес (среднее_поколения±стд_отклонение)"
)
print(f"Усреднено по {NUM_RUNS} запускам")
print(table) print(table)
pop_exp_dir = os.path.join(BASE_DIR, str(pop_size)) pop_exp_dir = os.path.join(BASE_DIR, str(pop_size))

View File

@@ -205,9 +205,6 @@ def genetic_algorithm(config: GARunConfig) -> GARunResult:
if config.variance_threshold is not None: if config.variance_threshold is not None:
fitness_variance = np.var(fits) fitness_variance = np.var(fits)
if fitness_variance < config.variance_threshold: if fitness_variance < config.variance_threshold:
print(
f"Остановка на поколении {generation}: дисперсия {fitness_variance:.6f} < {config.variance_threshold}"
)
stop_algorithm = True stop_algorithm = True
# Критерий остановки по среднему значению фитнес функции # Критерий остановки по среднему значению фитнес функции
@@ -216,10 +213,6 @@ def genetic_algorithm(config: GARunConfig) -> GARunResult:
if (config.minimize and mean_fitness < config.fitness_avg_threshold) or ( if (config.minimize and mean_fitness < config.fitness_avg_threshold) or (
not config.minimize and mean_fitness > config.fitness_avg_threshold not config.minimize and mean_fitness > config.fitness_avg_threshold
): ):
comparator = "<" if config.minimize else ">"
print(
f"Остановка на поколении {generation}: среднее значение {mean_fitness:.6f} {comparator} {config.fitness_avg_threshold}"
)
stop_algorithm = True stop_algorithm = True
# Сохраняем график последнего поколения при досрочной остановке # Сохраняем график последнего поколения при досрочной остановке

View File

@@ -440,78 +440,80 @@
\item $p_c = 0.3, 0.4, 0.5, 0.6, 0.7, 0.8$ -- вероятность кроссинговера. \item $p_c = 0.3, 0.4, 0.5, 0.6, 0.7, 0.8$ -- вероятность кроссинговера.
\item $p_m = 0.001, 0.01, 0.05, 0.1, 0.2$ -- вероятность мутации. \item $p_m = 0.001, 0.01, 0.05, 0.1, 0.2$ -- вероятность мутации.
\end{itemize} \end{itemize}
Результаты измерений представлены в таблицах \ref{tab:pc_pm_results}--\ref{tab:pc_pm_results4}. В ячейках указано усредненное время в миллисекундах нахождения минимума функции. В скобках указано усредненное количество поколений, за которое было найдено решение. Каждый эксперимент запускался 30 раз. Если в ячейке стоит прочерк, то это означает, что решение не было найдено за 200 поколений. Лучшее значение по времени выполнения для каждого размера популяции выделено жирным шрифтом.
\newcolumntype{Y}{>{\centering\arraybackslash}X} \newcolumntype{Y}{>{\centering\arraybackslash}X}
\begin{table}[ht] \begin{table}[h!]
\centering \centering
\small \small
\begin{tabularx}{\linewidth}{l *{5}{Y}} \begin{tabularx}{\linewidth}{l *{5}{Y}}
\toprule \toprule
$\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\ $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
\midrule \midrule
\textbf{0.3} & -- & 6.8 (83) & 4.7 (57) & 3.4 (37) & 2.3 (29) \\ \textbf{0.3} & 11.5 (167) & 8.4 (123) & 5.4 (78) & 4.9 (71) & 3.3 (48) \\
\textbf{0.4} & -- & 3.7 (48) & 3.6 (24) & 5.2 (64) & 2.3 (17) \\ \textbf{0.4} & 10.1 (144) & 7.1 (104) & 6.3 (92) & 4.7 (67) & 4.7 (67) \\
\textbf{0.5} & -- & -- & 6.2 (86) & 2.5 (27) & 2.8 (34) \\ \textbf{0.5} & 11.4 (168) & 7.7 (112) & 5.4 (79) & 6.1 (83) & \textbf{3.1 (44)} \\
\textbf{0.6} & -- & 12.6 (163)& 5.7 (56) & 2.7 (34) & 2.1 (25) \\ \textbf{0.6} & 11.0 (160) & 6.7 (97) & 4.9 (70) & 4.7 (67) & 5.3 (74) \\
\textbf{0.7} & -- & -- & 7.9 (103) & 2.4 (23) & 2.3 (25) \\ \textbf{0.7} & 12.1 (174) & 9.3 (135) & 3.7 (52) & 4.7 (67) & 6.5 (92) \\
\textbf{0.8} & -- & 11.8 (159)& 2.9 (23) & 2.0 (23) & 1.3 (13) \\ \textbf{0.8} & 8.7 (126) & 8.3 (119) & 3.9 (57) & 7.9 (113)& 4.4 (61) \\
\bottomrule \bottomrule
\end{tabularx} \end{tabularx}
\caption{Результаты для $N = 10$} \caption{Результаты для $N = 10$}
\label{tab:pc_pm_results} \label{tab:pc_pm_results}
\end{table} \end{table}
\begin{table}[ht] \begin{table}[h!]
\centering \centering
\small \small
\begin{tabularx}{\linewidth}{l *{5}{Y}} \begin{tabularx}{\linewidth}{l *{5}{Y}}
\toprule \toprule
$\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\ $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
\midrule \midrule
\textbf{0.3} & 20.6 (146) & 13.5 (90) & 6.5 (43) & 5.3 (29) & 7.1 (48) \\ \textbf{0.3} & 14.7 (111) & 8.2 (62) & 4.9 (37) & 4.7 (35) & 8.7 (63) \\
\textbf{0.4} & 2.7 (13) & 6.7 (38) & 3.4 (20) & 3.0 (20) & 19.2 (122) \\ \textbf{0.4} & 12.8 (95) & 7.3 (54) & 4.7 (35) & 4.3 (32) & 8.2 (61) \\
\textbf{0.5} & -- & 3.0 (15) & 2.5 (16) & 3.7 (20) & -- \\ \textbf{0.5} & 10.5 (78) & 5.4 (40) & \textbf{2.2 (16)} & 5.5 (40) & 12.1 (89) \\
\textbf{0.6} & 1.8 (11) & 14.3 (102)& 2.3 (13) & 2.4 (14) & -- \\ \textbf{0.6} & 14.0 (103) & 6.5 (48) & 3.4 (25) & 4.0 (30) & 14.0 (87) \\
\textbf{0.7} & 2.1 (12) & 3.3 (17) & 6.4 (36) & 2.5 (15) & 9.1 (60) \\ \textbf{0.7} & 11.5 (84) & 6.2 (46) & 3.0 (22) & 3.2 (24) & 11.6 (83) \\
\textbf{0.8} & -- & 2.6 (12) & 3.8 (22) & 3.7 (24) & 6.8 (47) \\ \textbf{0.8} & 9.2 (64) & 5.8 (41) & 2.5 (18) & 3.0 (22) & 11.2 (78) \\
\bottomrule \bottomrule
\end{tabularx} \end{tabularx}
\caption{Результаты для $N = 25$} \caption{Результаты для $N = 25$}
\label{tab:pc_pm_results2} \label{tab:pc_pm_results2}
\end{table} \end{table}
\begin{table}[ht] \begin{table}[h!]
\centering \centering
\small \small
\begin{tabularx}{\linewidth}{l *{5}{Y}} \begin{tabularx}{\linewidth}{l *{5}{Y}}
\toprule \toprule
$\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\ $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
\midrule \midrule
\textbf{0.3} & 25.8 (101) & 6.3 (24) & 9.5 (30) & 7.2 (27) & -- \\ \textbf{0.3} & 6.1 (26) & 5.2 (22) & 6.3 (26) & 11.6 (48) & 40.2 (147) \\
\textbf{0.4} & 4.8 (18) & 4.6 (16) & 21.4 (86) & 42.5 (167)& 43.2 (175) \\ \textbf{0.4} & 6.1 (26) & 4.5 (19) & 5.2 (22) & 9.8 (40) & 37.2 (149) \\
\textbf{0.5} & 23.6 (95) & 21.3 (82) & 8.5 (34) & 6.4 (23) & 20.0 (76) \\ \textbf{0.5} & 10.5 (44) & 4.9 (20) & 7.6 (28) & 17.1 (65) & 36.2 (144) \\
\textbf{0.6} & 5.5 (20) & 10.9 (41) & 12.8 (43) & -- & 28.6 (113) \\ \textbf{0.6} & 7.5 (31) & \textbf{4.6 (19)} & 5.6 (23) & 18.8 (76) & 42.0 (158) \\
\textbf{0.7} & -- & 7.4 (28) & 8.8 (35) & -- & -- \\ \textbf{0.7} & 7.6 (31) & 4.7 (20) & 7.6 (31) & 13.9 (55) & 34.3 (136) \\
\textbf{0.8} & -- & 11.7 (47) & 9.1 (36) & -- & -- \\ \textbf{0.8} & 10.8 (44) & 5.0 (21) & 6.1 (24) & 13.9 (56) & 36.5 (145) \\
\bottomrule \bottomrule
\end{tabularx} \end{tabularx}
\caption{Результаты для $N = 50$} \caption{Результаты для $N = 50$}
\label{tab:pc_pm_results3} \label{tab:pc_pm_results3}
\end{table} \end{table}
\begin{table}[h!]
\begin{table}[ht]
\centering \centering
\small \small
\begin{tabularx}{\linewidth}{l *{5}{Y}} \begin{tabularx}{\linewidth}{l *{5}{Y}}
\toprule \toprule
$\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\ $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
\midrule \midrule
\textbf{0.3} & 7.6 (16) & 9.5 (16) & 10.6 (23) & 18.0 (38) & -- \\ \textbf{0.3} & \textbf{7.6 (16)} & 9.5 (21) & 29.0 (60) & 62.9 (128) & -- \\
\textbf{0.4} & 6.1 (13) & 10.0 (21) & 12.5 (25) & 67.1 (143) & -- \\ \textbf{0.4} & 8.0 (17) & 9.6 (21) & 31.5 (68) & 56.6 (120) & -- \\
\textbf{0.5} & 7.4 (15) & 7.9 (16) & 9.5 (20) & 79.7 (166) & -- \\ \textbf{0.5} & 9.1 (20) & 9.2 (20) & 22.6 (48) & 59.4 (124) & -- \\
\textbf{0.6} & 7.5 (16) & 10.1 (21) & -- & 51.1 (107) & -- \\ \textbf{0.6} & 17.8 (38) & 12.3 (26) & 30.0 (64) & 61.1 (128) & 95.3 (196) \\
\textbf{0.7} & 7.6 (16) & 28.6 (56) & 22.7 (48) & 43.7 (91) & -- \\ \textbf{0.7} & 10.0 (22) & 14.3 (31) & 30.3 (64) & 49.1 (103) & -- \\
\textbf{0.8} & 6.7 (14) & 10.4 (22) & 13.4 (25) & 23.0 (47) & -- \\ \textbf{0.8} & 16.4 (34) & 12.1 (25) & 31.4 (64) & 54.9 (114) & -- \\
\bottomrule \bottomrule
\end{tabularx} \end{tabularx}
\caption{Результаты для $N = 100$} \caption{Результаты для $N = 100$}