Ejemplo n.º 1
0
    def calc(self, problem, evaluator, solution, values, eps, hessian):
        jacobian_estm, hessian_estm = self.jacobian, self.hessian

        jac_approx = Population.new(X=jacobian_estm.points(solution.X, eps))
        evaluator.eval(problem, jac_approx)

        for value in values:
            f, F = solution.get(value), jac_approx.get(value)
            dF = np.array([
                jacobian_estm.calc(f[m], F[:, m], eps)
                for m in range(F.shape[1])
            ])
            solution.set("d" + value, dF)

        # if the hessian should be calculated as well
        if hessian:
            hess_approx = Population.new(
                X=self.hessian.points(solution.X, eps))
            evaluator.eval(problem, hess_approx)

            for value in values:
                f, F, FF = solution.get(value), jac_approx.get(
                    value), hess_approx.get(value)
                ddF = np.array([
                    hessian_estm.calc(f[m], F[:, m], FF[:, m], eps)
                    for m in range(FF.shape[1])
                ])
                solution.set("dd" + value, ddF)
Ejemplo n.º 2
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)
Ejemplo n.º 3
0
    def _infill(self):
        pop, mu, _lambda = self.pop, self.pop_size, self.n_offsprings
        xl, xu = self.problem.bounds()
        X, sigma = pop.get("X", "sigma")

        # cycle through the elites individuals for create the solutions
        I = np.arange(_lambda) % mu

        # transform X and sigma to the shape of number of offsprings
        X, sigma = X[I], sigma[I]

        # copy the original sigma to sigma prime to be modified
        Xp, sigmap = np.copy(X), np.copy(sigma)

        # for the best individuals do differential variation to provide a direction to search in
        Xp[:mu - 1] = X[:mu - 1] + self.gamma * (X[0] - X[1:mu])

        # update the sigma values for elite and non-elite individuals
        sigmap[mu - 1:] = np.minimum(
            self.sigma_max, es_sigma(sigma[mu - 1:], self.tau, self.taup))

        # execute the evolutionary strategy to calculate the offspring solutions
        Xp[mu - 1:] = X[mu - 1:] + sigmap[mu - 1:] * np.random.normal(
            size=sigmap[mu - 1:].shape)

        # repair the individuals which are not feasible by sampling from sigma again
        Xp = es_mut_repair(Xp, X, sigmap, xl, xu, 10)

        # now update the sigma values of the non-elites only
        sigmap[mu:] = sigma[mu:] + self.alpha * (sigmap[mu:] - sigma[mu:])

        # create the population to proceed further
        off = Population.new(X=Xp, sigma=sigmap)

        return off
Ejemplo n.º 4
0
def test_survival():
    problem = DTLZ2(n_obj=3)

    for k in range(1, 11):
        print("TEST RVEA GEN", k)

        ref_dirs = np.loadtxt(
            path_to_test_resource('rvea', f"ref_dirs_{k}.txt"))
        F = np.loadtxt(path_to_test_resource('rvea', f"F_{k}.txt"))
        pop = Population.new(F=F)

        algorithm = RVEA(ref_dirs)
        algorithm.setup(problem, termination=('n_gen', 500))
        algorithm.n_gen = k
        algorithm.pop = pop

        survival = APDSurvival(ref_dirs)
        survivors = survival.do(problem,
                                algorithm.pop,
                                n_survive=len(pop),
                                algorithm=algorithm,
                                return_indices=True)

        apd = pop[survivors].get("apd")
        correct_apd = np.loadtxt(path_to_test_resource('rvea', f"apd_{k}.txt"))
        np.testing.assert_allclose(apd, correct_apd)
Ejemplo n.º 5
0
 def _backward(self, X, inplace=False, **kwargs):
     assert isinstance(X, np.ndarray) and X.ndim == 2
     if inplace:
         self.obj.set(self.attr, X)
         return self.obj
     else:
         return Population.new(**{self.attr: X})
