def _metric(self, data): ret = super()._metric(data) if not self.sliding_window: data = self.data[-self.metric_window_size:] # get necessary data from the current population current = data[-1] c_F, c_ideal, c_nadir = current["F"], current["ideal"], current[ "nadir"] # normalize all previous generations with respect to current ideal and nadir N = [normalize(e["F"], c_ideal, c_nadir) for e in data] # check if the movement of all points is significant if self.all_to_current: c_N = normalize(c_F, c_ideal, c_nadir) if self.perf_indicator == "igd": delta_f = [IGD(c_N).do(N[k]) for k in range(len(N))] elif self.perf_indicator == "hv": hv = Hypervolume(ref_point=np.ones(c_F.shape[1])) delta_f = [hv.do(N[k]) for k in range(len(N))] else: delta_f = [IGD(N[k + 1]).do(N[k]) for k in range(len(N) - 1)] ret["delta_f"] = delta_f return ret
def __init__(self, min_igd, pf) -> None: super().__init__() if pf is None: raise Exception( "You can only use IGD termination criteria if the pareto front is known!" ) self.obj = IGD(pf) self.igd = min_igd
def _metric(self, data): last, current = data[-2], data[-1] # this is the range between the nadir and the ideal point norm = current["nadir"] - current["ideal"] # if the range is degenerated (very close to zero) - disable normalization by dividing by one norm[norm < 1e-32] = 1 # calculate the change from last to current in ideal and nadir point delta_ideal = calc_delta_norm(current["ideal"], last["ideal"], norm) delta_nadir = calc_delta_norm(current["nadir"], last["nadir"], norm) # get necessary data from the current population c_F, c_ideal, c_nadir = current["F"], current["ideal"], current[ "nadir"] # normalize last and current with respect to most recent ideal and nadir c_N = normalize(c_F, c_ideal, c_nadir) l_N = normalize(last["F"], c_ideal, c_nadir) # calculate IGD from one to another delta_f = IGD(c_N).do(l_N) return { "delta_ideal": delta_ideal, "delta_nadir": delta_nadir, "delta_f": delta_f }
def disp_multi_objective(problem, evaluator, D): attrs = [('n_gen', D['n_gen'], 5), ('n_eval', evaluator.n_eval, 7)] pf = problem.pareto_front() if pf is not None: attrs.append(('igd', "%.5f" % IGD(pf).calc(D['pop'].F), 8)) return attrs
class IGDTermination(Termination): def __init__(self, min_igd, pf) -> None: super().__init__() if pf is None: raise Exception( "You can only use IGD termination criteria if the pareto front is known!" ) self.obj = IGD(pf) self.igd = min_igd def _do_continue(self, algorithm): F = algorithm.pop.get("F") return self.obj.calc(F) > self.igd
def _do(self, problem, evaluator, algorithm): super()._do(problem, evaluator, algorithm) F, CV, feasible = algorithm.pop.get("F", "CV", "feasible") feasible = np.where(feasible[:, 0])[0] if problem.n_constr > 0: self.output.append("cv (min)", CV.min()) self.output.append("cv (avg)", np.mean(CV)) if self.pareto_front_is_available: igd, gd, hv = "-", "-", "-" if len(feasible) > 0: _F = algorithm.opt.get("F") igd, gd = IGD(self.pf, zero_to_one=True).do(_F), GD( self.pf, zero_to_one=True).do(_F) if problem.n_obj == 2: hv = Hypervolume(pf=self.pf, zero_to_one=True).do(_F) self.output.extend(*[('igd', igd), ('gd', gd)]) if problem.n_obj == 2: self.output.append("hv", hv) else: self.output.append("n_nds", len(algorithm.opt), width=7) self.term.do_continue(algorithm) max_from, eps = "-", "-" if len(self.term.metrics) > 0: metric = self.term.metrics[-1] tol = self.term.tol delta_ideal, delta_nadir, delta_f = metric[ "delta_ideal"], metric["delta_nadir"], metric["delta_f"] if delta_ideal > tol: max_from = "ideal" eps = delta_ideal elif delta_nadir > tol: max_from = "nadir" eps = delta_nadir else: max_from = "f" eps = delta_f self.output.append("eps", eps) self.output.append("indicator", max_from)
def do(self, data, scope=None, benchmark=None, inplace=False, **kwargs): assert benchmark is not None, "The benchmark is necessary to retrieve the known optimum of a function" problem = benchmark.problems[data["problem"]]["obj"] CV, F = from_dict(data, "CV", "F") igd = np.inf pf = problem.pareto_front(**kwargs) if pf is not None: igd = IGD(pf, zero_to_one=True).do(F) ret = { "pf": pf, "igd": igd, } if inplace: for k, v in ret.items(): data[k] = v return ret
def disp_multi_objective(problem, evaluator, algorithm, pf=None): attrs = [('n_gen', algorithm.n_gen, 5), ('n_eval', evaluator.n_eval, 7)] F, CV, feasible = algorithm.pop.get("F", "CV", "feasible") feasible = np.where(feasible[:, 0])[0] if problem.n_constr > 0: attrs.append(('cv (min/avg)', "%.5f / %.5f" % (np.min(CV), np.mean(CV)), 13)) if len(feasible) > 0: if pf is not None: attrs.append(('igd', "%.5f" % IGD(pf).calc(F[feasible]), 8)) attrs.append(('gd', "%.5f" % GD(pf).calc(F[feasible]), 8)) if problem.n_obj == 2: attrs.append(('hv', "%.5f" % Hypervolume(pf=pf).calc(F[feasible]), 8)) else: attrs.append(('igd', "-", 8)) attrs.append(('gd', "-", 8)) if problem.n_obj == 2: attrs.append(('hv', "-", 8)) return attrs
def do(self, F, others=None, calc_hv=True): """ This method calculates the R-IGD and R-HV based off of the values provided. Parameters ---------- F : numpy.ndarray The objective space values others : numpy.ndarray Results from other algorithms which should be used for filtering nds solutions calc_hv : bool Whether the hv is calculate - (None if more than 3 dimensions) Returns ------- rigd : float R-IGD rhv : float R-HV if calc_hv is true and less or equal to 3 dimensions """ self.F, self.others = F, others translated = [] final_PF = [] # 1. Prescreen Procedure - NDS Filtering pop = self._filter() pf = self.pf if pf is None: pf = self.problem.pareto_front() if pf is None: raise Exception( "Please provide the Pareto front to calculate the R-Metric!") labels = np.argmin(cdist(pop, self.ref_points), axis=1) for i in range(len(self.ref_points)): cluster = pop[np.where(labels == i)] if len(cluster) != 0: # 2. Representative Point Identification zp = self._preprocess(cluster, self.ref_points[i], w_point=self.w_points[i])[0] # 3. Filtering Procedure - Filter points trimmed_data = self._trim(cluster, zp, range=self.delta) # 4. Solution Translation pop_t = self._translate(zp, trimmed_data, self.ref_points[i], w_point=self.w_points[i]) translated.extend(pop_t) # 5. R-Metric Computation target = self._preprocess(data=pf, ref_point=self.ref_points[i], w_point=self.w_points[i]) PF = self._trim(pf, target) final_PF.extend(PF) translated = np.array(translated) final_PF = np.array(final_PF) rigd, rhv = None, None if len(translated) > 0: # IGD Computation rigd = IGD(final_PF).do(translated) nadir_point = np.amax(self.w_points, axis=0) front = translated dim = self.ref_points[0].shape[0] if calc_hv: if dim <= 3: try: rhv = Hypervolume(ref_point=nadir_point).do(front) except: pass if calc_hv: return rigd, rhv else: return rigd
def calc(self, hyper_volume=True, delta=0.2, pf=None): """ This method calculates the R-IGD and R-HV based off of the population that was provided :return: R-IGD and R-HV """ translated = [] final_PF = [] # 1. Prescreen Procedure - NDS Filtering pop = self._filter() if pf is not None: solution = pf else: solution = self.problem.pareto_front() # solution = calc_PF(1, 10000, 2) labels = np.argmin(cdist(pop, self.ref_points), axis=1) for i in range(len(self.ref_points)): cluster = pop[np.where(labels == i)] if len(cluster) != 0: # 2. Representative Point Identification zp = self._preprocess(cluster, self.ref_points[i], w_point=self.w_points[i])[0] # 3. Filtering Procedure - Filter points trimmed_data = self._trim(cluster, zp, range=delta) # 4. Solution Translation pop_t = self._translate(zp, trimmed_data, self.ref_points[i], w_point=self.w_points[i]) translated.extend(pop_t) # 5. R-Metric Computation target = self._preprocess(data=solution, ref_point=self.ref_points[i], w_point=self.w_points[i]) PF = self._trim(solution, target) final_PF.extend(PF) translated = np.array(translated) if np.size(translated) == 0: igd = -1 volume = -1 else: # IGD Computation from pymoo.indicators.igd import IGD IGD_ = IGD(final_PF) igd = IGD_.calc(translated) # HV Computation nadir_point = np.amax(self.w_points, axis=0) front = translated dim = self.ref_points[0].shape[0] if hyper_volume: if dim < 3: try: # Python from pymoo.indicators.hv import HyperVolume hv = HyperVolume(nadir_point) volume = hv.compute(front) except TypeError: volume = -1 else: # cpp from pymoo.cpp.hypervolume.build import hypervolume volume = hypervolume.calculate(dim, len(front), front, nadir_point) else: volume = np.nan return igd, volume
def _metric(self, data): last, current = data[-2], data[-1] return IGD(current).do(last)
def test_multi_obj(problem, algorithm): res = minimize(problem, algorithm, ('n_gen', 300), seed=1, verbose=True) pf = problem.pareto_front() assert IGD(pf).do(res.F) < 0.05