Фитнес функция как параметр

This commit is contained in:
2025-09-11 11:06:19 +03:00
parent a1a53ef749
commit 1732a1dbb6
3 changed files with 33 additions and 19 deletions

View File

@@ -1,9 +1,16 @@
import math
import os
import shutil
from gen import GARunConfig, genetic_algorithm
from prettytable import PrettyTable
def target_function(x: float) -> float:
"""f(x) = sin(x)/x^2"""
return math.sin(x) / (x * x)
# Базовая папка для экспериментов
BASE_DIR = "experiments"
@@ -16,6 +23,7 @@ PM_VALUES = [0.001, 0.01, 0.05, 0.1, 0.2] # вероятности мутаци
BASE_CONFIG = {
"x_min": 3.1,
"x_max": 20.0,
"fitness_func": target_function,
"precision_digits": 3,
"max_generations": 200,
"seed": 17,

View File

@@ -10,11 +10,6 @@ import matplotlib.pyplot as plt
import numpy as np
def target_function(x: float) -> float:
"""f(x) = sin(x)/x^2"""
return math.sin(x) / (x * x)
def bits_for_precision(x_min: float, x_max: float, digits_after_decimal: int) -> int:
"""
Подбор числа бит L так, чтобы шаг сетки был ≤ 10^{-digits_after_decimal}.
@@ -133,13 +128,14 @@ def mutation(chrom: List[int], pm: float) -> None:
@dataclass
class GARunConfig:
x_min: float = 3.1
x_max: float = 20.0
precision_digits: int = 3 # точность сетки ~0.001
pop_size: int = 100 # размер популяции
pc: float = 0.7 # вероятность кроссинговера
pm: float = 0.01 # вероятность мутации
max_generations: int = 200 # максимальное количество поколений
x_min: float
x_max: float
fitness_func: Callable[[float], float]
precision_digits: int # точность сетки ~0.001
pop_size: int # размер популяции
pc: float # вероятность кроссинговера
pm: float # вероятность мутации
max_generations: int # максимальное количество поколений
seed: int | None = None # seed для генератора случайных чисел
save_generations: list[int] | None = (
None # индексы поколений для сохранения графиков
@@ -166,10 +162,7 @@ class GARunResult:
L: int # число бит
def genetic_algorithm(
config: GARunConfig,
fitness_func: Callable[[float], float] = target_function,
) -> GARunResult:
def genetic_algorithm(config: GARunConfig) -> GARunResult:
if config.seed is not None:
random.seed(config.seed)
np.random.seed(config.seed)
@@ -187,7 +180,9 @@ def genetic_algorithm(
best_x, best_f = 0, -float("inf")
for generation in range(config.max_generations):
xs, fits = eval_population(population, config.x_min, config.x_max, fitness_func)
xs, fits = eval_population(
population, config.x_min, config.x_max, config.fitness_func
)
# лучший в поколении + глобально лучший
gi = int(np.argmax(fits))
@@ -233,6 +228,7 @@ def genetic_algorithm(
config.x_min,
config.x_max,
config.results_dir,
config.fitness_func,
)
break
@@ -247,6 +243,7 @@ def genetic_algorithm(
config.x_min,
config.x_max,
config.results_dir,
config.fitness_func,
)
# селекция
@@ -285,6 +282,7 @@ def plot_generation_snapshot(
x_min: float,
x_max: float,
results_dir: str,
fitness_func: Callable[[float], float],
) -> str:
"""
График для конкретного поколения с отображением всей популяции.
@@ -292,10 +290,10 @@ def plot_generation_snapshot(
os.makedirs(results_dir, exist_ok=True)
xs = np.linspace(x_min, x_max, 1500)
ys = np.sin(xs) / (xs * xs)
ys = [fitness_func(x) for x in xs]
fig = plt.figure(figsize=(10, 6))
plt.plot(xs, ys, label="f(x)=sin(x)/x^2", alpha=0.7, color="blue")
plt.plot(xs, ys, label="Целевая функция", alpha=0.7, color="blue")
# Отображаем всю популяцию текущего поколения
if generation < len(history_populations_x):

View File

@@ -1,11 +1,19 @@
import math
import os
from gen import GARunConfig, genetic_algorithm
def target_function(x: float) -> float:
"""f(x) = sin(x)/x^2"""
return math.sin(x) / (x * x)
# Запуск эксперимента с генетическим алгоритмом
config = GARunConfig(
x_min=3.1,
x_max=20.0,
fitness_func=target_function,
precision_digits=3,
pop_size=15,
pc=0.7,