Ejemplo n.º 6
0
    def _infill(self):
        pop, mu, _lambda = self.pop, self.pop_size, self.n_offsprings
        xl, xu = self.problem.bounds()
        X, sigma = pop.get("X", "sigma")

        # cycle through the elites individuals for create the solutions
        I = np.arange(_lambda) % mu

        # transform X and sigma to the shape of number of offsprings
        X, sigma = X[I], sigma[I]

        # get the sigma only of the elites to be used
        sigmap = es_intermediate_recomb(sigma)

        # calculate the new sigma based on tau and tau prime
        sigmap = np.minimum(self.sigma_max,
                            es_sigma(sigmap, self.tau, self.taup))

        # execute the evolutionary strategy to calculate the offspring solutions
        Xp = X + sigmap * np.random.normal(size=sigmap.shape)

        # if gamma is not none do the differential variation overwrite Xp and sigmap for the first mu-1 individuals
        if self.gamma is not None:
            Xp[:mu - 1] = X[:mu - 1] + self.gamma * (X[0] - X[1:mu])
            sigmap[:mu - 1] = sigma[:mu - 1]

        # if we have bounds to consider -> repair the individuals which are out of bounds
        if self.problem.has_bounds():
            Xp = es_mut_repair(Xp, X, sigmap, xl, xu, 10)

        # create the population to proceed further
        off = Population.new(X=Xp, sigma=sigmap)

        return off
Ejemplo n.º 7
0
    def do(self, problem, n_samples, pop=Population(), **kwargs):
        """
        Sample new points with problem information if necessary.

        Parameters
        ----------

        problem : :class:`~pymoo.core.problem.Problem`
            The problem to which points should be sampled. (lower and upper bounds, discrete, binary, ...)

        n_samples : int
            Number of samples

        pop : :class:`~pymoo.core.population.Population`
            The sampling results are stored in a population. The template of the population can be changed.
            If 'none' simply a numpy array is returned.

        Returns
        -------
        X : numpy.array
            Samples points in a two dimensional array

        """
        val = self._do(problem, n_samples, **kwargs)

        if pop is None:
            return val

        return Population.new("X", val)
Ejemplo n.º 8
0
    def __init__(self,
                 ref_dirs,
                 n_neighbors=20,
                 decomposition=Tchebicheff2(),
                 prob_neighbor_mating=0.9,
                 sampling=FloatRandomSampling(),
                 crossover=SimulatedBinaryCrossover(prob=1.0, eta=20),
                 mutation=PolynomialMutation(prob=None, eta=20),
                 display=MultiObjectiveDisplay(),
                 **kwargs):
        """
        Parameters
        ----------
        ref_dirs
        n_neighbors
        decomposition
        prob_neighbor_mating
        display
        kwargs
        """

        self.ref_dirs = ref_dirs
        self.pc_capacity = len(ref_dirs)
        self.pc_pop = Population.new()
        self.npc_pop = Population.new()
        self.n_neighbors = min(len(ref_dirs), n_neighbors)
        self.prob_neighbor_mating = prob_neighbor_mating
        self.decomp = decomposition

        # initialise the neighborhood of subproblems based on the distances of weight vectors
        self.neighbors = np.argsort(cdist(self.ref_dirs, self.ref_dirs),
                                    axis=1,
                                    kind='quicksort')[:, :self.n_neighbors]

        self.selection = NeighborhoodSelection(self.neighbors,
                                               prob=prob_neighbor_mating)

        super().__init__(pop_size=len(ref_dirs),
                         sampling=sampling,
                         crossover=crossover,
                         mutation=mutation,
                         eliminate_duplicates=DefaultDuplicateElimination(),
                         display=display,
                         advance_after_initialization=False,
                         **kwargs)
Ejemplo n.º 9
0
    def _local_infill(self):
        X = np.array(self.next_X)
        self.send_array_to_yield = X.ndim > 1
        X = np.atleast_2d(X)

        # evaluate the population
        self.pop = Population.new("X", self.norm.backward(X))

        return self.pop
