Source code for jmetal.core.problem

import logging
import random
from abc import ABC, abstractmethod
from typing import Generic, TypeVar, List

from jmetal.core.observer import Observer
from jmetal.core.solution import BinarySolution, FloatSolution, IntegerSolution, PermutationSolution

LOGGER = logging.getLogger('jmetal')

S = TypeVar('S')


[docs]class Problem(Generic[S], ABC): """ Class representing problems. """ MINIMIZE = -1 MAXIMIZE = 1 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] = None self.directions: List[int] = [] self.labels: List[str] = []
[docs] @abstractmethod def create_solution(self) -> S: """ Creates a random_search solution to the problem. :return: Solution. """ pass
[docs] @abstractmethod def evaluate(self, solution: S) -> S: """ Evaluate a solution. For any new problem inheriting from :class:`Problem`, this method should be replaced. Note that this framework ASSUMES minimization, thus solutions must be evaluated in consequence. :return: Evaluated solution. """ pass
[docs] @abstractmethod def get_name(self) -> str: pass
[docs]class DynamicProblem(Problem[S], Observer, ABC):
[docs] @abstractmethod def the_problem_has_changed(self) -> bool: pass
[docs] @abstractmethod def clear_changed(self) -> None: pass
[docs]class BinaryProblem(Problem[BinarySolution], ABC): """ Class representing binary problems. """ def __init__(self): super(BinaryProblem, self).__init__()
[docs]class FloatProblem(Problem[FloatSolution], ABC): """ Class representing float problems. """ def __init__(self): super(FloatProblem, self).__init__() self.lower_bound = [] self.upper_bound = []
[docs] def create_solution(self) -> FloatSolution: new_solution = FloatSolution( self.lower_bound, self.upper_bound, self.number_of_objectives, self.number_of_constraints) new_solution.variables = \ [random.uniform(self.lower_bound[i]*1.0, self.upper_bound[i]*1.0) for i in range(self.number_of_variables)] return new_solution
[docs]class IntegerProblem(Problem[IntegerSolution], ABC): """ Class representing integer problems. """ def __init__(self): super(IntegerProblem, self).__init__() self.lower_bound = None self.upper_bound = None
[docs] def create_solution(self) -> IntegerSolution: new_solution = IntegerSolution( self.lower_bound, self.upper_bound, self.number_of_objectives, self.number_of_constraints) new_solution.variables = \ [int(random.uniform(self.lower_bound[i]*1.0, self.upper_bound[i]*1.0)) for i in range(self.number_of_variables)] return new_solution
[docs]class PermutationProblem(Problem[PermutationSolution], ABC): """ Class representing permutation problems. """ def __init__(self): super(PermutationProblem, self).__init__()
[docs]class OnTheFlyFloatProblem(FloatProblem): """ Class for defining float problems on the fly. Example: >>> # Defining problem Srinivas on the fly >>> def f1(x: [float]): >>> return 2.0 + (x[0] - 2.0) * (x[0] - 2.0) + (x[1] - 1.0) * (x[1] - 1.0) >>> >>> def f2(x: [float]): >>> return 9.0 * x[0] - (x[1] - 1.0) * (x[1] - 1.0) >>> >>> def c1(x: [float]): >>> return 1.0 - (x[0] * x[0] + x[1] * x[1]) / 225.0 >>> >>> def c2(x: [float]): >>> return (3.0 * x[1] - x[0]) / 10.0 - 1.0 >>> >>> problem = OnTheFlyFloatProblem()\ .set_name("Srinivas")\ .add_variable(-20.0, 20.0)\ .add_variable(-20.0, 20.0)\ .add_function(f1)\ .add_function(f2)\ .add_constraint(c1)\ .add_constraint(c2) """ def __init__(self): super(OnTheFlyFloatProblem, self).__init__() self.functions = [] self.constraints = [] self.name = None
[docs] def set_name(self, name): self.name = name return self
[docs] def add_function(self, function): self.functions.append(function) self.number_of_objectives += 1 return self
[docs] def add_constraint(self, constraint): self.constraints.append(constraint) self.number_of_constraints += 1 return self
[docs] def add_variable(self, lower_bound, upper_bound): self.lower_bound.append(lower_bound) self.upper_bound.append(upper_bound) self.number_of_variables += 1 return self
[docs] def evaluate(self, solution: FloatSolution): for i in range(self.number_of_objectives): solution.objectives[i] = self.functions[i](solution.variables) for i in range(self.number_of_constraints): solution.constraints[i] = self.constraints[i](solution.variables)
[docs] def get_name(self) -> str: return self.name