예제 #1
0
    def do(pop, n_survive):
        # get the objective space values and objects
        F = pop.get('F')

        # the final indices of surviving individuals
        survivors = []

        # do the non-dominated sorting until splitting front
        fronts = NonDominatedSorting().do(F, n_stop_if_ranked=n_survive)

        for k, front in enumerate(fronts):

            # calculate the crowding distance of the front
            crowding_of_front = calc_crowding_distance(F[front, :])

            # save rank and crowding in the individual class
            for j, i in enumerate(front):
                pop[i].set('rank', k)
                pop[i].set('crowding', crowding_of_front[j])

            # current front sorted by crowding distance if splitting
            if len(survivors) + len(front) > n_survive:
                I = randomized_argsort(crowding_of_front,
                                       order='descending',
                                       method='numpy')
                I = I[:(n_survive - len(survivors))]

            # otherwise take the whole front unsorted
            else:
                I = np.arange(len(front))

            # extend the survivors by all or selected individuals
            survivors.extend(front[I])
        return pop[survivors]
예제 #2
0
    def _do(self, pop, n_survive, D=None, **kwargs):

        # attributes to be set after the survival
        F = pop.get("F")

        # find or usually update the new ideal point - from feasible solutions
        self.ideal_point = np.min(np.vstack((self.ideal_point, F)), axis=0)
        self.worst_point = np.max(np.vstack((self.worst_point, F)), axis=0)

        # calculate the fronts of the population
        fronts, rank = NonDominatedSorting().do(F,
                                                return_rank=True,
                                                n_stop_if_ranked=n_survive)
        self.nadir_point = get_nadir_point_from_fronts(F, fronts,
                                                       self.ideal_point)

        #  consider only the population until we come to the splitting front
        I = np.concatenate(fronts)
        pop, rank, F = pop[I], rank[I], F[I]

        # update the front indices for the current population
        counter = 0
        for i in range(len(fronts)):
            for j in range(len(fronts[i])):
                fronts[i][j] = counter
                counter += 1
        last_front = fronts[-1]

        # associate individuals to niches
        niche_of_individuals, dist_to_niche = associate_to_niches(
            F, self.ref_dirs, self.ideal_point, self.nadir_point)
        pop.set('rank', rank, 'niche', niche_of_individuals, 'dist_to_niche',
                dist_to_niche)

        # if we need to select individuals to survive
        if len(pop) > n_survive:

            # if there is only one front
            if len(fronts) == 1:
                n_remaining = n_survive
                until_last_front = np.array([], dtype=np.int)
                niche_count = np.zeros(len(self.ref_dirs), dtype=np.int)

            # if some individuals already survived
            else:
                until_last_front = np.concatenate(fronts[:-1])
                niche_count = calc_niche_count(
                    len(self.ref_dirs), niche_of_individuals[until_last_front])
                n_remaining = n_survive - len(until_last_front)

            S = niching(F[last_front, :], n_remaining, niche_count,
                        niche_of_individuals[last_front],
                        dist_to_niche[last_front])

            survivors = np.concatenate(
                (until_last_front, last_front[S].tolist()))
            pop = pop[survivors]

        return pop
예제 #3
0
    def eval(self, problem=None, x=None, archive=None, **kwargs):
        if x.ndim == 1:
            n = 1
            x = np.expand_dims(x, 0)
        else:
            n = x.shape[0]
        f = np.zeros((n, problem.n_obj))
        g = np.zeros((n, np.max([problem.n_constr, 1])))

        if self.n_eval + x.shape[0] > self.n_max_eval:
            rest = self.n_max_eval - self.n_eval
            I = np.random.permutation(x.shape[0])
            I = I[:rest]
            x = x[I]
            f = f[I]
            g = g[I]

        problem._evaluate_high_fidelity(x=x, f=f, g=g)
        archive['x'] = np.concatenate((x, archive['x']), axis=0)
        archive['f'] = np.concatenate((f, archive['f']), axis=0)
        archive['g'] = np.concatenate((g, archive['g']), axis=0)
        cv = np.copy(archive['g'])
        index = np.any(archive['g'] > 0, axis=1)
        cv[archive['g'] <= 0] = 0
        cv = np.sum(cv, axis=1)
        acv = np.sum(archive['g'], axis=1)
        acv[index] = np.copy(cv[index])
        archive['feasible_index'] = cv <= 0
        archive['feasible_index'] = np.vstack(
            np.asarray(archive['feasible_index']).flatten())
        archive['cv'] = np.vstack(np.asarray(cv).flatten())
        archive['acv'] = np.vstack(np.asarray(acv).flatten())

        feasible = archive['f'][archive['feasible_index'][:, 0], :]
        if feasible.size > 0:
            nd = NonDominatedSorting()
            index = nd.do(F=feasible, only_non_dominated_front=True)
            archive['non_dominated_front'] = archive['x'][index]
        else:
            archive['non_dominated_front'] = np.empty([0, f.size])

        self.n_eval = archive["x"].shape[0]
        return archive
