def test_survival(self): problem = DTLZ2(n_obj=3) for k in range(1, 11): print("TEST RVEA GEN", k) ref_dirs = np.loadtxt( path_to_test_resources('rvea', f"ref_dirs_{k}.txt")) F = np.loadtxt(path_to_test_resources('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, len(pop), algorithm=algorithm, return_indices=True) apd = pop[survivors].get("apd") correct_apd = np.loadtxt( path_to_test_resources('rvea', f"apd_{k}.txt")) np.testing.assert_allclose(apd, correct_apd)
def _initialize(self): # ! get the initial population - different ways are possible # provide a whole population object - (individuals might be already evaluated) if isinstance(self.sampling, Population): pop = self.sampling else: pop = Population(0, individual=self.individual) if isinstance(self.sampling, np.ndarray): pop = pop.new("X", self.sampling) else: pop = self.sampling.do(self.problem, self.pop_size, pop=pop, algorithm=self) # repair all solutions that are not already evaluated if self.repair: I = [k for k in range(len(pop)) if pop[k].F is None] pop = self.repair.do(self.problem, pop[I], algorithm=self) # then evaluate using the objective function self.evaluator.eval(self.problem, pop, algorithm=self) # that call is a dummy survival to set attributes that are necessary for the mating selection if self.survival: pop = self.survival.do(self.problem, pop, len(pop), algorithm=self) self.pop = pop
def do(self, problem, pop, n_offsprings, **kwargs): X, F, G = pop.get("X", "F", "G") xl, xu = problem.bounds() # defining a params dict for the parameters to be sent to the API DATA = { 'X': numpy_to_json(X), 'F': numpy_to_json(F), 'xl': numpy_to_json(xl), 'xu': numpy_to_json(xu), } if problem.has_constraints(): DATA['G'] = numpy_to_json(G) DATA = {**DATA, 'n_infills': n_offsprings, **self.params} # sending get request and saving the response as response object r = requests.post(url=f"{self.url}/{self.endpoint}", json=json.dumps(DATA)) # extracting data in json format resp = r.json() if not resp["success"]: raise Exception(f"ERROR during remote call: {resp['error']}") X = np.array(resp["X"]) return Population.new(X=X)
def _initialize(self): # ! get the initial population - different ways are possible # provide a whole population object - (individuals might be already evaluated) if isinstance(self.sampling, Population): pop = self.sampling else: pop = Population(0, individual=self.individual) if isinstance(self.sampling, np.ndarray): pop = pop.new("X", self.sampling) else: pop = self.sampling.sample(self.problem, pop, self.pop_size, algorithm=self) # repair in case it is necessary if self.func_repair: pop = self.func_repair(self.problem, pop, algorithm=self) # in case the initial population was not evaluated if np.any(pop.collect(lambda ind: ind.F is None, as_numpy_array=True)): self.evaluator.eval(self.problem, pop, algorithm=self) # that call is a dummy survival to set attributes that are necessary for the mating selection if self.survival: pop = self.survival.do(self.problem, pop, self.pop_size, algorithm=self) return pop
def do(self, problem, n_samples, pop=Population(), **kwargs): """ Sample new points with problem information if necessary. Parameters ---------- problem : :class:`~pymoo.model.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.model.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)
def _new_crossover_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 print(X.shape) if len(X.shape) > 3: X = X.reshape(offspring, X.shape[-2], X.shape[-1]) else: X = X.reshape(-1, X.shape[-1]) # create a population object off = Population.new("X", X) return off
def _each_iteration_samoo(self, X, **kwargs): self.archive = self.samoo_evaluator.eval(problem=self.samoo_problem, x=X, archive=self.archive) temp_pop = Population(0, individual=Individual()) temp_pop = temp_pop.new("X", self.archive['x'], "F", self.archive['f'], "CV", self.archive['cv'], "G", self.archive['g'], "feasible", self.archive['feasible_index']) self.func_eval = self.archive['x'].shape[0] return temp_pop
def test_preevaluated(self): evaluator = Evaluator() pop = Population.new("X", X) evaluator.eval(problem, pop) pop[range(30)].set("F", None) evaluator = Evaluator() evaluator.eval(problem, pop) np.testing.assert_allclose(F, pop.get("F")) self.assertTrue(evaluator.n_eval == 30)
def solve(self, X_init, Y_init): ''' Solve the real multi-objective problem from initial data. Parameters ---------- X_init: np.array Initial design variables. Y_init: np.array Initial performance values. Returns ------- X_next: np.array Proposed design samples to evaluate next. Y_prediction: tuple (None, None) because there is no prediction in MOO algorithms. ''' # forward transformation X_init = self.transformation.do(X_init) # convert maximization to minimization X, Y = X_init, Y_init.copy() obj_type = self.real_problem.obj_type if isinstance(obj_type, str): obj_type = [obj_type] * Y.shape[1] assert isinstance(obj_type, Iterable) maxm_idx = np.array(obj_type) == 'max' Y[:, maxm_idx] = -Y[:, maxm_idx] # construct population pop = Population(0, individual=Individual()) pop = pop.new('X', X) pop.set('F', Y) pop.set('CV', np.zeros([X.shape[0], 1])) # assume input samples are all feasible off = self._solve(pop) X_next = off.get('X')[:self.batch_size] # backward transformation X_next = self.transformation.undo(X_next) return X_next, (None, None)
def _next(self): if self.pop is None or len(self.pop) == 0: X = next(self.es) else: F = self.pop.get("F")[:, 0].tolist() # # if self.problem.n_constr > 0: # G = self.pop.get("G").tolist() # self.al.set_coefficients(F, G) # # x = self.es.gi_frame.f_locals["es"].ask(1, sigma_fac=0)[0] # ind = Individual(X=x) # self.evaluator.eval(self.problem, ind, algorithm=self) # self.al.update(ind.F[0], ind.G) # # F = F + sum(self.al(G)) if not self.send_array_to_yield: F = F[0] try: X = self.es.send(F) except StopIteration: X = None self.termination.force_termination = True if X is not None: X = np.array(X) self.send_array_to_yield = X.ndim > 1 X = np.atleast_2d(X) # evaluate the population self.pop = Population.new("X", X) self.evaluator.eval(self.problem, self.pop, algorithm=self) # set infeasible individual's objective values to np.nan - then CMAES can handle it for ind in self.pop: if not ind.feasible[0]: ind.F[0] = np.nan
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
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
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: pop = Population(0, individual=self.individual) if isinstance(self.sampling, np.ndarray): pop = pop.new("X", self.sampling) else: pop = self.sampling.do(problem, n_samples, pop=pop, **kwargs) # repair all solutions that are not already evaluated if self.repair: I = [k for k in range(len(pop)) if pop[k].F is None] pop = self.repair.do(problem, pop[I], **kwargs) if self.eliminate_duplicates is not None: pop = self.eliminate_duplicates.do(pop) return pop
def _do(self, problem, pop, n_offsprings, parents=None, **kwargs): if parents is None: raise Exception("For levy flights please provide the parents!") X, F = pop.get("X", "F") xl, xu = problem.bounds() a, b, c = parents.T # the direction to be used for improvement direction = (X[b] - X[c]) # get random levy values to be used for the step size levy = self.levy.do(size=(len(parents), 1)) # levy = np.random.normal(0, 1, size=(len(parents), problem.n_var)) _X = X[a] + (xu - xl) / self.alpha * levy * direction _X = ToBoundOutOfBoundsRepair().do(problem, _X) # _X = InversePenaltyOutOfBoundsRepair().do(problem, _X, P=X[a]) return Population.new(X=_X, index=a)
def test_evaluate_pop(self): evaluator = Evaluator() pop = Population.new("X", X) evaluator.eval(problem, pop) np.testing.assert_allclose(F, pop.get("F")) self.assertTrue(evaluator.n_eval == len(X))
import numpy as np from pymoo.algorithms.nsga2 import NSGA2 from pymoo.factory import get_problem from pymoo.model.evaluator import Evaluator from pymoo.model.population import Population from pymoo.optimize import minimize problem = get_problem("zdt2") # create initial data and set to the population object X = np.random.random((300, problem.n_var)) pop = Population.new("X", X) Evaluator().eval(problem, pop) algorithm = NSGA2(pop_size=100, sampling=pop) minimize(problem, algorithm, ('n_gen', 10), seed=1, verbose=True)