pythonpygad

How to make mutation which is inversion of one of the solution's genes when solutions are bit arrays


That's what I have so far. As I see from the output, my parameters are not enough to constraint mutation to my needs. Sometimes no one gene is changed, sometimes more than one.

import pygad
import numpy as np


def divider(ga_instance):
    return np.max(np.sum(ga_instance.population, axis=1))


def on_start(ga_instance):
    print("on_start()")
    print(f'Начальная популяция:\n {ga_instance.population}')


def fitness_function(ga_instance, solution, _):
    return np.sum(solution) / divider(ga_instance)


def on_fitness(ga_instance, population_fitness):
    print(f'\non_fitness()')
    print(f'Делитель: {divider(ga_instance)}')
    for idx, (instance, fitness) in enumerate(zip(ga_instance.population, ga_instance.last_generation_fitness)):
        print(f'{idx}. {instance}: {fitness}')


def on_parents(ga_instance, selected_parents):
    print("\non_parents()")
    print(f'Выбранные индексы родителей: {ga_instance.last_generation_parents_indices}')
    print(f'Выбранные родители:\n {ga_instance.last_generation_parents}')


def on_crossover(ga_instance, offspring_crossover):
    print("\non_crossover()")
    print(f'Результат кроссинговера:\n {ga_instance.last_generation_offspring_crossover}')


def on_mutation(ga_instance, offspring_mutation):
    print("\non_mutation()")
    print(f'Результат мутации:\n {ga_instance.last_generation_offspring_mutation}')


def on_generation(ga_instance):
    print(f"\non_generation()")
    print("Выведенное поколение:\n ", ga_instance.population)
    sol = ga_instance.best_solution()
    print(f"Лучшее решение: {sol[0]} : {sol[1]}")


ga_instance = pygad.GA(
    num_generations=1,
    num_parents_mating=2,
    fitness_func=fitness_function,
    gene_type=int,
    init_range_low=0,
    init_range_high=2,
    sol_per_pop=10,
    num_genes=8,
    crossover_type='single_point',
    parent_selection_type="rws",
    mutation_type="inversion",
    mutation_num_genes=1,
    on_start=on_start,
    on_fitness=on_fitness,
    on_parents=on_parents,
    on_crossover=on_crossover,
    on_mutation=on_mutation,
    on_generation=on_generation,
)

ga_instance.run()

More details for stackoverflow algorithm: sdfgdsfdddddddddddfffffffffadsgadfgdafgdasgadsgdsagdsagdsagadsgdsagdsagdsag.


Solution

  • Inversion mutation inverts the order of subset of the genes. It does not invert the value of the genes from 0 to 1. That is if you have a chromosome like abcd, then inversion mutation inverts the genes to be dcba.

    To apply a mutation operator that flips the genes from 0 to 1 and from 1 to 0, use this code. It creates a new function flip_mutation() to flip the bits.

    import pygad
    import numpy as np
    
    
    def divider(ga_instance):
        return np.max(np.sum(ga_instance.population, axis=1))
    
    
    def on_start(ga_instance):
        print("on_start()")
        print(f'Начальная популяция:\n {ga_instance.population}')
    
    
    def fitness_function(ga_instance, solution, _):
        return np.sum(solution) / divider(ga_instance)
    
    
    def on_fitness(ga_instance, population_fitness):
        print(f'\non_fitness()')
        print(f'Делитель: {divider(ga_instance)}')
        for idx, (instance, fitness) in enumerate(zip(ga_instance.population, ga_instance.last_generation_fitness)):
            print(f'{idx}. {instance}: {fitness}')
    
    
    def on_parents(ga_instance, selected_parents):
        print("\non_parents()")
        print(f'Выбранные индексы родителей: {ga_instance.last_generation_parents_indices}')
        print(f'Выбранные родители:\n {ga_instance.last_generation_parents}')
    
    
    def on_crossover(ga_instance, offspring_crossover):
        print("\non_crossover()")
        print(f'Результат кроссинговера:\n {ga_instance.last_generation_offspring_crossover}')
    
    
    def on_mutation(ga_instance, offspring_mutation):
        print("\non_mutation()")
        print(f'Результат мутации:\n {ga_instance.last_generation_offspring_mutation}')
    
    
    def on_generation(ga_instance):
        print(f"\non_generation()")
        print("Выведенное поколение:\n ", ga_instance.population)
        sol = ga_instance.best_solution()
        print(f"Лучшее решение: {sol[0]} : {sol[1]}")
    
    
    def flip_mutation(offspring, ga_instance):
        for idx in range(offspring.shape[0]):
            mutation_gene1 = np.random.randint(low=0, high=np.ceil(offspring.shape[1]/2 + 1), size=1)[0]
            if offspring[idx, mutation_gene1] == 1:
                offspring[idx, mutation_gene1] = 0
            else:
                offspring[idx, mutation_gene1] = 1
    
        return offspring
    
    ga_instance = pygad.GA(
        num_generations=1,
        num_parents_mating=2,
        fitness_func=fitness_function,
        gene_type=int,
        init_range_low=0,
        init_range_high=2,
        sol_per_pop=10,
        num_genes=8,
        crossover_type='single_point',
        parent_selection_type="rws",
        mutation_type=flip_mutation,
        mutation_num_genes=1,
        on_start=on_start,
        on_fitness=on_fitness,
        on_parents=on_parents,
        on_crossover=on_crossover,
        on_mutation=on_mutation,
        on_generation=on_generation,
    )
    
    ga_instance.run()