from abc import ABC, abstractmethod
from math import cos, floor, pi, pow, sin, sqrt
import numpy
from jmetal.core.problem import DynamicProblem, FloatProblem
from jmetal.core.solution import FloatSolution
"""
.. module:: FDA
:platform: Unix, Windows
:synopsis: FDA problem family of dynamic multi-objective problems.
.. moduleauthor:: Antonio J. Nebro <antonio@lcc.uma.es>
"""
[docs]
class FDA(DynamicProblem, FloatProblem, ABC):
def __init__(self):
super(FDA, self).__init__()
self.tau_T = 5
self.nT = 10
self.time = 1.0
self.problem_modified = False
[docs]
def update(self, *args, **kwargs):
counter: int = kwargs["COUNTER"]
self.time = (1.0 / self.nT) * floor(counter * 1.0 / self.tau_T)
self.problem_modified = True
[docs]
def the_problem_has_changed(self) -> bool:
return self.problem_modified
[docs]
def clear_changed(self) -> None:
self.problem_modified = False
[docs]
@abstractmethod
def evaluate(self, solution: FloatSolution):
pass
[docs]
class FDA1(FDA):
"""Problem FDA1.
.. note:: Bi-objective dynamic unconstrained problem. The default number of variables is 100.
"""
def __init__(self, number_of_variables: int = 100):
""":param number_of_variables: Number of decision variables of the problem."""
super(FDA1, self).__init__()
self.number_of_variables = number_of_variables
self.number_of_objectives = 2
self.number_of_constraints = 0
self.obj_directions = [self.MINIMIZE, self.MINIMIZE]
self.obj_labels = ["f(x)", "f(y)"]
self.lower_bound = self.number_of_variables * [-1.0]
self.upper_bound = self.number_of_variables * [1.0]
self.lower_bound[0] = 0.0
self.upper_bound[0] = 1.0
[docs]
def evaluate(self, solution: FloatSolution) -> FloatSolution:
g = self.__eval_g(solution)
h = self.__eval_h(solution.variables[0], g)
solution.objectives[0] = solution.variables[0]
solution.objectives[1] = h * g
return solution
def __eval_g(self, solution: FloatSolution):
gT = sin(0.5 * pi * self.time)
g = 1.0 + sum([pow(v - gT, 2) for v in solution.variables[1:]])
return g
def __eval_h(self, f: float, g: float) -> float:
return 1.0 - sqrt(f / g)
[docs]
def get_name(self):
return "FDA1"
[docs]
class FDA2(FDA):
"""Problem FDA2
.. note:: Bi-objective dynamic unconstrained problem. The default number of variables is 31.
"""
def __init__(self, number_of_variables: int = 31):
""":param number_of_variables: Number of decision variables of the problem."""
super(FDA2, self).__init__()
self.number_of_variables = number_of_variables
self.number_of_objectives = 2
self.number_of_constraints = 0
self.obj_directions = [self.MINIMIZE, self.MINIMIZE]
self.obj_labels = ["f(x)", "f(y)"]
self.lower_bound = self.number_of_variables * [-1.0]
self.upper_bound = self.number_of_variables * [1.0]
self.lower_bound[0] = 0.0
self.upper_bound[0] = 1.0
[docs]
def evaluate(self, solution: FloatSolution) -> FloatSolution:
g = self.__eval_g(solution, 1, len(solution.variables))
h = self.__eval_h(solution.variables[0], g)
solution.objectives[0] = solution.variables[0]
solution.objectives[1] = h * g
return solution
def __eval_g(self, solution: FloatSolution, lower_limit: int, upper_limit: int):
g = sum([pow(v, 2) for v in solution.variables[lower_limit:upper_limit]])
g += 1.0 + sum([pow(v + 1.0, 2.0) for v in solution.variables[upper_limit:]])
return g
def __eval_h(self, f: float, g: float) -> float:
ht = 0.2 + 4.8 * pow(self.time, 2.0)
return 1.0 - pow(f / g, ht)
[docs]
def get_name(self):
return "FDA2"
[docs]
class FDA3(FDA):
"""Problem FDA3
.. note:: Bi-objective dynamic unconstrained problem. The default number of variables is 30.
"""
def __init__(self, number_of_variables: int = 30):
""":param number_of_variables: Number of decision variables of the problem."""
super(FDA3, self).__init__()
self.number_of_variables = number_of_variables
self.number_of_objectives = 2
self.number_of_constraints = 0
self.limitInfI = 0
self.limitSupI = 1
self.limitInfII = 1
self.obj_directions = [self.MINIMIZE, self.MINIMIZE]
self.obj_labels = ["f(x)", "f(y)"]
self.lower_bound = self.number_of_variables * [-1.0]
self.upper_bound = self.number_of_variables * [1.0]
self.lower_bound[0] = 0.0
self.upper_bound[0] = 1.0
[docs]
def evaluate(self, solution: FloatSolution) -> FloatSolution:
g = self.__eval_g(solution, self.limitInfII)
h = self.__eval_h(solution.variables[0], g)
solution.objectives[0] = self.__eval_f(solution, self.limitInfI, self.limitSupI)
solution.objectives[1] = g * h
return solution
def __eval_f(self, solution: FloatSolution, lower_limit: int, upper_limit: int):
f = 0.0
aux = 2.0 * sin(0.5 * pi * self.time)
ft = pow(10, aux)
f += sum([pow(v, ft) for v in solution.variables[lower_limit:upper_limit]])
return f
def __eval_g(self, solution: FloatSolution, lower_limit: int):
gt = abs(sin(0.5 * pi * self.time))
g = sum([pow(v - gt, 2) for v in solution.variables[lower_limit:]])
g = g + 1.0 + gt
return g
def __eval_h(self, f: float, g: float) -> float:
h = 1.0 - sqrt(f / g)
return h
[docs]
def get_name(self):
return "FDA3"
[docs]
class FDA4(FDA):
"""Problem FDA4
.. note:: Three-objective dynamic unconstrained problem. The default number of variables is 12.
"""
M = 3
def __init__(self, number_of_variables: int = 12):
""":param number_of_variables: Number of decision variables of the problem."""
super(FDA4, self).__init__()
self.number_of_variables = number_of_variables
self.number_of_objectives = 3
self.number_of_constraints = 0
self.obj_directions = [self.MINIMIZE, self.MINIMIZE]
self.obj_labels = ["f(x)", "f(y)", "f(z)"]
self.lower_bound = self.number_of_variables * [0.0]
self.upper_bound = self.number_of_variables * [1.0]
[docs]
def evaluate(self, solution: FloatSolution) -> FloatSolution:
g = self.__eval_g(solution, self.M - 1)
solution.objectives[0] = self.__eval_f1(solution, g)
solution.objectives[1] = self.__eval_fk(solution, g, 2)
solution.objectives[2] = self.__eval_fm(solution, g)
return solution
def __eval_g(self, solution: FloatSolution, lower_limit: int):
gt = abs(sin(0.5 * pi * self.time))
g = sum([pow(v - gt, 2) for v in solution.variables[lower_limit:]])
return g
def __eval_f1(self, solution: FloatSolution, g: float) -> float:
f = 1.0 + g
mult = numpy.prod([cos(v * pi / 2.0) for v in solution.variables[: self.M - 1]])
return f * mult
def __eval_fk(self, solution: FloatSolution, g: float, k: int) -> float:
f = 1.0 + g
aux = sin((solution.variables[self.M - k] * pi) / 2.0)
mult = numpy.prod([cos(v * pi / 2.0) for v in solution.variables[: self.M - k]])
return f * mult * aux
def __eval_fm(self, solution: FloatSolution, g: float) -> float:
fm = 1.0 + g
fm *= sin((solution.variables[0] * pi) / 2.0)
return fm
[docs]
def get_name(self):
return "FDA4"
[docs]
class FDA5(FDA):
"""Problem FDA5
.. note:: Three-objective dynamic unconstrained problem. The default number of variables is 12.
"""
M = 3
def __init__(self, number_of_variables: int = 12):
""":param number_of_variables: Number of decision variables of the problem."""
super(FDA5, self).__init__()
self.number_of_variables = number_of_variables
self.number_of_objectives = 3
self.number_of_constraints = 0
self.obj_directions = [self.MINIMIZE, self.MINIMIZE]
self.obj_labels = ["f(x)", "f(y)", "f(z)"]
self.lower_bound = self.number_of_variables * [0.0]
self.upper_bound = self.number_of_variables * [1.0]
[docs]
def evaluate(self, solution: FloatSolution) -> FloatSolution:
g = self.__eval_g(solution, self.M - 1)
ft = 1.0 + 100.0 * pow(sin(0.5 * pi * self.time), 4.0)
solution.objectives[0] = self.__eval_f1(solution, g, ft)
solution.objectives[1] = self.__eval_fk(solution, g, 2, ft)
solution.objectives[2] = self.__eval_fm(solution, g, ft)
return solution
def __eval_g(self, solution: FloatSolution, lower_limit: int):
gt = abs(sin(0.5 * pi * self.time))
g = sum([pow(v - gt, 2) for v in solution.variables[lower_limit:]])
return g
def __eval_f1(self, solution: FloatSolution, g: float, ft: float) -> float:
f = 1.0 + g
mult = numpy.prod([cos(pow(v, ft) * pi / 2.0) for v in solution.variables[: self.M - 1]])
return f * mult
def __eval_fk(self, solution: FloatSolution, g: float, k: int, ft: float) -> float:
f = 1.0 + g
mult = numpy.prod([cos(pow(v, ft) * pi / 2.0) for v in solution.variables[: self.M - k]])
yy = pow(solution.variables[self.M - k], ft)
mult *= sin(yy * pi / 2.0)
return f * mult
def __eval_fm(self, solution: FloatSolution, g: float, ft: float) -> float:
fm = 1.0 + g
y_1 = pow(solution.variables[0], ft)
mult = sin(y_1 * pi / 2.0)
return fm * mult
[docs]
def get_name(self):
return "FDA5"