import random from typing import Callable from .chromosome import Chromosome, InitFunc, init_full, init_grow type Population = list[Chromosome] def ramped_initialization( population_size: int, depths: list[int], make_chromosome: Callable[[InitFunc], Chromosome], ) -> Population: """Комбинация методов grow и full инициализации хромосом для инициализации начальной популяции. Начальная популяция генерируется так, чтобы в нее входили деревья с разной максимальной длиной примерно поровну. Для каждой глубины первая половина деревьев генерируется полным методом, а вторая – растущей инициализацией. """ population: Population = [] per_depth = population_size / len(depths) for depth in depths: n_full = int(per_depth / 2) n_grow = int(per_depth / 2) population.extend( make_chromosome(lambda c: init_full(c, depth)) for _ in range(n_full) ) population.extend( make_chromosome(lambda c: init_grow(c, depth)) for _ in range(n_grow) ) # Из-за округления хромосом может оказаться меньше заданного количества, # поэтому дозаполняем остаток популяции случайными хромосомами while len(population) < population_size: depth = random.choice(depths) init_func = init_full if random.random() < 0.5 else init_grow population.append(make_chromosome(lambda c: init_func(c, depth))) return population