示例#1
0
        def zoom(alpha_low, alpha_high, max_iter=100):

            while True:

                _alpha = (alpha_high.get("alpha") + alpha_low.get("alpha")) / 2
                _point = Individual(X=_alpha)
                evaluator.eval(problem, _point, evaluate_values_of=["F", "CV"])

                if _point.F[
                        0] > sol_F + self.c1 * _alpha * sol_dF @ direction or _point.F[
                            0] > alpha_low.F[0]:
                    alpha_high = _point
                else:
                    evaluator.eval(problem, _point, evaluate_values_of=["dF"])
                    point_dF = _point.get("dF")[0]

                    if np.abs(point_dF
                              @ direction) <= -self.c2 * sol_dF @ direction:
                        return _point

                    if (point_dF @ direction) * (alpha_high.get("alpha") -
                                                 alpha_low.get("alpha")) >= 0:
                        alpha_high = alpha_low

                    alpha_low = _point
示例#2
0
文件: line.py 项目: msu-coinlab/pymoo
class LineSearch(Algorithm):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.point, self.direction = None, None

    def setup(self, problem, point=None, direction=None, **kwargs):
        super().setup(problem, **kwargs)

        msg = "Only problems with one objective and no constraints can be solved using a line search!"
        assert not problem.has_constraints() and problem.n_obj == 1, msg

        assert point is not None, "You have to define a starting point for the algorithm"
        self.point = point

        assert direction is not None, "You have to define a direction point for the algorithm"
        self.direction = direction

        return self

    def _initialize_infill(self):

        # x could be a vector or an individual
        if isinstance(self.point, np.ndarray):
            self.point = Individual(X=self.point)

        # make sure it is evaluated - if not yet also get the gradient
        if self.point.get("F") is None:
            self.evaluator.eval(self.problem, self.point, algorithm=self)

        self.infill = self.point
示例#3
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)
示例#4
0
    def _infill(self):

        problem, evaluator = self.problem, self.evaluator
        evaluator.skip_already_evaluated = False

        sol, direction = self.problem.point, self.problem.direction

        # the function value and gradient of the initial solution
        sol.set("alpha", 0.0)
        sol_F, sol_dF = sol.F[0], sol.get("dF")[0]

        def zoom(alpha_low, alpha_high, max_iter=100):

            while True:

                _alpha = (alpha_high.get("alpha") + alpha_low.get("alpha")) / 2
                _point = Individual(X=_alpha)
                evaluator.eval(problem, _point, evaluate_values_of=["F", "CV"])

                if _point.F[
                        0] > sol_F + self.c1 * _alpha * sol_dF @ direction or _point.F[
                            0] > alpha_low.F[0]:
                    alpha_high = _point
                else:
                    evaluator.eval(problem, _point, evaluate_values_of=["dF"])
                    point_dF = _point.get("dF")[0]

                    if np.abs(point_dF
                              @ direction) <= -self.c2 * sol_dF @ direction:
                        return _point

                    if (point_dF @ direction) * (alpha_high.get("alpha") -
                                                 alpha_low.get("alpha")) >= 0:
                        alpha_high = alpha_low

                    alpha_low = _point

        last = sol

        alpha = 1.0
        current = Individual(X=alpha)

        for i in range(1, self.max_iter + 1):

            # evaluate the solutions
            evaluator.eval(problem, current, evaluate_values_of=["F", "CV"])

            # get the values from the solution to be used to evaluate the conditions
            F, dF, _F = last.F[0], last.get("dF")[0], current.F[0]

            # if the wolfe condition is violate we have found our upper bound
            if _F > sol_F + self.c1 * sol_dF @ direction or (i > 1
                                                             and F >= _F):
                return zoom(last, current)

            # for the other condition we need the gradient information
            evaluator.eval(problem, current, evaluate_values_of=["dF"])
            _dF = current.get("dF")[0]

            if np.abs(_dF @ direction) <= -self.c2 * sol_dF @ direction:
                return current

            if _dF @ direction >= 0:
                return zoom(current, last)

            alpha = 2 * alpha
            last = current
            current = Individual(X=alpha)

        return current
示例#5
0
def wolfe_line_search(problem,
                      sol,
                      direction,
                      c1=1e-4,
                      c2=0.9,
                      max_iter=10,
                      evaluator=None):
    # initialize the evaluator to be used (this will make sure evaluations are counted)
    evaluator = evaluator if evaluator is not None else Evaluator()
    evaluator.skip_already_evaluated = False

    # the function value and gradient of the initial solution
    sol.set("alpha", 0.0)
    sol_F, sol_dF = sol.F[0], sol.get("dF")[0]

    def zoom(alpha_low, alpha_high, max_iter=100):

        while True:

            _alpha = (alpha_high.get("alpha") + alpha_low.get("alpha")) / 2
            _point = Individual(X=sol.X + _alpha * direction, alpha=_alpha)
            evaluator.eval(problem, _point, evaluate_values_of=["F", "CV"])

            if _point.F[
                    0] > sol_F + c1 * _alpha * sol_dF @ direction or _point.F[
                        0] > alpha_low.F[0]:
                alpha_high = _point
            else:
                evaluator.eval(problem, _point, evaluate_values_of=["dF"])
                point_dF = _point.get("dF")[0]

                if np.abs(point_dF @ direction) <= -c2 * sol_dF @ direction:
                    return _point

                if (point_dF @ direction) * (alpha_high.get("alpha") -
                                             alpha_low.get("alpha")) >= 0:
                    alpha_high = alpha_low

                alpha_low = _point

    last = sol

    alpha = 1.0
    current = Individual(X=sol.X + alpha * direction, alpha=alpha)

    for i in range(1, max_iter + 1):

        # evaluate the solutions
        evaluator.eval(problem, current, evaluate_values_of=["F", "CV"])

        # get the values from the solution to be used to evaluate the conditions
        F, dF, _F = last.F[0], last.get("dF")[0], current.F[0]

        # if the wolfe condition is violate we have found our upper bound
        if _F > sol_F + c1 * sol_dF @ direction or (i > 1 and F >= _F):
            return zoom(last, current)

        # for the other condition we need the gradient information
        evaluator.eval(problem, current, evaluate_values_of=["dF"])
        _dF = current.get("dF")[0]

        if np.abs(_dF @ direction) <= -c2 * sol_dF @ direction:
            return current

        if _dF @ direction >= 0:
            return zoom(current, last)

        alpha = 2 * alpha
        last = current
        current = Individual(X=sol.X + alpha * direction, alpha=alpha)

    return current