Exemple #1
0
    def _next(self, pop):

        # iterate for each member of the population in random order
        for i in random.perm(len(pop)):

            # all neighbors of this individual and corresponding weights
            N = self.neighbors[i, :]

            if random.random() < self.prob_neighbor_mating:
                parents = N[random.perm(self.n_neighbors)][:self.crossover.n_parents]
            else:
                parents = random.perm(self.pop_size)[:self.crossover.n_parents]

            # do recombination and create an offspring
            off = self.crossover.do(self.problem, pop, parents[None, :])
            off = self.mutation.do(self.problem, off)
            off = off[random.randint(0, len(off))]

            # evaluate the offspring
            self.evaluator.eval(self.problem, off)

            # update the ideal point
            self.ideal_point = np.min(np.vstack([self.ideal_point, off.F]), axis=0)

            # calculate the decomposed values for each neighbor
            FV = self._decomposition.do(pop[N].get("F"), weights=self.ref_dirs[N, :], ideal_point=self.ideal_point)
            off_FV = self._decomposition.do(off.F[None, :], weights=self.ref_dirs[N, :], ideal_point=self.ideal_point)

            # get the absolute index in F where offspring is better than the current F (decomposed space)
            I = np.where(off_FV < FV)[0]
            pop[N[I]] = off

        return pop
Exemple #2
0
def random_permuations(n, l):
    from pymoo.rand import random
    perms = []
    for i in range(n):
        perms.append(random.perm(l))
    P = np.concatenate(perms)
    return P
Exemple #3
0
    def _do(self, problem, pop, parents, **kwargs):

        # get the X of parents and count the matings
        X = pop.get("X")[parents.T]
        _, n_matings, n_var = X.shape

        # start point of crossover
        r = np.row_stack([random.perm(n_var-1) + 1 for _ in range(n_matings)])[:, :self.n_points]
        r.sort(axis=1)
        r = np.column_stack([r, np.full(n_matings, n_var)])

        # the mask do to the crossover
        M = np.full((n_matings, n_var), False)

        # create for each individual the crossover range
        for i in range(n_matings):

            j = 0
            while j < r.shape[1] - 1:
                a, b = r[i, j], r[i, j + 1]
                M[i, a:b] = True
                j += 2

        _X = crossover_mask(X, M)
        return pop.new("X", _X)
Exemple #4
0
    def next(self, n_selected):
        """

        Parameters
        ----------
        n_selected: int
            Number of individuals to be selected.

        Returns
        -------
        v: vector
            Selected indices of individuals as a integer vector.

        """

        selected = np.zeros(n_selected, dtype=np.int)

        for i in range(n_selected):

            if self.counter + self.pressure >= self.pop.size():
                self.perm = random.perm(self.pop.size())
                self.counter = 0
            selected[i] = self.f_comp(
                self.pop, self.perm[self.counter:self.counter + self.pressure],
                self.data)
            self.counter = self.counter + self.pressure

        return selected
Exemple #5
0
    def _mating(self, pop):

        # the population object to be used
        off = pop.new()

        # mating counter - counts how often the mating needs to be done to fill up n_offsprings
        n_matings = 0

        # iterate until enough offsprings are created
        while len(off) < self.n_offsprings:

            # how many parents need to be select for the mating - depending on number of offsprings remaining
            n_select = math.ceil(
                (self.n_offsprings - len(off)) / self.crossover.n_offsprings)

            # select the parents for the mating - just an index array
            parents = self.selection.do(pop,
                                        n_select,
                                        self.crossover.n_parents,
                                        algorithm=self)

            # do the crossover using the parents index and the population - additional data provided if necessary
            _off = self.crossover.do(self.problem,
                                     pop,
                                     parents,
                                     algorithm=self)

            # do the mutation on the offsprings created through crossover
            _off = self.mutation.do(self.problem, _off, algorithm=self)

            # repair the individuals if necessary
            if self.func_repair is not None:
                _off = self.func_repair(self.problem, _off, algorithm=self)

            if self.eliminate_duplicates:
                is_duplicate = self.eliminate_duplicates(_off,
                                                         pop,
                                                         off,
                                                         algorithm=self)
                _off = _off[np.logical_not(is_duplicate)]

            # if more offsprings than necessary - truncate them
            if len(_off) > self.n_offsprings - len(off):
                I = random.perm(self.n_offsprings - len(off))
                _off = _off[I]

            # add to the offsprings and increase the mating counter
            off = off.merge(_off)
            n_matings += 1

            # if no new offsprings can be generated within 100 trails -> return the current result
            if n_matings > 100:
                print(
                    "WARNING: Recombination could not produce new offsprings which are not already in the population!"
                )
                break

        return off
