In the following different ways of loading or implementing an optimization problem in our framework are discussed.
An optimization problem can be defined by inheriting from the Problem class. In the following the definition of a simple optimization problem with one objective and two constraints is considered. The problem has two constants, const_1 and const_2 which can be modified by initiating the problem with different parameters. By default, it consists of 10 variable and the lower and upper bounds are within \([-5, 5]\) for all variables.
import autograd.numpy as anp from pymoo.model.problem import Problem class MyProblem(Problem): def __init__(self, const_1=5, const_2=0.1): # define lower and upper bounds - 1d array with length equal to number of variable xl = -5 * anp.ones(10) xu = 5 * anp.ones(10) super().__init__(n_var=10, n_obj=1, n_constr=2, xl=xl, xu=xu, evaluation_of="auto") # store custom variables needed for evaluation self.const_1 = const_1 self.const_2 = const_2 def _evaluate(self, x, out, *args, **kwargs): f = anp.sum(anp.power(x, 2) - self.const_1 * anp.cos(2 * anp.pi * x), axis=1) g1 = (x[:, 0] + x[:, 1]) - self.const_2 g2 = self.const_2 - (x[:, 2] + x[:, 3]) out["F"] = f out["G"] = anp.column_stack([g1, g2])
After creating a problem object the evaluate function can be called. The return_values_of variable can be overwritten to modify the list of returned parameters.
problem = MyProblem() F, G, CV, feasible, dF, dG = problem.evaluate(anp.random.rand(100, 10), return_values_of=["F", "G", "CV", "feasible", "dF", "dG"])
If the problem can not be executed by using matrix operations a serialized evaluation can be indicated by using the elementwise_evaluation flag. If true, then an outer loop is already implemented an x is just one individual.
class MyProblem(Problem): def __init__(self, **kwargs): super().__init__(n_var=2, n_obj=1, elementwise_evaluation=True, **kwargs) def _evaluate(self, x, out, *args, **kwargs): out["F"] = x.sum()
In our framework various test problems are already implemented and available by providing the corresponding problem name we have assigned to it. A couple of problems can be further parameterized by provided for instance the number of variables, constraints or other problem dependent constants.
from pymoo.factory import get_problem p = get_problem("dtlz1_-1", n_var=20, n_obj=5) # create a simple test problem from string p = get_problem("Ackley") # the input name is not case sensitive p = get_problem("ackley") # also input parameter can be provided directly p = get_problem("dtlz1_-1", n_var=20, n_obj=5)
We recommend defining a problem by class because this provides you all the functionalities provided by the framework, such as implementing the pareto_front function or variable types and many more. However, many frameworks define a problem just by a function which is also supported in pymoo by the get_problem_from_func which takes the evaluation function and optional the boundaries as an input.
import numpy as np from pymoo.model.problem import get_problem_from_func def my_evaluate_func(x, out, *args, **kwargs): # define the objective as x^2 f1 = np.sum(np.square(x - 2), axis=1) f2 = np.sum(np.square(x + 2), axis=1) out["F"] = np.column_stack([f1, f2]) # x^2 < 2 constraint out["G"] = np.sum(np.square(x - 1), axis=1) # load the problem from a function - define 3 variables with the same lower bound problem = get_problem_from_func(my_evaluate_func, xl=-10, xu=10, n_var=3) F, CV = problem.evaluate(np.random.rand(100, 3)) # or define a problem with varying lower and upper bounds problem = get_problem_from_func(my_evaluate_func, xl=np.array([-10, -5, -10]), xu=np.array([10, 5, 10])) F, CV = problem.evaluate(np.random.rand(100, 3))
evaluate(self, X, *args, return_values_of=’auto’, return_as_dictionary=False, **kwargs)¶
Evaluate the given problem.
The function values set as defined in the function. The constraint values are meant to be positive if infeasible. A higher positive values means “more” infeasible”. If they are 0 or negative, they will be considered as feasible what ever their value is.
A two dimensional matrix where each row is a point to evaluate and each column a variable.
If this is true than only one object, a dictionary, is returned. This contains all the results that are defined by return_values_of. Otherwise, by default a tuple as defined is returned.
- return_values_oflist of strings
You can provide a list of strings which defines the values that are returned. By default it is set to “auto” which means depending on the problem the function values or additional the constraint violation (if the problem has constraints) are returned. Otherwise, you can provide a list of values to be returned.
Allowed is [“F”, “CV”, “G”, “dF”, “dG”, “dCV”, “feasible”] where the d stands for derivative and h stands for hessian matrix.
- A dictionary, if return_as_dictionary enabled, or a list of values as defined in return_values_of.
pareto_front(self, *args, use_cache=True, exception_if_failing=True, **kwargs)¶
- argsSame problem implementation need some more information to create the Pareto front. For instance
the DTLZ problem suite generates the Pareto front by usage of the reference directions. We refer to the corresponding problem for more information.
Whether to throw an exception when generating the Pareto front has failed.
Whether to use the cache if the Pareto front has been generated beforehand.
The Pareto front of a given problem. It is only loaded or calculate the first time and then cached. For a single-objective problem only one point is returned but still in a two dimensional array.