Source code for desdeo.problem.RangeEstimators

"""
Contains tools to estimate the range of objective values in the Patero optimal
set. The vector with the best objective values is called the ideal, and the
vector with the worst values is called the nadir.
"""

from typing import List, Tuple, Type

import numpy as np

from desdeo.optimization.OptimizationMethod import OptimizationMethod
from desdeo.optimization.OptimizationProblem import SelectedOptimizationProblem
from desdeo.problem.Problem import MOProblem


[docs]def estimate_payoff_table( opt_meth_cls: Type[OptimizationMethod], mo_prob: MOProblem ) -> Tuple[List[float], List[float]]: """ Estimates the ideal and nadir by using a payoff table. This should give a good estimate for the ideal, but can be very inaccurate for the nadir. For an explanation of why, see [DEB2010]_. References ---------- .. [DEB2010] Deb, K., Miettinen, K., & Chaudhuri, S. (2010). Toward an estimation of nadir objective vector using a hybrid of evolutionary and local search approaches. IEEE Transactions on Evolutionary Computation, 14(6), 821-841. """ ideal = [float("inf")] * mo_prob.nobj nadir = [float("-inf")] * mo_prob.nobj for i in range(mo_prob.nobj): meth = opt_meth_cls(SelectedOptimizationProblem(mo_prob, i)) _decis, obj = meth.search() for j, obj_val in enumerate(obj): if obj_val < ideal[j]: ideal[j] = obj_val if obj_val > nadir[j]: nadir[j] = obj_val return ideal, nadir
[docs]def pad(idnad: Tuple[List[float], List[float]], pad_nadir=0.05, pad_ideal=0.0): """ Pad an ideal/nadir estimate. This is mainly useful for padding the nadir estimated by a payoff table for safety purposes. """ ideal, nadir = idnad ideal_arr = np.array(ideal) nadir_arr = np.array(nadir) idnad_range = nadir_arr - ideal_arr nadir_arr += pad_nadir * idnad_range ideal_arr -= pad_ideal * idnad_range return list(ideal_arr), list(nadir_arr)
[docs]def round_off(idnad: Tuple[List[float], List[float]], dp: int = 2): """ Round off an ideal/nadir estimate e.g. so that it's looks nicer when plotted. This function is careful to round so only ever move the values away from the contained range. """ ideal, nadir = idnad mult = np.power(10, dp) ideal_arr = np.floor(np.array(ideal) * mult) / mult nadir_arr = np.ceil(np.array(nadir) * mult) / mult return list(ideal_arr), list(nadir_arr)
[docs]def default_estimate( opt_meth: Type[OptimizationMethod], mo_prob: MOProblem, dp: int = 2 ) -> Tuple[List[float], List[float]]: """ The recommended nadir/ideal estimator - use a payoff table and then round off the result. """ return round_off(estimate_payoff_table(opt_meth, mo_prob), dp)