예제 #4
0
    def test_rank_and_crowding_distance(self):
        for i, D in enumerate(self.data):

            survivor_and_last_front = np.where(D['rank'] != -1.0)[0]
            crowding = D['crowding'][survivor_and_last_front]
            rank = D['rank'][survivor_and_last_front].astype(np.int)
            F = D['F'][survivor_and_last_front, :]

            fronts, _rank = NonDominatedSorting().do(F, return_rank=True)
            _rank += 1
            _crowding = np.full(len(F), np.nan)
            for front in fronts:
                _crowding[front] = calc_crowding_distance(F[front])

            is_equal = np.all(rank == _rank)
            if not is_equal:
                index = np.where(rank == _rank)
                print(index)
                print(D['rank'][index])
                print(D['F'][index])

            self.assertTrue(is_equal)

            is_equal = np.all(np.abs(_crowding - crowding) < 0.001)
            if not is_equal:

                index = np.where(np.abs(_crowding - crowding) > 0.001)[0]
                index = index[np.argsort(rank[index])]

                # only an error if it is not a duplicate F value
                for i_not_equal in index:

                    if len(
                            np.where(np.all(F[i_not_equal, :] == F,
                                            axis=1))[0]) == 1:
                        print("-" * 30)
                        print("Generation: ", i)
                        print("Is rank equal: ", np.all(rank == _rank))

                        print(index)
                        print(rank[index])
                        print(F[index])
                        print(
                            np.concatenate(
                                [_crowding[:, None], crowding[:, None]],
                                axis=1)[index, :])
                        print()

                        self.assertTrue(is_equal)
예제 #5
0
    def calc_normalized_constraints(self, G):

        # update the ideal point for constraints
        if self.min_constraints is None:
            self.min_constraints = np.full(G.shape[1], np.inf)
        self.min_constraints = np.min(np.vstack((self.min_constraints, G)), axis=0)

        # update the nadir point for constraints
        non_dominated = NonDominatedSorting().do(G, return_rank=True, only_non_dominated_front=True)

        if self.max_constraints is None:
            self.max_constraints = np.full(G.shape[1], np.inf)
        self.max_constraints = np.min(np.vstack((self.max_constraints, np.max(G[non_dominated, :], axis=0))), axis=0)

        return normalize(G, self.min_constraints, self.max_constraints)
예제 #6
0
    def _calc(self, F):
        non_dom = NonDominatedSorting().do(F, only_non_dominated_front=True)

        _F = F[non_dom, :]

        if self.normalize:
            hv = _HyperVolume(np.ones(F.shape[1]))
            _F = normalize(_F,
                           x_min=np.min(self.pf, axis=0),
                           x_max=np.max(self.pf, axis=0))
        else:
            hv = _HyperVolume(np.max(self.pf, axis=0))

        val = hv.compute(_F)
        return val
예제 #7
0
파일: hv.py 프로젝트: yidan3166/pymoo
    def _calc(self, F):

        # only consider the non-dominated solutions for HV
        non_dom = NonDominatedSorting().do(F, only_non_dominated_front=True)
        _F = np.copy(F[non_dom, :])

        if self.normalize:
            # because we normalize now the reference point is (1,...1)
            ref_point = np.ones(F.shape[1])
            hv = _HyperVolume(ref_point)
            _F = normalize(_F, x_min=self.ideal_point, x_max=self.nadir_point)
        else:
            hv = _HyperVolume(self.ref_point)

        val = hv.compute(_F)
        return val
