def calculate_bounds( self, objectives: Callable, n_objectives: int, x0: np.ndarray, epsilons: np.ndarray, bounds: Union[np.ndarray, None], constraints: Optional[Callable], method: Union[ScalarMethod, str, None], ) -> np.ndarray: """ Calculate the new bounds using Epsilon constraint method. Args: objectives (np.ndarray): The objective function values for each input vector. n_objectives (int): Total number of objectives. x0 (np.ndarray): Initial values for decision variables. epsilons (np.ndarray): Previous iteration point. bounds (Union[np.ndarray, None]): Bounds for decision variables. constraints (Callable): Constraints of the problem. method (Union[ScalarMethod, str, None]): The optimization method the scalarizer should be minimized with. Returns: np.ndarray: New lower bounds for objective functions. """ new_lower_bounds: np.ndarray = [None] * n_objectives # set polish to False method_e: ScalarMethod = ScalarMethod( lambda x, _, **y: differential_evolution(x, **y), method_args={"disp": False, "polish": False, "tol": 0.000001, "popsize": 10, "maxiter": 50000}, use_scipy=True, ) # solve new lower bounds for each objective for i in range(n_objectives): eps = ECM.EpsilonConstraintMethod( objectives, i, # take out the objective to be minimized np.array([val for ind, val in enumerate(epsilons) if ind != i]), constraints=constraints, ) cons_evaluate = eps.evaluate_constraints scalarized_objective = Scalarizer(objectives, eps) minimizer = ScalarMinimizer( scalarized_objective, bounds, constraint_evaluator=cons_evaluate, method=method_e ) res = minimizer.minimize(x0) # store objective function values as new lower bounds new_lower_bounds[i] = objectives(res["x"])[0][i] return new_lower_bounds
def test_dummy_cons(): method = ScalarMethod(dummy_minimizer) solver = ScalarMinimizer(simple_problem, np.array([[0, 0, 0], [1, 1, 1]]), simple_constr, method) res = solver.minimize(np.array([0.5, 0.5, 0.1])) assert res["success"] res = solver.minimize(np.array([0.5, 0.5, 0.5])) assert not res["success"]
def test_dummy_no_cons(): method = ScalarMethod(dummy_minimizer) solver = ScalarMinimizer(simple_problem, np.array([[0, 0, 0], [1, 1, 1]]), None, method) x0 = np.array([0.5, 0.5, 0.5]) res = solver.minimize(x0) assert np.array_equal(res["x"], x0) assert res["success"] assert (res["message"] == "I just retruned the initial guess as the optimal solution.")
def __init__( self, problem: MOProblem, starting_point: np.ndarray, ideal: np.ndarray, nadir: np.ndarray, epsilon: float = 1e-6, objective_names: Optional[List[str]] = None, minimize: Optional[List[int]] = None, ): if not ideal.shape == nadir.shape: raise NautilusException("The dimensions of the ideal and nadir point do not match.") if not ideal.shape == starting_point.shape: raise NautilusException("The dimension of the ideal and starting point do not match.") if all(np.less(nadir, starting_point)): raise NautilusException("Starting point cannot be worse than nadir point.") if objective_names: if not len(objective_names) == ideal.shape[0]: raise NautilusException( "The supplied objective names must have a length equal to " "the number of objectives." ) self._objective_names = objective_names else: self._objective_names = [f"f{i + 1}" for i in range(ideal.shape[0])] if minimize: if not len(objective_names) == ideal.shape[0]: raise NautilusException("The minimize list must have " "as many elements as there are objectives.") self._minimize = minimize else: self._minimize = [1 for _ in range(ideal.shape[0])] # initialize method with problem super().__init__(problem) self._problem = problem self._objectives: Callable = lambda x: self._problem.evaluate(x).objectives self._variable_bounds: Union[np.ndarray, None] = problem.get_variable_bounds() self._constraints: Optional[Callable] = lambda x: self._problem.evaluate(x).constraints # Used to calculate the utopian point from the ideal point self._epsilon = epsilon self._ideal = ideal self._nadir = nadir self._starting_point = starting_point # calculate utopian vector self._utopian = np.array([ideal_i - self._epsilon for ideal_i in self._ideal]) # bounds of the reachable region self._lower_bounds: List[np.ndarray] = [] self._upper_bounds: List[np.ndarray] = [] # current iteration step number self._step_number = 1 # iteration points self._zs: np.ndarray = [] # solutions, objectives, and distances for each iteration self._xs: np.ndarray = [] self._fs: np.ndarray = [] self._ds: np.ndarray = [] # The current reference point self._q: Union[None, np.ndarray] = None # preference information self._preference_method = None self._preference_info = None self._preferential_factors = None # number of total iterations and iterations left self._n_iterations = None self._n_iterations_left = None # flags for the iteration phase # not utilized atm self._use_previous_preference: bool = False self._step_back: bool = False self._short_step: bool = False self._first_iteration: bool = True # evolutionary method for minimizing self._method_de: ScalarMethod = ScalarMethod( lambda x, _, **y: differential_evolution(x, **y), method_args={"disp": False, "polish": False, "tol": 0.000001, "popsize": 10, "maxiter": 50000}, use_scipy=True, )
def __init__( self, problem: Union[MOProblem, DiscreteDataProblem], ideal: np.ndarray, nadir: np.ndarray, epsilon: float = 1e-6, objective_names: Optional[List[str]] = None, minimize: Optional[List[int]] = None, ): if not ideal.shape == nadir.shape: raise RPMException( "The dimensions of the ideal and nadir point do not match.") if objective_names: if not len(objective_names) == ideal.shape[0]: raise RPMException( "The supplied objective names must have a leangth equal to " "the number of objectives.") self._objective_names = objective_names else: self._objective_names = [ f"f{i + 1}" for i in range(ideal.shape[0]) ] if minimize: if not len(objective_names) == ideal.shape[0]: raise RPMException("The minimize list must have " "as many elements as there are objectives.") self._minimize = minimize else: self._minimize = [1 for _ in range(ideal.shape[0])] self._ideal = ideal self._nadir = nadir self._utopian = ideal - epsilon self._n_objectives = self._ideal.shape[0] # current iteration step number self._h = 1 # solutions in decision and objective space, distances and referation points for each iteration self._xs = [None] * 10 self._fs = [None] * 10 self._ds = [None] * 10 self._qs = [None] * 10 # perturbed reference points self._pqs = [None] * 10 # additional solutions self._axs = [None] * 10 self._afs = [None] * 10 # current reference point self._q: Union[None, np.ndarray] = None # weighting vector for achievement function self._w: np.ndarray = [] self._problem = problem if isinstance(problem, MOProblem): # initialize method with MOProblem self._objectives: Callable = lambda x: self._problem.evaluate( x).objectives self._variable_bounds: Union[np.ndarray, None] = problem.get_variable_bounds() self._variable_vectors = None self._constraints: Optional[ Callable] = lambda x: self._problem.evaluate(x).constraints # evolutionary method for minimizing self._method_de: ScalarMethod = ScalarMethod( lambda x, _, **y: differential_evolution(x, **y), method_args={ "disp": False, "polish": False, "tol": 0.000001, "popsize": 10, "maxiter": 50000 }, use_scipy=True, ) else: # Initialize the method with DiscreteData self._objectives = problem.objectives self._variable_bounds = None # TODO: check me self._variable_vectors = problem.decision_variables self._constraints = None # TODO: check me self._method_de = "discrete"
x1 = np.linspace(min(f1_range), max(f1_range), 1000) x2 = np.linspace(min(f2_range), max(f2_range), 1000) y = np.linspace(0, 0, 1000) problem = MOProblem(variables=varsl, objectives=[f1, f2], ideal=np.array([-20, -12]), nadir=np.array([-14, 0.5])) from desdeo_mcdm.interactive.NIMBUS import NIMBUS from scipy.optimize import minimize, differential_evolution scalar_method = ScalarMethod( lambda x, _, **y: differential_evolution(x, **y), use_scipy=True, method_args={ "polish": True, "disp": True }) method = NIMBUS(problem, scalar_method) classification_request, plot_request = method.start() # print(classification_request.content.keys()) # print(classification_request.content["message"]) print(classification_request.content["objective_values"]) #Ploting F1! plt.scatter(x1, y, label="Range")