Skip to content

Merge pull request #48 from industrial-optimization-group/bshavazipou… #5

Merge pull request #48 from industrial-optimization-group/bshavazipou…

Merge pull request #48 from industrial-optimization-group/bshavazipou… #5

Triggered via push September 25, 2023 15:48
Status Success
Total duration 42s
Artifacts

DESDEO-tools.yml

on: push
Matrix: test
Fit to window
Zoom out
Zoom in

Annotations

77 errors and 2 warnings
desdeo_tools/scalarization/ASF.py#L389
Blank line contains whitespace (W293)
desdeo_tools/scalarization/ASF.py#L392
Trailing whitespace (W291)
desdeo_tools/scalarization/ASF.py#L393
Trailing whitespace (W291)
desdeo_tools/scalarization/ASF.py#L395
Blank line contains whitespace (W293)
desdeo_tools/scalarization/ASF.py#L403
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/validators.py#L1
import pandas as pd import numpy as np class ValidationError(Exception): - """Raised when an error related to the validation is encountered. - """ + """Raised when an error related to the validation is encountered.""" -def validate_ref_point_with_ideal_and_nadir( - dimensions_data: pd.DataFrame, reference_point: pd.DataFrame -): +def validate_ref_point_with_ideal_and_nadir(dimensions_data: pd.DataFrame, reference_point: pd.DataFrame): validate_ref_point_dimensions(dimensions_data, reference_point) validate_ref_point_data_type(reference_point) validate_ref_point_with_ideal(dimensions_data, reference_point) validate_with_ref_point_nadir(dimensions_data, reference_point) -def validate_ref_point_with_ideal( - dimensions_data: pd.DataFrame, reference_point: pd.DataFrame -): +def validate_ref_point_with_ideal(dimensions_data: pd.DataFrame, reference_point: pd.DataFrame): validate_ref_point_dimensions(dimensions_data, reference_point) ideal_fitness = dimensions_data.loc["ideal"] * dimensions_data.loc["minimize"] ref_point_fitness = reference_point * dimensions_data.loc["minimize"] if not (ideal_fitness <= ref_point_fitness).all(axis=None): - problematic_columns = ideal_fitness.index[ - (ideal_fitness > ref_point_fitness).values.tolist()[0] - ].values + problematic_columns = ideal_fitness.index[(ideal_fitness > ref_point_fitness).values.tolist()[0]].values msg = ( f"Reference point should be worse than or equal to the ideal point\n" f"The following columns have problematic values: {problematic_columns}" ) raise ValidationError(msg) -def validate_with_ref_point_nadir( - dimensions_data: pd.DataFrame, reference_point: pd.DataFrame -): +def validate_with_ref_point_nadir(dimensions_data: pd.DataFrame, reference_point: pd.DataFrame): validate_ref_point_dimensions(dimensions_data, reference_point) nadir_fitness = dimensions_data.loc["nadir"] * dimensions_data.loc["minimize"] ref_point_fitness = reference_point * dimensions_data.loc["minimize"] if not (ref_point_fitness <= nadir_fitness).all(axis=None): - problematic_columns = nadir_fitness.index[ - (nadir_fitness < ref_point_fitness).values.tolist()[0] - ].values + problematic_columns = nadir_fitness.index[(nadir_fitness < ref_point_fitness).values.tolist()[0]].values msg = ( f"Reference point should be better than or equal to the nadir point\n" f"The following columns have problematic values: {problematic_columns}" ) raise ValidationError(msg) -def validate_ref_point_dimensions( - dimensions_data: pd.DataFrame, reference_point: pd.DataFrame -): +def validate_ref_point_dimensions(dimensions_data: pd.DataFrame, reference_point: pd.DataFrame): if not dimensions_data.shape[1] == reference_point.shape[1]: msg = ( f"There is a mismatch in the number of columns of the dataframes.\n" f"Columns in dimensions data: {dimensions_data.columns}\n" f"Columns in the reference point provided: {reference_point.columns}"
desdeo_tools/scalarization/ASF.py#L406
Trailing whitespace (W291)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/validators.py#L70
def validate_ref_point_data_type(reference_point: pd.DataFrame): for dtype in reference_point.dtypes: if not pd.api.types.is_numeric_dtype(dtype): - msg = ( - f"Type of data in reference point dataframe should be numeric.\n" - f"Provided datatype: {dtype}" - ) + msg = f"Type of data in reference point dataframe should be numeric.\n" f"Provided datatype: {dtype}" raise ValidationError(msg) def validate_specified_solutions(indices: np.ndarray, n_solutions: int) -> None: """Validate the Decision maker's choice of preferred/non-preferred solutions.
desdeo_tools/scalarization/ASF.py#L407
Trailing whitespace (W291)
desdeo_tools/scalarization/ASF.py#L409
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/validators.py#L94
if indices.shape[0] < 1: raise ValidationError("Please specify at least one (non-)preferred solution.") if not isinstance(indices, (np.ndarray, list)): raise ValidationError( - "Please specify index/indices of (non-)preferred solutions in a list, even if there is only " - "one." + "Please specify index/indices of (non-)preferred solutions in a list, even if there is only " "one." ) if not all(0 <= i <= (n_solutions - 1) for i in indices): msg = "indices of (non-)preferred solutions should be between 0 and {}. Current indices are {}.".format( n_solutions - 1, indices ) raise ValidationError(msg) -def validate_bounds( - dimensions_data: pd.DataFrame, bounds: np.ndarray, n_objectives: int -) -> None: +def validate_bounds(dimensions_data: pd.DataFrame, bounds: np.ndarray, n_objectives: int) -> None: """Validate the Decision maker's desired lower and upper bounds for objective values. Args: dimensions_data (pd.DataFrame): DataFrame including information whether an objective is minimized or maximized, for each objective. In addition, includes ideal and nadir vectors.
desdeo_tools/scalarization/ASF.py#L412
Trailing whitespace (W291)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/validators.py#L122
Raises: ValidationError: In case desired bounds are invalid. """ if not isinstance(bounds, np.ndarray): - msg = "Please specify bounds as a numpy array. Current type: {}.".format( - type(bounds) - ) + msg = "Please specify bounds as a numpy array. Current type: {}.".format(type(bounds)) raise ValidationError(msg) if len(bounds) != n_objectives: - msg = "Length of 'bounds' ({}) must be the same as number of objectives ({}).".format( - len(bounds), n_objectives - ) + msg = "Length of 'bounds' ({}) must be the same as number of objectives ({}).".format(len(bounds), n_objectives) raise ValidationError(msg) if not all(isinstance(b, (np.ndarray, list)) for b in bounds): print(type(bounds[0])) msg = "Please give bounds for each objective in a list." raise ValidationError(msg)
desdeo_tools/scalarization/ASF.py#L417
Continuation line under-indented for visual indent (E128)
desdeo_tools/scalarization/ASF.py#L438
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/validators.py#L144
msg = "Lower bound cannot be greater than upper bound. Please specify lower bound first, then upper bound." raise ValidationError(msg) # check that bounds are within ideal and nadir points for each objective for i, b in enumerate(bounds): - if ( - dimensions_data.loc["minimize"].values.tolist()[i] == 1 - ): # minimized objectives + if dimensions_data.loc["minimize"].values.tolist()[i] == 1: # minimized objectives if dimensions_data.loc["ideal"].values.tolist()[i] is not None: if b[0] < dimensions_data.loc["ideal"].values.tolist()[i]: msg = "Lower bound cannot be lower than ideal value for objective. Ideal vector: {}.".format( dimensions_data.loc["ideal"].values.tolist() )
desdeo_tools/scalarization/ASF.py#L442
Blank line contains whitespace (W293)
desdeo_tools/scalarization/ASF.py#L445
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/request.py#L215
f"Mismatch in column names of data and dimensions_data.\n" f"Column names in data: {data.columns}" f"Column names in dimensions_data: {dimensions_data.columns}" ) raise RequestError(msg) - rouge_indices = [ - index - for index in dimensions_data.index - if index not in acceptable_dimensions_data_indices - ] + rouge_indices = [index for index in dimensions_data.index if index not in acceptable_dimensions_data_indices] if rouge_indices: msg = ( f"dimensions_data should only contain the following indices:\n" f"{acceptable_dimensions_data_indices}\n" f"The dataframe provided contains the following unsupported indices:\n" f"{rouge_indices}" ) raise RequestError(msg) if not isinstance(chart_title, (str, type(None))): - msg = ( - f"Chart title should be a string. Provided chart type is:" - f"{type(chart_title)}" - ) + msg = f"Chart title should be a string. Provided chart type is:" f"{type(chart_title)}" raise RequestError(msg) if not isinstance(message, str): if not isinstance(message, list): msg = ( f"Message/s to be printed should be string or list of strings"
desdeo_tools/scalarization/ASF.py#L448
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/request.py#L324
msg = ( f"Dimensional data should be in a pandas dataframe.\n" f"Provided data is of type: {type(dimensions_data)}" ) raise RequestError(msg) - rouge_indices = [ - index - for index in dimensions_data.index - if index not in acceptable_dimensions_data_indices - ] + rouge_indices = [index for index in dimensions_data.index if index not in acceptable_dimensions_data_indices] if rouge_indices: msg = ( f"dimensions_data should only contain the following indices:\n" f"{acceptable_dimensions_data_indices}\n" f"The dataframe provided contains the following unsupported indices:\n"
desdeo_tools/scalarization/ASF.py#L449
Blank line contains whitespace (W293)
desdeo_tools/scalarization/ASF.py#L450
Too many blank lines (2) (E303)
desdeo_tools/scalarization/ASF.py#L455
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/interaction/request.py#L375
RequestError: If reference point is not provided in a pandas DataFrame. """ if not isinstance(value, pd.DataFrame): msg = "Reference should be provided in a pandas dataframe format" raise RequestError(msg) - self.content["validator"]( - reference_point=value, dimensions_data=self.content["dimensions_data"] - ) + self.content["validator"](reference_point=value, dimensions_data=self.content["dimensions_data"]) self._response = value class PreferredSolutionPreference(BaseRequest): """Methods can use this class to ask the Decision maker to provide their preferences
desdeo_tools/scalarization/ASF.py#L458
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/maps/preference_incorporated_space_RP.py#L11
from typing import Type, List, Union, Dict class PreferenceIncorporatedSpaceError(Exception): - """Raised when an error related to the preference incorporated space is encountered. - """ + """Raised when an error related to the preference incorporated space is encountered.""" class PreferenceIncorporatedSpace: def __init__( self,
desdeo_tools/scalarization/ASF.py#L463
Blank line contains whitespace (W293)
desdeo_tools/scalarization/ASF.py#L466
Trailing whitespace (W291)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/maps/preference_incorporated_space_RP.py#L45
if utopian is not None: self.utopian = utopian if nadir is not None: self.nadir = nadir - self.initialized_scalarizers = [ - scalarizer(utopian=utopian, nadir=nadir, rho=rho) - for scalarizer in scalarizers - ] + self.initialized_scalarizers = [scalarizer(utopian=utopian, nadir=nadir, rho=rho) for scalarizer in scalarizers] self.has_additional_constraints = False self.constrained_scalarizers = [] for scalarizer in self.initialized_scalarizers: # self.required_keys = scalarizer.required_keys.keys() self.constrained_scalarizers.append(scalarizer.has_additional_constraints) - self.has_additional_constraints = ( - self.has_additional_constraints or scalarizer.has_additional_constraints - ) + self.has_additional_constraints = self.has_additional_constraints or scalarizer.has_additional_constraints def __call__(self, objective_vector: np.ndarray): - mapped_vectors = np.zeros( - (len(objective_vector), len(self.initialized_scalarizers)) - ) + mapped_vectors = np.zeros((len(objective_vector), len(self.initialized_scalarizers))) for i, scalarizer in enumerate(self.initialized_scalarizers): mapped_vectors[:, i] = scalarizer(objective_vector, self.preferences[i]) return mapped_vectors def evaluate_constraints(self, objective_vector: np.ndarray):
desdeo_tools/scalarization/ASF.py#L485
Local variable 'phi' is assigned to but never used (F841)
desdeo_tools/scalarization/ASF.py#L486
Trailing whitespace (W291)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/maps/preference_incorporated_space_RP.py#L81
if not has_constraints: continue constraints = np.hstack( ( constraints, - scalarizer.evaluate_constraints( - objective_vector, self.preferences[i] - ), + scalarizer.evaluate_constraints(objective_vector, self.preferences[i]), ) ) class classificationPIS:
desdeo_tools/scalarization/ASF.py#L487
Blank line contains whitespace (W293)
desdeo_tools/scalarization/ASF.py#L490
Trailing whitespace (W291)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/maps/preference_incorporated_space_RP.py#L132
self.nadir = nadir self.nimbus = NIMBUS_GLIDE(utopian=utopian, nadir=nadir) self.nimbus_copycat = reference_point_method_GLIDE(utopian=utopian, nadir=nadir) - self.initialized_scalarizers = [ - scalarizer(utopian=utopian, nadir=nadir, rho=rho) - for scalarizer in scalarizers - ] + self.initialized_scalarizers = [scalarizer(utopian=utopian, nadir=nadir, rho=rho) for scalarizer in scalarizers] self.has_additional_constraints = False def update_preference(self, preference: dict): - self.preference = preference if "classifications" in preference.keys(): self.classification_preference = preference - self.RP_preference = classification_to_reference_point( - preference, ideal=self.utopian, nadir=self.nadir - ) + self.RP_preference = classification_to_reference_point(preference, ideal=self.utopian, nadir=self.nadir) else: - raise PreferenceIncorporatedSpaceError( - "Classification preference expected." - ) + raise PreferenceIncorporatedSpaceError("Classification preference expected.") def __call__(self, objective_vector: np.ndarray): - # IOPIS/NIMBUS logic - nimbus_obj = self.nimbus( - objective_vector=objective_vector, preference=self.classification_preference - ) - nimbus_constraint = self.nimbus.evaluate_constraints( - objective_vector, self.classification_preference - ) + nimbus_obj = self.nimbus(objective_vector=objective_vector, preference=self.classification_preference) + nimbus_constraint = self.nimbus.evaluate_constraints(objective_vector, self.classification_preference) feasible = np.all(nimbus_constraint > 0, axis=1) if not feasible.any(): nimbus_optimal = objective_vector[nimbus_constraint.max(axis=1).argmax()] else: nimbus_obj[~feasible] = np.inf nimbus_optimal = objective_vector[nimbus_obj.argmin()] # IOPIS mapping - mapped_vectors = np.zeros( - (len(objective_vector), len(self.initialized_scalarizers) + 1) - ) + mapped_vectors = np.zeros((len(objective_vector), len(self.initialized_scalarizers) + 1)) mapped_vectors[:, 0] = self.nimbus_copycat( objective_vector=objective_vector, preference={"reference point": nimbus_optimal}, )
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/maps/preference_incorporated_space_RP.py#L192
num_DM: int = 2, scalarizer: Type[GLIDEBase] = AUG_STOM_GLIDE, nadir: np.ndarray = None, rho: float = 1e-6, ): - super().__init__( - scalarizers=[scalarizer] * num_DM, utopian=utopian, nadir=nadir, rho=rho - ) + super().__init__(scalarizers=[scalarizer] * num_DM, utopian=utopian, nadir=nadir, rho=rho) def update_preference(self, preference: List[Dict]): self.preferences = preference
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/EpsilonConstraintMethod.py#L4
from desdeo_tools.solver.ScalarSolver import ScalarMinimizer from typing import Optional, Callable, Union class ECMError(Exception): - """Raised when an error related to the Epsilon Constraint Method is encountered. - """ + """Raised when an error related to the Epsilon Constraint Method is encountered.""" class EpsilonConstraintMethod: """A class to represent a class for scalarizing MOO problems using the epsilon constraint method.
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/EpsilonConstraintMethod.py#L61
if ival != self._to_be_minimized ] ) if len(epsilon_left_side) != len(self.epsilons): - msg = ( - "The lenght of the epsilons array ({}) must match the total number of objectives - 1 ({})." - ).format(len(self.epsilons), len(self.objectives(xs)) - 1) + msg = ("The lenght of the epsilons array ({}) must match the total number of objectives - 1 ({}).").format( + len(self.epsilons), len(self.objectives(xs)) - 1 + ) raise ECMError(msg) # evaluate values of epsilon constraint functions - e: np.ndarray = np.array( - [-(f - v) for f, v in zip(epsilon_left_side, self.epsilons)] - ) + e: np.ndarray = np.array([-(f - v) for f, v in zip(epsilon_left_side, self.epsilons)]) if self.constraints(xs) is not None: c = self.constraints(xs) - return np.concatenate( - [c, e], axis=None - ) # does it work with multiple constraints? + return np.concatenate([c, e], axis=None) # does it work with multiple constraints? else: return e def __call__(self, objective_vector: np.ndarray) -> Union[float, np.ndarray]: """
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/EpsilonConstraintMethod.py#L90
Returns: Value of objective function to be minimized. """ if np.shape(objective_vector)[0] > 1: # more rows than one - return np.array( - [ - objective_vector[i][self._to_be_minimized] - for i, _ in enumerate(objective_vector) - ] - ) + return np.array([objective_vector[i][self._to_be_minimized] for i, _ in enumerate(objective_vector)]) else: return objective_vector[0][self._to_be_minimized] # Testing the method if __name__ == "__main__": # 1. Define objective functions, bounds and constraints def volume(r, h): - return np.pi * r ** 2 * h + return np.pi * r**2 * h def area(r, h): - return 2 * np.pi ** 2 + np.pi * r * h + return 2 * np.pi**2 + np.pi * r * h # add third objective def weight(v): return 0.01 * v
tests/conftest.py#L9
Blank line contains whitespace (W293)
tests/conftest.py#L13
Blank line contains whitespace (W293)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/EpsilonConstraintMethod.py#L146
# index of which objective function to minimize obj_min = 2 # set upper bound(s) for the other objectives, in the same order than which corresponding objective functions # are defined - epsil = np.array( - [2000, -100] - ) # multiply the epsilons with -1, if the constraint is of form f_i(x) >= e_i + epsil = np.array([2000, -100]) # multiply the epsilons with -1, if the constraint is of form f_i(x) >= e_i # create an instance of EpsilonConstraintMethod-class for given problem eps = EpsilonConstraintMethod(objective, obj_min, epsil, constraints=con_golden) # constraint evaluator, used by the solver
tests/solver/test_scalarsolver.py#L10
Block comment should start with '# ' (E265)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/EpsilonConstraintMethod.py#L164
# 3. Solve # starting point x0 = np.array([2, 11]) - minimizer = ScalarMinimizer( - scalarized_objective, bounds, constraint_evaluator=cons_evaluate, method=None - ) + minimizer = ScalarMinimizer(scalarized_objective, bounds, constraint_evaluator=cons_evaluate, method=None) # minimize res = minimizer.minimize(x0) final_r, final_h = res["x"][0], res["x"][1] final_obj = objective(res["x"]).squeeze() final_V, final_A, final_W = final_obj[0], final_obj[1], final_obj[2] print(f"Final cake specs: radius: {final_r}cm, height: {final_h}cm.") - print( - f"Final cake dimensions: volume: {final_V}, area: {-final_A}, weight: {final_W}." - ) + print(f"Final cake dimensions: volume: {final_V}, area: {-final_A}, weight: {final_W}.") print(final_r / final_h) print(res)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L14
Instances of the implementations of this class should function as function. """ @AbstractMethod - def __call__( - self, objective_vector: np.ndarray, reference_point: np.ndarray - ) -> Union[float, np.ndarray]: + def __call__(self, objective_vector: np.ndarray, reference_point: np.ndarray) -> Union[float, np.ndarray]: """Evaluate the ASF. Args: objective_vectors (np.ndarray): The objective vectors to calculate the values.
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L53
""" def __init__(self, weights: np.ndarray): self.weights = weights - def __call__( - self, objective_vector: np.ndarray, reference_point: np.ndarray - ) -> Union[float, np.ndarray]: + def __call__(self, objective_vector: np.ndarray, reference_point: np.ndarray) -> Union[float, np.ndarray]: """Evaluate the simple order-representing ASF. Args: objective_vector (np.ndarray): A vector representing a solution in the solution space.
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L118
self.preferential_factors = preferential_factors self.nadir = nadir self.utopian_point = utopian_point self.rho = rho - def __call__( - self, objective_vector: np.ndarray, reference_point: np.ndarray - ) -> Union[float, np.ndarray]: + def __call__(self, objective_vector: np.ndarray, reference_point: np.ndarray) -> Union[float, np.ndarray]: mu = self.preferential_factors f = objective_vector q = reference_point rho = self.rho z_nad = self.nadir
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L181
self.lt_inds = lt_inds self.lte_inds = lte_inds self.rho = rho self.rho_sum = rho_sum - def __call__( - self, objective_vector: np.ndarray, reference_point: np.ndarray - ) -> Union[float, np.ndarray]: + def __call__(self, objective_vector: np.ndarray, reference_point: np.ndarray) -> Union[float, np.ndarray]: # assure this function works with single objective vectors if objective_vector.ndim == 1: f = objective_vector.reshape((1, -1)) else: f = objective_vector
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L231
def __init__(self, ideal: np.ndarray, rho: float = 1e-6, rho_sum: float = 1e-6): self.ideal = ideal self.rho = rho self.rho_sum = rho_sum - def __call__( - self, objective_vectors: np.ndarray, reference_point: np.ndarray - ) -> Union[float, np.ndarray]: + def __call__(self, objective_vectors: np.ndarray, reference_point: np.ndarray) -> Union[float, np.ndarray]: # assure this function works with single objective vectors if objective_vectors.ndim == 1: f = objective_vectors.reshape((1, -1)) else: f = objective_vectors
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L346
nad = self.nadir uto = self.ideal - self.rho ex_mask = np.full((f.shape[1]), True, dtype=bool) ex_mask[self.index_to_exclude] = False - max_term = np.max( - (f[:, ex_mask] - nad[ex_mask]) / (nad[ex_mask] - z[ex_mask]), axis=1 - ) - sum_term_1 = self.rho_sum * np.sum( - (f[:, ex_mask]) / (nad[ex_mask] - z[ex_mask]), axis=1 - ) + max_term = np.max((f[:, ex_mask] - nad[ex_mask]) / (nad[ex_mask] - z[ex_mask]), axis=1) + sum_term_1 = self.rho_sum * np.sum((f[:, ex_mask]) / (nad[ex_mask] - z[ex_mask]), axis=1) # avoid division by zeros - sum_term_2 = self.rho_sum * np.sum( - (f[:, ~ex_mask]) / (nad[~ex_mask] - uto[~ex_mask]), axis=1 - ) + sum_term_2 = self.rho_sum * np.sum((f[:, ~ex_mask]) / (nad[~ex_mask] - uto[~ex_mask]), axis=1) return max_term + sum_term_1 + sum_term_2 class GuessASF(ASFBase):
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L384
max_term = np.max((f - nad) / (nad - z), axis=1) return max_term - + class AspResASF(ASFBase): """Implementation of an ASF using both aspiration and reservation levels. - directly consider both upper and lower bounds of the preferred ranges within the solution - generation process, the variant of ASF utilizing both aspirations and reservations levels. + directly consider both upper and lower bounds of the preferred ranges within the solution + generation process, the variant of ASF utilizing both aspirations and reservations levels. Originally proposed by Wierzbicki (1986), and also used in the PIE method (Sindhya et al. (2011)). - + Args: nadir (np.ndarray): The nadir point. ideal (np.ndarray): The ideal point. rho A small number to form the utopian point. rho_sum (float): A small number to be used as a weight for the sum term. alpha (float): An extricly positive number. beta(float): An extricly positive number. - + References: Wierzbicki, A. P. - On the completeness and constructiveness of parametric characterizations to vector optimization - problems, + On the completeness and constructiveness of parametric characterizations to vector optimization + problems, OR Spektrum, 1986, 8(2), 73–87. - + Sindhya, K., Ruiz, A. B. and Miettinen, K. A preference based interactive evolutionary algorithm for multi-objective optimization: PIE - in H. Takahashi, K. Deb, E. Wanner and S. Greco, eds, ‘Evolutionary Multi-Criterion Optimization: + in H. Takahashi, K. Deb, E. Wanner and S. Greco, eds, ‘Evolutionary Multi-Criterion Optimization: 6th International Conference’, Proceedings, Springer-Verlag, Berlin, Heidelberg, 2011, pp. 212–225. """ - def __init__(self, nadir: np.ndarray, ideal: np.ndarray, rho: float = 1e-6, rho_sum: float = 1e-6, - alpha: float = 1e-1, beta: float = 1e-1,): + def __init__( + self, + nadir: np.ndarray, + ideal: np.ndarray, + rho: float = 1e-6, + rho_sum: float = 1e-6, + alpha: float = 1e-1, + beta: float = 1e-1, + ): self.nadir = nadir self.ideal = ideal self.rho = rho self.rho_sum = rho_sum self.alpha = alpha
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L433
r = reservation_point - self.rho nad = self.nadir ide = self.ideal uto = self.ideal - self.rho phi = np.zeros((objective_vectors.ndim,)) - + for i in range(objective_vectors.ndim): if ide[i] <= f[0][i] <= z[i]: - phi[i] = -1 + self.alpha * (1/(z-uto))[i] * (f[0][i] - z[i]) - + phi[i] = -1 + self.alpha * (1 / (z - uto))[i] * (f[0][i] - z[i]) + if z[i] <= f[0][i] <= r[i]: - phi[i] = (1/(r-z))[i] * (f[0][i] - r[i]) - + phi[i] = (1 / (r - z))[i] * (f[0][i] - r[i]) + if r[i] <= f[0][i] <= nad[i]: - phi[i] = self.beta * (1/(nad-r))[i] * (f[0][i] - r[i]) - - + phi[i] = self.beta * (1 / (nad - r))[i] * (f[0][i] - r[i]) + max_term = np.array([np.max(phi)]) sum_term = np.array([self.rho_sum * np.sum(phi)]) return max_term + sum_term - + class STEM(ASFBase): """Implementation of the Step Method (STEM). - + Args: nadir (np.ndarray): The nadir point. ideal (np.ndarray): The ideal point. rho A small number to form the utopian point. - + References: Benayoun, R., De Montgolfier, J., Tergny, J. and Laritchev, O. - Linear programming with multiple objective functions: Step method (STEM)’, + Linear programming with multiple objective functions: Step method (STEM)’, Mathematical programming, 1971, 1(1), 366–375. """ def __init__(self, nadir: np.ndarray, ideal: np.ndarray, rho: float = 1e-6):
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/ASF.py#L481
f = objective_vectors nad = self.nadir uto = self.ideal - self.rho phi = np.zeros((objective_vectors.ndim,)) - e = abs(nad-uto)/np.max((nad, uto), axis=0) - - max_term = np.array([(e/e.sum() * (f - uto)).max()]) - - return max_term + e = abs(nad - uto) / np.max((nad, uto), axis=0) + + max_term = np.array([(e / e.sum() * (f - uto)).max()]) + + return max_term
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/MOEADSF.py#L4
from abc import abstractmethod from typing import Union class MOEADSFError(Exception): - """Raised when an error related to the MOEADSF classes is encountered. - """ + """Raised when an error related to the MOEADSF classes is encountered.""" class MOEADSFBase(abc.ABC): """A base class for representing scalarizing functions for the MOEA/D algorithm. Instances of the implementations of this class should work as function.
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/MOEADSF.py#L38
""" pass class Tchebycheff(MOEADSFBase): - """Implements the Tchebycheff scalarizing function. - """ + """Implements the Tchebycheff scalarizing function.""" def __call__( self, objective_vector: np.ndarray, reference_vector: np.ndarray,
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/MOEADSF.py#L62
Note: The shaped of objective_vector and reference_vector must match. """ if not objective_vector.shape == reference_vector.shape: - msg = ( - "The dimensions of the objective vector {} and " - "reference_vector {} do not match." - ).format(objective_vector.shape, reference_vector.shape) + msg = ("The dimensions of the objective vector {} and " "reference_vector {} do not match.").format( + objective_vector.shape, reference_vector.shape + ) raise MOEADSFError(msg) feval = np.abs(objective_vector - ideal_vector) * reference_vector max_fun = np.max(feval) return max_fun class WeightedSum(MOEADSFBase): - """Implements the Weighted sum scalarization function - """ + """Implements the Weighted sum scalarization function""" - def __call__( - self, objective_vector: np.ndarray, reference_vector: np.ndarray - ) -> Union[float, np.ndarray]: + def __call__(self, objective_vector: np.ndarray, reference_vector: np.ndarray) -> Union[float, np.ndarray]: """Evaluate the WeightedSum scalarizing function. Args: objective_vector (np.ndarray): A vector representing a solution in the objective space.
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/MOEADSF.py#L94
Note: The shaped of objective_vector and reference_vector must match. A reference point is not needed. """ if not objective_vector.shape == reference_vector.shape: - msg = ( - "The dimensions of the objective vector {} and " - "reference_vector {} do not match." - ).format(objective_vector.shape, reference_vector.shape) + msg = ("The dimensions of the objective vector {} and " "reference_vector {} do not match.").format( + objective_vector.shape, reference_vector.shape + ) raise MOEADSFError(msg) feval = np.sum(objective_vector * reference_vector) return feval
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/MOEADSF.py#L141
Note: The shaped of objective_vector and reference_vector must match. The reference point is not needed. """ if not objective_vector.shape == reference_vector.shape: - msg = ( - "The dimensions of the objective vector {} and " - "reference_vector {} do not match." - ).format(objective_vector.shape, reference_vector.shape) + msg = ("The dimensions of the objective vector {} and " "reference_vector {} do not match.").format( + objective_vector.shape, reference_vector.shape + ) raise MOEADSFError(msg) norm_weights = np.linalg.norm(reference_vector) weights = np.true_divide(reference_vector, norm_weights) fx_a = objective_vector - ideal_vector
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/Scalarizer.py#L54
res_scal = self._scalarizer(res_eval) return res_scal def __call__(self, xs: np.ndarray) -> np.ndarray: - """Wrapper to the evaluate method. - """ + """Wrapper to the evaluate method.""" return self.evaluate(xs) class DiscreteScalarizer: - """Implements a class to scalarize discrete vectors given a scalarizing function. - """ + """Implements a class to scalarize discrete vectors given a scalarizing function.""" def __init__(self, scalarizer: Callable, scalarizer_args: Dict = None): self._scalarizer = scalarizer self._scalarizer_args = scalarizer_args
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/Scalarizer.py#L85
if __name__ == "__main__": vectors = np.array([[1, 1, 1], [2, 2, 2], [4, 5, 6.0]]) vector = np.array([1, 2, 3]) - dscalarizer = DiscreteScalarizer( - lambda x, a=1: a * np.sum(x, axis=1), scalarizer_args={"a": 2} - ) + dscalarizer = DiscreteScalarizer(lambda x, a=1: a * np.sum(x, axis=1), scalarizer_args={"a": 2}) res = dscalarizer(vectors) res_1d = dscalarizer(vector) print(res) print(res_1d)
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L3
from abc import abstractmethod from typing import Union class GLIDEError(Exception): - """Raised when an error related to the ASF classes is encountered. - """ + """Raised when an error related to the ASF classes is encountered.""" class GLIDEBase: """ Implements the non-differentiable variant of GLIDE-II as proposed in
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L29
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): - + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): self.has_additional_constraints = False self.utopian = utopian self.nadir = nadir self.rho = rho self.required_keys: dict = {}
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L68
max_term = np.max(mu[:, I_alpha] * f_minus_q[:, I_alpha], axis=1) sum_term = self.rho * np.sum(self.w * f_minus_q, axis=1) return max_term + sum_term - def evaluate_constraints( - self, objective_vector: np.ndarray, preference: dict - ) -> Union[None, np.ndarray]: + def evaluate_constraints(self, objective_vector: np.ndarray, preference: dict) -> Union[None, np.ndarray]: # TODO: Description for Args & Returns are yet to be filled. """Evaluate the additional contraints generated by the GLIDE-II formulation. Note: Additional contraints produced by the GLIDE-II formulation are implemented
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L159
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=nadir, rho=rho, **kwargs) self.has_additional_constraints = False - self.__I_alpha = np.full_like( - utopian, dtype=np.bool_, fill_value=True - ).flatten() - self.__I_epsilon = np.full_like( - utopian, dtype=np.bool_, fill_value=False - ).flatten() + self.__I_alpha = np.full_like(utopian, dtype=np.bool_, fill_value=True).flatten() + self.__I_epsilon = np.full_like(utopian, dtype=np.bool_, fill_value=False).flatten() self.__w = 1 self.__mu = 1 / (nadir - utopian) self.required_keys = { "reference point": ( "Used to calculate the direction of improvement: "
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L237
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=nadir, rho=rho, **kwargs) self.has_additional_constraints = False - self.__I_alpha = np.full_like( - utopian, dtype=np.bool_, fill_value=True - ).flatten() - self.__I_epsilon = np.full_like( - utopian, dtype=np.bool_, fill_value=False - ).flatten() + self.__I_alpha = np.full_like(utopian, dtype=np.bool_, fill_value=True).flatten() + self.__I_epsilon = np.full_like(utopian, dtype=np.bool_, fill_value=False).flatten() self.__w = 0 self.required_keys = { "reference point": ( "Used to calculate the direction of improvement: " "a line going from the nadir point to the reference point. "
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L313
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=nadir, rho=rho, **kwargs) self.__w = 1 class NIMBUS_GLIDE(GLIDEBase):
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L340
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=nadir, rho=rho, **kwargs) self.__mu = self.__w = 1 / (self.nadir - self.utopian) self.has_additional_constraints = True self.required_keys = { - "current solution": ( - "A solution preferred by the DM currently. " "(type: numpy.ndarray)" - ), + "current solution": ("A solution preferred by the DM currently. " "(type: numpy.ndarray)"), "classifications": ( "A list of same length as the number of objectives. Elements can only " "include some or all of ['<', '<=', '=', '>=', '0']. These classify " "the different objectives as defined in the NIMBUS or GLIDE-II paper. " "(type: list)"
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L410
def I_alpha(self): return self.improve_unconstrained + self.improve_constrained @Property def I_epsilon(self): - return ( - self.improve_unconstrained - + self.improve_constrained - + self.satisfactory - + self.relax_constrained - ) + return self.improve_unconstrained + self.improve_constrained + self.satisfactory + self.relax_constrained @Property def w(self): # This was in the paper return self.__w
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L434
@Property def q(self): q = np.full_like(self.utopian, fill_value=0, dtype=float) q[self.improve_unconstrained] = self.utopian[self.improve_unconstrained] - q[self.improve_constrained] = self.preference["levels"][ - self.improve_constrained - ] + q[self.improve_constrained] = self.preference["levels"][self.improve_constrained] return q @Property def epsilon(self): e = np.full_like(self.utopian, fill_value=np.nan, dtype=float) - case1 = ( - self.improve_constrained + self.improve_unconstrained + self.satisfactory - ) + case1 = self.improve_constrained + self.improve_unconstrained + self.satisfactory case2 = self.relax_constrained e[case1] = self.preference["current solution"][case1] e[case2] = self.preference["levels"][case2] return e
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L477
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=nadir, rho=rho, **kwargs) - self.__mu = (self.nadir - self.utopian) / np.max( - np.abs(np.vstack((utopian, nadir))), axis=0 - ) + self.__mu = (self.nadir - self.utopian) / np.max(np.abs(np.vstack((utopian, nadir))), axis=0) self.__w = 0 self.I_epsilon = np.full_like(self.utopian, dtype=np.bool_, fill_value=True) self.has_additional_constraints = True self.required_keys = { - "current solution": ( - "A solution preferred by the DM currently. " "(type: numpy.ndarray)" - ), + "current solution": ("A solution preferred by the DM currently. " "(type: numpy.ndarray)"), "classifications": ( "A list of same length as the number of objectives. Elements can only " "include some or all of [<=', '=', '>=']. These classify " "the different objectives as defined in the GLIDE-II paper. " "(type: list)"
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L586
nadir (np.ndarray, optional): The nadir point. Has no effect on STOM calculation. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=None, rho=rho, **kwargs) self.has_additional_constraints = False - self.__I_alpha = np.full_like( - utopian, dtype=np.bool_, fill_value=True - ).flatten() - self.__I_epsilon = np.full_like( - utopian, dtype=np.bool_, fill_value=False - ).flatten() + self.__I_alpha = np.full_like(utopian, dtype=np.bool_, fill_value=True).flatten() + self.__I_epsilon = np.full_like(utopian, dtype=np.bool_, fill_value=False).flatten() self.__w = 0 self.required_keys = { "reference point": ( "Used to calculate the direction of improvement: " "a line going from the reference point to the utopian point. "
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L662
nadir (np.ndarray, optional): The nadir point. Has no effect on STOM calculation. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=None, rho=rho, **kwargs) self.has_additional_constraints = False self.__w = 1
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L690
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, - utopian: np.ndarray = None, - nadir: np.ndarray = None, - rho: float = 1e-6, - **kwargs - ): + def __init__(self, utopian: np.ndarray = None, nadir: np.ndarray = None, rho: float = 1e-6, **kwargs): super().__init__(utopian=utopian, nadir=None, rho=rho, **kwargs) self.has_additional_constraints = False - self.__I_alpha = np.full_like( - utopian, dtype=np.bool_, fill_value=True - ).flatten() - self.__I_epsilon = np.full_like( - utopian, dtype=np.bool_, fill_value=False - ).flatten() + self.__I_alpha = np.full_like(utopian, dtype=np.bool_, fill_value=True).flatten() + self.__I_epsilon = np.full_like(utopian, dtype=np.bool_, fill_value=False).flatten() self.__w = 1 self.required_keys = { - "mu": ( - "Vector defining the direction of improvement of the scalarizer. " - "(type: numpy.ndarray)" - ) + "mu": ("Vector defining the direction of improvement of the scalarizer. " "(type: numpy.ndarray)") } @Property def I_epsilon(self): return self.__I_epsilon
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L765
nadir (np.ndarray, optional): The nadir point. Defaults to None. rho (float, optional): The augmentation term for the scalarization function. Defaults to 1e-6. """ - def __init__( - self, current_objective_vector: np.ndarray, rho: float = 1e-6, **kwargs - ): + def __init__(self, current_objective_vector: np.ndarray, rho: float = 1e-6, **kwargs): super().__init__(utopian=None, nadir=None, rho=rho, **kwargs) self.current_objective_vector = current_objective_vector self.has_additional_constraints = False - self.__I_alpha = np.full_like( - current_objective_vector, dtype=np.bool_, fill_value=True - ).flatten() - self.__I_epsilon = np.full_like( - current_objective_vector, dtype=np.bool_, fill_value=False - ).flatten() + self.__I_alpha = np.full_like(current_objective_vector, dtype=np.bool_, fill_value=True).flatten() + self.__I_epsilon = np.full_like(current_objective_vector, dtype=np.bool_, fill_value=False).flatten() self.__w = 0 @Property def I_epsilon(self): return self.__I_epsilon
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/scalarization/GLIDE_II.py#L789
def I_alpha(self): return self.__I_alpha @Property def mu(self): - return 1 / np.abs( - self.preference["reference point"] - self.current_objective_vector - ) + return 1 / np.abs(self.preference["reference point"] - self.current_objective_vector) @Property def w(self): return self.__w
/home/runner/work/desdeo-tools/desdeo-tools/desdeo_tools/solver/ScalarSolver.py#L23
class ScalarMethod: """A class the define and implement methods for minimizing scalar valued functions.""" - def __init__( - self, method: Callable, method_args=None, use_scipy: Optional[bool] = False - ): + def __init__(self, method: Callable, method_args=None, use_scipy: Optional[bool] = False): """ Args: method (Callable): A callable minimizer function which expects a callable scalar valued function to be minimized. The function should accept as its first argument a two dimensional numpy array and should
build
The following actions uses node12 which is deprecated and will be forced to run on node16: actions/checkout@v2, actions/setup-python@v2, actions/cache@v2. For more info: https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/
test (ubuntu-latest, 3.11)
The following actions uses node12 which is deprecated and will be forced to run on node16: actions/checkout@v2, actions/setup-python@v2, actions/cache@v2. For more info: https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/