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

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 os
import shutil import shutil
from gen import GARunConfig, genetic_algorithm from gen import GARunConfig, genetic_algorithm
from prettytable import PrettyTable 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" BASE_DIR = "experiments"
@@ -16,6 +23,7 @@ PM_VALUES = [0.001, 0.01, 0.05, 0.1, 0.2] # вероятности мутаци
BASE_CONFIG = { BASE_CONFIG = {
"x_min": 3.1, "x_min": 3.1,
"x_max": 20.0, "x_max": 20.0,
"fitness_func": target_function,
"precision_digits": 3, "precision_digits": 3,
"max_generations": 200, "max_generations": 200,
"seed": 17, "seed": 17,

View File

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

View File

@@ -1,11 +1,19 @@
import math
import os import os
from gen import GARunConfig, genetic_algorithm 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( config = GARunConfig(
x_min=3.1, x_min=3.1,
x_max=20.0, x_max=20.0,
fitness_func=target_function,
precision_digits=3, precision_digits=3,
pop_size=15, pop_size=15,
pc=0.7, pc=0.7,