Exemple #6
0
    def _next(self, pop):

        # get the vectors from the population
        F, CV, feasible = pop.get("F", "CV", "feasible")
        F = parameter_less(F, CV)

        # create offsprings and add it to the data of the algorithm
        if self.var_selection == "rand":
            P = self.selection.do(pop, self.pop_size, self.crossover.n_parents)

        elif self.var_selection == "best":
            best = np.argmin(F[:, 0])
            P = self.selection.do(pop, self.pop_size,
                                  self.crossover.n_parents - 1)
            P = np.column_stack([np.full(len(pop), best), P])

        elif self.var_selection == "rand+best":
            best = np.argmin(F[:, 0])
            P = self.selection.do(pop, self.pop_size, self.crossover.n_parents)
            use_best = random.random(len(pop)) < 0.3
            P[use_best, 0] = best

        else:
            raise Exception("Unknown selection: %s" % self.var_selection)

        self.off = self.crossover.do(self.problem, pop, P)

        # do the mutation by using the offsprings
        self.off = self.mutation.do(self.problem, self.off, algorithm=self)

        # bring back to bounds if violated through crossover - bounce back strategy
        X = self.off.get("X")
        xl = np.repeat(self.problem.xl[None, :], X.shape[0], axis=0)
        xu = np.repeat(self.problem.xu[None, :], X.shape[0], axis=0)

        # otherwise bounds back into the feasible space
        X[X < xl] = (xl + (xl - X))[X < xl]
        X[X > xu] = (xu - (X - xu))[X > xu]
        self.off.set("X", X)

        # evaluate the results
        self.evaluator.eval(self.problem, self.off, algorithm=self)

        _F, _CV, _feasible = self.off.get("F", "CV", "feasible")
        _F = parameter_less(_F, _CV)

        # find the individuals which are indeed better
        is_better = np.where((_F <= F)[:, 0])[0]

        # truncate the replacements if desired
        if self.n_replace is not None and self.n_replace < len(is_better):
            is_better = is_better[random.perm(len(is_better))[:self.n_replace]]

        # replace the individuals in the population
        pop[is_better] = self.off[is_better]

        return pop
    def next(self, n_selected):
        if self.perm is None or self.counter + n_selected >= self.pop.size():
            self.perm = random.perm(self.pop.size())
            self.counter = 0

        selected = self.perm[self.counter:self.counter + n_selected]
        self.counter = self.counter + n_selected

        return selected
Exemple #8
0
def niching(pop, n_remaining, niche_count, niche_of_individuals,
            dist_to_niche):
    survivors = []

    # boolean array of elements that are considered for each iteration
    mask = np.full(len(pop), True)

    while len(survivors) < n_remaining:

        # number of individuals to select in this iteration
        n_select = n_remaining - len(survivors)

        # all niches where new individuals can be assigned to and the corresponding niche count
        next_niches_list = np.unique(niche_of_individuals[mask])
        next_niche_count = niche_count[next_niches_list]

        # the minimum niche count
        min_niche_count = next_niche_count.min()

        # all niches with the minimum niche count (truncate if randomly if more niches than remaining individuals)
        next_niches = next_niches_list[np.where(
            next_niche_count == min_niche_count)[0]]
        next_niches = next_niches[random.perm(len(next_niches))[:n_select]]

        for next_niche in next_niches:

            # indices of individuals that are considered and assign to next_niche
            next_ind = np.where(
                np.logical_and(niche_of_individuals == next_niche, mask))[0]

            # shuffle to break random tie (equal perp. dist) or select randomly
            next_ind = random.shuffle(next_ind)

            if niche_count[next_niche] == 0:
                next_ind = next_ind[np.argmin(dist_to_niche[next_ind])]
                is_closest = True
            else:
                # already randomized through shuffling
                next_ind = next_ind[0]
                is_closest = False

            # add the selected individual to the survivors
            mask[next_ind] = False
            pop[next_ind].data["closest"] = is_closest
            survivors.append(int(next_ind))

            # increase the corresponding niche count
            niche_count[next_niche] += 1

    return survivors
Exemple #9
0
    def set_population(self, pop, data):
        """

        Parameters
        ----------
        pop: class
            The population to be selected from.
        data: class
            Any additional data that might be needed for the selection.

        """
        self.pop = pop
        self.data = data
        self.perm = random.perm(self.pop.size())
        self.counter = 0
Exemple #10
0
def randomized_argsort(A, method="numpy", order='ascending'):
    if method == "numpy":
        P = random.perm(len(A))
        I = np.argsort(A[P], kind='quicksort')
        I = P[I]

    elif method == "quicksort":
        I = quicksort(A)

    else:
        raise Exception("Randomized sort method not known.")

    if order == 'ascending':
        return I
    elif order == 'descending':
        return np.flip(I, axis=0)
    else:
        raise Exception("Unknown sorting order: ascending or descending.")
