Beispiel #1
0
def test_restricted_mating_selection(ref_dirs, evaluator):
    np.random.seed(200)
    selection = RestrictedMating(func_comp=comp_by_cv_dom_then_random)

    problem = C3DTLZ4(n_var=12, n_obj=3)
    ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case2', 'preCA.x'))
    CA = Population.create(ca_x)
    evaluator.eval(problem, CA)

    da_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case2', 'preDA.x'))
    DA = Population.create(da_x)
    evaluator.eval(problem, DA)

    Hm = Population.merge(CA, DA)
    n_pop = len(CA)

    _, rank = NonDominatedSorting().do(Hm.get('F'), return_rank=True)

    Pc = (rank[:n_pop] == 0).sum() / len(Hm)
    Pd = (rank[n_pop:] == 0).sum() / len(Hm)

    P = selection.do(Hm, len(CA))

    assert P.shape == (91, 2)
    if Pc > Pd:
        assert (P[:, 0] < n_pop).all()
    else:
        assert (P[:, 0] >= n_pop).all()
    assert (P[:, 1] >= n_pop).any()
    assert (P[:, 1] < n_pop).any()
Beispiel #2
0
def test_association(ref_dirs, evaluator):
    problem = C1DTLZ3(n_var=12, n_obj=3)
    ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'preCA.x'))
    CA = Population.create(ca_x)
    evaluator.eval(problem, CA)

    da_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'preDA.x'))
    DA = Population.create(da_x)
    evaluator.eval(problem, DA)

    off_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'offspring.x'))
    off = Population.create(off_x)
    evaluator.eval(problem, off)

    true_assoc = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'feasible_rank0.txt'))
    true_niche = true_assoc[:, 1]
    true_id = true_assoc[:, 0]
    sorted_id = np.argsort(true_id)

    survival = CADASurvival(ref_dirs)
    mixed = Population.merge(CA, off)
    survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0)

    fronts = NonDominatedSorting().do(mixed.get("F"), n_stop_if_ranked=len(ref_dirs))
    I = np.concatenate(fronts)
    niche, _ = survival._associate(mixed[I])
    sorted_I = np.argsort(I)

    assert (niche[sorted_I] == true_niche[sorted_id]).all()
Beispiel #3
0
    def do(self, problem, pop, off, return_indices=False, inplace=False, **kwargs):

        # this makes it usable as a traditional survival
        if isinstance(off, int):
            k = off
            off = pop[k:]
            pop = pop[:k]

        # if the offsprings are simply empty don't do anything
        if len(off) == 0:
            return pop

        assert len(pop) == len(off), "For the replacement pop and off must have the same number of individuals."

        pop = Population.create(pop) if isinstance(pop, Individual) else pop
        off = Population.create(off) if isinstance(off, Individual) else off

        I = self._do(problem, pop, off, **kwargs)

        if return_indices:
            return I
        else:
            if not inplace:
                pop = pop.copy()
            pop[I] = off[I]
            return pop
Beispiel #4
0
    def _next(self):
        sol = self.opt[0]
        x = sol.get("X")
        jac, hess = self.gradient_and_hessian(sol)

        method = "cholesky"
        func = direction_cholesky if method == "cholesky" else direction_inv
        direction, decrement, adapted, success = func(jac, hess)

        # in case we can not calculate the newton direction fall back to the gradient approach
        if not success:
            direction = -jac
            decrement = np.linalg.norm(direction) ** 2

        if self.damped:
            line = LineSearchProblem(self.problem, sol, direction)
            _next = WolfeSearch().setup(line, evaluator=self.evaluator).run()
            # _next = wolfe_line_search(self.problem, sol, direction, evaluator=self.evaluator)

            # if the newton step was not successful, then try the gradient
            if adapted and (sol.F[0] - _next.F[0]) < 1e-16:
                _next = inexact_line_search(self.problem, sol, -jac, evaluator=self.evaluator)

        else:
            _x = x + direction
            _next = Solution(X=_x)

        if isinstance(_next, Individual):
            _next = Population.create(_next)

        self.pop = Population.merge(self.opt, _next)

        if decrement / 2 <= self.eps:
            self.termination.force_termination = True