Ejemplo n.º 10
0
def crossover(crossover,
              a,
              b,
              c=None,
              xl=0,
              xu=1,
              type_var=np.double,
              **kwargs):
    n = a.shape[0]
    _pop = Population.merge(Population.new("X", a), Population.new("X", b))
    _P = np.column_stack([np.arange(n), np.arange(n) + n])

    if c is not None:
        _pop = Population.merge(_pop, Population.new("X", c))
        _P = np.column_stack([_P, np.arange(n) + 2 * n])

    problem = get_problem_func(a.shape[1], xl, xu, type_var)(**kwargs)
    return crossover.do(problem, _pop, _P, **kwargs).get("X")
Ejemplo n.º 11
0
    def do(self, problem, pop, parents, **kwargs):
        X = pop.get("X")[parents.T].copy()

        _, n_matings, n_var = X.shape
        M = mut_binomial(n_matings, n_var, self.bias, at_least_once=True)

        Xp = X[0]
        Xp[~M] = X[1][~M]

        return Population.new(X=Xp)
Ejemplo n.º 12
0
def to_solution_set(X, F=None, G=None):
    if isinstance(X, np.ndarray):
        if X.ndim == 1:
            X = Solution(X=X, F=F, G=G)
        else:
            X = Population.new(X=X, F=F, G=G)

    if isinstance(X, Individual):
        X = SolutionSet.create(X)

    return X
Ejemplo n.º 13
0
    def do(self, problem, pop, parents, **kwargs):

        X = pop.get("X")[parents.T].copy()
        assert len(
            X.shape
        ) == 3, "Please provide a three-dimensional matrix n_parents x pop_size x n_vars."

        n_parents, n_matings, n_var = X.shape

        # a mask over matings that need to be repeated
        m = np.arange(n_matings)

        # if the user provides directly an F value to use
        F = self.F if self.F is not None else rnd_F(m)

        # prepare the out to be set
        Xp = de_differential(X[:, m], F)

        # if the problem has boundaries to be considered
        if problem.has_bounds():

            for k in range(self.n_iter):
                # find the individuals which are still infeasible
                m = is_out_of_bounds_by_problem(problem, Xp)

                F = rnd_F(m)

                # actually execute the differential equation
                Xp[m] = de_differential(X[:, m], F)

            # if still infeasible do a random initialization
            Xp = repair_random_init(Xp, X[0], *problem.bounds())

        if self.variant == "bin":
            M = mut_binomial(n_matings,
                             n_var,
                             self.CR,
                             at_least_once=self.at_least_once)
        elif self.variant == "exp":
            M = mut_exp(n_matings,
                        n_var,
                        self.CR,
                        at_least_once=self.at_least_once)
        else:
            raise Exception(f"Unknown variant: {self.variant}")

        # take the first parents (this is already a copy)
        X = X[0]

        # set the corresponding values from the donor vector
        X[M] = Xp[M]

        return Population.new("X", X)
Ejemplo n.º 14
0
def test_preevaluated():
    evaluator = Evaluator()
    pop = Population.new("X", X)
    evaluator.eval(problem, pop)

    pop[range(30)].set("evaluated", None)

    evaluator = Evaluator()
    evaluator.eval(problem, pop)

    np.testing.assert_allclose(F, pop.get("F"))
    assert evaluator.n_eval == 30
Ejemplo n.º 15
0
    def do(self, problem, pop, parents, **kwargs):
        """

        This method executes the crossover on the parents. This class wraps the implementation of the class
        that implements the crossover.

        Parameters
        ----------
        problem: class
            The problem to be solved. Provides information such as lower and upper bounds or feasibility
            conditions for custom crossovers.

        pop : Population
            The population as an object

        parents: numpy.array
            The select parents of the population for the crossover

        kwargs : dict
            Any additional data that might be necessary to perform the crossover. E.g. constants of an algorithm.

        Returns
        -------
        offsprings : Population
            The off as a matrix. n_children rows and the number of columns is equal to the variable
            length of the problem.

        """

        if self.n_parents != parents.shape[1]:
            raise ValueError(
                'Exception during crossover: Number of parents differs from defined at crossover.'
            )

        # get the design space matrix form the population and parents
        X = pop.get("X")[parents.T].copy()

        # now apply the crossover probability
        do_crossover = np.random.random(len(parents)) < self.prob

        # execute the crossover
        _X = self._do(problem, X, **kwargs)

        X[:, do_crossover, :] = _X[:, do_crossover, :]

        # flatten the array to become a 2d-array
        X = X.reshape(-1, X.shape[-1])

        # create a population object
        off = Population.new("X", X)

        return off