예제 #8
0
def solve(fd: FoodDistribution):
    problem = SolverProblem(fd)
    method = nsga2(pop_size=70)
    t = time.time()
    print('start')
    res = minimize(problem,
                   method,
                   termination=('n_gen', 20),
                   seed=2,
                   save_history=True,
                   disp=True)
    print('end: ', time.time() - t)
    plt.figure(1)
    plt.clf()
    for g, a in enumerate(res.history):
        a.opt = a.pop.copy()
        a.opt = a.opt[a.opt.collect(lambda ind: ind.feasible)[:, 0]]
        I = NonDominatedSorting().do(a.opt.get("F"),
                                     only_non_dominated_front=True)
        a.opt = a.opt[I]
        X, F, CV, G = a.opt.get("X", "F", "CV", "G")
        plt.figure(1)
        plt.scatter(F[:, 0], F[:, 1], c=[[g / len(res.history), 0, 0]], s=5**2)
        plt.figure(2)
        plt.clf()
        plt.scatter(F[:, 0], F[:, 1], s=5**2)
        plt.xlabel('remaining demand')
        plt.ylabel('cost')
        plt.savefig('../g_{}.eps'.format(g), format='eps')
    plt.figure(1)
    #plotting.plot(res.F, no_fill=True, show=False)
    plt.xlabel('remaining demand')
    plt.ylabel('cost')
    plt.show()
    plt.savefig('../scatter.eps', format='eps')
    return res.X
예제 #9
0
    def _do(self, pop, n_survive, D=None, **kwargs):

        # attributes to be set after the survival
        F = pop.get("F")

        # find or usually update the new ideal point - from feasible solutions
        self.ideal_point = np.min(np.vstack((self.ideal_point, F)), axis=0)
        self.worst_point = np.max(np.vstack((self.worst_point, F)), axis=0)

        # calculate the fronts of the population
        fronts, rank = NonDominatedSorting().do(F,
                                                return_rank=True,
                                                n_stop_if_ranked=n_survive)
        non_dominated, last_front = fronts[0], fronts[-1]

        # find the extreme points for normalization
        self.extreme_points = get_extreme_points_c(
            F[non_dominated, :],
            self.ideal_point,
            extreme_points=self.extreme_points)

        # find the intercepts for normalization and do backup if gaussian elimination fails
        worst_of_population = np.max(F, axis=0)
        worst_of_front = np.max(F[non_dominated, :], axis=0)

        self.nadir_point = get_nadir_point(self.extreme_points,
                                           self.ideal_point, self.worst_point,
                                           worst_of_population, worst_of_front)

        #  consider only the population until we come to the splitting front
        I = np.concatenate(fronts)
        pop, rank, F = pop[I], rank[I], F[I]

        # update the front indices for the current population
        counter = 0
        for i in range(len(fronts)):
            for j in range(len(fronts[i])):
                fronts[i][j] = counter
                counter += 1

        # normalize the whole population by the estimations made
        N = normalize(F, self.ideal_point, self.nadir_point)

        # the final indices of surviving individuals
        survivors = []

        for k, front in enumerate(fronts):

            # calculate the crowding distance of the front
            crowding_of_front = calc_asf_crowding_distance(N[front, :])

            # save rank and crowding in the individual class
            for j, i in enumerate(front):
                pop[i].set("rank", k)
                pop[i].set("crowding", crowding_of_front[j])

            # current front sorted by crowding distance if splitting
            if len(survivors) + len(front) > n_survive:
                I = randomized_argsort(crowding_of_front,
                                       order='descending',
                                       method='numpy')
                I = I[:(n_survive - len(survivors))]

            # otherwise take the whole front unsorted
            else:
                I = np.arange(len(front))

            # extend the survivors by all or selected individuals
            survivors.extend(front[I])

        return pop[survivors]