Beispiel #5
0
    def _initialize_infill(self):
        self.step_size = self.alpha

        if self.point is None:
            return Population.new(X=np.copy(self.problem.xl[None, :]))
        else:
            return Population.create(self.point)
Beispiel #6
0
    def _advance(self, **kwargs):

        # all the elements in the interval
        a, c, d, b = self.pop

        # the golden ratio (precomputed constant)
        R = self.R

        # if the left solution is better than the right
        if c.F[0] < d.F[0]:

            # make the right to be the new right bound and the left becomes the right
            a, b = a, d
            d = c

            # create a new left individual and evaluate
            c = Individual(X=b.X - R * (b.X - a.X))
            self.evaluator.eval(self.problem, c, algorithm=self)
            self.infills = c

        # if the right solution is better than the left
        else:

            # make the left to be the new left bound and the right becomes the left
            a, b = c, b
            c = d

            # create a new right individual and evaluate
            d = Individual(X=a.X + R * (b.X - a.X))
            self.evaluator.eval(self.problem, d, algorithm=self)
            self.infills = d

        # update the population with all the four individuals
        self.pop = Population.create(a, c, d, b)
Beispiel #7
0
def test_update_da(ref_dirs, evaluator):
    problem = C1DTLZ3(n_var=12, n_obj=3)
    for i in range(2):
        ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', f'case{i + 1}', 'preCA.x'))
        CA = Population.create(ca_x)
        evaluator.eval(problem, CA)

        da_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', f'case{i + 1}', 'preDA.x'))
        DA = Population.create(da_x)
        evaluator.eval(problem, DA)

        off_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', f'case{i + 1}', 'offspring.x'))
        off = Population.create(off_x)
        evaluator.eval(problem, off)

        survival = CADASurvival(ref_dirs)
        mixed = Population.merge(CA, off)
        survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0)

        post_ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', f'case{i + 1}', 'postCA.x'))
        CA = Population.create(post_ca_x)
        evaluator.eval(problem, CA)

        Hd = Population.merge(DA, off)
        pDA = survival._updateDA(CA, Hd, 91)

        true_S1 = [151, 35, 6, 63, 67, 24, 178, 106, 134, 172, 148, 159, 41,
                   173, 145, 77, 62, 40, 127, 61, 130, 27, 171, 115, 52, 176,
                   22, 75, 55, 87, 36, 149, 154, 47, 78, 170, 90, 15, 53, 175,
                   179, 165, 56, 89, 132, 82, 141, 39, 32, 25, 131, 14, 72, 65,
                   177, 140, 66, 143, 34, 81, 103, 99, 147, 168, 51, 26, 70, 94,
                   54, 97, 158, 107, 29, 120, 50, 108, 157, 11, 85, 174, 80, 0,
                   95, 13, 142, 101, 156, 19, 8, 98, 20]

        true_S2 = [78, 173, 59, 21, 101, 52, 36, 94, 17, 20, 37, 96, 90, 129,
                   150, 136, 162, 70, 146, 75, 138, 154, 65, 179, 98, 32, 97,
                   11, 26, 107, 12, 128, 95, 170, 24, 171, 40, 180, 14, 44, 49,
                   43, 130, 23, 60, 79, 148, 62, 87, 56, 157, 73, 104, 45, 177,
                   74, 15, 152, 164, 28, 80, 113, 41, 33, 158, 57, 77, 34, 114,
                   118, 18, 54, 53, 145, 93, 115, 121, 174, 142, 39, 13, 105,
                   10, 69, 120, 55, 6, 153, 91, 137, 46]
        if i == 0:
            assert np.all(pDA == Hd[true_S1])
        else:
            assert np.all(pDA == Hd[true_S2])
