def __init__(self, problem, epsilon=None, evaluator=None) -> None: super().__init__() self.epsilon = epsilon if self.epsilon is None: self.epsilon = np.sqrt(np.finfo(float).eps) self.problem = problem self.evaluator = evaluator if evaluator is not None else Evaluator()
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 initialize(self, problem, termination=None, seed=None, pf=True, evaluator=None, verbose=False, save_history=False, **kwargs): # if this run should be verbose or not self.verbose = verbose # set the problem that is optimized for the current run self.problem = problem # the termination criterion to be used to stop the algorithm if self.termination is None: self.termination = termination # if nothing given fall back to default if self.termination is None: self.termination = self.default_termination # set the random seed in the algorithm object self.seed = seed if self.seed is None: self.seed = np.random.randint(0, 10000000) np.random.seed(self.seed) self.pf = pf # by default make sure an evaluator exists if nothing is passed if evaluator is None: evaluator = Evaluator() self.evaluator = evaluator # whether the history should be stored or not self.save_history = save_history # other run dependent variables that are reset self.n_gen = None self.history = [] self.pop = None self.opt = None
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
def setUpClass(cls): cls.ref_dirs = np.loadtxt(path_to_test_resources('ctaea', 'weights.txt')) cls.evaluator = Evaluator()
def initialize( self, problem, pf=True, evaluator=None, # START Default minimize seed=None, verbose=False, save_history=False, return_least_infeasible=False, # END Default minimize # START Overwrite by minimize termination=None, callback=None, display=None, # END Overwrite by minimize **kwargs): # set the problem that is optimized for the current run self.problem = problem # set the provided pareto front self.pf = pf # by default make sure an evaluator exists if nothing is passed if evaluator is None: evaluator = Evaluator() self.evaluator = evaluator # ! # START Default minimize # ! # if this run should be verbose or not self.verbose = verbose # whether the least infeasible should be returned or not self.return_least_infeasible = return_least_infeasible # whether the history should be stored or not self.save_history = save_history # set the random seed in the algorithm object self.seed = seed if self.seed is None: self.seed = np.random.randint(0, 10000000) np.random.seed(self.seed) # ! # END Default minimize # ! # ! # START Overwrite by minimize # ! # the termination criterion to be used to stop the algorithm if self.termination is None: self.termination = termination # if nothing given fall back to default if self.termination is None: self.termination = self.default_termination if callback is not None: self.callback = callback if display is not None: self.display = display # ! # END Overwrite by minimize # ! # by default the algorithm as not terminated self.has_terminated = False # other run dependent variables that are reset self.n_gen = 1 self.history = [] self.pop = Population() self.opt = None
run = params[id] name = names[id] output = output + name if not os.path.exists(output): os.makedirs(output) print(output) i = 0 for algorithm, problem, run, points, n in run: try: problem = problem() except TypeError: pass points = np.array(points) eval = Evaluator(100 * n_gen) start_time = time.time() X, F, G = algorithm.solve(problem, evaluator=eval, seed=run) print("--- %s seconds ---" % (time.time() - start_time)) fname = os.path.join(output, problem.name() + "_" + str(i)) print(fname) np.savetxt(fname + ".out", F) if id <= 5: metric_time = time.time() igd, hv = RMetric(curr_pop=F, whole_pop=F, ref_points=points, problem=problem).calc() results.append(np.array([run, igd, hv])) print(igd, " - ", hv) print("--- %s seconds ---" % (time.time() - metric_time))
def solve( self, problem, evaluator, seed=1, return_only_feasible=True, return_only_non_dominated=True, history=None, ): """ 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 evaluator: 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. return_only_feasible : bool If true, only feasible solutions are returned. return_only_non_dominated : bool If true, only the non dominated solutions are returned. Otherwise, it might be - dependend on the algorithm - the final population Returns ------- X: matrix Design space F: matrix Objective space G: matrix Constraint space """ # set the random seed for generator pymoo.rand.random.seed(seed) # just to be sure also for the others seed = pymoo.rand.random.randint(0, 100000) random.seed(seed) np.random.seed(seed) # this allows to provide only an integer instead of an evaluator object if not isinstance(evaluator, Evaluator): evaluator = Evaluator(evaluator) # call the algorithm to solve the problem X, F, G = self._solve(problem, evaluator) if return_only_feasible: if G is not None and G.shape[0] == len(F) and G.shape[1] > 0: cv = Problem.calc_constraint_violation(G)[:, 0] X = X[cv <= 0, :] F = F[cv <= 0, :] if G is not None: G = G[cv <= 0, :] if return_only_non_dominated: idx_non_dom = NonDominatedRank.calc_as_fronts(F, G)[0] X = X[idx_non_dom, :] F = F[idx_non_dom, :] if G is not None: G = G[idx_non_dom, :] return X, F, G
def test_evaluate_array_single(self): evaluator = Evaluator(evaluate_values_of=["F", "CV"]) _F, _CV = evaluator.eval(problem, X[0]) np.testing.assert_allclose(F[0], _F) self.assertTrue(evaluator.n_eval == 1)
def _initialize(self): self.evaluator = Evaluator( skip_already_evaluated=False ) if self.evaluate_each_ant else MockEvaluator() self.opt = Population() self._next()
class ACO(Algorithm): def __init__(self, ant, pheromones, n_ants=10, global_update='best', local_update=True, evaluate_each_ant=True, display=ACODisplay(), **kwargs): """ Parameters ---------- ant : class An objective defining the behavior of each ant pheromones : class The pheromone implementation storing the amount of pheromones on each edge, the evaporation and update. n_ants : int Number of ants to be used each iteration global_update : {'all', 'it-best', 'best'} """ super().__init__(display=display, **kwargs) # make the ant always to be a function being able to call if not callable(ant): proto = deepcopy(ant) def new_ant(): return deepcopy(proto) ant = new_ant self.ant = ant self.pheromones = pheromones self.n_ants = n_ants self.global_update = global_update self.local_update = local_update self.evaluate_each_ant = evaluate_each_ant def _initialize(self): self.evaluator = Evaluator( skip_already_evaluated=False ) if self.evaluate_each_ant else MockEvaluator() self.opt = Population() self._next() def _next(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 def _set_optimum(self, **kwargs): pass
def setup(self, problem, # START Overwrite by minimize termination=None, callback=None, display=None, # END Overwrite by minimize # START Default minimize seed=None, verbose=False, save_history=False, return_least_infeasible=False, # END Default minimize pf=True, evaluator=None, **kwargs): # set the problem that is optimized for the current run self.problem = problem # set the provided pareto front self.pf = pf # by default make sure an evaluator exists if nothing is passed if evaluator is None: evaluator = Evaluator() self.evaluator = evaluator # ! # START Default minimize # ! # if this run should be verbose or not self.verbose = verbose # whether the least infeasible should be returned or not self.return_least_infeasible = return_least_infeasible # whether the history should be stored or not self.save_history = save_history # set the random seed in the algorithm object self.seed = seed if self.seed is None: self.seed = np.random.randint(0, 10000000) # set the random seed for Python and Numpy methods random.seed(self.seed) np.random.seed(self.seed) # ! # END Default minimize # ! # ! # START Overwrite by minimize # ! # the termination criterion to be used to stop the algorithm if self.termination is None: self.termination = termination_from_tuple(termination) # if nothing given fall back to default if self.termination is None: self.termination = self.default_termination if callback is not None: self.callback = callback if display is not None: self.display = display # ! # END Overwrite by minimize # ! return self
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") X = np.random.random((300, problem.n_var)) algorithm = NSGA2(pop_size=100, sampling=X) minimize(problem, algorithm, ('n_gen', 10), seed=1, verbose=True) 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)
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))
def test_evaluate_individual(self): evaluator = Evaluator() ind = evaluator.eval(problem, Individual(X=X[0])) np.testing.assert_allclose(F[0], ind.get("F")) self.assertTrue(evaluator.n_eval == 1)
def minimize(fun, xl=None, xu=None, termination=('n_eval', 10000), n_var=None, fun_args={}, method='auto', method_args={}, seed=None, callback=None, disp=True): """ Minimization of function of one or more variables, objectives and constraints. This is used as a convenience function to execute several algorithms with default settings which turned out to work for a test problems. However, evolutionary computations utilizes the idea of customizing a meta-algorithm. Customizing the algorithm using the object oriented interface is recommended to improve the convergence. Parameters ---------- fun : callable A function that gets X which is a 2d array as input. Each row represents a solution to evaluate and each column a variable. The function needs to return also the same number of rows and each column is one objective to optimize. In case of constraints, a second 2d array can be returned. xl : numpy.array or number The lower boundaries of variables as a 1d array xu : numpy.array or number The upper boundaries of variables as a 1d array n_var : int If xl or xu is only a number, this is used to create the boundary numpy arrays. Other it remains unused. termination : tuple The termination criterium that is used to stop the algorithm when the result is satisfying. fun_args : dict Additional arguments if necessary to evaluate the solutions (constants, random seed, ...) method : string Algorithm that is used to solve the problem. callback : callable, optional Called after each iteration, as ``callback(D)``, where ``D`` is a dictionary with algorithm information, such as the current design, objective and constraint space. disp : bool Whether to display each generation the current result or not. Returns ------- res : Result The optimization result represented as a ``Result`` object. """ problem = None if isinstance(fun, Problem): problem = fun elif callable(fun): if xl is None or xu is None: raise Exception( "Please provide lower and upper bounds for the problem.") if isinstance(xl, (int, float)): xl = xl * np.ones(n_var) if isinstance(xu, (int, float)): xu = xu * np.ones(n_var) # determine through a test evaluation details about the problem n_var = xl.shape[0] n_obj = -1 n_constr = 0 res = fun(xl[None, :], **fun_args) if isinstance(res, tuple): # if there are constraints it is a tuple of length two if len(res) > 1: n_constr = res[1].shape[1] n_obj = res[0].shape[1] else: n_obj = res.shape[1] # create an optimization problem given the function properties class OptimizationProblem(Problem): def __init__(self): Problem.__init__(self) self.n_var = n_var self.n_constr = n_constr self.n_obj = n_obj self.func = self._evaluate self.xl = xl self.xu = xu def _evaluate(self, x, f, g=None): if g is None: f[:, :] = fun(x, **fun_args) else: f[:, :], g[:, :] = fun(x, **fun_args) problem = OptimizationProblem() else: raise Exception( "fun arguments needs to be either a function or an object of the class problem." ) # create an evaluator defined by the termination criterium termination_criterium, termination_val = termination if termination_criterium == 'n_eval': evaluator = Evaluator(termination_val) else: raise Exception('Unknown Termination criterium: %s' % termination_criterium) return minimize_(problem, evaluator, method=method, method_args=method_args, seed=seed, callback=callback, disp=disp)
def fun(x, n): ind = Individual(X=np.copy(x)) Evaluator().eval(problem, ind) global pop pop = Population.merge(pop, ind) return ind.F[0]
def test_evaluate_array(self): evaluator = Evaluator(evaluate_values_of=["F", "CV"]) _F, _CV = evaluator.eval(problem, X) np.testing.assert_allclose(F, _F) self.assertTrue(evaluator.n_eval == len(X))