예제 #10
0
    def test_run(self):

        ref_dirs = np.array(self.data['ref_dir'])
        survival = ReferenceLineSurvival(ref_dirs)

        D = self.data['hist'][0]
        pop = Population()
        pop.X = np.array(D['before_X'])
        pop.F = np.array(D['before_F'])

        _, _rank = NonDominatedSorting(epsilon=1e-10).do(pop.F,
                                                         return_rank=True)
        rank = np.array(D['before_rank'])

        if not np.all(_rank + 1 == rank):
            print("")
        self.assertTrue(np.all(_rank + 1 == rank))

        survival.do(pop, pop.size())

        for i, D in enumerate(self.data['hist']):

            out = {}
            vars = {'out': out}

            pop = Population()
            pop.X = np.array(D['before_X'])
            pop.F = np.array(D['before_F'])

            off = Population()
            off.X = np.array(D['off_X'])
            off.F = np.array(D['off_F'])

            pop.merge(off)

            cand = Population()
            cand.X = np.array(D['cand_X'])
            cand.F = np.array(D['cand_F'])

            Configuration.rand.randint = MagicMock()
            Configuration.rand.randint.side_effect = D['rnd_niching']

            fronts = []
            ranks = np.array(D['cand_rank'])
            for r in np.unique(ranks):
                fronts.append(np.where(ranks == r)[0].tolist())

            NonDominatedSorting.do = MagicMock()
            NonDominatedSorting.do.return_value = [
                np.array(front) for front in fronts
            ], ranks - 1

            cand_copy = cand.copy()

            # necessary because only candidates are provided
            if survival.ideal_point is None:
                survival.ideal_point = np.min(pop.F, axis=0)
            else:
                survival.ideal_point = np.min(np.concatenate(
                    [survival.ideal_point[None, :], pop.F], axis=0),
                                              axis=0)

            survival.do(cand, pop.size() / 2, **vars)

            is_equal = np.all(
                survival.extreme_points == np.array(D['extreme']))
            self.assertTrue(is_equal)

            is_equal = np.all(survival.ideal_point == np.array(D['ideal']))
            self.assertTrue(is_equal)

            is_equal = np.all(
                np.abs(survival.intercepts -
                       np.array(D['intercepts'])) < 0.0001)

            if not is_equal:
                print(i)
                print(survival.intercepts, np.array(D['intercepts']))
            self.assertTrue(is_equal)

            niche_of_individuals, dist_to_niche = associate_to_niches(
                cand_copy.F, ref_dirs, survival.ideal_point,
                survival.intercepts)
            for r, v in enumerate(D['ref_dir']):
                self.assertTrue(np.all(ref_dirs[niche_of_individuals[r]] == v))

            is_equal = np.all(
                np.abs(dist_to_niche - np.array(D['perp_dist'])) < 0.000001)

            if not is_equal:
                print(i)

            self.assertTrue(is_equal)

            surv_pop = Population()
            surv_pop.X = np.array(D['X'])
            surv_pop.F = np.array(D['F'])

            for k in range(surv_pop.size()):
                is_equal = np.any(np.all(surv_pop.X[k, :] == cand.X, axis=1))

                if not is_equal:
                    print(i)
                    print(k)

                self.assertTrue(is_equal)

            for k in range(cand.size()):
                is_equal = np.any(np.all(cand.F[k, :] == surv_pop.F, axis=1))
                self.assertTrue(is_equal)
예제 #11
0
    def solve(self,
              problem,
              termination,
              seed=None,
              disp=False,
              callback=None,
              save_history=False,
              pf=None,
              **kwargs):
        """

        Solve a given problem by a given evaluator. The evaluator determines the termination condition and
        can either have a maximum budget, hypervolume or whatever. The problem can be any problem the algorithm
        is able to solve.

        Parameters
        ----------

        problem: class
            Problem to be solved by the algorithm

        termination: class
            object that evaluates and saves the number of evaluations and determines the stopping condition

        seed: int
            Random seed for this run. Before the algorithm starts this seed is set.

        disp : bool
            If it is true than information during the algorithm execution are displayed

        callback : func
            A callback function can be passed that is executed every generation. The parameters for the function
            are the algorithm itself, the number of evaluations so far and the current population.

                def callback(algorithm):
                    pass

        save_history : bool
            If true, a current snapshot of each generation is saved.

        pf : np.array
            The Pareto-front for the given problem. If provided performance metrics are printed during execution.

        Returns
        -------
        res : dict
            A dictionary that saves all the results of the algorithm. Also, the history if save_history is true.

        """

        # set the random seed for generator
        if seed is not None:
            random.seed(seed)

        # the evaluator object which is counting the evaluations
        self.evaluator = Evaluator()
        self.problem = problem
        self.termination = termination
        self.pf = pf

        self.disp = disp
        self.callback = callback
        self.save_history = save_history

        # call the algorithm to solve the problem
        pop = self._solve(problem, termination)

        # get the optimal result by filtering feasible and non-dominated
        opt = pop.copy()
        opt = opt[opt.collect(lambda ind: ind.feasible)[:, 0]]

        # if at least one feasible solution was found
        if len(opt) > 0:

            if problem.n_obj > 1:
                I = NonDominatedSorting().do(opt.get("F"),
                                             only_non_dominated_front=True)
                opt = opt[I]
                X, F, CV, G = opt.get("X", "F", "CV", "G")

            else:
                opt = opt[np.argmin(opt.get("F"))]
                X, F, CV, G = opt.X, opt.F, opt.CV, opt.G
        else:
            opt = None

        res = Result(opt, opt is None, "")
        res.algorithm, res.problem, res.pf = self, problem, pf
        res.pop = pop

        if opt is not None:
            res.X, res.F, res.CV, res.G = X, F, CV, G

        res.history = self.history

        return res