Beispiel #8
0
    def _initialize_infill(self):
        super()._initialize_infill()
        a, b = self.a, self.b

        # set c to be directly in the middle between the two brackets
        c = Individual(X=(b.X - a.X) / 2)

        # create a population with all three individuals
        pop = Population.create(a, b, c)

        return pop
Beispiel #9
0
def test_update(ref_dirs, evaluator):
    problem = C3DTLZ4(n_var=12, n_obj=3)
    ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case2', 'preCA.x'))
    CA = Population.create(ca_x)
    evaluator.eval(problem, CA)

    da_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case2', 'preDA.x'))
    DA = Population.create(da_x)
    evaluator.eval(problem, DA)

    off_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case2', 'offspring.x'))
    off = Population.create(off_x)
    evaluator.eval(problem, off)

    post_ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case2', 'postCA.x'))
    true_pCA = Population.create(post_ca_x)
    evaluator.eval(problem, true_pCA)

    post_da_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case2', 'postDA.x'))
    true_pDA = Population.create(post_da_x)
    evaluator.eval(problem, true_pDA)

    survival = CADASurvival(ref_dirs)
    mixed = Population.merge(CA, off)
    survival.ideal_point = np.array([0., 0., 0.])

    pCA, pDA = survival.do(problem, mixed, DA, len(ref_dirs))

    pCA_X = set([tuple(x) for x in pCA.get("X")])
    tpCA_X = set([tuple(x) for x in true_pCA.get("X")])

    pDA_X = set([tuple(x) for x in pDA.get("X")])
    tpDA_X = set([tuple(x) for x in true_pDA.get("X")])

    assert pCA_X == tpCA_X
    assert pDA_X == tpDA_X
Beispiel #10
0
    def _initialize_infill(self):
        super()._initialize_infill()
        a, b = self.a, self.b

        # the golden ratio (precomputed constant)
        R = self.R

        # create the left and right in the interval itself
        c, d = Individual(X=b.X - R * (b.X - a.X)), Individual(X=a.X + R *
                                                               (b.X - a.X))

        # create a population with all four individuals
        pop = Population.create(a, c, d, b)

        self.pop, self.infills = pop, pop

        return pop
Beispiel #11
0
    def _infill(self):

        # the offspring population to finally evaluate and attach to the population
        infills = Population()

        # find the potential optimal solution in the current population
        potential_optimal = self._potential_optimal()

        # for each of those solutions execute the division move
        for current in potential_optimal:

            # find the largest dimension the solution has not been evaluated yet
            nxl, nxu = norm_bounds(current, self.problem)
            k = np.argmax(nxu - nxl)

            # the delta value to be used to get left and right - this is one sixth of the range
            xl, xu = current.get("xl"), current.get("xu")

            delta = (xu[k] - xl[k]) / 6

            # create the left individual
            left_x = np.copy(current.X)
            left_x[k] = xl[k] + delta
            left = Individual(X=left_x)

            # create the right individual
            right_x = np.copy(current.X)
            right_x[k] = xu[k] - delta
            right = Individual(X=right_x)

            # update the boundaries for all the points accordingly
            for ind in [current, left, right]:
                update_bounds(ind, xl, xu, k, delta)

            # create the offspring population, evaluate and attach to current population
            _infill = Population.create(left, right)
            _infill.set("depth", current.get("depth") + 1)

            infills = Population.merge(infills, _infill)

        return infills
Beispiel #12
0
    def _infill(self):
        pop_size, cross_parents, cross_off = self.pop_size, self.mating.crossover.n_parents, self.mating.crossover.n_offsprings

        # do the mating in a random order
        I = np.random.permutation(len(self.pop))[:self.n_offsprings]

        # get the parents using the neighborhood selection
        P = self.selection.do(self.pop, self.n_offsprings, cross_parents, k=I)

        # do not any duplicates elimination - thus this results in exactly pop_size * n_offsprings offsprings
        off = self.mating.do(self.problem, self.pop, np.inf, parents=P)

        # select a random offspring from each mating
        off = Population.create(*[
            np.random.choice(pool)
            for pool in np.reshape(off, (self.n_offsprings, -1))
        ])

        # store the indices because of the neighborhood matching in advance
        self.indices = I

        return off