Ejemplo n.º 16
0
    def _infill(self):
        problem, particles, pbest = self.problem, self.particles, self.pop

        (X, V) = particles.get("X", "V")
        P_X = pbest.get("X")

        sbest = self._social_best()
        S_X = sbest.get("X")

        Xp, Vp = pso_equation(X, P_X, S_X, V, self.V_max, self.w, self.c1,
                              self.c2)

        # if the problem has boundaries to be considered
        if problem.has_bounds():

            for k in range(20):
                # find the individuals which are still infeasible
                m = is_out_of_bounds_by_problem(problem, Xp)

                # actually execute the differential equation
                Xp[m], Vp[m] = pso_equation(X[m], P_X[m], S_X[m], V[m],
                                            self.V_max, self.w, self.c1,
                                            self.c2)

            # if still infeasible do a random initialization
            Xp = repair_random_init(Xp, X, *problem.bounds())

        # create the offspring population
        off = Population.new(X=Xp, V=Vp)

        # try to improve the current best with a pertubation
        if self.pertube_best:
            k = FitnessSurvival().do(problem,
                                     pbest,
                                     n_survive=1,
                                     return_indices=True)[0]
            eta = int(np.random.uniform(20, 30))
            mutant = PolynomialMutation(eta).do(problem, pbest[[k]])[0]
            off[k].set("X", mutant.X)

        self.repair.do(problem, off)

        self.sbest = sbest.copy()

        return off
Ejemplo n.º 17
0
    def do(self, problem, n_samples, **kwargs):

        # provide a whole population object - (individuals might be already evaluated)
        if isinstance(self.sampling, Population):
            pop = self.sampling

        else:
            if isinstance(self.sampling, np.ndarray):
                pop = Population.new(X=self.sampling)
            else:
                pop = self.sampling.do(problem, n_samples, **kwargs)

        # repair all solutions that are not already evaluated
        not_eval_yet = [k for k in range(len(pop)) if pop[k].F is None]
        if len(not_eval_yet) > 0:
            pop[not_eval_yet] = self.repair.do(problem, pop[not_eval_yet],
                                               **kwargs)

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

        return pop
Ejemplo n.º 18
0
def pop_from_sampling(problem, sampling, n_initial_samples, pop=None):
    # the population type can be different - (different type of individuals)
    if pop is None:
        pop = Population()

    # provide a whole population object - (individuals might be already evaluated)
    if isinstance(sampling, Population):
        pop = sampling

    else:
        # if just an X array create a pop
        if isinstance(sampling, np.ndarray):
            pop = pop.new("X", sampling)

        elif isinstance(sampling, Sampling):
            # use the sampling
            pop = sampling.do(problem, n_initial_samples, pop=pop)

        else:
            return None

    return pop
Ejemplo n.º 19
0
def mutation(mutation, X, xl=0, xu=1, type_var=np.double, **kwargs):
    problem = get_problem_func(X.shape[1], xl, xu, type_var)(**kwargs)
    return mutation.do(problem, Population.new("X", X), **kwargs).get("X")
Ejemplo n.º 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)
Ejemplo n.º 21
0
def test_evaluate_pop():
    evaluator = Evaluator()
    pop = Population.new("X", X)
    evaluator.eval(problem, pop)
    np.testing.assert_allclose(F, pop.get("F"))
    assert evaluator.n_eval == len(X)
Ejemplo n.º 22
0
 def _local_infill(self):
     X = self.norm.backward(np.array(self.es.ask()))
     return Population.new("X", X)