예제 #12
0
 def _filter_fast(self):
     filtered_pop = NonDominatedSorting.get_non_dominated(
         self.whole_pop, self.curr_pop)
     return filtered_pop
예제 #13
0
    def seeking(P, gamma=210):
        P_F = P.get('F')
        idx_front_0 = NonDominatedSorting().do(P_F,
                                               n_stop_if_ranked=len(P),
                                               only_non_dominated_front=True)
        PS = P[idx_front_0].copy()
        PF = P_F[idx_front_0].copy()

        # Normalize validation error for calculating angle between two individuals
        PF_norm = PF.copy()

        mi_f0 = np.min(PF[:, 0])
        ma_f0 = np.max(PF[:, 0])

        mi_f1 = np.min(PF[:, 1])
        ma_f1 = np.max(PF[:, 1])

        PF_norm[:, 0] = (PF[:, 0] - mi_f0) / (ma_f0 - mi_f0)
        PF_norm[:, 1] = (PF[:, 1] - mi_f1) / (ma_f1 - mi_f1)

        new_idx = np.argsort(PF[:, 0])

        PS = PS[new_idx]
        PF = PF[new_idx]
        PF_norm = PF_norm[new_idx]
        idx_front_0 = idx_front_0[new_idx]

        angle = [np.array([360, 0])]
        for i in range(1, len(PF) - 1):
            l = None
            u = None
            for m in range(i - 1, -1, -1):
                if np.sum(np.abs(PF[m] - PF[i])) != 0:
                    l = m
                    break
            for m in range(i + 1, len(PF), 1):
                if np.sum(np.abs(PF[m] - PF[i])) != 0:
                    u = m
                    break

            if l is None or u is None:
                angle.append(np.array([0, i]))
            else:
                position = above_or_below(PF[i], PF[l], PF[u])
                if position == -1:
                    angle.append(
                        np.array([
                            calculating_angle(p_middle=PF_norm[i],
                                              p_top=PF_norm[l],
                                              p_bot=PF_norm[u]), i
                        ]))
                else:
                    angle.append(np.array([0, i]))

        angle.append(np.array([360, len(PS) - 1]))
        angle = np.array(angle)
        angle = angle[np.argsort(angle[:, 0])]

        angle = angle[angle[:, 0] > gamma]

        idx_potential_solutions = np.array(angle[:, 1], dtype=np.int)
        return PS, idx_potential_solutions, idx_front_0