Beispiel #13
0
    def _local_advance(self, **kwargs):

        # this happens only in the first iteration
        if self._explr is None:
            self._explr = self._exploration_move(self._center)

        else:
            # whether the last iteration has resulted in a new optimum
            has_improved = is_better(self._explr, self._center, eps=0.0)

            # that means that the exploration did not found any new point and was thus unsuccessful
            if not has_improved:

                # keep track of the rho values in the normalized space
                self._rho = self._rho * self.rho

                # explore around the current center to try finding a suitable direction
                self._explr = self._exploration_move(self._center)

            # if we have found a direction in the last iteration to be worth following
            else:

                # get the direction which was successful in the last move
                self._direction = (self._explr.X - self._center.X)

                # declare the exploration point the new center
                self._center = self._explr

                # use the pattern move to get a new trial vector along that given direction
                self._trial = self._pattern_move(self._center, self._direction)

                # get the delta sign adjusted for the exploration
                self._sign = calc_sign(self._direction)

                # explore around the current center to try finding a suitable direction
                self._explr = self._exploration_move(self._trial)

        self.pop = Population.create(self._center, self._explr)
Beispiel #14
0
    def _advance(self, **kwargs):

        # all the elements in the interval
        a, b, c = self.pop

        # if this is the case then the function is not convex (which means U shaped)
        if c.F[0] >= a.F[0] or c.F[0] >= b.F[0]:

            # choose the left side if a smaller than b, or the right side otherwise
            if a.F[0] <= b.F[0]:
                a = c
            else:
                b = c

            c = Individual(X=(b.X - a.X) / 2)
            self.evaluator.eval(self.problem, c, algorithm=self)
            self.infills = c

        else:

            d = quadr_interp(a, b, c)
            self.evaluator.eval(self.problem, d, algorithm=self)
            self.infills = d

            # swap c and d -> make sure d is always on the right of c -> a, c, d, b
            if c.X[0] > d.X[0]:
                c, d = d, c

            # if c is better than d, then d becomes the new right bound
            if c.F[0] <= d.F[0]:
                b = d

            # if d is better than c, then c becomes the new left bound and d the new right bound
            else:
                a, c = c, d

        self.pop = Population.create(a, b, c)
Beispiel #15
0
    def _advance(self, infills=None, **kwargs):
        assert infills is not None, "This algorithms uses the AskAndTell interface thus 'infills' must to be provided."

        # the indices for the creating of offsprings considered in the last generation
        I = infills.get("index")

        # the individuals that are considered for the survival later and final survive
        survivors = []

        # now for each of the infill solutions
        for k, i in enumerate(I):

            # get the offspring an the parent it is coming from
            off, parent = infills[k], self.pop[i]

            # check whether the new solution dominates the parent or not
            rel = get_relation(parent, off)

            # if indifferent we add both
            if rel == 0:
                survivors.extend([parent, off])

            # if offspring dominates parent
            elif rel == -1:
                survivors.append(off)

            # if parent dominates offspring
            else:
                survivors.append(parent)

        # create the population
        survivors = Population.create(*survivors)

        # perform a survival to reduce to pop size
        self.pop[I] = RankAndCrowdingSurvival().do(self.problem,
                                                   survivors,
                                                   n_survive=len(I))
Beispiel #16
0
 def _social_best(self):
     return Population.create(*[self.opt] * len(self.pop))
