Поиск минимума

This commit is contained in:
2025-09-11 11:40:37 +03:00
parent 1732a1dbb6
commit 4eb3031869
3 changed files with 30 additions and 14 deletions

View File

@@ -27,9 +27,10 @@ BASE_CONFIG = {
"precision_digits": 3, "precision_digits": 3,
"max_generations": 200, "max_generations": 200,
"seed": 17, "seed": 17,
"min_fitness_avg": 0.015, # критерий остановки "minimize": True,
"fitness_avg_threshold": -0.048, # критерий остановки
# при включенном сохранении графиков на время смотреть бессмысленно # при включенном сохранении графиков на время смотреть бессмысленно
# "save_generations": [0, 50, 199], "save_generations": [0, 50, 199],
} }
@@ -83,7 +84,9 @@ 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"Критерий остановки: среднее значение > {BASE_CONFIG['min_fitness_avg']}") print(
f"Критерий остановки: среднее значение > {BASE_CONFIG['fitness_avg_threshold']}"
)
print("=" * 60) print("=" * 60)
# Создаем базовую папку # Создаем базовую папку

View File

@@ -137,6 +137,7 @@ class GARunConfig:
pm: float # вероятность мутации pm: float # вероятность мутации
max_generations: int # максимальное количество поколений max_generations: int # максимальное количество поколений
seed: int | None = None # seed для генератора случайных чисел seed: int | None = None # seed для генератора случайных чисел
minimize: bool = False # если True, ищем минимум вместо максимума
save_generations: list[int] | None = ( save_generations: list[int] | None = (
None # индексы поколений для сохранения графиков None # индексы поколений для сохранения графиков
) )
@@ -144,7 +145,7 @@ class GARunConfig:
variance_threshold: float | None = ( variance_threshold: float | None = (
None # порог дисперсии для остановки (если None - не используется) None # порог дисперсии для остановки (если None - не используется)
) )
min_fitness_avg: float | None = ( fitness_avg_threshold: float | None = (
None # порог среднего значения фитнес функции для остановки None # порог среднего значения фитнес функции для остановки
) )
@@ -177,7 +178,7 @@ def genetic_algorithm(config: GARunConfig) -> GARunResult:
start = time.perf_counter() start = time.perf_counter()
history_best_x, history_best_f = [], [] history_best_x, history_best_f = [], []
history_populations_x, history_populations_f = [], [] history_populations_x, history_populations_f = [], []
best_x, best_f = 0, -float("inf") best_x, best_f = 0, (float("inf") if config.minimize else -float("inf"))
for generation in range(config.max_generations): for generation in range(config.max_generations):
xs, fits = eval_population( xs, fits = eval_population(
@@ -185,9 +186,11 @@ def genetic_algorithm(config: GARunConfig) -> GARunResult:
) )
# лучший в поколении + глобально лучший # лучший в поколении + глобально лучший
gi = int(np.argmax(fits)) gi = int(np.argmin(fits)) if config.minimize else int(np.argmax(fits))
gen_best_x, gen_best_f = xs[gi], fits[gi] gen_best_x, gen_best_f = xs[gi], fits[gi]
if gen_best_f > best_f: if (config.minimize and gen_best_f < best_f) or (
not config.minimize and gen_best_f > best_f
):
best_x, best_f = gen_best_x, gen_best_f best_x, best_f = gen_best_x, gen_best_f
history_best_x.append(gen_best_x) history_best_x.append(gen_best_x)
@@ -208,11 +211,14 @@ def genetic_algorithm(config: GARunConfig) -> GARunResult:
stop_algorithm = True stop_algorithm = True
# Критерий остановки по среднему значению фитнес функции # Критерий остановки по среднему значению фитнес функции
if config.min_fitness_avg is not None: if config.fitness_avg_threshold is not None:
mean_fitness = np.mean(fits) mean_fitness = np.mean(fits)
if mean_fitness > config.min_fitness_avg: if (config.minimize and mean_fitness < config.fitness_avg_threshold) or (
not config.minimize and mean_fitness > config.fitness_avg_threshold
):
comparator = "<" if config.minimize else ">"
print( print(
f"Остановка на поколении {generation}: среднее значение {mean_fitness:.6f} > {config.min_fitness_avg}" f"Остановка на поколении {generation}: среднее значение {mean_fitness:.6f} {comparator} {config.fitness_avg_threshold}"
) )
stop_algorithm = True stop_algorithm = True
@@ -229,6 +235,7 @@ def genetic_algorithm(config: GARunConfig) -> GARunResult:
config.x_max, config.x_max,
config.results_dir, config.results_dir,
config.fitness_func, config.fitness_func,
minimize=config.minimize,
) )
break break
@@ -244,10 +251,12 @@ def genetic_algorithm(config: GARunConfig) -> GARunResult:
config.x_max, config.x_max,
config.results_dir, config.results_dir,
config.fitness_func, config.fitness_func,
minimize=config.minimize,
) )
# селекция # селекция (для минимума инвертируем знак, чтобы минимальные значения становились максимальными)
parents = reproduction(population, fits) fitnesses_for_selection = fits if not config.minimize else [-f for f in fits]
parents = reproduction(population, fitnesses_for_selection)
# кроссинговер попарно # кроссинговер попарно
next_population = crossover(parents, config.pc) next_population = crossover(parents, config.pc)
@@ -283,6 +292,7 @@ def plot_generation_snapshot(
x_max: float, x_max: float,
results_dir: str, results_dir: str,
fitness_func: Callable[[float], float], fitness_func: Callable[[float], float],
minimize: bool = False,
) -> str: ) -> str:
""" """
График для конкретного поколения с отображением всей популяции. График для конкретного поколения с отображением всей популяции.
@@ -311,7 +321,9 @@ def plot_generation_snapshot(
) )
# Лучшая особь красной точкой # Лучшая особь красной точкой
best_idx = np.argmax(current_pop_f) best_idx = (
int(np.argmin(current_pop_f)) if minimize else int(np.argmax(current_pop_f))
)
plt.scatter( plt.scatter(
[current_pop_x[best_idx]], [current_pop_x[best_idx]],
[current_pop_f[best_idx]], [current_pop_f[best_idx]],

View File

@@ -20,6 +20,7 @@ config = GARunConfig(
pm=0.01, pm=0.01,
max_generations=200, max_generations=200,
seed=17, seed=17,
minimize=True,
save_generations=[ save_generations=[
0, 0,
1, 1,
@@ -34,7 +35,7 @@ config = GARunConfig(
], # поколения для сохранения графиков ], # поколения для сохранения графиков
results_dir="results", results_dir="results",
# variance_threshold=1e-6, # порог дисперсии для остановки # variance_threshold=1e-6, # порог дисперсии для остановки
min_fitness_avg=0.015, # порог среднего значения для остановки fitness_avg_threshold=-0.048, # порог среднего значения для остановки
) )
# Запускаем генетический алгоритм # Запускаем генетический алгоритм