예제 #14
0
    def improve_potential_solutions(self, P):
        P_F = P.get('F')

        front_0 = NonDominatedSorting().do(P_F,
                                           n_stop_if_ranked=len(P),
                                           only_non_dominated_front=True)

        PF = P[front_0].copy()
        PF_F = P_F[front_0].copy()

        # normalize val_error for calculating angle between two individuals
        nPF_F = P_F[front_0].copy()

        mi_f0 = np.min(PF_F[:, 0])
        ma_f0 = np.max(PF_F[:, 0])

        mi_f1 = np.min(PF_F[:, 1])
        ma_f1 = np.max(PF_F[:, 1])

        nPF_F[:, 0] = (PF_F[:, 0] - mi_f0) / (ma_f0 - mi_f0)
        nPF_F[:, 1] = (PF_F[:, 1] - mi_f1) / (ma_f1 - mi_f1)

        new_idx = np.argsort(PF_F[:, 0])  # --> use for sort

        PF = PF[new_idx]
        PF_F = PF_F[new_idx]
        nPF_F = nPF_F[new_idx]
        front_0 = front_0[new_idx]

        angle = [np.array([360, 0])]
        for i in range(1, len(PF_F) - 1):
            l = None
            u = None
            for m in range(i - 1, -1, -1):
                if np.sum(np.abs(PF_F[m] - PF_F[i])) != 0:
                    l = m
                    break
            for m in range(i + 1, len(PF_F), 1):
                if np.sum(np.abs(PF_F[m] - PF_F[i])) != 0:
                    u = m
                    break

            if l is None or u is None:
                angle.append(np.array([0, i]))
            else:
                tren_hay_duoi = kiem_tra_p1_nam_phia_tren_hay_duoi_p2_p3(
                    PF_F[i], PF_F[l], PF_F[u])
                if tren_hay_duoi == 'duoi':
                    angle.append(
                        np.array([
                            cal_angle(p_middle=nPF_F[i],
                                      p_top=nPF_F[l],
                                      p_bot=nPF_F[u]), i
                        ]))
                else:
                    angle.append(np.array([0, i]))

        angle.append(np.array([360, len(PF) - 1]))
        angle = np.array(angle)
        angle = angle[np.argsort(angle[:, 0])]

        angle = angle[angle[:, 0] > 210]

        idx_S = np.array(angle[:, 1], dtype=np.int)
        S = PF[idx_S].copy()

        S = self.local_search_on_X(P, X=S, ls_on_knee_solutions=True)

        PF[idx_S] = S

        P[front_0] = PF

        return P
예제 #15
0
    def _do(self, pop, n_survive, D=None, **kwargs):

        # attributes to be set after the survival
        F = pop.get("F")

        # find or usually update the new ideal point - from feasible solutions
        self.ideal_point = np.min(np.vstack(
            (self.ideal_point, F, self.ref_points)),
                                  axis=0)
        self.worst_point = np.max(np.vstack(
            (self.worst_point, F, self.ref_points)),
                                  axis=0)

        # calculate the fronts of the population
        fronts, rank = NonDominatedSorting().do(F,
                                                return_rank=True,
                                                n_stop_if_ranked=n_survive)
        non_dominated, last_front = fronts[0], fronts[-1]

        # find the extreme points for normalization
        self.extreme_points = get_extreme_points_c(
            np.vstack([F[non_dominated], self.ref_points]),
            self.ideal_point,
            extreme_points=self.extreme_points)

        # find the intercepts for normalization and do backup if gaussian elimination fails
        worst_of_population = np.max(F, axis=0)
        worst_of_front = np.max(F[non_dominated, :], axis=0)

        self.nadir_point = get_nadir_point(self.extreme_points,
                                           self.ideal_point, self.worst_point,
                                           worst_of_population, worst_of_front)

        #  consider only the population until we come to the splitting front
        I = np.concatenate(fronts)
        pop, rank, F = pop[I], rank[I], F[I]

        # update the front indices for the current population
        counter = 0
        for i in range(len(fronts)):
            for j in range(len(fronts[i])):
                fronts[i][j] = counter
                counter += 1
        last_front = fronts[-1]

        unit_ref_points = (self.ref_points - self.ideal_point) / (
            self.nadir_point - self.ideal_point)
        ref_dirs = get_ref_dirs_from_points(unit_ref_points,
                                            self.aspiration_ref_dirs,
                                            mu=self.mu)
        self.ref_dirs = denormalize(ref_dirs, self.ideal_point,
                                    self.nadir_point)

        # associate individuals to niches
        niche_of_individuals, dist_to_niche = associate_to_niches(
            F, ref_dirs, self.ideal_point, self.nadir_point)
        pop.set('rank', rank, 'niche', niche_of_individuals, 'dist_to_niche',
                dist_to_niche)

        # if we need to select individuals to survive
        if len(pop) > n_survive:

            # if there is only one front
            if len(fronts) == 1:
                n_remaining = n_survive
                until_last_front = np.array([], dtype=np.int)
                niche_count = np.zeros(len(ref_dirs), dtype=np.int)

            # if some individuals already survived
            else:
                until_last_front = np.concatenate(fronts[:-1])
                niche_count = calc_niche_count(
                    len(ref_dirs), niche_of_individuals[until_last_front])
                n_remaining = n_survive - len(until_last_front)

            S = niching(pop[last_front], n_remaining, niche_count,
                        niche_of_individuals[last_front],
                        dist_to_niche[last_front])

            survivors = np.concatenate(
                (until_last_front, last_front[S].tolist()))
            pop = pop[survivors]

        return pop
