Refactor class Problem
Opened this issue · 0 comments
ajnebro commented
Class Problem
in jMetalPy has the following constructor:
def __init__(self):
self.number_of_variables: int = 0
self.number_of_objectives: int = 0
self.number_of_constraints: int = 0
self.reference_front: List[S] = []
self.directions: List[int] = []
self.labels: List[str] = []
Several points can be pointed out here:
- Setting the number of variables, objectives and constraints should be made with methods instead of state variables.
- The reference front is not known for real-world problems and it is used mainly for plotting and for calculating quality indicatores. It does not make sense that it has to be part of a problem.
- The
directions
is used to indicate whether the objective functions are to be minimized or maximized, which is used for generating output results. However, jMetalPy assumes that all the objectives are to be minimized, so this field can bring confusion to users.
The proposal to deal with these issues is to redefine the constructor as follows:
def __init__(self):
self.directions: List[int] = []
self.labels: List[str] = []
@abstractmethod
def number_of_variables(self) -> int:
pass
@abstractmethod
def number_of_objectives(self) -> int:
pass
@abstractmethod
def number_of_constraints(self) -> int:
pass
This way, the FloatProblem
class can be implemented in this way:
def __init__(self):
super(FloatProblem, self).__init__()
self.lower_bound = []
self.upper_bound = []
def number_of_variables(self) -> int:
return len(self.lower_bound)
So the unconstrained benchmark problem Kursawe
can be defined as:
class Kursawe(FloatProblem):
"""Class representing problem Kursawe."""
def __init__(self, number_of_variables: int = 3):
super(Kursawe, self).__init__()
self.obj_directions = [self.MINIMIZE, self.MINIMIZE]
self.obj_labels = ["f(x)", "f(y)"]
self.lower_bound = [-5.0 for _ in range(number_of_variables)]
self.upper_bound = [5.0 for _ in range(number_of_variables)]
FloatSolution.lower_bound = self.lower_bound
FloatSolution.upper_bound = self.upper_bound
def number_of_objectives(self) -> int:
return 2
def number_of_constraints(self) -> int:
return 0
In the case of the constrained problem Srinivas
, it can defined in this way:
class Srinivas(FloatProblem):
"""Class representing problem Srinivas."""
def __init__(self):
super(Srinivas, self).__init__()
number_of_variables = 2
self.obj_directions = [self.MINIMIZE, self.MINIMIZE]
self.obj_labels = ["f(x)", "f(y)"]
self.lower_bound = [-20.0 for _ in range(number_of_variables)]
self.upper_bound = [20.0 for _ in range(number_of_variables)]
def number_of_objectives(self) -> int:
return 2
def number_of_constraints(self) -> int:
return 2
def evaluate(self, solution: FloatSolution) -> FloatSolution:
x1 = solution.variables[0]
x2 = solution.variables[1]
solution.objectives[0] = 2.0 + (x1 - 2.0) * (x1 - 2.0) + (x2 - 1.0) * (x2 - 1.0)
solution.objectives[1] = 9.0 * x1 - (x2 - 1.0) * (x2 - 1.0)
self.__evaluate_constraints(solution)
return solution
About the reference_front
and directions
state variables, the suggestion is to remove the first one while the second one should be properly documented.