Exemple #11
0
    def _next(self, pop):

        # iterate for each member of the population
        for i in range(self.pop_size):

            # all neighbors shuffled (excluding the individual itself)
            neighbors = self.neighbours[i][1:][random.perm(self.n_neighbors -
                                                           1)]
            parents = np.concatenate([[i],
                                      neighbors[:self.crossover.n_parents - 1]
                                      ])

            # do recombination and create an offspring
            X = self.crossover.do(self.problem,
                                  pop.X[None, parents, :],
                                  X=pop.X[[i], :])
            X = self.mutation.do(self.problem, X)

            # evaluate the offspring
            F, _ = self.evaluator.eval(self.problem, X)

            # update the ideal point
            self.ideal_point = np.min(np.concatenate(
                [self.ideal_point[None, :], F], axis=0),
                                      axis=0)

            # for each offspring that was created
            for k in range(self.crossover.n_children):
                # the weights of each neighbor
                weights_of_neighbors = self.weights[self.neighbours[i], :]

                # calculate the decomposed values for each neighbour
                FV = tchebi(pop.F[self.neighbours[i]], weights_of_neighbors,
                            self.ideal_point)
                off_FV = tchebi(F[[k], :], weights_of_neighbors,
                                self.ideal_point)

                # get the absolute index in F where offspring is better than the current F (decomposed space)
                off_is_better = self.neighbours[i][np.where(off_FV < FV)[0]]
                pop.F[off_is_better, :] = F[k, :]
                pop.X[off_is_better, :] = X[k, :]
Exemple #12
0
    def _do(self, problem, pop, parents, **kwargs):

        # get the X of parents and count the matings
        X = pop.get("X")[parents.T]
        _, n_matings, n_var = X.shape

        # start point of crossover
        r = np.row_stack([
            random.perm(n_var - 1) + 1 for _ in range(n_matings)
        ])[:, :self.n_points]
        r.sort(axis=1)
        r = np.column_stack([r, np.full(n_matings, n_var)])

        # genome defines a gene as (op, source), so we need to crossover on even values only
        # otherwise, we get op from 1 parent and source from the other
        r = r // 2 * 2

        # the mask do to the crossover
        M = np.full((n_matings, n_var), False)

        # create for each individual the crossover range
        for i in range(n_matings):
            j = 0
            while j < r.shape[1] - 1:
                a, b = r[i, j], r[i, j + 1]
                M[i, a:b] = True
                j += 2

        _X = crossover_mask(X, M)
        new_pop = pop.new("X", _X)

        # print(new_pop)

        for i, ind in enumerate(new_pop):
            ind.parents = pop.get("id")[parents][i // 2]

        # for ind in new_pop:
        #     print(ind.parents)

        return new_pop
    def _do(self, problem, pop, parents, **kwargs):

        # get the X of parents and count the matings
        X = pop.get("X")[parents.T]
        _, n_matings, n_var = X.shape

        # the mask do to the crossover
        M = np.full((n_matings, n_var), False)

        not_equal = X[0] != X[1]

        # create for each individual the crossover range
        for i in range(n_matings):
            I = np.where(not_equal[i])[0]

            n = math.ceil(len(I) / 2)
            if n > 0:
                _I = I[random.perm(len(I))[:n]]
                M[i, _I] = True

        _X = crossover_mask(X, M)
        return pop.new("X", _X)
Exemple #14
0
def random_permuations(n, l):
    perms = []
    for i in range(n):
        perms.append(random.perm(size=l))
    P = np.concatenate(perms)
    return P
Exemple #15
0
    def _mating(self, pop):
        # adjusted mating to preserve heritage

        # the population object to be used
        off = pop.new()

        # mating counter - counts how often the mating needs to be done to fill up n_offsprings
        n_matings = 0

        # iterate until enough offsprings are created
        while len(off) < self.n_offsprings:

            # # how many parents need to be select for the mating - depending on number of offsprings remaining
            # n_select = math.ceil((self.n_offsprings - len(off)) / self.crossover.n_offsprings)

            # set to one to simplify sources of error. 1 means two parents
            n_select = 1

            # select the parents for the mating - just an index array
            parents = self.selection.do(pop,
                                        n_select,
                                        self.crossover.n_parents,
                                        algorithm=self)

            # do the crossover using the parents index and the population - additional data provided if necessary
            _off = self.crossover.do(self.problem,
                                     pop,
                                     parents,
                                     algorithm=self)

            # do the mutation on the offsprings created through crossover

            muta_off = self.mutation.do(self.problem, _off, algorithm=self)

            for i, ind in enumerate(_off):
                mutation_map = ind.X == muta_off[i].X
                ind.X = muta_off[i].X
                ind.mutation_map = mutation_map

                # repair the individuals if necessary
            if self.repair:
                _off = self.repair.do(self.problem, _off, algorithm=self)

            if self.eliminate_duplicates:
                is_duplicate = self.eliminate_duplicates(_off,
                                                         pop,
                                                         off,
                                                         algorithm=self)
                _off = _off[np.logical_not(is_duplicate)]

            # if more offsprings than necessary - truncate them
            if len(_off) > self.n_offsprings - len(off):
                I = random.perm(self.n_offsprings - len(off))
                _off = _off[I]

            off = off.merge(_off)

            n_matings += 1

            # if no new offsprings can be generated within 100 trails -> return the current result
            if n_matings > 100:
                print(
                    "WARNING: Recombination could not produce new offsprings which are not already in the population!"
                )
                break

        for ind in off:
            assert hasattr(ind, "parents")
            assert hasattr(ind, "mutation_map")

        return off