예제 #16
0
파일: rnsga2.py 프로젝트: yidan3166/pymoo
    def _do(self, pop, n_survive, **kwargs):

        # get the objective space values and objects
        F = pop.get("F")

        # the final indices of surviving individuals
        survivors = []

        # do the non-dominated sorting until splitting front
        fronts = NonDominatedSorting().do(F)

        if self.normalization == "ever":
            # find or usually update the new ideal point - from feasible solutions
            self.ideal_point = np.min(np.vstack((self.ideal_point, F)), axis=0)
            self.nadir_point = np.max(np.vstack((self.nadir_point, F)), axis=0)

        elif self.normalization == "front":
            front = fronts[0]
            if len(front) > 1:
                self.ideal_point = np.min(F[front], axis=0)
                self.nadir_point = np.max(F[front], axis=0)

        elif self.normalization == "no":
            self.ideal_point = np.zeros(self.n_obj)
            self.nadir_point = np.ones(self.n_obj)

        if self.extreme_points_as_reference_points:
            self.ref_points = np.row_stack(
                [self.ref_points,
                 get_extreme_points_c(F, self.ideal_point)])

        # calculate the distance matrix from ever solution to all reference point
        dist_to_ref_points = calc_norm_pref_distance(F, self.ref_points,
                                                     self.weights,
                                                     self.ideal_point,
                                                     self.nadir_point)

        for k, front in enumerate(fronts):

            # save rank attributes to the individuals - rank = front here
            pop[front].set("rank", np.full(len(front), k))

            # number of individuals remaining
            n_remaining = n_survive - len(survivors)

            # the ranking of each point regarding each reference point (two times argsort is necessary)
            rank_by_distance = np.argsort(np.argsort(dist_to_ref_points[front],
                                                     axis=0),
                                          axis=0)

            # the reference point where the best ranking is coming from
            ref_point_of_best_rank = np.argmin(rank_by_distance, axis=1)

            # the actual ranking which is used as crowding
            ranking = rank_by_distance[np.arange(len(front)),
                                       ref_point_of_best_rank]

            if len(front) <= n_remaining:

                # we can simply copy the crowding to ranking. not epsilon selection here
                crowding = ranking
                I = np.arange(len(front))

            else:

                # Distance from solution to every other solution and set distance to itself to infinity
                dist_to_others = calc_norm_pref_distance(
                    F[front], F[front], self.weights, self.ideal_point,
                    self.nadir_point)
                np.fill_diagonal(dist_to_others, np.inf)

                # the crowding that will be used for selection
                crowding = np.full(len(front), np.nan)

                # solutions which are not already selected - for
                not_selected = np.argsort(ranking)

                # until we have saved a crowding for each solution
                while len(not_selected) > 0:

                    # select the closest solution
                    idx = not_selected[0]

                    # set crowding for that individual
                    crowding[idx] = ranking[idx]

                    # need to remove myself from not-selected array
                    to_remove = [idx]

                    # Group of close solutions
                    dist = dist_to_others[idx][not_selected]
                    group = not_selected[np.where(dist < self.epsilon)[0]]

                    # if there exists solution with a distance less than epsilon
                    if len(group):
                        # discourage them by giving them a high crowding
                        crowding[group] = ranking[group] + np.round(
                            len(front) / 2)

                        # remove group from not_selected array
                        to_remove.extend(group)

                    not_selected = np.array(
                        [i for i in not_selected if i not in to_remove])

                # now sort by the crowding (actually modified rank) ascending and let the best survive
                I = np.argsort(crowding)[:n_remaining]

            # set the crowding to all individuals
            pop[front].set("crowding", crowding)

            # extend the survivors by all or selected individuals
            survivors.extend(front[I])

        # inverse of crowding because nsga2 does maximize it (then tournament selection can stay the same)
        pop.set("crowding", -pop.get("crowding"))

        return pop[survivors]
