mcdm
desdeo.mcdm.nimbus
Functions related to the Sychronous NIMBUS method.
References
Miettinen, K., & Mäkelä, M. M. (2006). Synchronous approach in interactive multiobjective optimization. European Journal of Operational Research, 170(3), 909–922.
NimbusError
generate_starting_point
generate_starting_point(
problem: Problem,
reference_point: dict[str, float] | None = None,
scalarization_options: dict | None = None,
solver: BaseSolver | None = None,
solver_options: SolverOptions | None = None,
) -> SolverResults
Generates a starting point for the NIMBUS method.
Using the given reference point and achievement scalarizing function, finds one pareto optimal solution that can be used as a starting point for the NIMBUS method. If no reference point is given, ideal is used as the reference point.
Instead of using this function, the user can provide a starting point.
Raises:
| Type | Description |
|---|---|
NimbusError
|
the given problem has an undefined ideal or nadir point, or both. |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
reference_point
|
dict[str, float] | None
|
an objective dictionary with a reference point. If not given, ideal will be used as reference point. |
None
|
scalarization_options
|
dict | None
|
optional kwargs passed to the scalarization function. Defaults to None. |
None
|
solver
|
BaseSolver | None
|
solver used to solve the problem.
If not given, an appropriate solver will be automatically determined based on the features of |
None
|
solver_options
|
SolverOptions | None
|
optional options passed
to the |
None
|
Returns:
| Type | Description |
|---|---|
SolverResults
|
list[SolverResults]: a list of |
Source code in desdeo/mcdm/nimbus.py
infer_classifications
infer_classifications(
problem: Problem,
current_objectives: dict[str, float],
reference_point: dict[str, float],
) -> dict[str, tuple[str, float | None]]
Infers NIMBUS classifications based on a reference point and current objective values.
Infers the classifications based on a given reference point and current objective function values. The following classifications are inferred for each objective:
- \(I^{<}\): values that should improve, the reference point value of an objective function is equal to its ideal value;
- \(I^{\leq}\): values that should improve until a given aspiration level, the reference point value of an objective function is better than the current value;
- \(I^{=}\): values that should stay as they are, the reference point value of an objective function is equal to the current value;
- \(I^{\geq}\): values that can be impaired until some reservation level, the reference point value of an objective function is worse than the current value; and
- \(I^{\diamond}\): values that are allowed to change freely, the reference point value of and objective function is equal to its nadir value.
The aspiration levels and the reservation levels are then given for each classification, when relevant, in the return value of this function as the following example demonstrates:
classifications = {
"f_1": ("<", None),
"f_2": ("<=", 42.1),
"f_3": (">=", 22.2),
"f_4": ("0", None)
}
Raises:
| Type | Description |
|---|---|
NimbusError
|
the ideal or nadir point, or both, of the given problem are undefined. |
NimbusError
|
the reference point or current objectives are missing entries for one or more of the objective functions defined in the problem. |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem the current objectives and the reference point are related to. |
required |
current_objectives
|
dict[str, float]
|
an objective dictionary with the current objective functions values. |
required |
reference_point
|
dict[str, float]
|
an objective dictionary with the reference point values. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, tuple[str, float | None]]
|
dict[str, tuple[str, float | None]]: a dict with keys corresponding to the
symbols of the objective functions defined for the problem and with values
of tuples, where the first element is the classification (str) and the second
element is either a reservation level (in case of classification |
Source code in desdeo/mcdm/nimbus.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | |
solve_intermediate_solutions
solve_intermediate_solutions(
problem: Problem,
solution_1: dict[str, VariableType],
solution_2: dict[str, VariableType],
num_desired: int,
scalarization_options: dict | None = None,
solver: BaseSolver | None = None,
solver_options: SolverOptions | None = None,
) -> list[SolverResults]
Generates a desired number of intermediate solutions between two given solutions.
Generates a desires number of intermediate solutions given two Pareto optimal solutions. The solutions are generated by taking n number of steps between the two solutions in the objective space. The objective vectors corresponding to these solutions are then utilized as reference points in the achievement scalarizing function. Solving the functions for each reference point will project the reference point on the Pareto optimal front of the problem. These projected solutions are then returned. Note that the intermediate solutions are generated between the two given solutions, this means the returned solutions will not include the original points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
solution_1
|
dict[str, VariableType]
|
the first of the solutions between which the intermediate solutions are to be generated. |
required |
solution_2
|
dict[str, VariableType]
|
the second of the solutions between which the intermediate solutions are to be generated. |
required |
num_desired
|
int
|
the number of desired intermediate solutions to be generated. Must be at least |
required |
scalarization_options
|
dict | None
|
optional kwargs passed to the scalarization function. Defaults to None. |
None
|
solver
|
BaseSolver | None
|
solver used to solve the problem.
If not given, an appropriate solver will be automatically determined based on the features of |
None
|
solver_options
|
SolverOptions | None
|
optional options passed
to the |
None
|
Returns:
| Type | Description |
|---|---|
list[SolverResults]
|
list[SolverResults]: a list with the projected intermediate solutions as
|
Source code in desdeo/mcdm/nimbus.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
solve_sub_problems
solve_sub_problems(
problem: Problem,
current_objectives: dict[str, float],
reference_point: dict[str, float],
num_desired: int,
scalarization_options: dict | None = None,
solver: BaseSolver | None = None,
solver_options: SolverOptions | None = None,
) -> list[SolverResults]
Solves a desired number of sub-problems as defined in the NIMBUS methods.
Solves 1-4 scalarized problems utilizing different scalarization functions. The scalarizations are based on the classification of a solutions provided by a decision maker. The classifications are represented by a reference point. Returns a number of new solutions corresponding to the number of scalarization functions solved.
Depending on num_desired, solves the following scalarized problems corresponding
the the following scalarization functions:
- the NIMBUS scalarization function,
- the STOM scalarization function,
- the achievement scalarizing function, and
- the GUESS scalarization function.
Raises:
| Type | Description |
|---|---|
NimbusError
|
the given problem has an undefined ideal or nadir point, or both. |
NimbusError
|
either the reference point of current objective functions value are missing entries for one or more of the objective functions defined in the problem. |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
current_objectives
|
dict[str, float]
|
an objective dictionary with the objective functions values the classifications have been given with respect to. |
required |
reference_point
|
dict[str, float]
|
an objective dictionary with a reference point. The classifications utilized in the sub problems are derived from the reference point. |
required |
num_desired
|
int
|
the number of desired solutions to be solved. Solves as many scalarized problems. The value must be in the range 1-4. |
required |
scalarization_options
|
dict | None
|
optional kwargs passed to the scalarization function. Defaults to None. |
None
|
solver
|
BaseSolver | None
|
solver used to solve the problem.
If not given, an appropriate solver will be automatically determined based on the features of |
None
|
solver_options
|
SolverOptions | None
|
optional options passed
to the |
None
|
Returns:
| Type | Description |
|---|---|
list[SolverResults]
|
list[SolverResults]: a list of |
Source code in desdeo/mcdm/nimbus.py
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | |
desdeo.mcdm.enautilus
Functions related to the E-NAUTILUS method are defined here.
Reference of the method:
Ruiz, A. B., Sindhya, K., Miettinen, K., Ruiz, F., & Luque, M. (2015). E-NAUTILUS: A decision support system for complex multiobjective optimization problems based on the NAUTILUS method. European Journal of Operational Research, 246(1), 218-231.
ENautilusResult
Bases: BaseModel
The result of an iteration of the E-NAUTILUS method.
Source code in desdeo/mcdm/enautilus.py
calculate_closeness
calculate_closeness(
z_intermediate: ndarray,
z_nadir: ndarray,
z_representative: ndarray,
) -> float
Calculate the closeness of an intermediate point to the non-dominated set.
The greater the closeness is, the close intermediate point is to the non-dominated set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
z_intermediate
|
ndarray
|
the intermediate point. |
required |
z_nadir
|
ndarray
|
the nadir point of the non-dominated set. |
required |
z_representative
|
ndarray
|
the representative solution of |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
the closeness measure. |
Source code in desdeo/mcdm/enautilus.py
calculate_intermediate_points
calculate_intermediate_points(
z_previous: ndarray,
zs_representatives: ndarray,
iterations_left: int,
) -> np.ndarray
Calculates the intermediate points to be shown to the decision maker at each iteration.
The number of returned points depends on how many zs_representative points are supplied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
z_previous
|
ndarray
|
the point selected by the decision maker in the previous iteration. |
required |
zs_representatives
|
ndarray
|
the representative solutions at the current iteration. |
required |
iterations_left
|
int
|
the number of iterations left (including the current one). |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: an array of intermediate points. |
Source code in desdeo/mcdm/enautilus.py
calculate_lower_bounds
Calculates the lower bounds of reachable solutions from an intermediate point.
The lower bounds are calculated by solving an epsilon-constraint problem with the epsilon values taken from the intermediate point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
non_dominated_points
|
ndarray
|
a set of non-dominated points according to which the reachable values are computed. |
required |
z_intermediate
|
ndarray
|
the intermediate point according to which the lower bounds are calculated. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: the lower bounds of reachable solutions on the non-dominated set based from the intermediate point. |
Source code in desdeo/mcdm/enautilus.py
calculate_reachable_subset
calculate_reachable_subset(
non_dominated_points: ndarray,
reachable_indices: ndarray,
lower_bounds: ndarray,
z_preferred: ndarray,
) -> list[int]
Calculates the reachable subset on a non-dominated set from a selected intermediate point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
non_dominated_points
|
ndarray
|
the original set of non-dominated points. |
required |
reachable_indices
|
ndarray
|
the currently reachable indices, which will be used to select the new reachable points. |
required |
lower_bounds
|
ndarray
|
the lower bounds of the reachable subset of non-dominates points. |
required |
z_preferred
|
ndarray
|
the selected intermediate point subject to the reachable subset is calculated. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
list[int]: the indices of the reachable solutions |
Source code in desdeo/mcdm/enautilus.py
enautilus_get_representative_solutions
enautilus_get_representative_solutions(
problem: Problem,
result: ENautilusResult,
non_dominated_points: DataFrame,
) -> list[SolverResults]
Returns the solution corresponding to the intermediate points.
The representative points are selected based on the current intermediate points. If the number of iterations left is 0, then the intermediate and representative points are equal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
result
|
ENautilusResult
|
an ENautilusResponse returned by |
required |
non_dominated_points
|
DataFrame
|
a dataframe from which the representative solutions are taken. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
SolverResults |
list[SolverResults]
|
full information about the solutions. If information
other than just objective function values are expected, then the
supplied |
Source code in desdeo/mcdm/enautilus.py
enautilus_step
enautilus_step(
problem: Problem,
non_dominated_points: DataFrame | dict[str, float],
current_iteration: int,
iterations_left: int,
selected_point: dict[str, float],
reachable_point_indices: list[int],
number_of_intermediate_points: int,
) -> ENautilusResult
Compute one iteration of the E-NAUTILUS method.
It is assumed that information from a previous iteration (selected point,
etc.) is available either from a previous iteration of E-NAUTILUS, or if
this is the first iteration, then the selected (intermediate) point
selected_point should be the approximated nadir point from
non_dominated_points. In this case, the reachable_point_indices should
cover the whole of non_dominated_points. After the first iteration, all
the information for computing the next iteration is always available from
the previous iteration's result of this function (plus the selected_point
provided by e.g., a decision maker).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. Used mainly for manipulating the other arguments. |
required |
non_dominated_points
|
DataFrame
|
a set of non-dominated points
approximating the Pareto front of |
required |
current_iteration
|
int
|
the number of the current iteration. For the first iteration, this should be zero. |
required |
iterations_left
|
int
|
how many iteration are left (counting the current one). |
required |
selected_point
|
dict[str, float]
|
the selected intermediate point in
the previous iteration. If this is the first iteration, then this should
be the nadir point approximated from |
required |
reachable_point_indices
|
list[int]
|
the indices of the points in
|
required |
number_of_intermediate_points
|
int
|
how many intermediate points are generated. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ENautilusResult |
ENautilusResult
|
the result of the iteration. |
Source code in desdeo/mcdm/enautilus.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | |
prune_by_average_linkage
Prune a set of non-dominated points using average linkage clustering (Morse, 1980).
This is used to calculate the representative solutions in E-NAUTILUS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
non_dominated_points
|
ndarray
|
an array of non-dominated points in objective space. |
required |
k
|
int
|
Number of representative points to retain. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: an array of representative points. |
Source code in desdeo/mcdm/enautilus.py
desdeo.mcdm.nautili
Methods for the NAUTILI (a group decision making variant for NAUTILUS) method.
NAUTILI_Response
Bases: BaseModel
The response of the NAUTILI method.
Source code in desdeo/mcdm/nautili.py
NautiliError
nautili_init
Initializes the NAUTILI method.
Creates the initial response of the method, which sets the navigation point to the nadir point and the reachable bounds to the ideal and nadir points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem to be solved. |
required |
solver
|
BaseSolver | None
|
The solver to use. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
NAUTILUS_Response |
NAUTILI_Response
|
The initial response of the method. |
Source code in desdeo/mcdm/nautili.py
solve_reachable_bounds
solve_reachable_bounds(
problem: Problem,
navigation_point: dict[str, float],
solver: BaseSolver | None = None,
) -> tuple[dict[str, float], dict[str, float]]
Computes the current reachable (upper and lower) bounds of the solutions in the objective space.
The reachable bound are computed based on the current navigation point. The bounds are computed by solving an epsilon constraint problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
navigation_point
|
dict[str, float]
|
the navigation point limiting the reachable area. The key is the objective function's symbol and the value the navigation point. |
required |
solver
|
BaseSolver | None
|
solver based on BaseSolver used to solve the problem. If None, then a solver is utilized bases on the problem's properties. Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
NautiliError
|
when optimization of an epsilon constraint problem is not successful. |
Returns:
| Type | Description |
|---|---|
tuple[dict[str, float], dict[str, float]]
|
tuple[dict[str, float], dict[str, float]]: a tuple of dicts, where the first dict are the lower bounds and the second element the upper bounds, the key is the symbol of each objective. |
Source code in desdeo/mcdm/nautili.py
solve_reachable_solution
solve_reachable_solution(
problem: Problem,
group_improvement_direction: dict[str, float],
previous_nav_point: dict[str, float],
solver: BaseSolver | None = None,
solver_options: SolverOptions | None = None,
) -> SolverResults
Calculates the reachable solution on the Pareto optimal front.
For the calculation to make sense in the context of NAUTILI, the reference point should be bounded by the reachable bounds present at the navigation step the reference point has been given.
In practice, the reachable solution is calculated by solving an achievement scalarizing function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
group_improvement_direction
|
dict[str, float]
|
the improvement direction for the group. |
required |
previous_nav_point
|
dict[str, float]
|
the previous navigation point. The reachable solution found is always better than the previous navigation point. |
required |
solver
|
BaseSolver | None
|
solver based on BaseSolver used to solve the problem. If None, then a solver is utilized bases on the problem's properties. Defaults to None. |
None
|
solver_options
|
SolverOptions | None
|
optional options passed
to the |
None
|
Returns: SolverResults: the results of the projection.
Source code in desdeo/mcdm/nautili.py
desdeo.mcdm.nautilus
Functions related to the NAUTILUS 1/2 method are defined here.
Reference of the method:
TODO: update
NAUTILUS_Response
Bases: BaseModel
The response of the NAUTILUS method.
Source code in desdeo/mcdm/nautilus.py
NautilusError
__nautilus_all_steps
__nautilus_all_steps(
problem: Problem,
steps_remaining: int,
preference: dict,
previous_responses: list[NAUTILUS_Response],
solver: BaseSolver | None = None,
) -> list[NAUTILUS_Response]
Performs all steps of the NAUTILUS method.
NAUTILUS needs to be initialized before calling this function. Once initialized, this function performs all steps of the method. However, this method need not start from the beginning. The method conducts "steps_remaining" number of steps from the last navigation point. The last navigation point is taken from the last response in "previous_responses" list. The first step in this algorithm always involves recalculating the reachable solution. All subsequest steps are precalculated without recalculating the reachable solution, with the assumption that the reference point has not changed. It is up to the user to only show the steps that the DM thinks they have taken.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem to be solved. |
required |
steps_remaining
|
int
|
The number of steps remaining. |
required |
preference
|
dict
|
The points provided by the DM for defining preference. |
required |
previous_responses
|
list[NAUTILUS_Response]
|
The previous responses of the method. |
required |
solver
|
BaseSolver | None
|
The solver to use. Defaults to None, in which case the algorithm will guess the best solver for the problem. |
None
|
Returns:
| Type | Description |
|---|---|
list[NAUTILUS_Response]
|
list[NAUTILUS_Response]: The new responses of the method after all steps. Note, as only new responses are returned, the length of the list is equal to "steps_remaining". The analyst should append these responses to the "previous_responses" list to keep track of the entire process. |
Source code in desdeo/mcdm/nautilus.py
calculate_preferential_factors
get_current_path
Get the path of the current responses.
All responses may contain steps that the DM has gone back on. This function returns the path of the current active path being followed by the DM. The path is a list of indices of the responses in the "all_responses" list. Note that the path includes all steps until reaching the Pareto front (or whatever the last response is). It is up to the analyst/GUI to only show the steps that the DM has taken.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
all_responses
|
list[NAUTILUS_Response]
|
All responses returned by the NAUTILUS method. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
list[int]: The path of the current active responses. |
Source code in desdeo/mcdm/nautilus.py
nautilus_init
Initializes the NAUTILUS method.
Creates the initial response of the method, which sets the navigation point to the nadir point and the reachable bounds to the ideal and nadir points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem to be solved. |
required |
solver
|
BaseSolver | None
|
The solver to use. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
NAUTILUS_Response |
NAUTILUS_Response
|
The initial response of the method. |
Source code in desdeo/mcdm/nautilus.py
nautilus_step
nautilus_step(
problem: Problem,
steps_remaining: int,
step_number: int,
nav_point: dict,
solver: BaseSolver | None = None,
points: dict[str, float] | None = None,
ranks: dict[str, int] | None = None,
) -> NAUTILUS_Response
Performs a step of the NAUTILUS method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem to be solved. |
required |
steps_remaining
|
int
|
The number of steps remaining. |
required |
step_number
|
int
|
The current step number. Just used for the response. |
required |
nav_point
|
dict
|
The current navigation point. |
required |
solver
|
BaseSolver | None
|
The solver to use. Defaults to None. |
None
|
points
|
dict[str, float] | None
|
The points of the objectives. Defaults to None. |
None
|
ranks
|
dict[str, int] | None
|
The ranks of the objectives. Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
NautilusError
|
If neither preference nor reachable_solution is provided. |
NautilusError
|
If both preference and reachable_solution are provided. |
Returns:
| Name | Type | Description |
|---|---|---|
NAUTILUS_Response |
NAUTILUS_Response
|
The response of the method after the step. |
Source code in desdeo/mcdm/nautilus.py
points_to_weights
Convert points to weights.
The points are converted to weights using the following formula: weight = point * (nadir - utopian).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
dict[str, float]
|
The points of the objectives. |
required |
problem
|
Problem
|
The problem being solved. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
dict[str, float]: The weights calculated from the points. |
Source code in desdeo/mcdm/nautilus.py
ranks_to_weights
Convert ranks to weights.
The ranks are converted to weights using the following formula: weight = rank * (nadir - utopian). Note that this means that a lower rank is worse.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ranks
|
dict[str, int]
|
The ranks of the objectives. |
required |
problem
|
Problem
|
The problem being solved. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
dict[str, float]: The weights calculated from the ranks. |
Source code in desdeo/mcdm/nautilus.py
solve_reachable_solution
solve_reachable_solution(
problem: Problem,
weights: dict[str, float],
previous_nav_point: dict[str, float],
solver: BaseSolver | None = None,
) -> SolverResults
Calculates the reachable solution on the Pareto optimal front.
For the calculation to make sense in the context of NAUTILUS, the reference point should be bounded by the reachable bounds present at the navigation step the reference point has been given.
In practice, the reachable solution is calculated by solving an achievement scalarizing function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
weights
|
dict[str, float]
|
the weights defining the direction of improvement. Must be calculated from the preference provided by the DM (weights, ranks, or reference point). |
required |
previous_nav_point
|
dict[str, float]
|
the previous navigation point. The reachable solution found is always better than the previous navigation point. |
required |
solver
|
BaseSolver | None
|
solver to solve the problem. If None, then a solver is utilized bases on the problem's properties. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
SolverResults |
SolverResults
|
the results of the projection. |
Source code in desdeo/mcdm/nautilus.py
step_back_index
Find the index of the response with the given step number.
Note, multiple responses can have the same step number. This may happen if the DM takes a step back. In this case, the latest response with the given step number is returned. Note, as we precalculate all the responses, it is up to the analyst to show the steps that the DM thinks they have taken. Without this, the DM may be confused. In the worst case, the DM may take a step "back to the future".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
responses
|
list[NAUTILUS_Response]
|
Responses returned by the NAUTILUS method. |
required |
step_number
|
int
|
The step number to go back to. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index of the response with the given step number. |
Source code in desdeo/mcdm/nautilus.py
desdeo.mcdm.nautilus_navigator
Functions related to the NAUTILUS Navigator method are defined here.
Reference of the method:
Ruiz, Ana B., et al. "NAUTILUS Navigator: free search interactive multiobjective optimization without trading-off." Journal of Global Optimization 74.2 (2019): 213-231.
NAUTILUS_Response
Bases: BaseModel
The response of the NAUTILUS Navigator method.
Source code in desdeo/mcdm/nautilus_navigator.py
NautilusNavigatorError
calculate_distance_to_front
calculate_distance_to_front(
problem: Problem,
navigation_point: dict[str, float],
reachable_objective_vector: dict[str, float],
) -> float
Calculates the distance to the Pareto optimal front from a navigation point.
It is assumed that a nadir point is defined for the problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
navigation_point
|
dict[str, float]
|
the current navigation point. |
required |
reachable_objective_vector
|
dict[str, float]
|
the current reachable objective vector from the navigation point. |
required |
Raises:
| Type | Description |
|---|---|
NautilusNavigatorError
|
all or some of the components of the problem's nadir point are not defined. |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
the distance to the front. |
Source code in desdeo/mcdm/nautilus_navigator.py
calculate_navigation_point
calculate_navigation_point(
problem: Problem,
previous_navigation_point: dict[str, float],
reachable_objective_vector: dict[str, float],
number_of_steps_remaining: int,
) -> dict[str, float]
Calculates the navigation point.
The navigation point based on the previous navigation point, number of navigation steps remaining, and the reachable objective vector from the new navigation point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
previous_navigation_point
|
dict[str, float]
|
the previous navigation point. |
required |
reachable_objective_vector
|
dict[str, float]
|
the current reachable objective vector from the navigation point. |
required |
number_of_steps_remaining
|
int
|
the number of steps remaining in the navigation. Must be greater than 0. |
required |
Raises:
| Type | Description |
|---|---|
NautilusNavigatorError
|
when the given number of steps remaining is less than 0. |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
list[float]: the navigation point. |
Source code in desdeo/mcdm/nautilus_navigator.py
get_current_path
Get the path of the current responses.
All responses may contain steps that the DM has gone back on. This function returns the path of the current active path being followed by the DM. The path is a list of indices of the responses in the "all_responses" list. Note that the path includes all steps until reaching the Pareto front (or whatever the last response is). It is up to the analyst/GUI to only show the steps that the DM has taken.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
all_responses
|
list[NAUTILUS_Response]
|
All responses returned by the NAUTILUS method. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
list[int]: The path of the current active responses. |
Source code in desdeo/mcdm/nautilus_navigator.py
navigator_all_steps
navigator_all_steps(
problem: Problem,
steps_remaining: int,
reference_point: dict,
previous_responses: list[NAUTILUS_Response],
bounds: dict | None = None,
solver: BaseSolver | None = None,
) -> list[NAUTILUS_Response]
Performs all steps of the NAUTILUS method.
NAUTILUS needs to be initialized before calling this function. Once initialized, this function performs all steps of the method. However, this method need not start from the beginning. The method conducts "steps_remaining" number of steps from the last navigation point. The last navigation point is taken from the last response in "previous_responses" list. The first step in this algorithm always involves recalculating the reachable solution. All subsequest steps are precalculated without recalculating the reachable solution, with the assumption that the reference point has not changed. It is up to the user to only show the steps that the DM thinks they have taken.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem to be solved. |
required |
steps_remaining
|
int
|
The number of steps remaining. |
required |
reference_point
|
dict
|
The reference point provided by the DM. |
required |
bounds
|
dict
|
The bounds of the problem provided by the DM. |
None
|
previous_responses
|
list[NAUTILUS_Response]
|
The previous responses of the method. |
required |
solver
|
BaseSolver | None
|
The solver to use. Defaults to None, in which case the algorithm will guess the best solver for the problem. |
None
|
Returns:
| Type | Description |
|---|---|
list[NAUTILUS_Response]
|
list[NAUTILUS_Response]: The new responses of the method after all steps. Note, as only new responses are returned, the length of the list is equal to "steps_remaining". The analyst should append these responses to the "previous_responses" list to keep track of the entire process. |
Source code in desdeo/mcdm/nautilus_navigator.py
navigator_init
Initializes the NAUTILUS method.
Creates the initial response of the method, which sets the navigation point to the nadir point and the reachable bounds to the ideal and nadir points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem to be solved. |
required |
solver
|
BaseSolver | None
|
The solver to use. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
NAUTILUS_Response |
NAUTILUS_Response
|
The initial response of the method. |
Source code in desdeo/mcdm/nautilus_navigator.py
navigator_step
navigator_step(
problem: Problem,
steps_remaining: int,
step_number: int,
nav_point: dict,
bounds: dict | None = None,
solver: BaseSolver | None = None,
reference_point: dict | None = None,
reachable_solution: dict[str, float] | None = None,
) -> NAUTILUS_Response
Performs a step of the NAUTILUS method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem to be solved. |
required |
steps_remaining
|
int
|
The number of steps remaining. |
required |
step_number
|
int
|
The current step number. Just used for the response. |
required |
nav_point
|
dict
|
The current navigation point. |
required |
solver
|
BaseSolver | None
|
The solver to use. Defaults to None. |
None
|
reference_point
|
dict | None
|
The reference point provided by the DM. Defaults to None, in which case it is assumed that the DM has not changed their preference. The algorithm uses the last reachable solution, which must be provided in this case. |
None
|
bounds
|
dict | None
|
The bounds of the problem provided by the DM. Defaults to None. |
None
|
reachable_solution
|
dict | None
|
The previous reachable solution. Must only be provided if the DM has not changed their preference. Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
NautilusNavigatorError
|
If neither reference_point nor reachable_solution is provided. |
NautilusNavigatorError
|
If both reference_point and reachable_solution are provided. |
Returns:
| Name | Type | Description |
|---|---|---|
NAUTILUS_Response |
NAUTILUS_Response
|
The response of the method after the step. |
Source code in desdeo/mcdm/nautilus_navigator.py
solve_reachable_bounds
solve_reachable_bounds(
problem: Problem,
navigation_point: dict[str, float],
bounds: dict[str, float] | None = None,
solver: BaseSolver | None = None,
bound_th: float = 0.001,
) -> tuple[dict[str, float], dict[str, float]]
Computes the current reachable (upper and lower) bounds of the solutions in the objective space.
The reachable bound are computed based on the current navigation point. The bounds are computed by solving an epsilon constraint problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
navigation_point
|
dict[str, float]
|
the navigation point limiting the reachable area. The key is the objective function's symbol and the value the navigation point. |
required |
bounds
|
dict[str, float]
|
the user provided bounds preference. |
None
|
solver
|
BaseSolver | None
|
solver used to solve the problem. If None, then a solver is utilized bases on the problem's properties. Defaults to None. |
None
|
bound_th
|
float
|
a threshold for comparing the bounds to the set epsilon constraints. |
0.001
|
Raises:
| Type | Description |
|---|---|
NautilusNavigationError
|
when optimization of an epsilon constraint problem is not successful. |
Returns:
| Type | Description |
|---|---|
tuple[dict[str, float], dict[str, float]]
|
tuple[dict[str, float], dict[str, float]]: a tuple of dicts, where the first dict are the lower bounds and the second element the upper bounds, the key is the symbol of each objective. |
Source code in desdeo/mcdm/nautilus_navigator.py
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | |
solve_reachable_solution
solve_reachable_solution(
problem: Problem,
reference_point: dict[str, float],
previous_nav_point: dict[str, float],
solver: BaseSolver | None = None,
bounds: dict[str, float] | None = None,
) -> SolverResults
Calculates the reachable solution on the Pareto optimal front.
For the calculation to make sense in the context of NAUTILUS Navigator, the reference point should be bounded by the reachable bounds present at the navigation step the reference point has been given.
In practice, the reachable solution is calculated by solving an achievement scalarizing function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
reference_point
|
dict[str, float]
|
the reference point to project on the Pareto optimal front. |
required |
previous_nav_point
|
dict[str, float]
|
the previous navigation point. The reachable solution found is always better than the previous navigation point. |
required |
solver
|
BaseSolver | None
|
solver to solve the problem. If None, then a solver is utilized bases on the problem's properties. Defaults to None. |
None
|
bounds
|
dict[str, float] | None
|
the bounds of the problem. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
SolverResults |
SolverResults
|
the results of the projection. |
Source code in desdeo/mcdm/nautilus_navigator.py
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | |
step_back_index
Find the index of the response with the given step number.
Note, multiple responses can have the same step number. This may happen if the DM takes a step back. In this case, the latest response with the given step number is returned. Note, as we precalculate all the responses, it is up to the analyst to show the steps that the DM thinks they have taken. Without this, the DM may be confused. In the worst case, the DM may take a step "back to the future".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
responses
|
list[NAUTILUS_Response]
|
Responses returned by the NAUTILUS method. |
required |
step_number
|
int
|
The step number to go back to. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index of the response with the given step number. |
Source code in desdeo/mcdm/nautilus_navigator.py
desdeo.mcdm.pareto_navigator
Functions related to the Pareto Navigator method are defined here.
Reference of the method:
Eskelinen, Petri, et al. "Pareto navigator for interactive nonlinear multiobjective optimization." OR spectrum 32 (2010): 211-227.
calculate_adjusted_speed
calculate_adjusted_speed(
allowed_speeds: list[int],
speed: float,
scalar: float | None = 20,
) -> float
Calculate an adjusted speed from a given float.
Note
Adjusting the speed is not specified in the article but seems necessary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allowed_speeds
|
ndarray
|
An array of allowed speeds. |
required |
speed
|
float
|
A given speed value where. |
required |
scalar
|
float | None(optional)
|
A scale to adjust the speed. Defaults to 20. |
20
|
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
An adjusted speed value calculated from given float. Is between 0 and 1. |
Source code in desdeo/mcdm/pareto_navigator.py
calculate_all_solutions
calculate_all_solutions(
problem: Problem,
current_solution: dict[str, float],
alpha: float,
num_solutions: int,
pref_info: dict,
) -> list[dict[str, float]]
Performs a set number of steps in the current direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem being solved. |
required |
current_solution
|
dict[str, float]
|
The current solution. |
required |
alpha
|
float
|
Step size. Between 0 and 1. |
required |
num_solutions
|
int
|
Number of solutions calculated. |
required |
pref_info
|
dict
|
Preference information. Either "reference_point" or "classification". |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, float]]
|
list[dict[str, float]]: A list of the computed solutions. |
Source code in desdeo/mcdm/pareto_navigator.py
calculate_next_solution
calculate_next_solution(
problem: Problem,
search_direction: dict[str, float],
current_solution: dict[str, float],
alpha: float,
matrix_a: ndarray,
b: ndarray,
) -> dict[str, float]
Calculate the next solution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem being solved. |
required |
search_direction
|
dict[str, float]
|
The search direction. |
required |
current_solution
|
dict[str, float]
|
The currently navigated point. |
required |
alpha
|
float
|
Step size. Between 0 and 1. |
required |
matrix_a
|
ndarray
|
The A' matrix. |
required |
b
|
ndarray
|
The b vector. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
dict[str, float]: The next solution. |
Source code in desdeo/mcdm/pareto_navigator.py
calculate_search_direction
calculate_search_direction(
problem: Problem,
reference_point: dict[str, float],
current_point: dict[str, float],
) -> dict[str, float]
Calculate search direction from the current point to the reference point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem being solved. |
required |
reference_point
|
dict[str, float]
|
The given reference point. |
required |
current_point
|
dict[str, float]
|
Currently navigated point. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
dict[str, float]: The direction from the current point to the reference point. |
Source code in desdeo/mcdm/pareto_navigator.py
classification_to_reference_point
classification_to_reference_point(
problem: Problem,
pref_info: dict[str, str],
current_solution: dict[str, float],
) -> dict[str, float]
Convert preference information given as classification into a reference point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem being solved. |
required |
pref_info
|
dict[str, str]
|
The preference information given as classification. |
required |
current_solution
|
dict[str, float]
|
The current solution. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
dict[str, float]: A reference point converted from classification. |
Source code in desdeo/mcdm/pareto_navigator.py
construct_matrix_a
Construct the A' matrix in the linear parametric programming problem from the article.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem being solved. |
required |
matrix_a
|
ndarray
|
The A matrix from the polyhedral set equation. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: The A' matrix in the linear parametric programming problem from the article. |
Source code in desdeo/mcdm/pareto_navigator.py
get_polyhedral_set
Get a polyhedral set as convex hull from the set of pareto optimal solutions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
The problem being solved. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray]
|
tuple[np.ndarray, np.ndarray]: The A matrix and b vector from the polyhedral set equation. |
Source code in desdeo/mcdm/pareto_navigator.py
desdeo.mcdm.reference_point_method
Functions related to the reference point method.
This module contains functions related to the reference point method as presented in Wierzbicki, A. P. (1982). A mathematical basis for satisficing decision making. Mathematical modelling, 3(5), 391-405.
ReferencePointError
rpm_intermediate_solutions
rpm_intermediate_solutions(
problem: Problem,
solution_1: dict[str, float],
solution_2: dict[str, float],
num_desired: int,
scalarization_options: dict | None = None,
solver: BaseSolver | None = None,
solver_options: SolverOptions | None = None,
) -> list[SolverResults]
Generates a desired number of intermediate solutions between two given solutions.
Generates a desires number of intermediate solutions given reference vectors. The solutions are generated by taking n number of steps between the two reference points in the objective space. The vectors corresponding to these values are then utilized as reference points in the achievement scalarizing function. Solving the functions for each reference point will a solution close the the projection of the reference point on the Pareto optimal front of the problem. These solutions are then returned. Note that the intermediate solutions are generated between the two given reference points, this means the returned solutions will not include solutions corresponding to the original reference points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem being solved. |
required |
solution_1
|
dict[str, VariableType]
|
the first of the reference points between which the intermediate solutions are to be generated. |
required |
solution_2
|
dict[str, VariableType]
|
the second of the reference points between which the intermediate solutions are to be generated. |
required |
num_desired
|
int
|
the number of desired intermediate solutions to be generated. Must be at least |
required |
scalarization_options
|
dict | None
|
optional kwargs passed to the scalarization function. Defaults to None. |
None
|
solver
|
BaseSolver | None
|
solver used to solve the problem.
If not given, an appropriate solver will be automatically determined based on the features of |
None
|
solver_options
|
SolverOptions | None
|
optional options passed
to the |
None
|
Returns:
| Type | Description |
|---|---|
list[SolverResults]
|
list[SolverResults]: a list with the projected intermediate solutions as
|
Source code in desdeo/mcdm/reference_point_method.py
rpm_solve_solutions
rpm_solve_solutions(
problem: Problem,
reference_point: dict[str, float],
scalarization_options: dict | None = None,
solver: BaseSolver | None = None,
solver_options: SolverOptions | None = None,
) -> list[SolverResults]
Finds (near) Pareto optimal solutions based on a reference point.
Find a (near) Pareto optimal solution based on the given reference point by optimizing an achievement scalarizing function. The original reference point is also perturbed, and another k (near) Pareto optimal solutions are found. The k+1 solutions are then returned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
Problem
|
the problem to be solved. |
required |
reference_point
|
dict[str, float]
|
the reference point. The keys of the dict represent the objective function symbols defined in problem. The values represent the aspiration level values. |
required |
scalarization_options
|
dict | None
|
keyword arguments to be passed to the achievement scalarizing function. Defaults to None. |
None
|
solver
|
BaseSolver | None
|
solver to optimize the achievement scalarizing function. If not given, the method tried to guess the most suitable solver based on the problem. Defaults to None. |
None
|
solver_options
|
SolverOptions | None
|
options passed to the solver. If not given, the solver will use its default options. Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
ReferencePointError
|
the reference point is ill-defined. |
Returns:
| Type | Description |
|---|---|
list[SolverResults]
|
list[SolverResults]: a list of results containing the solutions found using the reference point and the k perturbed reference points. |
Note
If the problem is twice differentiable, add_asf_diff is used from desdeo.tools.
If the problem is not twice differentiable, then add_asf_nondiff is used.