Beispiel #17
0
    def step(self):

        # initialize all ants to be used in this iteration
        ants = []
        for k in range(self.n_ants):
            ant = self.ant()
            ant._initialize(self.problem, self.pheromones)
            ants.append(ant)

        active = list(range(self.n_ants))

        while len(active) > 0:

            for k in active:
                ant = ants[k]

                if ant.has_next():
                    ant.next()

                    if self.local_update:
                        e = ant.last()
                        if e is None or e.pheromone is None:
                            raise Exception(
                                "For a local update the ant has to set the pheromones when notified."
                            )
                        else:
                            self.pheromones.set(
                                e.key,
                                self.pheromones.get(e.key) * ant.alpha +
                                e.pheromone * ant.alpha)
                            # self.pheromones.update(e.key, e.pheromone * ant.alpha)

                else:
                    ant.finalize()
                    active = [i for i in active if i != k]

        colony = Population.create(*ants)

        # this evaluation can be disabled or faked if evaluate_each_ant is false - then the finalize method of the
        # ant has to set the objective and/or constraint values accordingly
        self.evaluator.eval(self.problem, colony)
        set_cv(colony)
        set_feasibility(colony)

        # set the current best including the new colony
        opt = FitnessSurvival().do(problem, Population.merge(colony, self.opt),
                                   1)

        # do the evaporation after this iteration
        self.pheromones.evaporate()

        # select the ants to be used for the global pheromone update
        if self.global_update == "all":
            ants_to_update = colony
        elif self.global_update == "it-best":
            ants_to_update = FitnessSurvival().do(problem, colony, 1)
        elif self.global_update == "best":
            ants_to_update = self.opt
        else:
            raise Exception(
                "Unknown value for global updating the pheromones!")

        # now spread the pheromones for each ant depending on performance
        for ant in ants_to_update:
            for e in ant.path:
                if e.pheromone is None:
                    raise Exception(
                        "The ant has to set the pheromone of each entry in the path."
                    )
                else:
                    self.pheromones.update(e.key, e.pheromone * pheromones.rho)

        self.pop, self.off = colony, colony
        self.opt = opt
Beispiel #18
0
 def _initialize_infill(self, **kwargs):
     return Population.create(self.x0)
Beispiel #19
0
def test_update_ca(ref_dirs, evaluator):
    problem = C1DTLZ3(n_var=12, n_obj=3)
    ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'preCA.x'))
    CA = Population.create(ca_x)
    evaluator.eval(problem, CA)

    da_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'preDA.x'))
    DA = Population.create(da_x)
    evaluator.eval(problem, DA)

    off_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'offspring.x'))
    off = Population.create(off_x)
    evaluator.eval(problem, off)

    post_ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz3', 'case3', 'postCA.x'))
    true_pCA = Population.create(post_ca_x)
    evaluator.eval(problem, true_pCA)

    survival = CADASurvival(ref_dirs)
    mixed = Population.merge(CA, off)
    survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0)

    pCA = survival._updateCA(mixed, len(ref_dirs))

    pX = set([tuple(x) for x in pCA.get("X")])
    tpX = set([tuple(x) for x in true_pCA.get("X")])
    assert pX == tpX

    problem = C1DTLZ1(n_var=9, n_obj=3)
    ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz1', 'preCA.x'))
    CA = Population.create(ca_x)
    evaluator.eval(problem, CA)

    da_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz1', 'preDA.x'))
    DA = Population.create(da_x)
    evaluator.eval(problem, DA)

    off_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz1', 'offspring.x'))
    off = Population.create(off_x)
    evaluator.eval(problem, off)

    post_ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c1dtlz1', 'postCA.x'))
    true_pCA = Population.create(post_ca_x)
    evaluator.eval(problem, true_pCA)

    survival = CADASurvival(ref_dirs)
    mixed = Population.merge(CA, off)
    survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0)

    pCA = survival._updateCA(mixed, len(ref_dirs))

    pX = set([tuple(x) for x in pCA.get("X")])
    tpX = set([tuple(x) for x in true_pCA.get("X")])
    assert pX == tpX

    problem = C3DTLZ4(n_var=12, n_obj=3)
    ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case1', 'preCA.x'))
    CA = Population.create(ca_x)
    evaluator.eval(problem, CA)

    da_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case1', 'preDA.x'))
    DA = Population.create(da_x)
    evaluator.eval(problem, DA)

    off_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case1', 'offspring.x'))
    off = Population.create(off_x)
    evaluator.eval(problem, off)

    post_ca_x = np.loadtxt(path_to_test_resource('ctaea', 'c3dtlz4', 'case1', 'postCA.x'))
    true_pCA = Population.create(post_ca_x)
    evaluator.eval(problem, true_pCA)

    survival = CADASurvival(ref_dirs)
    mixed = Population.merge(CA, off)
    survival.ideal_point = np.min(np.vstack((DA.get("F"), mixed.get("F"))), axis=0)

    pCA = survival._updateCA(mixed, len(ref_dirs))

    pX = set([tuple(x) for x in pCA.get("X")])
    tpX = set([tuple(x) for x in true_pCA.get("X")])
    assert pX == tpX
