Exemple #1
0
def execute(toolbox: base.Toolbox, cases: int = 100) -> List[str]:
    population = toolbox.population(n=POPULATION_SIZE)
    hall_of_fame = tools.ParetoFront()

    stats = tools.Statistics(lambda i: i.fitness.values)
    stats.register("avg", numpy.mean, axis=0)
    stats.register("std", numpy.std, axis=0)
    stats.register("min", numpy.min, axis=0)
    stats.register("max", numpy.max, axis=0)

    logbook = tools.Logbook()
    logbook.header = "gen", "evals", "std", "min", "avg", "max", "best"

    # Evaluate every individuals
    for individual in population:
        individual.fitness.values = toolbox.evaluate(individual)

    hall_of_fame.update(population)
    record = stats.compile(population)
    logbook.record(gen=0, evals=len(population), **record)
    print(logbook.stream)

    generated_cases = list
    last_fitness = float('inf')
    current_fitness = None
    generation_count = 1
    while generation_count <= MAX_GENERATIONS and (
            last_fitness != current_fitness
            or current_fitness == float('inf')):
        last_fitness = current_fitness

        # Select the next generation individuals
        offspring = toolbox.select(population, floor(POPULATION_SIZE * 0.9))

        # Clone the selected individuals
        offspring = list(toolbox.map(toolbox.clone, offspring))

        # Add new individuals from the population
        offspring += toolbox.population(n=POPULATION_SIZE - len(offspring))

        # Apply crossover and mutation on the offspring
        for child1, child2 in zip(offspring[::2], offspring[1::2]):
            if not random() < MATE_RATIO:
                continue
            toolbox.mate(child1, child2)
            del child1.fitness.values
            del child2.fitness.values

        for mutant in offspring:
            if not random() < MUTATION_RATIO:
                continue
            toolbox.mutate(mutant)
            del mutant.fitness.values

        # Evaluate the individuals with an invalid fitness
        invalid_ind = [
            individual for individual in offspring
            if not individual.fitness.valid
        ]
        for individual in offspring:
            individual.fitness.values = toolbox.evaluate(individual)

        generated_cases = tools.selBest(population, k=cases)
        current_fitness = sum(
            toolbox.map(op.itemgetter(0),
                        toolbox.map(toolbox.evaluate, generated_cases)))
        best = choice(generated_cases)
        word = "".join(best)

        # Select the next generation population
        population = toolbox.select(population + offspring, POPULATION_SIZE)
        record = stats.compile(population)
        logbook.record(gen=generation_count,
                       evals=len(invalid_ind),
                       best=word,
                       **record)
        print(logbook.stream)

        generation_count += 1

    return [''.join(case) for case in generated_cases]
Exemple #2
0
def run_opd_ga(toolbox: base.Toolbox,
               popsize: int,
               gens: int,
               cxpb: float,
               mutpb: float,
               elitism_k: int,
               new_inds_per_gen: int,
               target_lambda: int,
               verbose: bool = False):

    if verbose:
        print('Starting GA...')

    fitness_history = []

    pop = toolbox.generate_population(n=popsize)

    fitnesses = toolbox.parallel_map(toolbox.evaluate, pop)
    for ind, fit in zip(pop, fitnesses):
        ind.fitness.values = fit

    if verbose:
        print('Initial evaluation done.')

    fits = [ind.fitness.values[0] for ind in pop]
    fitness_history += [fits.copy()]

    g = 0
    min_fits, max_fits, avg_fits, var_fits = [], [], [], []
    while min(fits) > target_lambda and g < gens:
        g = g + 1

        elite = tools.selBest(pop, elitism_k)
        offspring = toolbox.select(
            pop,
            len(pop) - elitism_k - new_inds_per_gen) + elite
        offspring = list(
            map(toolbox.clone,
                offspring)) + toolbox.generate_population(n=new_inds_per_gen)

        for child1, child2 in zip(offspring[::2], offspring[1::2]):

            if random.random() < cxpb:
                toolbox.mate(child1, child2)
                del child1.fitness.values
                del child2.fitness.values

        for mutant in offspring:
            if random.random() < mutpb:
                toolbox.mutate(mutant)
                del mutant.fitness.values

        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        fitnesses = toolbox.parallel_map(toolbox.evaluate, invalid_ind)
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        pop[:] = offspring
        fits = [ind.fitness.values[0] for ind in pop]
        fitness_history += [fits.copy()]

        if verbose == 2:
            min_fits += [min(fits)]
            max_fits += [max(fits)]
            avg_fits += [statistics.mean(fits)]
            var_fits += [statistics.variance(fits)]

        if verbose and (g % (gens // 10) == 0 or g == 1):
            print(f'Generation {g}')
            if verbose == 2:
                print('  Min %s' % min_fits[-1])
                print('  Max %s' % max_fits[-1])
                print('  Avg %s' % avg_fits[-1])
                print('  Var %s' % var_fits[-1])

    timeout = min(fits) == target_lambda

    return {'fitness_history': fitness_history, 'timeout': timeout}
Exemple #3
0
def learn_causal_structure(
    toolbox: base.Toolbox,
    pop_size: int = 10,
    crossover_pr: float = 1,
    mutation_pr: float = 0.2,
    num_elites: int = 1,
    max_gens: int = 50,
):
    """
    Perform the structur learning task using a genetic algorithm
    :param toolbox: registry of tools provided by DEAP
    :param pop_size: the number of individuals per generation
    :param crossover_pr: the crossover rate for every (monogamous) couple
    :param mutation_pr: the mutation rate for every individual
    :param num_elites:
    :param max_gens: the maximum number of generations
    :return:
    """
    # initialize a collection of instrumentation utilities to facilitate later analysis
    instrumentation = initialize_instrumentation()

    # ====== 0️⃣ initialize population  ======
    population = toolbox.population(n=pop_size)

    # ====== 1️⃣ Evaluate the entire population ======
    n_evals = evaluate_population(population, toolbox)
    # Log initial stats for later analysis
    log_generation_stats(0, population, n_evals, **instrumentation)

    # ====== 2️⃣ the loop is the only termination criterion ======
    for gen in range(max_gens):
        elites = get_fittest_individuals(population, num_elites)

        # ====== 3️⃣ Parent selection ======
        # Select the next generation individuals
        offspring = toolbox.select(population, len(population))
        # Clone the selected individuals
        offspring = list(map(toolbox.clone, offspring))

        # ====== 4️⃣ Apply crossover and mutation on the offspring ======
        for child1, child2 in zip(offspring[::2], offspring[1::2]):
            # crossover probability applies to every couple
            if random.random() < crossover_pr:
                toolbox.mate(child1, child2)
                child1.fitness = np.nan
                child2.fitness = np.nan

        # mutation probability applies to every individual
        for mutant in offspring:
            if random.random() < mutation_pr:
                toolbox.mutate(mutant)
                mutant.fitness = np.nan

        # ====== 5️⃣ Evaluate the individuals with an invalid fitness ======
        n_evals = evaluate_population(offspring, toolbox)
        # Log intermediary stats for later analysis
        log_generation_stats(gen + 1, population, n_evals, **instrumentation)

        # ====== 6️⃣ Replacement ======
        # The population is entirely replaced by the offspring, except for the top elites
        fittest_offsprings = get_fittest_individuals(offspring,
                                                     pop_size - num_elites)
        population[:] = elites + fittest_offsprings

    # ====== 7️⃣ Return final population ======
    return population, instrumentation