예제 #1
0
def nsga_tournament(parents, children, pareto_front, optimization_type):
    '''
    Replaces population using the non-dominated sorting technique from
    NSGA-II. Fill new parent population according to the best front
    respectively crowding distance within a front 
    '''
    pool = Population()
    pool.add_population(parents)
    pool.add_population(children)
    survivors = Population()

    # give each individual their attributes:
    for indi in pool.individuals:
        indi.crowding_distance = 0
        indi.pareto_rank = -1

    # get a list filled with the pareto fronts
    pareto_shells = pool.get_pareto_shells(optimization_type)

    # calculate the crowding distance for each individual (yes, this can be
    # optimized,but this way it can be used by other methods as well
    # -> copy + paste)
    for pareto_rank, shell in enumerate(pareto_shells):
        for objective, score in enumerate(shell.individuals[0].score):
            # sort by this objective
            shell.individuals.sort(key=lambda x: x.score[objective])
            for indi_index, indi in enumerate(shell.individuals):
                if indi_index == 0:
                    indi.crowding_distance = np.inf
                    indi.pareto_rank = pareto_rank + 1
                elif indi_index == shell.size() - 1:
                    indi.crowding_distance = np.inf
                    indi.pareto_rank = pareto_rank + 1
                else:
                    # individuals are sorted by the current objective and now we
                    # get the min and max value to normalize the fitness
                    diff_min = shell.individuals[0].score[objective]
                    diff_max = shell.individuals[-1].score[objective]
                    diff = diff_max - diff_min
                    if diff == 0:
                        diff = 1
                    distance_l = shell.individuals[indi_index -
                                                   1].score[objective]
                    distance_r = shell.individuals[indi_index +
                                                   1].score[objective]
                    indi.crowding_distance = (indi.crowding_distance +
                                              distance_l + distance_r)

    # fill survivors
    for shell in pareto_shells:
        if len(survivors.individuals) == len(parents.individuals):
            break

        elif len(survivors.individuals) + shell.size() > len(
                parents.individuals):
            # we can not add all elements, so we sort them by their crowding
            # distance and use the best until survivors is full
            shell.individuals.sort(key=lambda x: x.crowding_distance)

            i = 0
            while len(survivors.individuals) < len(parents.individuals):
                survivors.add(shell.individuals[i])
                i += 1

        else:
            for indi in shell.individuals:
                survivors.add(indi)

    return survivors
예제 #2
0
def nsga_random_tournament(parents, children, pareto_front, optimization_type):
    """
    Replaces population using the non-dominated sorting technique from NSGA-II.
    Fill new parent population according to the best front respectively crowding distance within a front 
    """
    pool = Population()
    pool.add_population(parents)
    pool.add_population(children)
    survivors = Population()

    # give each individual their attributes:
    for indi in pool.individuals:
        indi.crowding_distance = 0
        indi.pareto_rank = -1

    # get a list filled with the pareto fronts
    pareto_shells = pool.get_pareto_shells(optimization_type)

    # calculate the crowding distance for each individual (yes, this can be
    # optimized,but this way it can be used by other methods as well
    # -> copy + paste)
    for pareto_rank, shell in enumerate(pareto_shells):
        for objective, score in enumerate(shell[0].score):
            # sort by this objective
            shell.sort(key=lambda x: x.score[objective])
            for indi_index, indi in enumerate(shell):
                if indi_index == 0:
                    indi.crowding_distance = np.inf
                    indi.pareto_rank = pareto_rank + 1
                elif indi_index == len(shell) - 1:
                    indi.crowding_distance = np.inf
                    indi.pareto_rank = pareto_rank + 1
                else:
                    # individuals are sorted by the current objective and now we
                    # get the min and max value to normalize the fitness
                    diff_min = shell[0].score[objective]
                    diff_max = shell[-1].score[objective]
                    diff = diff_max - diff_min
                    if diff == 0:
                        diff = 1
                    distance_l = shell[indi_index - 1].score[objective]
                    distance_r = shell[indi_index + 1].score[objective]
                    indi.crowding_distance = (indi.crowding_distance +
                                              distance_l + distance_r)

    for i in range(len(parents.individuals)):
        choose_1 = np.random.randint(0, len(pool.individuals))
        c1 = pool.individuals.pop(choose_1)
        choose_2 = np.random.randint(0, len(pool.individuals))
        c2 = pool.individuals.pop(choose_2)

        if c1.pareto_rank < c2.pareto_rank:
            # c1 is better
            survivors.add(c1)
        elif c1.pareto_rank > c2.pareto_rank:
            # c2 is better
            survivors.add(c2)
        else:
            # both are in the same shell
            if c1.crowding_distance > c2.crowding_distance:
                # c1 should be prefered because it is lonley, there are
                # no friends nearby
                survivors.add(c1)
            elif c1.crowding_distance < c2.crowding_distance:
                # c2 should be prefered
                survivors.add(c2)
            else:
                # very unlikely, both are equal -> choose random
                if np.random.randint(0, 2) == 1:
                    # c1 won the lottery
                    survivors.add(c1)
                else:
                    # c2 has won
                    survivors.add(c2)

    return survivors