Beispiel #20
0
    def _advance(self, **kwargs):
        repair, crossover, mutation = self.repair, self.mating.crossover, self.mating.mutation

        pc_pop = self.pc_pop.copy(deep=True)
        npc_pop = self.npc_pop.copy(deep=True)

        ##############################################################
        # PC evolving
        ##############################################################

        # Normalise both poulations according to the PC individuals
        pc_pop, npc_pop = normalize_bothpop(pc_pop, npc_pop)

        PCObj = pc_pop.get("F")
        NPCObj = npc_pop.get("F")
        pc_size = PCObj.shape[0]
        npc_size = NPCObj.shape[0]

        ######################################################
        # Calculate the Euclidean distance among individuals
        ######################################################
        d = np.zeros((pc_size, pc_size))
        d = cdist(PCObj, PCObj, 'euclidean')
        d[d == 0] = np.inf

        # Determine the size of the niche
        if pc_size == 1:
            radius = 0
        else:
            radius = determine_radius(d, pc_size, self.pc_capacity)

        # calculate the radius for individual exploration
        r = pc_size / self.pc_capacity * radius

        ########################################################
        # find the promising individuals in PC for exploration
        ########################################################

        # promising_num: record how many promising individuals in PC
        promising_num = 0
        # count: record how many NPC individuals are located in each PC individual's niche
        count = np.array([])

        d2 = np.zeros((pc_size, npc_size))
        d2 = cdist(PCObj, NPCObj, 'euclidean')

        # Count of True elements in each row (each individual in PC) of 2D Numpy Array
        count = np.count_nonzero(d2 <= r, axis=1)

        # Check if the niche has no NPC individual or has only one NPC individual
        # Record the indices of promising individuals.
        # Since np.nonzero() returns a tuple of arrays, we change the type of promising_index to a numpy.ndarray.
        promising_index = np.nonzero(count <= 1)
        promising_index = np.asarray(promising_index).flatten()

        # Record total number of promising individuals in PC for exploration
        promising_num = len(promising_index)

        ########################################
        # explore these promising individuals
        ########################################

        original_size = pc_size
        off = Individual()

        if promising_num > 0:
            for i in range(promising_num):
                if original_size > 1:
                    parents = Population.new(2)

                    # The explored individual is considered as one parent
                    parents[0] = pc_pop[promising_index[i]]

                    # The remaining parent will be selected randomly from the PC population
                    rnd = np.random.permutation(pc_size)

                    for j in rnd:
                        if j != promising_index[i]:
                            parents[1] = pc_pop[j]
                            break

                    index = np.array([0, 1])
                    parents_shape = index[None, :]

                    # do recombination and create an offspring
                    off = crossover.do(self.problem, parents, parents_shape)[0]

                else:
                    off = pc_pop[0]

                # mutation
                off = Population.create(off)
                off = mutation.do(self.problem, off)

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

                # update the PC population by the offspring
                self.pc_pop = update_PCpop(self.pc_pop, off)

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

                # update at most one solution in NPC population
                self.npc_pop = update_NPCpop(self.npc_pop, off, self.ideal,
                                             self.ref_dirs, self.decomp)

        ########################################################
        # NPC evolution based on MOEA/D
        ########################################################

        # iterate for each member of the population in random order
        for i in np.random.permutation(len(self.npc_pop)):
            # get the parents using the neighborhood selection
            P = self.selection.do(self.npc_pop,
                                  1,
                                  self.mating.crossover.n_parents,
                                  k=[i])

            # perform a mating using the default operators (recombination & mutation) - if more than one offspring just pick the first
            off = self.mating.do(self.problem, self.npc_pop, 1, parents=P)[0]

            off = Population.create(off)

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

            # update the PC population by the offspring
            self.pc_pop = update_PCpop(self.pc_pop, off)

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

            # now actually do the replacement of the individual is better
            self.npc_pop = self._replace(i, off)

        ########################################################
        # population maintenance operation in the PC evolution
        ########################################################

        current_pop = Population.merge(self.pc_pop, self.npc_pop)
        current_pop = Population.merge(current_pop, self.pop)

        # filter duplicate in the population
        pc_pop = self.eliminate_duplicates.do(current_pop)

        pc_size = len(pc_pop)

        if (pc_size > self.pc_capacity):

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

            fronts, rank = NonDominatedSorting().do(pc_objs, return_rank=True)
            front_0_index = fronts[0]

            # put the nondominated individuals of the NPC population into the PC population
            self.pc_pop = pc_pop[front_0_index]

            if len(self.pc_pop) > self.pc_capacity:
                self.pc_pop = maintain_PCpop(self.pc_pop, self.pc_capacity)

        self.pop = self.pc_pop.copy(deep=True)