예제 #17
0
    def _do(self, pop, n_survive, algorithm=None, **kwargs):

        if True:

            if self.archive is None:
                self.archive = pop
            else:
                self.archive = self.archive.merge(pop)

            # get the function values of the current archive for operations
            F = self.archive.get("F")

            # filter out all the duplicate solutions
            I = np.logical_not(default_is_duplicate(F))
            self.archive, F = self.archive[I], F[I]

            # get only the non-dominated solutions
            I = NonDominatedSorting().do(F, only_non_dominated_front=True)
            self.archive, F = self.archive[I], F[I]

            if len(self.archive) > self.n_archive:
                cd = calc_crowding_distance(F)
                self.archive = self.archive[np.argsort(cd)[::-1]
                                            [:self.n_archive]]

            # attributes to be set after the survival
            pop.merge(self.archive)

        F = pop.get("F")

        # find or usually update the new ideal point - from feasible solutions
        self.ideal_point = np.min(np.vstack((self.ideal_point, F)), axis=0)
        self.worst_point = np.max(np.vstack((self.worst_point, F)), axis=0)

        # calculate the fronts of the population
        fronts, rank = NonDominatedSorting(epsilon=1e-10).do(
            F, return_rank=True, n_stop_if_ranked=n_survive)
        non_dominated, last_front = fronts[0], fronts[-1]

        # find the extreme points for normalization
        self.extreme_points = non_dominated[get_extreme_points(
            F[non_dominated, :], self.ideal_point)]

        # find the intercepts for normalization and do backup if gaussian elimination fails
        worst_of_population = np.max(F, axis=0)
        worst_of_front = np.max(F[non_dominated, :], axis=0)

        self.nadir_point = get_nadir_point(F[self.extreme_points],
                                           self.ideal_point, self.worst_point,
                                           worst_of_population, worst_of_front)

        # associate individuals to niches
        pop.set('rank', rank)

        # if we need to select individuals to survive
        if len(pop) > n_survive:

            for i in range(len(fronts)):
                fronts[i] = np.array(
                    [j for j in fronts[i] if j not in self.extreme_points])

            survivors = np.unique(self.extreme_points).tolist()

            for k, front in enumerate(fronts):

                # current front sorted by crowding distance if splitting
                if len(survivors) + len(front) > n_survive:
                    I = selection(survivors, list(front), F,
                                  (n_survive - len(survivors)))
                    survivors.extend(I)

                # otherwise take the whole front unsorted
                else:
                    # extend the survivors by all or selected individuals
                    survivors.extend(front)

            pop = pop[survivors]

        return pop
예제 #18
0
    def _seeking(self, pop, **kwargs):
        pop_F = pop.get('F')
        pos_front_0 = NonDominatedSorting().do(pop_F,
                                               n_stop_if_ranked=len(pop),
                                               only_non_dominated_front=True)
        pareto_set = pop[pos_front_0].copy()
        pf = pop_F[pos_front_0].copy()

        # Normalize validation error for calculating angle between two individuals
        pf_norm = pf.copy()

        mi_f0 = np.min(pf[:, 0])
        ma_f0 = np.max(pf[:, 0])

        mi_f1 = np.min(pf[:, 1])
        ma_f1 = np.max(pf[:, 1])

        pf_norm[:, 0] = (pf[:, 0] - mi_f0) / (ma_f0 - mi_f0)
        pf_norm[:, 1] = (pf[:, 1] - mi_f1) / (ma_f1 - mi_f1)

        new_idx = np.argsort(pf[:, 0])

        pareto_set = pareto_set[new_idx]
        pf = pf[new_idx]
        pf_norm = pf_norm[new_idx]
        pos_front_0 = pos_front_0[new_idx]

        angle = [np.array([360, 0])]
        for i in range(1, len(pf) - 1):
            l = None
            u = None
            for m in range(i - 1, -1, -1):
                if np.sum(np.abs(pf[m] - pf[i])) != 0:
                    l = m
                    break
            for m in range(i + 1, len(pf), 1):
                if np.sum(np.abs(pf[m] - pf[i])) != 0:
                    u = m
                    break

            if l is None or u is None:
                angle.append(np.array([0, i]))
            else:
                position = above_or_below(pf[i], pf[l], pf[u])
                if position == -1:
                    angle.append(
                        np.array([
                            cal_angle(p_middle=pf_norm[i],
                                      p_top=pf_norm[l],
                                      p_bot=pf_norm[u]), i
                        ]))
                else:
                    angle.append(np.array([0, i]))

        angle.append(np.array([360, len(pareto_set) - 1]))
        angle = np.array(angle)
        angle = angle[np.argsort(angle[:, 0])]

        angle = angle[angle[:, 0] > self.gamma]

        pos_potential_sols = np.array(angle[:, 1], dtype=np.int)

        return pareto_set, pos_potential_sols, pos_front_0