Beispiel #21
0
    def _advance(self, **kwargs):
        problem, evaluator = self.problem, self.evaluator

        # add the box constraints defined in the problem
        bounds = None
        if self.use_bounds:

            xl, xu = self.problem.bounds()
            if self.with_bounds:
                bounds = np.column_stack([xl, xu])
            else:
                if xl is not None or xu is not None:
                    raise Exception(
                        f"Error: Boundary constraints can not be handled by {self.method}"
                    )

        # define the actual constraints if supported by the algorithm
        constr = []
        if self.use_constr:

            constr = [LinearConstraint(np.eye(self.problem.n_var), xl, xu)]

            if problem.has_constraints():

                if self.with_constr:

                    def fun_constr(x):
                        g, cv = problem.evaluate(x,
                                                 return_values_of=["G", "CV"])
                        return cv[0]

                    non_lin_constr = NonlinearConstraint(
                        fun_constr, -float("inf"), 0)

                    constr.append(non_lin_constr)

                else:
                    raise Exception(
                        f"Error: Constraint handling is not supported by {self.method}"
                    )

        # the objective function to be optimized and add gradients if available
        if self.estm_gradients:
            jac = None

            def fun_obj(x):
                f = problem.evaluate(x, return_values_of=["F"])[0]
                evaluator.n_eval += 1
                return f

        else:
            jac = True

            def fun_obj(x):
                f, df = problem.evaluate(x, return_values_of=["F", "dF"])

                if df is None:
                    raise Exception(
                        "If the gradient shall not be estimate, please set out['dF'] in _evaluate. "
                    )

                evaluator.n_eval += 1
                return f[0], df[0]

        # the arguments to be used
        kwargs = dict(args=(),
                      method=self.method,
                      bounds=bounds,
                      constraints=constr,
                      jac=jac,
                      options=self.options)

        # the starting solution found by sampling beforehand
        x0 = self.opt[0].X

        # actually run the optimization
        if not self.show_warnings:
            warnings.simplefilter("ignore")
        res = scipy_minimize(fun_obj, x0, **kwargs)

        opt = Population.create(Individual(X=res.x))
        self.evaluator.eval(self.problem, opt, algorithm=self)

        self.pop, self.off = opt, opt

        self.termination.force_termination = True

        if hasattr("res", "nit"):
            self.n_gen = res.nit + 1
Beispiel #22
0
 def do(self, problem, *args, **kwargs):
     pop = Population.create(*args)
     parents = np.arange(len(args))[None, :]
     return self.crossover.do(problem, pop, parents, **kwargs)