From 10397517d95bde1aa6386e4aad87156f98e44793 Mon Sep 17 00:00:00 2001 From: eTuDpy <38726220+eTuDpy@users.noreply.github.com> Date: Wed, 5 Sep 2018 13:07:12 +0200 Subject: [PATCH 01/11] implementation of alpha-level-optimization Signed-off-by: eTuDpy <38726220+eTuDpy@users.noreply.github.com> --- phuzzy/mpl/__init__.py | 11 +- phuzzy/optimization/__init__.py | 539 ++++++++++++++++++++++++++++++++ 2 files changed, 549 insertions(+), 1 deletion(-) create mode 100644 phuzzy/optimization/__init__.py diff --git a/phuzzy/mpl/__init__.py b/phuzzy/mpl/__init__.py index ac8c621..a9fc346 100644 --- a/phuzzy/mpl/__init__.py +++ b/phuzzy/mpl/__init__.py @@ -25,7 +25,7 @@ def mix_mpl(obj): class MPL_Mixin(): - def plot(self, ax=None, filepath=None, show=False, xlim=None, labels=True, title=False, ppf=None): + def plot(self, ax=None, filepath=None, show=False, xlim=None, labels=True, title=False, ppf=None, defuzzy=None): """plots fuzzy number with mpl""" logging.debug("plots fuzzy number with mpl") df = self.df @@ -43,6 +43,15 @@ def plot(self, ax=None, filepath=None, show=False, xlim=None, labels=True, title ax.grid(c="gray", alpha=.5, lw=.5, dashes=[1, 3]) + if defuzzy is not None: + ax.plot([defuzzy[0], defuzzy[0]], [0, defuzzy[1]], linestyle= ':',color='#3188cb', label=defuzzy[0]) + + if defuzzy is not None and labels is True: + ax.annotate('%.3g' % defuzzy[0], xy=(defuzzy[0], (defuzzy[1]+0.018)), xycoords='data', + xytext=(-2, 2), textcoords='offset points', + horizontalalignment='right', verticalalignment='bottom', alpha=.4) + + xs = np.hstack([df["l"].values, df["r"].values[::-1]]) ys = np.hstack([df["alpha"].values, df["alpha"].values[::-1]]) ax.plot(xs, ys, lw=1, alpha=.7) diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py new file mode 100644 index 0000000..3aaf3a2 --- /dev/null +++ b/phuzzy/optimization/__init__.py @@ -0,0 +1,539 @@ +# -*- coding: utf-8 -*- + +from shgo._shgo import SHGO + +import datetime + +import os +import subprocess + + +import phuzzy +from phuzzy.mpl import MPL_Mixin +from phuzzy.shapes import FuzzyNumber + +import matplotlib.pyplot as plt +import matplotlib +from matplotlib.patches import Polygon +from matplotlib.collections import PatchCollection + +from scipy.optimize import minimize +import numpy as np +import pandas as pd +import xarray as xr + + +class ObjFunction(object): + def __init__(self): + self.x_glob = [] + self.local = 1 + + self.ob_func_link = 'C:\\Users\\boos\\Desktop\\Topo_exe_deg\\Topo.exe' + + def min_function_value(self, x): + if isinstance(self.x_glob, np.ndarray): + for row in self.x_glob: + x = np.insert(x, (row[0].astype(int)), row[1]) + return self.objective_function(x) + + def max_function_value(self, x): + if isinstance(self.x_glob, np.ndarray): + for row in self.x_glob: + x = np.insert(x, (row[0].astype(int)), row[1]) + return -1 * (self.objective_function(x)) + + def objective_function(self, x): + if self.local == 1: + return -1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2) + else: + # external Routine + np.savetxt('C:\\Users\\boos\\Desktop\\Topo_exe_deg\\load.txt', x, fmt='%1.5e') + subprocess.call(self.ob_func_link, shell=0) + + f1 = open("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\compliance.txt", 'r') + c = f1.readlines() + c = np.loadtxt(c, delimiter=',', skiprows=0) + f1.close() + os.remove("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\compliance.txt") + + # f2 = open("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\x_phys.txt", 'r') + # x_phys = f2.readlines() + # x_phys = np.loadtxt(x_phys, delimiter=',', skiprows=0) + # x_phys = x_phys[:,(0,5)] + # f2.close() + # os.remove("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\x_phys.txt") + # self.cc.append(c) + # self.xphys.append(x_phys) + return c + + +class Constraints(object): + def __init__(self, bound=True, **kwargs): + """ + Optimization Constraints + """ + if bound == True: + self.boundary_constraints(**kwargs) + + def boundary_constraints(self, **kwargs): + + filter_fuzzy_variables_dict = {} + list_of_n_alpha_levels = np.zeros(1, dtype='int') + + # check if number_of_alpha_levels is the same + for key, value in kwargs.items(): + if isinstance(value, phuzzy.FuzzyNumber): + if list_of_n_alpha_levels[0] == 0: + np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) + else: + list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) + + # extract fuzzy variables from kwargs and safe in dict + for key, value in kwargs.items(): + # if number_of_alpha_levels are different + if (len(set(list_of_n_alpha_levels)) == 1) == False: + max = np.max(list_of_n_alpha_levels) + if isinstance(value, phuzzy.FuzzyNumber): + if value.number_of_alpha_levels < max: value.convert_df(alpha_levels=max) + filter_fuzzy_variables_dict[key] = value._df + elif isinstance(value, phuzzy.FuzzyNumber): + # if number_of_alpha_levels are the same + filter_fuzzy_variables_dict[key] = value._df + + # extract fuzzy values from dict and safe as DataArray + fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) + for k, v in filter_fuzzy_variables_dict.items()} + + self.global_bounds_DataArray = xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') + + def inequality_constraints(self): + # cons = ({'type': 'ineq', 'fun': g1}, #>= + # {'type': 'ineq', 'fun': g2}, + # {'type': 'eq', 'fun': h1}) + pass + + def equality_constraints(self): + # cons = ({'type': 'ineq', 'fun': g1}, #>= + # {'type': 'ineq', 'fun': g2}, + # {'type': 'eq', 'fun': h1}) + pass + + +class Alpha_Level_Optimization(Constraints, ObjFunction, FuzzyNumber, MPL_Mixin): + + def __init__(self, n = 15, iters=3, optimizer = 'sobol', **kwargs): + ObjFunction.__init__(self) + Constraints.__init__(self, **kwargs) + #super().__init__(**kwargs) + + if kwargs.get('name') is None: self.name = 'Fuzzy Objective Value' + else: self.name = kwargs.get('name') + + self.dim = self.global_bounds_DataArray['fuzzy_variables'].size + self.number_of_alpha_levels = len(self.global_bounds_DataArray['number_of_alpha_levels'].values) + + self.n = n + self.iters = iters + self.optimizer = optimizer # simplicial / sobol + + self.best_indi_list_min = [] + self.best_indi_list_max = [] + + def __repr__(self): + return "Z(x:[[{:.3g}, {:.3g}], [{:.3g}, {:.3g}]])".format(self._df.iloc[0].l, self._df.iloc[0].r, + self._df.iloc[-1].l, self._df.iloc[-1].r) + + def calculation(self): + global bounds + zmin_value_list = [] + zmax_value_list = [] + boundlist = [] + + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + for lvl, bounds in enumerate(boundlist): + comp_bounds = [] + for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) + + if lvl == 0: # Alpha-Level = 1 + if all(comp_bounds) == True: # if all bounds are constants + ## calculate objective value + zmin = self.objective_function(bounds[:, 0]) + + ## safe values in list + zmin_value_list.append(np.array(zmin)) + zmax_value_list.append(np.array(zmin)) + + best_indi_min = np.array(bounds[:, 0]) + best_indi_max = np.array(bounds[:, 0]) + + elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants + ## prepare bounds / pop constants + bounds = self.pop_constants(comp_bounds, bounds) + + ## optimization routine + if self.optimizer == 'simplicial': + shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + else: + shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + + #shc_const_min.construct_complex() + #shc_const_max.construct_complex() + shc_const_min = self.find_result(shc_const_min) + shc_const_max = self.find_result(shc_const_max) + + ## safe results in lists + best_indi_min = self.safe_best_array(comp_bounds, shc_const_min.res) + best_indi_max = self.safe_best_array(comp_bounds, shc_const_max.res) + + zmin_value_list.append(shc_const_min.res.fun * (1)) + zmax_value_list.append(shc_const_max.res.fun * (-1)) + self.x_glob = [] + + else: # Alpha-Level < 1 + # if all bounds are Fuzzy-Intervalls + if 'shc_fuzzy_min' in locals(): + shc_fuzzy_min.bounds = bounds + shc_fuzzy_min.iterate() + shc_fuzzy_min.find_minima() + + shc_fuzzy_max.bounds = bounds + shc_fuzzy_max.iterate() + shc_fuzzy_max.find_minima() + else: + if self.optimizer == 'simplicial': + shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + else: + shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + + #shc_fuzzy_min.construct_complex() + #shc_fuzzy_max.construct_complex() + shc_fuzzy_min = self.find_result(shc_fuzzy_min) + shc_fuzzy_max = self.find_result(shc_fuzzy_max) + + ## safe results in lists + best_indi_min = shc_fuzzy_min.res.x + best_indi_max = shc_fuzzy_max.res.x + + zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) + zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) + + self.best_indi_list_min.append(best_indi_min) + self.best_indi_list_max.append(best_indi_max) + + self.zmin_values = self.safe_z_values(min_max='min', z_value_list=zmin_value_list) + self.zmax_values = self.safe_z_values(min_max='max', z_value_list=zmax_value_list) + + self.simple_dataframe() + + + def find_result(self, shc): + shc.construct_complex() + if len(shc.LMC.xl_maps) > 0: + return shc + else: + lres = minimize(shc.func, shc.x_lowest, + **shc.minimizer_kwargs) + shc.res.nlfev += lres.nfev + try: + lres.fun = lres.fun[0] + except (IndexError, TypeError): + lres.fun + + shc.LMC[shc.x_lowest] + shc.LMC.add_res(shc.x_lowest, lres) + shc.sort_result() + # Lowest values used to report in case of failures + shc.f_lowest = shc.res.fun + shc.x_lowest = shc.res.x + return shc + + + def separat_minimization(self): + + zmin_value_list = [] + boundlist = [] + self.best_indi_list_min = [] + + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + for lvl, bounds in enumerate(boundlist): + + comp_bounds = [] + for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) + + if lvl == 0: + if all(comp_bounds) == True: + # if all bounds are constants (equal) + # calculate objective value + zmin = self.objective_function(bounds[:, 0]) + + # safe values in list + zmin_value_list.append(np.array(zmin)) + best_indi = np.array(bounds[:, 0]) + + elif all(comp_bounds) == False and any(comp_bounds) == True: + # if one or more bounds are constants + # prepare bounds / pop constants + bounds = self.pop_constants(comp_bounds, bounds) + + # optimization routine + if self.optimizer == 'simplicial': + shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + else: + shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + shc_const_min.construct_complex() + + # safe values in list + best_indi = self.safe_best_array(comp_bounds, shc_const_min.res) + zmin_value_list.append(shc_const_min.res.fun * (1)) + self.x_glob = [] + else: + # if all bounds are intervalls + if 'shc_fuzzy_min' in locals(): + shc_fuzzy_min.bounds = bounds + shc_fuzzy_min.iterate() + shc_fuzzy_min.find_minima() + + else: + if self.optimizer == 'simplicial': + shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + else: + shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + shc_fuzzy_min.construct_complex() + + best_indi = shc_fuzzy_min.res.x + zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) + + self.best_indi_list_min.append(best_indi) + + self.zmin_values = self.safe_z_values('min', zmin_value_list) + + + def separat_maximization(self): + + zmax_value_list = [] + boundlist = [] + self.best_indi_list_max = [] + + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + for lvl, bounds in enumerate(boundlist): + + comp_bounds = [] + for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) + + if lvl == 0: + if all(comp_bounds) == True: + # if all bounds are constants (equal) + # calculate objective value + zmax = self.objective_function(bounds[:, 0]) + + # safe values in list + zmax_value_list.append(np.array(zmax)) + best_indi = np.array(bounds[:, 0]) + + elif all(comp_bounds) == False and any(comp_bounds) == True: + # if one or more bounds are constants + # prepare bounds / pop constants + bounds = self.pop_constants(comp_bounds, bounds) + + # optimization routine + if self.optimizer == 'simplicial': + shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + else: + shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + shc_const_max.construct_complex() + + # safe values in list + best_indi = self.safe_best_array(comp_bounds, shc_const_max.res) + + zmax_value_list.append(shc_const_max.res.fun * (-1)) + self.x_glob = [] + else: + # if all bounds are intervalls + if 'shc_fuzzy_max' in locals(): + shc_fuzzy_max.bounds = bounds + shc_fuzzy_max.iterate() + shc_fuzzy_max.find_minima() + else: + if self.optimizer == 'simplicial': + shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-6}) + else: + shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, + sampling_method='sobol', options={'ftol': 1e-4}) + shc_fuzzy_max.construct_complex() + + best_indi = shc_fuzzy_max.res.x + zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) + + self.best_indi_list_max.append(best_indi) + + self.zmax_values = self.safe_z_values('max', zmax_value_list) + + + def simple_dataframe(self): + self._df = pd.DataFrame(data={'alpha': np.linspace(0, 1.0, self.number_of_alpha_levels), 'l': self.zmin_values, 'r': self.zmax_values}) + self.df = self._df + + + + + + def expanded_dataframe(self): + self.best_indi_list_min.reverse() + self.best_indi_list_max.reverse() + self._df = pd.DataFrame(data={'alpha': np.linspace(0, 1.0, self.number_of_alpha_levels), + 'l': self.zmin_values, 'best_indi_l': self.best_indi_list_min, + 'r': self.zmax_values, 'best_indi_r': self.best_indi_list_max}) + + + def export_to_csv(self, filepath= None): + if filepath is None: + datatype_str = '_results.csv' + self._df.to_csv(self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) + else: + if filepath[-2:] != '\\': filepath = filepath + '\\' + datatype_str = '_results.csv' + self._df.to_csv(filepath+self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) + + + def safe_best_array(self, comp_bounds, z_res): + best_indi = np.zeros((self.dim), dtype=float) + j = 0 + for i, comp in enumerate(comp_bounds): + if comp: + best_indi[i] = self.global_bounds_DataArray[i, -1, 1].values + else: + best_indi[i] = z_res.x[j] + j += 1 + return best_indi + + + def pop_constants(self, comp_bounds, bounds): + pop = np.array([i for i, x in enumerate(comp_bounds) if x]) + self.x_glob = np.concatenate((np.atleast_2d(pop).T, np.atleast_2d(bounds[pop, 0]).T), axis=1) + bounds = np.delete(bounds, pop, 0) + return bounds + + + def defuzzification(self, method = 'centroid'): + + self.zmax_values = np.flip(self.zmax_values) + if method == 'alpha_one': + self.deter_objective = ((self.alpha1['l']+self.alpha1['r']) / 2) + + elif method == 'mean': + if self.zmin_values[-1]==self.zmax_values[0]: + self.deter_objective = np.mean(np.concatenate((self.zmin_values[:-1],self.zmax_values), axis=0)) + else: + self.deter_objective = np.mean(np.concatenate((self.zmin_values,self.zmax_values), axis=0)) + #self.deter_objective = np.mean((self.df['l'].values+self.df['r'].values)/2) + elif method == 'centroid': + A = 0 + B = 0 + if self.zmin_values[-1]==self.zmax_values[0]: + X = np.hstack((np.hstack((self.zmin_values[:-1],self.zmax_values)),self.zmin_values[0])) + Y = np.hstack((np.hstack((np.linspace(0,1,self.number_of_alpha_levels)[:-1],np.linspace(1,0,self.number_of_alpha_levels))),np.array([0]))) + else: + X = np.hstack((np.hstack((self.zmin_values,self.zmax_values)),self.zmin_values[0])) + Y = np.hstack((np.hstack((np.linspace(0,1,self.number_of_alpha_levels),np.linspace(1,0,self.number_of_alpha_levels))),np.array([0]))) + + for i in range(0,len(X)-1): + a = (X[i]*Y[i+1]-X[i+1]*Y[i]) + b = (X[i]+X[i+1])*(X[i]*Y[i+1]-X[i+1]*Y[i]) + A = A + a + B = B + b + self.deter_objective = (1/(3*A))*B + + + if self.deter_objective < self.zmin_values[-1]: + index_i = np.where(self.zmin_values < self.deter_objective)[0][-1] + index_ii = np.where(self.zmin_values > self.deter_objective)[0][0] + self.y_interpol = np.interp(self.deter_objective, [self.zmin_values[index_i],self.zmin_values[index_ii]], + [np.linspace(0,1,self.number_of_alpha_levels)[index_i], + np.linspace(0,1,self.number_of_alpha_levels)[index_ii]]) + elif self.deter_objective > self.zmax_values[0]: + index_i = np.where(self.deter_objective > self.zmax_values)[0][-1] + index_ii = np.where(self.deter_objective < self.zmax_values)[0][0] + self.y_interpol = np.interp(self.deter_objective, [self.zmax_values[index_i],self.zmax_values[index_ii]], + [np.linspace(1,0,self.number_of_alpha_levels)[index_i], + np.linspace(1,0,self.number_of_alpha_levels)[index_ii]]) + elif self.deter_objective == ((self.alpha1['l']+self.alpha1['r']) / 2): + self.y_interpol = 1.0 + + + @staticmethod + def safe_z_values(min_max, z_value_list): + if min_max == 'min': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item < next_item: + z_value_list[i + 1] = current_item + elif min_max == 'max': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item > next_item: + z_value_list[i + 1] = current_item + else: + print('Please define -min- or -max- in min_max') + return np.flip(z_value_list, axis=0) + + + @classmethod + def from_str(cls, s): + pass + + def to_str(self): + pass + + def discretize(self, alpha0, alpha1, alpha_levels): + pass + + +# FUZZY ALPHA LEVEL OPT ROUTINE +var_1 = phuzzy.Trapezoid(alpha0=[0, 4], alpha1=[2, 3], number_of_alpha_levels=5) +var_2 = phuzzy.Trapezoid(alpha0=[2, 4], alpha1=[3, 3], number_of_alpha_levels=5) +var_3 = phuzzy.Triangle(alpha0=[-3, 1], alpha1=[1, 1], number_of_alpha_levels=5) +var_4 = phuzzy.Triangle(alpha0=[0, 5], alpha1=[3, 3], number_of_alpha_levels=8) +var_5 = phuzzy.Triangle(alpha0=[-10, 1], alpha1=[-4, -4], number_of_alpha_levels=5) +var_6 = phuzzy.Trapezoid(alpha0=[-10, 10], alpha1=[-2, 2], number_of_alpha_levels=5) + +kwargs = {"var_1": var_1, "var_2": var_2, "var_3": var_3, "var_4": var_4, "var_5": var_5, "var_6": var_6} + +a = datetime.datetime.now() +z = Alpha_Level_Optimization(**kwargs) +z.calculation() +b = datetime.datetime.now() +print(b-a) + +z.defuzzification() +z.plot(defuzzy=[z.deter_objective, z.y_interpol]) +plt.show() + +r = 1 + + + + + From a875cf8c6c1a4af734be7b65750cfe1e2512453e Mon Sep 17 00:00:00 2001 From: eTuDpy <38726220+eTuDpy@users.noreply.github.com> Date: Wed, 5 Sep 2018 13:25:07 +0200 Subject: [PATCH 02/11] implementation of alpha-level-optimization Signed-off-by: eTuDpy <38726220+eTuDpy@users.noreply.github.com> --- phuzzy/optimization/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py index 3aaf3a2..f33624e 100644 --- a/phuzzy/optimization/__init__.py +++ b/phuzzy/optimization/__init__.py @@ -468,7 +468,6 @@ def defuzzification(self, method = 'centroid'): B = B + b self.deter_objective = (1/(3*A))*B - if self.deter_objective < self.zmin_values[-1]: index_i = np.where(self.zmin_values < self.deter_objective)[0][-1] index_ii = np.where(self.zmin_values > self.deter_objective)[0][0] From 1b5046acc4e1ba5023f872a14c1439a7048393be Mon Sep 17 00:00:00 2001 From: lepy Date: Fri, 3 Aug 2018 14:26:00 +0200 Subject: [PATCH 03/11] fix number_of_alphalevel interpolation --- phuzzy/shapes/__init__.py | 5 +++-- tests/test_data.py | 8 ++++---- tests/test_fuzzy_number.py | 11 +++++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/phuzzy/shapes/__init__.py b/phuzzy/shapes/__init__.py index 98160a3..3d65651 100644 --- a/phuzzy/shapes/__init__.py +++ b/phuzzy/shapes/__init__.py @@ -43,7 +43,8 @@ def _get_number_of_alpha_levels(self): return self._number_of_alpha_levels def _set_number_of_alpha_levels(self, value): - self._number_of_alpha_levels = int(value) + self.convert_df(alpha_levels=int(value)) + # self._number_of_alpha_levels = int(value) number_of_alpha_levels = property(fget=_get_number_of_alpha_levels, fset=_set_number_of_alpha_levels, doc="number of alpha levels") @@ -74,7 +75,7 @@ def discretize(self, alpha0, alpha1, alpha_levels): def convert_df(self, alpha_levels=None, zero=0): df = self.df.copy() if alpha_levels is not None: - self.number_of_alpha_levels = alpha_levels + self._number_of_alpha_levels = int(alpha_levels) df.sort_values(['alpha'], ascending=[True], inplace=True) # print("!",df) xs_l = df.l.values diff --git a/tests/test_data.py b/tests/test_data.py index d4a59b5..70c8666 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -15,7 +15,7 @@ def test_bootstrapping(): df_boot = data.bootstrap(n=1000) print(df_boot.head()) - phuzzy.data.plots.bootstrapping(data, df_boot, show=True) + # phuzzy.data.plots.bootstrapping(data, df_boot, show=True) def test_shuffling(): @@ -27,7 +27,7 @@ def test_shuffling(): df_boot = data.shuffling(n=1000, train_fraction=.7) print(df_boot.head()) - phuzzy.data.plots.bootstrapping(data, df_boot, show=True) + # phuzzy.data.plots.bootstrapping(data, df_boot, show=True) def test_estimate_probability(): @@ -37,7 +37,7 @@ def test_estimate_probability(): data = phuzzy.data.Data(raw_data) df = data.estimate_probability() print(df) - phuzzy.data.plots.p_estimates(df, show=True) + # phuzzy.data.plots.p_estimates(df, show=True) def test_histogram(): @@ -63,4 +63,4 @@ def test_histogram(): ax.set_ylabel("frequency") axcdf.set_xlabel("x") axcdf.set_ylabel("p") - plt.show() + # plt.show() diff --git a/tests/test_fuzzy_number.py b/tests/test_fuzzy_number.py index ff82a0d..b0020d4 100644 --- a/tests/test_fuzzy_number.py +++ b/tests/test_fuzzy_number.py @@ -7,6 +7,17 @@ import numpy as np from io import StringIO +def test_number_of_alpha_levels(): + t = phuzzy.Triangle(alpha0=[1, 3], alpha1=[2], number_of_alpha_levels=4) + print(t.number_of_alpha_levels) + print(t.df) + assert t.number_of_alpha_levels==4 + t.number_of_alpha_levels = 5 + # t.convert_df(alpha_levels=5) + print(t.number_of_alpha_levels) + print(t.df) + + def test_fuzzy(): n = phuzzy.FuzzyNumber() print(n) From 79290654f6bf9845ffcff067ee62c2342e3b043a Mon Sep 17 00:00:00 2001 From: eTuDpy <38726220+eTuDpy@users.noreply.github.com> Date: Wed, 5 Sep 2018 13:34:27 +0200 Subject: [PATCH 04/11] implementation of alpha-level-optimization Signed-off-by: eTuDpy <38726220+eTuDpy@users.noreply.github.com> --- phuzzy/optimization/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py index f33624e..edf3a4c 100644 --- a/phuzzy/optimization/__init__.py +++ b/phuzzy/optimization/__init__.py @@ -7,15 +7,11 @@ import os import subprocess - import phuzzy from phuzzy.mpl import MPL_Mixin from phuzzy.shapes import FuzzyNumber import matplotlib.pyplot as plt -import matplotlib -from matplotlib.patches import Polygon -from matplotlib.collections import PatchCollection from scipy.optimize import minimize import numpy as np From 26cb1aaeb756aeb136859d62ce8a2abc21bfa56f Mon Sep 17 00:00:00 2001 From: eTuDpy <38726220+eTuDpy@users.noreply.github.com> Date: Thu, 6 Sep 2018 10:30:13 +0200 Subject: [PATCH 05/11] implementation of alpha-level-optimization Signed-off-by: eTuDpy <38726220+eTuDpy@users.noreply.github.com> --- phuzzy/optimization/__init__.py | 51 +++------------------------------ 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py index edf3a4c..3d1fc4d 100644 --- a/phuzzy/optimization/__init__.py +++ b/phuzzy/optimization/__init__.py @@ -3,7 +3,6 @@ from shgo._shgo import SHGO import datetime - import os import subprocess @@ -22,9 +21,6 @@ class ObjFunction(object): def __init__(self): self.x_glob = [] - self.local = 1 - - self.ob_func_link = 'C:\\Users\\boos\\Desktop\\Topo_exe_deg\\Topo.exe' def min_function_value(self, x): if isinstance(self.x_glob, np.ndarray): @@ -39,28 +35,7 @@ def max_function_value(self, x): return -1 * (self.objective_function(x)) def objective_function(self, x): - if self.local == 1: - return -1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2) - else: - # external Routine - np.savetxt('C:\\Users\\boos\\Desktop\\Topo_exe_deg\\load.txt', x, fmt='%1.5e') - subprocess.call(self.ob_func_link, shell=0) - - f1 = open("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\compliance.txt", 'r') - c = f1.readlines() - c = np.loadtxt(c, delimiter=',', skiprows=0) - f1.close() - os.remove("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\compliance.txt") - - # f2 = open("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\x_phys.txt", 'r') - # x_phys = f2.readlines() - # x_phys = np.loadtxt(x_phys, delimiter=',', skiprows=0) - # x_phys = x_phys[:,(0,5)] - # f2.close() - # os.remove("C:\\Users\\boos\\Desktop\\Topo_exe_deg\\x_phys.txt") - # self.cc.append(c) - # self.xphys.append(x_phys) - return c + return -1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2) class Constraints(object): @@ -506,27 +481,9 @@ def discretize(self, alpha0, alpha1, alpha_levels): pass -# FUZZY ALPHA LEVEL OPT ROUTINE -var_1 = phuzzy.Trapezoid(alpha0=[0, 4], alpha1=[2, 3], number_of_alpha_levels=5) -var_2 = phuzzy.Trapezoid(alpha0=[2, 4], alpha1=[3, 3], number_of_alpha_levels=5) -var_3 = phuzzy.Triangle(alpha0=[-3, 1], alpha1=[1, 1], number_of_alpha_levels=5) -var_4 = phuzzy.Triangle(alpha0=[0, 5], alpha1=[3, 3], number_of_alpha_levels=8) -var_5 = phuzzy.Triangle(alpha0=[-10, 1], alpha1=[-4, -4], number_of_alpha_levels=5) -var_6 = phuzzy.Trapezoid(alpha0=[-10, 10], alpha1=[-2, 2], number_of_alpha_levels=5) - -kwargs = {"var_1": var_1, "var_2": var_2, "var_3": var_3, "var_4": var_4, "var_5": var_5, "var_6": var_6} - -a = datetime.datetime.now() -z = Alpha_Level_Optimization(**kwargs) -z.calculation() -b = datetime.datetime.now() -print(b-a) - -z.defuzzification() -z.plot(defuzzy=[z.deter_objective, z.y_interpol]) -plt.show() - -r = 1 +if __name__ == "__main__": + # execute only if run as a script + main() From f094b3a8ce0a8998c39f4c5772eac5bdbfd13244 Mon Sep 17 00:00:00 2001 From: Eugen Boos Date: Tue, 13 Nov 2018 13:28:12 +0100 Subject: [PATCH 06/11] Revised Alpha-Level-Optimization Signed-off-by: Eugen Boos --- ipynb/sample_points.ipynb | 6 +- phuzzy/optimization/Alpha Opti Notebook.ipynb | 792 ++++++++++++++++++ phuzzy/optimization/__init__.py | 479 +---------- phuzzy/optimization/alphaOpt.py | 758 +++++++++++++++++ phuzzy/optimization/function_constraints.py | 75 ++ 5 files changed, 1645 insertions(+), 465 deletions(-) create mode 100644 phuzzy/optimization/Alpha Opti Notebook.ipynb create mode 100644 phuzzy/optimization/alphaOpt.py create mode 100644 phuzzy/optimization/function_constraints.py diff --git a/ipynb/sample_points.ipynb b/ipynb/sample_points.ipynb index 08df9b4..478ed3f 100644 --- a/ipynb/sample_points.ipynb +++ b/ipynb/sample_points.ipynb @@ -6,11 +6,7 @@ "metadata": {}, "outputs": [ { - "data": { - "application/javascript": [ - "IPython.notebook.set_autosave_interval(0)" - ] - }, + "data": {}, "metadata": {}, "output_type": "display_data" }, diff --git a/phuzzy/optimization/Alpha Opti Notebook.ipynb b/phuzzy/optimization/Alpha Opti Notebook.ipynb new file mode 100644 index 0000000..7d71a5a --- /dev/null +++ b/phuzzy/optimization/Alpha Opti Notebook.ipynb @@ -0,0 +1,792 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "no display found. Using non-interactive Agg backend\n" + ] + } + ], + "source": [ + "import phuzzy\n", + "from phuzzy.optimization import alphaOpt\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "v1 = phuzzy.Triangle(alpha0=[0,4], alpha1=[1], number_of_alpha_levels=5)\n", + "v2 = phuzzy.Superellipse(alpha0=[-1, 2.], alpha1=None, m=1.0, n=.5, number_of_alpha_levels=6)\n", + "v3 = phuzzy.TruncGenNorm(alpha0=[1, 4], alpha1=[2, 3], number_of_alpha_levels=5, beta=3.)\n", + "v4 = phuzzy.Trapezoid(alpha0=[0, 4], alpha1=[2, 3], number_of_alpha_levels=5)\n", + "v5 = phuzzy.TruncNorm(alpha0=[1, 3], number_of_alpha_levels=5, name=\"y\")\n", + "v6 = phuzzy.Triangle(alpha0=[1,4], alpha1=[3], number_of_alpha_levels=5)\n", + "\n", + "obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)'\n", + "name = 'Opti_Test'\n", + "\n", + "kwargs = {'var1': v1, 'var2': v2, 'var3': v3,\n", + " 'var4': v4,'var5': v5, 'var6': v6,\n", + " 'obj_function': obj_function, 'name': name}" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\r 0%| | 0/6 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.0-3.510000195.109998
10.212.251661146.263084
20.416.409011119.703942
30.626.304469101.314470
40.839.43945583.907310
51.059.40000064.200000
\n", + "" + ], + "text/plain": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.0-3.510000195.109998
10.212.251661146.263084
20.416.409011119.703942
30.626.304469101.314470
40.839.43945583.907310
51.059.40000064.200000
\n", + "
" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z.df" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.0-3.5164.20
10.212.2583.91
20.416.41101.31
30.626.30119.70
40.839.44146.26
51.059.40195.11
\n", + "
" + ], + "text/plain": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.0-3.5164.20
10.212.2583.91
20.416.41101.31
30.626.30119.70
40.839.44146.26
51.059.40195.11
\n", + "
" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z.simple_dataframe(round=2) # Default: round=None\n", + "z.df" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalbest_indi_lnfev_lnit_lrbest_indi_rnfev_rnit_r
00.0-3.5100[4.0, 2.0, 1.0, 0.1, 1.0, 1.0]173195.1100[1.0007, -0.0988, 4.0, 4.0, 3.0, 4.0]943
10.212.2517[0.2, 1.3292, 1.3676, 0.4, 1.356, 1.4]443146.2631[0.9999, -0.1, 3.6324, 3.8, 2.644, 3.8]123
20.416.4090[2.8, 1.0513, 1.5883, 0.8, 1.5425, 1.8]313119.7039[1.0, -0.0513, 3.4117, 3.6, 2.4575, 3.6]23
30.626.3045[2.2, 0.8381, 1.7581, 1.2, 1.6634, 2.2]893101.3145[1.0, 0.1619, 3.2419, 3.4, 2.3366, 3.4]1103
40.839.4395[0.8, 0.6584, 2.0072, 1.6, 1.7977, 2.6]196383.9073[0.9978, 0.3416, 2.9928, 3.2, 2.2023, 3.2]2043
51.059.4000[1.0, 0.5, 2.5, 2.0, 2.0, 3.0]183364.2000[1.0, 0.5, 2.5, 3.0, 2.0, 3.0]1863
\n", + "
" + ], + "text/plain": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalbest_indi_lnfev_lnit_lrbest_indi_rnfev_rnit_r
00.0-3.5100[4.0, 2.0, 1.0, 0.1, 1.0, 1.0]173195.1100[1.0007, -0.0988, 4.0, 4.0, 3.0, 4.0]943
10.212.2517[0.2, 1.3292, 1.3676, 0.4, 1.356, 1.4]443146.2631[0.9999, -0.1, 3.6324, 3.8, 2.644, 3.8]123
20.416.4090[2.8, 1.0513, 1.5883, 0.8, 1.5425, 1.8]313119.7039[1.0, -0.0513, 3.4117, 3.6, 2.4575, 3.6]23
30.626.3045[2.2, 0.8381, 1.7581, 1.2, 1.6634, 2.2]893101.3145[1.0, 0.1619, 3.2419, 3.4, 2.3366, 3.4]1103
40.839.4395[0.8, 0.6584, 2.0072, 1.6, 1.7977, 2.6]196383.9073[0.9978, 0.3416, 2.9928, 3.2, 2.2023, 3.2]2043
51.059.4000[1.0, 0.5, 2.5, 2.0, 2.0, 3.0]183364.2000[1.0, 0.5, 2.5, 3.0, 2.0, 3.0]1863
\n", + "
" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z.extanded_dataframe(round=4) # Default: round=None\n", + "z.df_extanded" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1168" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z.total_nfev" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z.plot(show=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "75.41381950397155" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z.defuzzification(method = 'centroid') # mean / alpha_one / centroid\n", + "z.plot(show=True, defuzzy=z.determin_point,labels=True)\n", + "z.determin_objective\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Export Simple Dataframe as CSV\n", + "z.export_to_csv() # Default df='simple', filepath=None\n", + "\n", + "# Export Extanded Dataframe as CSV\n", + "z.export_to_csv(df='extended') # Default df='simple', filepath=None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.4" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py index 3d1fc4d..f1bdfcb 100644 --- a/phuzzy/optimization/__init__.py +++ b/phuzzy/optimization/__init__.py @@ -11,481 +11,40 @@ from phuzzy.shapes import FuzzyNumber import matplotlib.pyplot as plt +from phuzzy.optimization import alphaOpt -from scipy.optimize import minimize import numpy as np import pandas as pd import xarray as xr +#from math import * -class ObjFunction(object): - def __init__(self): - self.x_glob = [] - def min_function_value(self, x): - if isinstance(self.x_glob, np.ndarray): - for row in self.x_glob: - x = np.insert(x, (row[0].astype(int)), row[1]) - return self.objective_function(x) - def max_function_value(self, x): - if isinstance(self.x_glob, np.ndarray): - for row in self.x_glob: - x = np.insert(x, (row[0].astype(int)), row[1]) - return -1 * (self.objective_function(x)) - def objective_function(self, x): - return -1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2) +if __name__ == "__main__": -class Constraints(object): - def __init__(self, bound=True, **kwargs): - """ - Optimization Constraints - """ - if bound == True: - self.boundary_constraints(**kwargs) - - def boundary_constraints(self, **kwargs): - - filter_fuzzy_variables_dict = {} - list_of_n_alpha_levels = np.zeros(1, dtype='int') - - # check if number_of_alpha_levels is the same - for key, value in kwargs.items(): - if isinstance(value, phuzzy.FuzzyNumber): - if list_of_n_alpha_levels[0] == 0: - np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) - else: - list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) - - # extract fuzzy variables from kwargs and safe in dict - for key, value in kwargs.items(): - # if number_of_alpha_levels are different - if (len(set(list_of_n_alpha_levels)) == 1) == False: - max = np.max(list_of_n_alpha_levels) - if isinstance(value, phuzzy.FuzzyNumber): - if value.number_of_alpha_levels < max: value.convert_df(alpha_levels=max) - filter_fuzzy_variables_dict[key] = value._df - elif isinstance(value, phuzzy.FuzzyNumber): - # if number_of_alpha_levels are the same - filter_fuzzy_variables_dict[key] = value._df - - # extract fuzzy values from dict and safe as DataArray - fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) - for k, v in filter_fuzzy_variables_dict.items()} - - self.global_bounds_DataArray = xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') - - def inequality_constraints(self): - # cons = ({'type': 'ineq', 'fun': g1}, #>= - # {'type': 'ineq', 'fun': g2}, - # {'type': 'eq', 'fun': h1}) - pass - - def equality_constraints(self): - # cons = ({'type': 'ineq', 'fun': g1}, #>= - # {'type': 'ineq', 'fun': g2}, - # {'type': 'eq', 'fun': h1}) - pass - - -class Alpha_Level_Optimization(Constraints, ObjFunction, FuzzyNumber, MPL_Mixin): - - def __init__(self, n = 15, iters=3, optimizer = 'sobol', **kwargs): - ObjFunction.__init__(self) - Constraints.__init__(self, **kwargs) - #super().__init__(**kwargs) - - if kwargs.get('name') is None: self.name = 'Fuzzy Objective Value' - else: self.name = kwargs.get('name') - - self.dim = self.global_bounds_DataArray['fuzzy_variables'].size - self.number_of_alpha_levels = len(self.global_bounds_DataArray['number_of_alpha_levels'].values) - - self.n = n - self.iters = iters - self.optimizer = optimizer # simplicial / sobol - - self.best_indi_list_min = [] - self.best_indi_list_max = [] - - def __repr__(self): - return "Z(x:[[{:.3g}, {:.3g}], [{:.3g}, {:.3g}]])".format(self._df.iloc[0].l, self._df.iloc[0].r, - self._df.iloc[-1].l, self._df.iloc[-1].r) - - def calculation(self): - global bounds - zmin_value_list = [] - zmax_value_list = [] - boundlist = [] - - for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): - boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) - - for lvl, bounds in enumerate(boundlist): - comp_bounds = [] - for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) - - if lvl == 0: # Alpha-Level = 1 - if all(comp_bounds) == True: # if all bounds are constants - ## calculate objective value - zmin = self.objective_function(bounds[:, 0]) - - ## safe values in list - zmin_value_list.append(np.array(zmin)) - zmax_value_list.append(np.array(zmin)) - - best_indi_min = np.array(bounds[:, 0]) - best_indi_max = np.array(bounds[:, 0]) - - elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants - ## prepare bounds / pop constants - bounds = self.pop_constants(comp_bounds, bounds) - - ## optimization routine - if self.optimizer == 'simplicial': - shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - else: - shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - - #shc_const_min.construct_complex() - #shc_const_max.construct_complex() - shc_const_min = self.find_result(shc_const_min) - shc_const_max = self.find_result(shc_const_max) - - ## safe results in lists - best_indi_min = self.safe_best_array(comp_bounds, shc_const_min.res) - best_indi_max = self.safe_best_array(comp_bounds, shc_const_max.res) - - zmin_value_list.append(shc_const_min.res.fun * (1)) - zmax_value_list.append(shc_const_max.res.fun * (-1)) - self.x_glob = [] - - else: # Alpha-Level < 1 - # if all bounds are Fuzzy-Intervalls - if 'shc_fuzzy_min' in locals(): - shc_fuzzy_min.bounds = bounds - shc_fuzzy_min.iterate() - shc_fuzzy_min.find_minima() - - shc_fuzzy_max.bounds = bounds - shc_fuzzy_max.iterate() - shc_fuzzy_max.find_minima() - else: - if self.optimizer == 'simplicial': - shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - else: - shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - - #shc_fuzzy_min.construct_complex() - #shc_fuzzy_max.construct_complex() - shc_fuzzy_min = self.find_result(shc_fuzzy_min) - shc_fuzzy_max = self.find_result(shc_fuzzy_max) - - ## safe results in lists - best_indi_min = shc_fuzzy_min.res.x - best_indi_max = shc_fuzzy_max.res.x - - zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) - zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) - - self.best_indi_list_min.append(best_indi_min) - self.best_indi_list_max.append(best_indi_max) - - self.zmin_values = self.safe_z_values(min_max='min', z_value_list=zmin_value_list) - self.zmax_values = self.safe_z_values(min_max='max', z_value_list=zmax_value_list) - - self.simple_dataframe() - - - def find_result(self, shc): - shc.construct_complex() - if len(shc.LMC.xl_maps) > 0: - return shc - else: - lres = minimize(shc.func, shc.x_lowest, - **shc.minimizer_kwargs) - shc.res.nlfev += lres.nfev - try: - lres.fun = lres.fun[0] - except (IndexError, TypeError): - lres.fun - - shc.LMC[shc.x_lowest] - shc.LMC.add_res(shc.x_lowest, lres) - shc.sort_result() - # Lowest values used to report in case of failures - shc.f_lowest = shc.res.fun - shc.x_lowest = shc.res.x - return shc - - - def separat_minimization(self): - - zmin_value_list = [] - boundlist = [] - self.best_indi_list_min = [] - - for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): - boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) - - for lvl, bounds in enumerate(boundlist): - - comp_bounds = [] - for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) - - if lvl == 0: - if all(comp_bounds) == True: - # if all bounds are constants (equal) - # calculate objective value - zmin = self.objective_function(bounds[:, 0]) - - # safe values in list - zmin_value_list.append(np.array(zmin)) - best_indi = np.array(bounds[:, 0]) - - elif all(comp_bounds) == False and any(comp_bounds) == True: - # if one or more bounds are constants - # prepare bounds / pop constants - bounds = self.pop_constants(comp_bounds, bounds) - - # optimization routine - if self.optimizer == 'simplicial': - shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - else: - shc_const_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - shc_const_min.construct_complex() - - # safe values in list - best_indi = self.safe_best_array(comp_bounds, shc_const_min.res) - zmin_value_list.append(shc_const_min.res.fun * (1)) - self.x_glob = [] - else: - # if all bounds are intervalls - if 'shc_fuzzy_min' in locals(): - shc_fuzzy_min.bounds = bounds - shc_fuzzy_min.iterate() - shc_fuzzy_min.find_minima() - - else: - if self.optimizer == 'simplicial': - shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - else: - shc_fuzzy_min = SHGO(self.min_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - shc_fuzzy_min.construct_complex() - - best_indi = shc_fuzzy_min.res.x - zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) - - self.best_indi_list_min.append(best_indi) - - self.zmin_values = self.safe_z_values('min', zmin_value_list) - - - def separat_maximization(self): - - zmax_value_list = [] - boundlist = [] - self.best_indi_list_max = [] - - for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): - boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) - - for lvl, bounds in enumerate(boundlist): - - comp_bounds = [] - for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) - - if lvl == 0: - if all(comp_bounds) == True: - # if all bounds are constants (equal) - # calculate objective value - zmax = self.objective_function(bounds[:, 0]) - - # safe values in list - zmax_value_list.append(np.array(zmax)) - best_indi = np.array(bounds[:, 0]) - - elif all(comp_bounds) == False and any(comp_bounds) == True: - # if one or more bounds are constants - # prepare bounds / pop constants - bounds = self.pop_constants(comp_bounds, bounds) - - # optimization routine - if self.optimizer == 'simplicial': - shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - else: - shc_const_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - shc_const_max.construct_complex() - - # safe values in list - best_indi = self.safe_best_array(comp_bounds, shc_const_max.res) - - zmax_value_list.append(shc_const_max.res.fun * (-1)) - self.x_glob = [] - else: - # if all bounds are intervalls - if 'shc_fuzzy_max' in locals(): - shc_fuzzy_max.bounds = bounds - shc_fuzzy_max.iterate() - shc_fuzzy_max.find_minima() - else: - if self.optimizer == 'simplicial': - shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - options={'ftol': 1e-6}) - else: - shc_fuzzy_max = SHGO(self.max_function_value, bounds, n=self.n, iters=self.iters, - sampling_method='sobol', options={'ftol': 1e-4}) - shc_fuzzy_max.construct_complex() - - best_indi = shc_fuzzy_max.res.x - zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) - - self.best_indi_list_max.append(best_indi) - - self.zmax_values = self.safe_z_values('max', zmax_value_list) - - - def simple_dataframe(self): - self._df = pd.DataFrame(data={'alpha': np.linspace(0, 1.0, self.number_of_alpha_levels), 'l': self.zmin_values, 'r': self.zmax_values}) - self.df = self._df - - - - - - def expanded_dataframe(self): - self.best_indi_list_min.reverse() - self.best_indi_list_max.reverse() - self._df = pd.DataFrame(data={'alpha': np.linspace(0, 1.0, self.number_of_alpha_levels), - 'l': self.zmin_values, 'best_indi_l': self.best_indi_list_min, - 'r': self.zmax_values, 'best_indi_r': self.best_indi_list_max}) - - - def export_to_csv(self, filepath= None): - if filepath is None: - datatype_str = '_results.csv' - self._df.to_csv(self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) - else: - if filepath[-2:] != '\\': filepath = filepath + '\\' - datatype_str = '_results.csv' - self._df.to_csv(filepath+self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) - - - def safe_best_array(self, comp_bounds, z_res): - best_indi = np.zeros((self.dim), dtype=float) - j = 0 - for i, comp in enumerate(comp_bounds): - if comp: - best_indi[i] = self.global_bounds_DataArray[i, -1, 1].values - else: - best_indi[i] = z_res.x[j] - j += 1 - return best_indi - - - def pop_constants(self, comp_bounds, bounds): - pop = np.array([i for i, x in enumerate(comp_bounds) if x]) - self.x_glob = np.concatenate((np.atleast_2d(pop).T, np.atleast_2d(bounds[pop, 0]).T), axis=1) - bounds = np.delete(bounds, pop, 0) - return bounds - - - def defuzzification(self, method = 'centroid'): - - self.zmax_values = np.flip(self.zmax_values) - if method == 'alpha_one': - self.deter_objective = ((self.alpha1['l']+self.alpha1['r']) / 2) - - elif method == 'mean': - if self.zmin_values[-1]==self.zmax_values[0]: - self.deter_objective = np.mean(np.concatenate((self.zmin_values[:-1],self.zmax_values), axis=0)) - else: - self.deter_objective = np.mean(np.concatenate((self.zmin_values,self.zmax_values), axis=0)) - #self.deter_objective = np.mean((self.df['l'].values+self.df['r'].values)/2) - elif method == 'centroid': - A = 0 - B = 0 - if self.zmin_values[-1]==self.zmax_values[0]: - X = np.hstack((np.hstack((self.zmin_values[:-1],self.zmax_values)),self.zmin_values[0])) - Y = np.hstack((np.hstack((np.linspace(0,1,self.number_of_alpha_levels)[:-1],np.linspace(1,0,self.number_of_alpha_levels))),np.array([0]))) - else: - X = np.hstack((np.hstack((self.zmin_values,self.zmax_values)),self.zmin_values[0])) - Y = np.hstack((np.hstack((np.linspace(0,1,self.number_of_alpha_levels),np.linspace(1,0,self.number_of_alpha_levels))),np.array([0]))) - - for i in range(0,len(X)-1): - a = (X[i]*Y[i+1]-X[i+1]*Y[i]) - b = (X[i]+X[i+1])*(X[i]*Y[i+1]-X[i+1]*Y[i]) - A = A + a - B = B + b - self.deter_objective = (1/(3*A))*B - - if self.deter_objective < self.zmin_values[-1]: - index_i = np.where(self.zmin_values < self.deter_objective)[0][-1] - index_ii = np.where(self.zmin_values > self.deter_objective)[0][0] - self.y_interpol = np.interp(self.deter_objective, [self.zmin_values[index_i],self.zmin_values[index_ii]], - [np.linspace(0,1,self.number_of_alpha_levels)[index_i], - np.linspace(0,1,self.number_of_alpha_levels)[index_ii]]) - elif self.deter_objective > self.zmax_values[0]: - index_i = np.where(self.deter_objective > self.zmax_values)[0][-1] - index_ii = np.where(self.deter_objective < self.zmax_values)[0][0] - self.y_interpol = np.interp(self.deter_objective, [self.zmax_values[index_i],self.zmax_values[index_ii]], - [np.linspace(1,0,self.number_of_alpha_levels)[index_i], - np.linspace(1,0,self.number_of_alpha_levels)[index_ii]]) - elif self.deter_objective == ((self.alpha1['l']+self.alpha1['r']) / 2): - self.y_interpol = 1.0 - - - @staticmethod - def safe_z_values(min_max, z_value_list): - if min_max == 'min': - for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): - if current_item < next_item: - z_value_list[i + 1] = current_item - elif min_max == 'max': - for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): - if current_item > next_item: - z_value_list[i + 1] = current_item - else: - print('Please define -min- or -max- in min_max') - return np.flip(z_value_list, axis=0) - - - @classmethod - def from_str(cls, s): - pass - - def to_str(self): - pass - - def discretize(self, alpha0, alpha1, alpha_levels): - pass -if __name__ == "__main__": - # execute only if run as a script - main() + v1 = phuzzy.Triangle(alpha0=[0,4], alpha1=[1], number_of_alpha_levels=4) + v2 = phuzzy.Superellipse(alpha0=[-1, 2.], alpha1=None, m=1.0, n=.5, number_of_alpha_levels=4) + v3 = phuzzy.TruncGenNorm(alpha0=[1, 4], alpha1=[2, 3], number_of_alpha_levels=4, beta=3.) + v4 = phuzzy.Trapezoid(alpha0=[0, 4], alpha1=[2, 3], number_of_alpha_levels=8) + v5 = phuzzy.TruncNorm(alpha0=[1, 3], number_of_alpha_levels=4, name="y") + v6 = phuzzy.Triangle(alpha0=[1,4], alpha1=[3], number_of_alpha_levels=4) + obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)' + kwargs = {'var1': v1, 'var2': v2, 'var3': v3, + 'var4': v4,'var5': v5, 'var6': v6, + 'obj_function': obj_function} + z = alphaOpt.Alpha_Level_Optimization(**kwargs) + z.calculation() + z.extanded_dataframe() + z.export() + z.plot() + plt.show() diff --git a/phuzzy/optimization/alphaOpt.py b/phuzzy/optimization/alphaOpt.py new file mode 100644 index 0000000..ba16117 --- /dev/null +++ b/phuzzy/optimization/alphaOpt.py @@ -0,0 +1,758 @@ +from shgo._shgo import SHGO +from scipy.optimize import minimize + +import phuzzy +from phuzzy.mpl import MPL_Mixin +from phuzzy.shapes import FuzzyNumber + +from asteval import Interpreter +from pathlib import Path +from tqdm import tqdm + +import numpy as np +import pandas as pd +import xarray as xr + + + +class Alpha_Level_Optimization(FuzzyNumber, MPL_Mixin): + + def __init__(self, **kwargs): + """ + :param kwargs: Inputvariables / Fuzzyvariables / Name (name) / Objective Function (obj_function) / Objective Link (obj_link) + """ + + # Define Bounds of Each Alpha Level + self.global_bounds_DataArray = self._boundary_constraints(**kwargs) + self.x_glob = [] + + # Filter Objective Function / Link and Safe it + if kwargs.get('obj_function') is not None: self.objective = kwargs.get('obj_function') + elif kwargs.get('obj_link') is not None: self.objective = kwargs.get('obj_link') + else: raise ValueError('PLEASE IMPORT OBJECTIVE') + + # Define Setup Parameters + if kwargs.get('name') is None: self.name = 'Fuzzy Objective Value' + else: self.name = kwargs.get('name') + + self.dim = self.global_bounds_DataArray['fuzzy_variables'].size + self.number_of_alpha_lvls = self.global_bounds_DataArray['number_of_alpha_levels'].size + self.best_indi_list_min = [] + self.best_indi_list_max = [] + self.nfev_list_min = [] + self.nfev_list_max = [] + self.nit_list_min = [] + self.nit_list_max = [] + + + def __repr__(self): + return "{}(x:[[{:.3g}, {:.3g}], [{:.3g}, {:.3g}]])".format(self.name, self._df.iloc[0].l, self._df.iloc[0].r, + self._df.iloc[-1].l, self._df.iloc[-1].r) + + + def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): + """ + Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate + the Fuzzy Objective Membershipfunction. + :param n: Number of Sampling Points / Individuals for the Optimization Algorithm + :param iters: Number of max. Iterations per Optimization Loop + :param optimizer: Selected Optimizer Strategy: "sobol" / "simplicial" + :param backup: Creates a Backup Folder saving the result of each Alpha Level Result + :param start_at: Start at certain Alpha Level (Counts starts from Alpha Level 1) + """ + + # Input Variables + self.n = n + self.iters = iters + self.optimizer = optimizer # simplicial / sobol + self.backup = backup + self.start_at = start_at + + zmin_value_list = [] + zmax_value_list = [] + boundlist = [] + + if self.start_at is not None: self._cut_global_blounds() + + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + with tqdm(total=len(boundlist)) as pbar: + for lvl, bounds in enumerate(boundlist): + comp_bounds = [] + + for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) + + if lvl == 0: # Alpha-Level = 1 + if self.start_at is None: + if all(comp_bounds) == True: # if all bounds are constants + ## calculate objective value + zmin = self.objective_function(bounds[:, 0]) + + ## safe values in list + zmin_value_list.append(np.array(zmin)) + zmax_value_list.append(np.array(zmin)) + + best_indi_min = np.array(bounds[:, 0]) + best_indi_max = np.array(bounds[:, 0]) + nfev_min = np.array(0) + nfev_max = np.array(0) + nit_min = np.array(0) + nit_max = np.array(0) + + elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants + ## prepare bounds / pop constants + bounds = self._pop_constants(comp_bounds, bounds) + + ## optimization routine + shc_const_min = self._call_minimizer_shgo(bounds) + shc_const_max = self._call_maximizer_shgo(bounds) + + shc_const_min = self._find_result(shc_const_min) + shc_const_max = self._find_result(shc_const_max) + + ## safe results in lists + best_indi_min = self._safe_best_array(comp_bounds, shc_const_min.res) + best_indi_max = self._safe_best_array(comp_bounds, shc_const_max.res) + nfev_min = shc_const_min.res.nfev + nfev_max = shc_const_max.res.nfev + nit_min = shc_const_min.res.nit + nit_max = shc_const_max.res.nit + + zmin_value_list.append(shc_const_min.res.fun * (1)) + zmax_value_list.append(shc_const_max.res.fun * (-1)) + self.x_glob = [] + else: + shc_const_min = self._call_minimizer_shgo(bounds) + shc_const_max = self._call_maximizer_shgo(bounds) + + shc_const_min = self._find_result(shc_const_min) + shc_const_max = self._find_result(shc_const_max) + + ## safe results in lists + best_indi_min = self._safe_best_array(comp_bounds, shc_const_min.res) + best_indi_max = self._safe_best_array(comp_bounds, shc_const_max.res) + nfev_min = shc_const_min.res.nfev + nfev_max = shc_const_max.res.nfev + nit_min = shc_const_min.res.nit + nit_max = shc_const_max.res.nit + + zmin_value_list.append(shc_const_min.res.fun * (1)) + zmax_value_list.append(shc_const_max.res.fun * (-1)) + + else: # Alpha-Level < 1 + # if all bounds are Fuzzy-Intervalls + if 'shc_fuzzy_min' in locals(): + shc_fuzzy_min.bounds = bounds + shc_fuzzy_min.iterate() + shc_fuzzy_min.find_minima() + + shc_fuzzy_max.bounds = bounds + shc_fuzzy_max.iterate() + shc_fuzzy_max.find_minima() + else: + shc_const_min = self._call_minimizer_shgo(bounds) + shc_const_max = self._call_maximizer_shgo(bounds) + + #shc_fuzzy_min.construct_complex() + #shc_fuzzy_max.construct_complex() + shc_fuzzy_min = self._find_result(shc_const_min) + shc_fuzzy_max = self._find_result(shc_const_max) + + ## safe results in lists + best_indi_min = shc_fuzzy_min.res.x + best_indi_max = shc_fuzzy_max.res.x + if lvl <= 1: + nfev_min = shc_const_min.res.nfev + nfev_max = shc_const_max.res.nfev + else: + nfev_min = np.absolute((shc_const_min.res.nfev - np.sum(self.nfev_list_min[0:lvl-1]))) + nfev_max = np.absolute((shc_const_max.res.nfev - np.sum(self.nfev_list_max[0:lvl-1]))) + nit_min = shc_const_min.res.nit + nit_max = shc_const_max.res.nit + + zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) + zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) + + self.best_indi_list_min.append(best_indi_min) + self.best_indi_list_max.append(best_indi_max) + self.nfev_list_min.append(nfev_min) + self.nfev_list_max.append(nfev_max) + self.nit_list_min.append(nit_min) + self.nit_list_max.append(nit_max) + + if self.backup == True: + self.zmin_values = self._safe_z_values(min_max='min', z_value_list=zmin_value_list) + self.zmax_values = self._safe_z_values(min_max='max', z_value_list=zmax_value_list) + self._call_backup(iteration=lvl) + + pbar.update() + + self.zmin_values = self._safe_z_values(min_max='min', z_value_list=zmin_value_list) + self.zmax_values = self._safe_z_values(min_max='max', z_value_list=zmax_value_list) + + self.total_nfev = sum(self.nfev_list_min) + sum(self.nfev_list_max) + self.simple_dataframe() + + + def separat_minimization(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): + """ + Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate + the Fuzzy Objective Membershipfunction. + :param n: Number of Sampling Points / Individuals for the Optimization Algorithm + :param iters: Number of max. Iterations per Optimization Loop + :param optimizer: Selected Optimizer Strategy: "sobol" / "simplicial" + :param backup: Creates a Backup Folder saving the result of each Alpha Level Result + :param start_at: Start at certain Alpha Level (Counts starts from Alpha Level 1) + """ + + # Input Variables + self.n = n + self.iters = iters + self.optimizer = optimizer # simplicial / sobol + self.backup = backup + self.start_at = start_at + + zmin_value_list = [] + boundlist = [] + + if self.start_at is not None: self._cut_global_blounds() + + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + with tqdm(total=len(boundlist)) as pbar: + for lvl, bounds in enumerate(boundlist): + comp_bounds = [] + + for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) + + if lvl == 0: # Alpha-Level = 1 + if self.start_at is None: + if all(comp_bounds) == True: # if all bounds are constants + ## calculate objective value + zmin = self.objective_function(bounds[:, 0]) + + ## safe values in list + zmin_value_list.append(np.array(zmin)) + best_indi_min = np.array(bounds[:, 0]) + nfev_min = np.array(0) + nit_min = np.array(0) + + elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants + ## prepare bounds / pop constants + bounds = self._pop_constants(comp_bounds, bounds) + + ## optimization routine + shc_const_min = self._call_minimizer_shgo(bounds) + shc_const_min = self._find_result(shc_const_min) + + ## safe results in lists + best_indi_min = self._safe_best_array(comp_bounds, shc_const_min.res) + nfev_min = shc_const_min.res.nfev + nit_min = shc_const_min.res.nit + zmin_value_list.append(shc_const_min.res.fun * (1)) + self.x_glob = [] + else: + shc_const_min = self._call_minimizer_shgo(bounds) + shc_const_min = self._find_result(shc_const_min) + + ## safe results in lists + best_indi_min = self._safe_best_array(comp_bounds, shc_const_min.res) + nfev_min = shc_const_min.res.nfev + nit_min = shc_const_min.res.nit + zmin_value_list.append(shc_const_min.res.fun * (1)) + + else: # Alpha-Level < 1 + # if all bounds are Fuzzy-Intervalls + if 'shc_fuzzy_min' in locals(): + shc_fuzzy_min.bounds = bounds + shc_fuzzy_min.iterate() + shc_fuzzy_min.find_minima() + else: + shc_const_min = self._call_minimizer_shgo(bounds) + shc_fuzzy_min = self._find_result(shc_const_min) + + ## safe results in lists + best_indi_min = shc_fuzzy_min.res.x + if lvl <= 1: + nfev_min = shc_const_min.res.nfev + else: + nfev_min = np.absolute((shc_const_min.res.nfev - np.sum(self.nfev_list_min[0:lvl-1]))) + nit_min = shc_const_min.res.nit + + zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) + + self.best_indi_list_min.append(best_indi_min) + self.nfev_list_min.append(nfev_min) + self.nit_list_min.append(nit_min) + pbar.update() + + self.zmin_values = self._safe_z_values(min_max='min', z_value_list=zmin_value_list) + + + def separat_maximization(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): + """ + Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate + the Fuzzy Objective Membershipfunction. + :param n: Number of Sampling Points / Individuals for the Optimization Algorithm + :param iters: Number of max. Iterations per Optimization Loop + :param optimizer: Selected Optimizer Strategy: "sobol" / "simplicial" + :param backup: Creates a Backup Folder saving the result of each Alpha Level Result + :param start_at: Start at certain Alpha Level (Counts starts from Alpha Level 1) + """ + + # Input Variables + self.n = n + self.iters = iters + self.optimizer = optimizer # simplicial / sobol + self.backup = backup + self.start_at = start_at + + zmax_value_list = [] + boundlist = [] + + if self.start_at is not None: self._cut_global_blounds() + + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + with tqdm(total=len(boundlist)) as pbar: + for lvl, bounds in enumerate(boundlist): + comp_bounds = [] + for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) + if lvl == 0: # Alpha-Level = 1 + if self.start_at is None: + if all(comp_bounds) == True: # if all bounds are constants + ## calculate objective value + zmax = self.objective_function(bounds[:, 0]) + + ## safe values in list + zmax_value_list.append(np.array(zmax)) + best_indi_max = np.array(bounds[:, 0]) + nfev_max = np.array(0) + nit_max = np.array(0) + + elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants + ## prepare bounds / pop constants + bounds = self._pop_constants(comp_bounds, bounds) + + ## optimization routine + shc_const_max = self._call_maximizer_shgo(bounds) + shc_const_max = self._find_result(shc_const_max) + + ## safe results in lists + best_indi_max = self._safe_best_array(comp_bounds, shc_const_max.res) + nfev_max = shc_const_max.res.nfev + nit_max = shc_const_max.res.nit + + zmax_value_list.append(shc_const_max.res.fun * (-1)) + self.x_glob = [] + else: + shc_const_max = self._call_maximizer_shgo(bounds) + shc_const_max = self._find_result(shc_const_max) + + ## safe results in lists + best_indi_max = self._safe_best_array(comp_bounds, shc_const_max.res) + nfev_max = shc_const_max.res.nfev + nit_max = shc_const_max.res.nit + zmax_value_list.append(shc_const_max.res.fun * (-1)) + + else: # Alpha-Level < 1 + # if all bounds are Fuzzy-Intervalls + if 'shc_fuzzy_min' in locals(): + shc_fuzzy_max.bounds = bounds + shc_fuzzy_max.iterate() + shc_fuzzy_max.find_minima() + else: + shc_const_max = self._call_maximizer_shgo(bounds) + shc_fuzzy_max = self._find_result(shc_const_max) + + ## safe results in lists + best_indi_max = shc_fuzzy_max.res.x + if lvl <= 1: + nfev_max = shc_const_max.res.nfev + else: + nfev_max = np.absolute((shc_const_max.res.nfev - np.sum(self.nfev_list_max[0:lvl-1]))) + nit_max = shc_const_max.res.nit + + zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) + + self.best_indi_list_max.append(best_indi_max) + self.nfev_list_max.append(nfev_max) + self.nit_list_max.append(nit_max) + pbar.update() + + self.zmax_values = self._safe_z_values(min_max='max', z_value_list=zmax_value_list) + + + def simple_dataframe(self,round=None): + """ + Returns Dataframe of Objective Memebership Function + :param round: Round Values of Dataframe + :return: Dataframe + """ + if self.start_at is None: + self._df = pd.DataFrame(data={'alpha': np.linspace(0, 1.0, self.number_of_alpha_lvls), + 'l': self.zmin_values, 'r': self.zmax_values}) + else: + self._df = pd.DataFrame(data={'alpha': np.linspace(0, + np.linspace(0, 1.0, self.orig_number_of_alpha_lvls) + [self.orig_number_of_alpha_lvls-self.start_at], self.number_of_alpha_lvls), + 'l': self.zmin_values, + 'r': self.zmax_values}) + + self.df = self._df + if round is not None: + self.df = self.df.round(round) + self._df = self._df.round(round) + + + def extanded_dataframe(self,round=None): + """ + Create extanded Solution Dataframe of Objective + :param round: Round Values of Dataframe + :return: Dataframe + """ + self.best_indi_list_min.reverse() + self.best_indi_list_max.reverse() + self.nfev_list_min.reverse() + self.nfev_list_max.reverse() + self.nit_list_min.reverse() + self.nit_list_max.reverse() + if round is not None: + min_arr = np.round(self.best_indi_list_min,round) + max_arr = np.round(self.best_indi_list_max,round) + else: + min_arr = np.array(self.best_indi_list_min) + max_arr = np.array(self.best_indi_list_max) + + if self.start_at is None: + self.df_extanded = pd.DataFrame(data={'alpha': np.linspace(0, 1.0, self.number_of_alpha_lvls), + 'l': self.zmin_values, 'best_indi_l': min_arr.tolist(), + 'nfev_l': self.nfev_list_min, 'nit_l': self.nit_list_min, + 'r': self.zmax_values, 'best_indi_r': max_arr.tolist(), + 'nfev_r':self.nfev_list_max, 'nit_r': self.nit_list_max}) + else: + self.df_extanded = pd.DataFrame(data={'alpha': np.linspace(0, + np.linspace(0, 1.0, self.orig_number_of_alpha_lvls) + [self.orig_number_of_alpha_lvls-self.start_at], self.number_of_alpha_lvls), + 'l': self.zmin_values, 'best_indi_l': min_arr.tolist(), + 'nfev_l': self.nfev_list_min, 'nit_l': self.nit_list_min, + 'r': self.zmax_values, 'best_indi_r': max_arr.tolist(), + 'nfev_r':self.nfev_list_max, 'nit_r': self.nit_list_max}) + + if round is not None: self.df_extanded = self.df_extanded.round(round) + + + def export_to_csv(self, df = 'simple' , filepath= None): + """ + Export Dataframe as CSV + :param df Define Dataframe-Type which is to be exported simple / extended + :param filepath: Filepath where to save the DF + :return: CSV of Dataframe + """ + if df == 'simple': + if filepath is None: + datatype_str = '_results.csv' + self._df.to_csv(self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) + else: + if filepath[-2:] != '\\': filepath = filepath + '\\' + datatype_str = '_results.csv' + self._df.to_csv(filepath+self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) + elif df == 'extended': + if filepath is None: + datatype_str = '_extended_results.csv' + self.df_extanded.to_csv(self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) + else: + if filepath[-2:] != '\\': filepath = filepath + '\\' + datatype_str = '_extended_results.csv' + self.df_extanded.to_csv(filepath+self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) + + + def defuzzification(self, method = 'mean'): + """ + Defuzzyfication of Uncertain Objective + :param method: Select Method of Defuzzyfication - alpha_one / mean / centroid + """ + self.zmax_values = np.flip(self.zmax_values) + if method == 'alpha_one': + self.determin_objective = ((self.alpha1['l']+self.alpha1['r']) / 2) + + elif method == 'mean': + if self.zmin_values[-1]==self.zmax_values[0]: + self.determin_objective = np.mean(np.concatenate((self.zmin_values[:-1],self.zmax_values), axis=0)) + else: + self.determin_objective = np.mean(np.concatenate((self.zmin_values,self.zmax_values), axis=0)) + #self.determin_objective = np.mean((self.df['l'].values+self.df['r'].values)/2) + elif method == 'centroid': + A = 0 + B = 0 + if self.zmin_values[-1]==self.zmax_values[0]: + X = np.hstack((np.hstack((self.zmin_values[:-1],self.zmax_values)),self.zmin_values[0])) + Y = np.hstack((np.hstack((np.linspace(0,1,self.number_of_alpha_lvls)[:-1],np.linspace(1,0,self.number_of_alpha_lvls))),np.array([0]))) + else: + X = np.hstack((np.hstack((self.zmin_values,self.zmax_values)),self.zmin_values[0])) + Y = np.hstack((np.hstack((np.linspace(0,1,self.number_of_alpha_lvls),np.linspace(1,0,self.number_of_alpha_lvls))),np.array([0]))) + + for i in range(0,len(X)-1): + a = (X[i]*Y[i+1]-X[i+1]*Y[i]) + b = (X[i]+X[i+1])*(X[i]*Y[i+1]-X[i+1]*Y[i]) + A = A + a + B = B + b + self.determin_objective = (1/(3*A))*B + + if self.determin_objective < self.zmin_values[-1]: + index_i = np.where(self.zmin_values < self.determin_objective)[0][-1] + index_ii = np.where(self.zmin_values > self.determin_objective)[0][0] + y_interpol = np.interp(self.determin_objective, [self.zmin_values[index_i],self.zmin_values[index_ii]], + [np.linspace(0,1,self.number_of_alpha_lvls)[index_i], + np.linspace(0,1,self.number_of_alpha_lvls)[index_ii]]) + elif self.determin_objective > self.zmax_values[0]: + index_i = np.where(self.determin_objective > self.zmax_values)[0][-1] + index_ii = np.where(self.determin_objective < self.zmax_values)[0][0] + y_interpol = np.interp(self.determin_objective, [self.zmax_values[index_i],self.zmax_values[index_ii]], + [np.linspace(1,0,self.number_of_alpha_lvls)[index_i], + np.linspace(1,0,self.number_of_alpha_lvls)[index_ii]]) + else: + y_interpol = 1.0 + + self.determin_point = np.array([self.determin_objective,y_interpol]) + + + def _call_minimizer_shgo(self,bounds): + """ + Minimizes Objective Function with the SHGO Optimizer + :param bounds: Boundary of the current Alpha Level + :return: Minimum + """ + if self.optimizer == 'sobol': + return SHGO(self._min_function_value, bounds = bounds, n=self.n, iters=self.iters, + sampling_method= 'sobol' , options={'ftol': 1e-4}, constraints = None) + else: + return SHGO(self._min_function_value, bounds = bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-4}, constraints = None) + + + def _call_maximizer_shgo(self,bounds): + """ + Maximizes Objective Function with the SHGO Optimizer + :param bounds: Boundary of the current Alpha Level + :return: Maximum + """ + if self.optimizer == 'sobol': + return SHGO(self._max_function_value, bounds = bounds, n=self.n, iters=self.iters, + sampling_method=self.optimizer , options={'ftol': 1e-4}, constraints = None) + else: + return SHGO(self._max_function_value, bounds = bounds, n=self.n, iters=self.iters, + options={'ftol': 1e-4}, constraints = None) + + + def _objective_function(self, x): + """ + Abstract Objective Function Call + :param x: Input Variable + :return: Function Value of Objective + """ + aeval = Interpreter() + exprc = aeval.parse(self.objective) + aeval.symtable['x'] = x + return aeval.run(exprc) + + + def _boundary_constraints(self, **kwargs): + """ + Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton + :param kwargs: Input Fuzzy Variables + :return: 3D DataArray representing each Fuzzy Inputvariables Boundaries for each Alpha Level + prepared for the Optimization Routine + """ + filter_fuzzy_variables_dict = {} + list_of_n_alpha_levels = np.zeros(1, dtype='int') + + # check if number_of_alpha_levels is the same + for key, value in kwargs.items(): + if isinstance(value, phuzzy.FuzzyNumber): + if list_of_n_alpha_levels[0] == 0: + np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) + else: + list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) + + # extract fuzzy variables from kwargs and safe in dict + for key, value in kwargs.items(): + # if number_of_alpha_levels are different + if (len(set(list_of_n_alpha_levels)) == 1) == False: + max = np.max(list_of_n_alpha_levels) + if isinstance(value, phuzzy.FuzzyNumber): + if value.number_of_alpha_levels < max: value.convert_df(alpha_levels=max) + filter_fuzzy_variables_dict[key] = value._df + elif isinstance(value, phuzzy.FuzzyNumber): + # if number_of_alpha_levels are the same + filter_fuzzy_variables_dict[key] = value._df + + # extract fuzzy values from dict and safe as DataArray + fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) + for k, v in filter_fuzzy_variables_dict.items()} + """ + if self.start_at is not None: + return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables')[:,0:self.start_at,:] + else: + return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') + """ + + return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') + + + def _cut_global_blounds(self): + """ + Cut global Bounds for the Option to -start at- a selected Alpha Level + """ + if self.start_at is not None: + self.orig_number_of_alpha_lvls = self.number_of_alpha_lvls + self.global_bounds_DataArray = self.global_bounds_DataArray[:,0:self.orig_number_of_alpha_lvls-self.start_at+1,:] + self.dim = self.global_bounds_DataArray['fuzzy_variables'].size + self.number_of_alpha_lvls = self.global_bounds_DataArray['number_of_alpha_levels'].size + else: + raise ValueError('Please select starting Alpha Level or keep variable "start_at=None"') + + + def _min_function_value(self, x): + """ + Call Minimization Opt Routine + :param x: Input Variable + :return: Objective Value + """ + if isinstance(self.x_glob, np.ndarray): + for row in self.x_glob: + x = np.insert(x, (row[0].astype(int)), row[1]) + return self._objective_function(x) + + + def _max_function_value(self, x): + """ + Call Maximization Opt Routine + :param x: Input Variable + :return: Objective Value + """ + if isinstance(self.x_glob, np.ndarray): + for row in self.x_glob: + x = np.insert(x, (row[0].astype(int)), row[1]) + return -1 * (self._objective_function(x)) + + + def _find_result(self, shc): + """ + Post Calculation for Shgo-Optimization Algorithm + """ + shc.construct_complex() + if len(shc.LMC.xl_maps) > 0: + return shc + else: + lres = minimize(shc.func, shc.x_lowest, + **shc.minimizer_kwargs) + shc.res.nlfev += lres.nfev + try: + lres.fun = lres.fun[0] + except (IndexError, TypeError): + lres.fun + + shc.LMC[shc.x_lowest] + shc.LMC.add_res(shc.x_lowest, lres) + shc.sort_result() + # Lowest values used to report in case of failures + shc.f_lowest = shc.res.fun + shc.x_lowest = shc.res.x + return shc + + + def _safe_best_array(self, comp_bounds, z_res): + """ + Post Preparation to extrapolate sampling Point with min/max Objective Value from Optimization Result + :param comp_bounds: Boolean Array of all Fuzzy Input Variables which are constants for a certain Alpha Level + :param z_res: Result of Optimization Loop + :return: + best_indi Best Individual + """ + best_indi = np.zeros((self.dim), dtype=float) + j = 0 + for i, comp in enumerate(comp_bounds): + if comp: + best_indi[i] = self.global_bounds_DataArray[i, -1, 1].values + else: + best_indi[i] = z_res.x[j] + j += 1 + return best_indi + + + def _pop_constants(self, comp_bounds, bounds): + """ + Pop Constant Fuzzy Variables of Input Variable + :param comp_bounds: Boolean Array of all Fuzzy Input Variables which are constants for a certain Alpha Level + :param bounds: All Optimization Bound of cetrain Alpha Level + :return: + bounds + """ + pop = np.array([i for i, x in enumerate(comp_bounds) if x]) + self.x_glob = np.concatenate((np.atleast_2d(pop).T, np.atleast_2d(bounds[pop, 0]).T), axis=1) + bounds = np.delete(bounds, pop, 0) + return bounds + + @staticmethod + def _safe_z_values(min_max, z_value_list): + """ + Post Preparation for Results of Optimization Routines for creation of Fuzzy Dataframe + :param min_max: Define if Result is from a Minimization or Maximization + :param z_value_list: List of all Objective Value Results (for each Alpha Level) + :return: + z_value_list Adapted List of all Objective Value Results + """ + if min_max == 'min': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item < next_item: + z_value_list[i + 1] = current_item + elif min_max == 'max': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item > next_item: + z_value_list[i + 1] = current_item + else: + raise ValueError('Please define -min- or -max- in min_max') + return np.flip(z_value_list, axis=0) + + + def _call_backup(self,iteration): + """ + Create Backup Dataframe for each Alpha Level and export it as CSV + :param iteration: Current Iterationstep / Alpha Level + """ + if Path('back_up').exists(): pass + else: Path('back_up').mkdir() + + cache_str = 'backup_'+ str(iteration) + '_iteration_step.csv' + filepath = Path.cwd() / 'back_up' / cache_str + if self.start_at is None: + df_cache = pd.DataFrame(data={'alpha': np.linspace(np.linspace(0, 1.0, self.number_of_alpha_lvls) + [self.number_of_alpha_lvls-1-iteration], 1.0, iteration+1), + 'l': self.zmin_values, + 'r': self.zmax_values}) + else: + df_cache = pd.DataFrame(data={'alpha': np.linspace(np.linspace(0, 1.0, self.number_of_alpha_lvls) + [self.number_of_alpha_lvls-1-iteration], + np.linspace(0, 1.0, self.orig_number_of_alpha_lvls) + [self.orig_number_of_alpha_lvls-self.start_at],iteration+1), + 'l': self.zmin_values, + 'r': self.zmax_values}) + + df_cache.to_csv(filepath, sep=';', encoding='utf8', index=None, header=True) + + @classmethod + def from_str(cls, s): + pass + + def to_str(self): + pass + + + + +if __name__ == "__main__": + pass diff --git a/phuzzy/optimization/function_constraints.py b/phuzzy/optimization/function_constraints.py new file mode 100644 index 0000000..b2d55b9 --- /dev/null +++ b/phuzzy/optimization/function_constraints.py @@ -0,0 +1,75 @@ +import numpy as np + + + +class ObjFunction(object): + def __init__(self): + self.x_glob = [] + + def min_function_value(self, x): + if isinstance(self.x_glob, np.ndarray): + for row in self.x_glob: + x = np.insert(x, (row[0].astype(int)), row[1]) + return self.objective_function(x) + + def max_function_value(self, x): + if isinstance(self.x_glob, np.ndarray): + for row in self.x_glob: + x = np.insert(x, (row[0].astype(int)), row[1]) + return -1 * (self.objective_function(x)) + + def objective_function(self, x): + return -1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2) + + +class Constraints(object): + def __init__(self, bound=True, **kwargs): + """ + Optimization Constraints + """ + if bound == True: + self.boundary_constraints(**kwargs) + + def boundary_constraints(self, **kwargs): + + filter_fuzzy_variables_dict = {} + list_of_n_alpha_levels = np.zeros(1, dtype='int') + + # check if number_of_alpha_levels is the same + for key, value in kwargs.items(): + if isinstance(value, phuzzy.FuzzyNumber): + if list_of_n_alpha_levels[0] == 0: + np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) + else: + list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) + + # extract fuzzy variables from kwargs and safe in dict + for key, value in kwargs.items(): + # if number_of_alpha_levels are different + if (len(set(list_of_n_alpha_levels)) == 1) == False: + max = np.max(list_of_n_alpha_levels) + if isinstance(value, phuzzy.FuzzyNumber): + if value.number_of_alpha_levels < max: value.convert_df(alpha_levels=max) + filter_fuzzy_variables_dict[key] = value._df + elif isinstance(value, phuzzy.FuzzyNumber): + # if number_of_alpha_levels are the same + filter_fuzzy_variables_dict[key] = value._df + + # extract fuzzy values from dict and safe as DataArray + fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) + for k, v in filter_fuzzy_variables_dict.items()} + + self.global_bounds_DataArray = xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') + + def inequality_constraints(self): + + # cons = ({'type': 'ineq', 'fun': g1}, #>= + # {'type': 'ineq', 'fun': g2}, + # {'type': 'eq', 'fun': h1}) + pass + + def equality_constraints(self): + # cons = ({'type': 'ineq', 'fun': g1}, #>= + # {'type': 'ineq', 'fun': g2}, + # {'type': 'eq', 'fun': h1}) + pass From a5838a22d93201ff8f3e7eeeb5be5f2421c6c983 Mon Sep 17 00:00:00 2001 From: Eugen Boos Date: Tue, 13 Nov 2018 13:53:09 +0100 Subject: [PATCH 07/11] Revised Alpha-Level-Optimization Signed-off-by: Eugen Boos --- phuzzy/optimization/Alpha Opti Notebook.ipynb | 126 +++++++++++++----- 1 file changed, 96 insertions(+), 30 deletions(-) diff --git a/phuzzy/optimization/Alpha Opti Notebook.ipynb b/phuzzy/optimization/Alpha Opti Notebook.ipynb index 7d71a5a..ce769b1 100644 --- a/phuzzy/optimization/Alpha Opti Notebook.ipynb +++ b/phuzzy/optimization/Alpha Opti Notebook.ipynb @@ -59,21 +59,21 @@ "name": "stderr", "output_type": "stream", "text": [ - "\r 17%|█▋ | 1/6 [00:00<00:01, 3.36it/s]" + "\r 17%|█▋ | 1/6 [00:00<00:01, 3.65it/s]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r 33%|███▎ | 2/6 [00:01<00:02, 1.81it/s]" + "\r 33%|███▎ | 2/6 [00:01<00:02, 1.86it/s]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r 50%|█████ | 3/6 [00:03<00:02, 1.03it/s]" + "\r 50%|█████ | 3/6 [00:03<00:02, 1.02it/s]" ] }, { @@ -87,14 +87,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "\r 83%|████████▎ | 5/6 [00:08<00:01, 1.77s/it]" + "\r 83%|████████▎ | 5/6 [00:08<00:01, 1.75s/it]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r100%|██████████| 6/6 [00:11<00:00, 2.25s/it]" + "\r100%|██████████| 6/6 [00:11<00:00, 2.21s/it]" ] }, { @@ -281,7 +281,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -315,37 +315,37 @@ " 0\n", " 0.0\n", " -3.51\n", - " 64.20\n", + " 195.11\n", " \n", " \n", " 1\n", " 0.2\n", " 12.25\n", - " 83.91\n", + " 146.26\n", " \n", " \n", " 2\n", " 0.4\n", " 16.41\n", - " 101.31\n", + " 119.70\n", " \n", " \n", " 3\n", " 0.6\n", " 26.30\n", - " 119.70\n", + " 101.31\n", " \n", " \n", " 4\n", " 0.8\n", " 39.44\n", - " 146.26\n", + " 83.91\n", " \n", " \n", " 5\n", " 1.0\n", " 59.40\n", - " 195.11\n", + " 64.20\n", " \n", " \n", "\n", @@ -380,44 +380,44 @@ " 0\n", " 0.0\n", " -3.51\n", - " 64.20\n", + " 195.11\n", " \n", " \n", " 1\n", " 0.2\n", " 12.25\n", - " 83.91\n", + " 146.26\n", " \n", " \n", " 2\n", " 0.4\n", " 16.41\n", - " 101.31\n", + " 119.70\n", " \n", " \n", " 3\n", " 0.6\n", " 26.30\n", - " 119.70\n", + " 101.31\n", " \n", " \n", " 4\n", " 0.8\n", " 39.44\n", - " 146.26\n", + " 83.91\n", " \n", " \n", " 5\n", " 1.0\n", " 59.40\n", - " 195.11\n", + " 64.20\n", " \n", " \n", "\n", "" ] }, - "execution_count": 12, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -429,7 +429,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "collapsed": false }, @@ -651,7 +651,7 @@ "" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -663,7 +663,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -672,7 +672,7 @@ "1168" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -683,14 +683,14 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "collapsed": true }, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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gahJVqFQKASiJlmFQqEQyGU/yba2tmIymSgoKIj/uffee2dcc/ToUa688krsdjt1dXW8/vrrWVKb2YI56fDZz34Wm802ox8T+ymbur/97W9z9dVXk5uby/333z/jtdHRUT796U9TWFhIeXk5f/d3f5fW65nUeuutt5Kbmzujj7u7u7OiNRQK8fnPf541a9bgdDrZtGkT+/fvT1mLkbQK79cl7xmTnJaWFg3QhoaGkr4+ODioud1u7Xvf+54WDAa1733ve5rH45nzetF89atf1a688kqtu7tb6+7u1q688krtiSeeyIqWRP7zf/7P2pe//OU5X8+m7p/97Gfaz3/+c+3hhx/WPvKRj8x47TOf+Yx21113aUNDQ1pjY6NWVVWl/eAHP0j59UxqveWWW7R//Md/nPNrM6l1fHxce/zxx7WmpiZtenpae/311zW32629+OKLKWkxklbR/aom2QUm2aefflrbsmXLjLbNmzdr+/fvz4S8S6isrNSee+65+L+fffZZrbq6OitaEllokjWC7q997WszJq5AIKDZbDbtrbfeird94xvf0G6++eaUXs+kVk2bfzLIptYYH/3oR7XHH3/c0P06W6umie/Xy94uiHHFFVdQUVHBfffdx9mzZ+PtJ06coK6ubsa1dXV1nDhxItMSGRoaorOzc4aeuro62tvbF3Xyrd788Ic/xOPxsGXLFv7hH/4hXvLOqLobGxuZmpq6RFfsd7vQ69ngySefxOPxcNVVV/HDH/4w3p5trcFgkGPHjrFt2zbD92ui1hgi+3VZT7LhcJhgMDjnH03TKCkp4c0336SlpYWzZ89SU1PDHXfcwejoKHCxSE1igRq4WKQmdjBiJlmoYE42+dKXvkRjYyMDAwPs27ePb33rW3zrW98CjKt7fHwch8MxY2NL4u92odczzf/4H/+D5uZm+vr6+PrXv87u3bv5+c9/nnWtmqbx0EMPUVNTwwMPPGDofp2tFcT367KeZD/60Y+Sn58/55+2tjYKCgrYuXMnVqsVt9vN//yf/5NwOMxrr70GXCxSM/tpa2RkJCsFaoxcMGf79u2UlpaSk5PDddddx9/8zd/w05/+FDCu7oKCAiYmJmYEcIm/24VezzTXX389LpcLq9XKXXfdxV/8xV/M6ONsaNU0jS984Qs0Njbyi1/8ArPZbNh+TaYVxPfrsp5kf/Ob36Bd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\n", "text/plain": [ "
" ] @@ -704,7 +704,7 @@ "True" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -715,14 +715,14 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -736,7 +736,7 @@ "75.41381950397155" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -749,7 +749,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -760,6 +760,72 @@ "z.export_to_csv(df='extended') # Default df='simple', filepath=None" ] }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\r 0%| | 0/3 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z.calculation(start_at=4)\n", + "z.plot(show=True)" + ] + }, { "cell_type": "code", "execution_count": null, From d80e72ffa527fbadf547c5dc0e8281485d23e99b Mon Sep 17 00:00:00 2001 From: Eugen Boos Date: Wed, 14 Nov 2018 11:10:23 +0100 Subject: [PATCH 08/11] Revised Alpha-Level-Optimization Signed-off-by: Eugen Boos --- phuzzy/optimization/Alpha Opti Notebook.ipynb | 4 +- phuzzy/optimization/alphaOpt.py | 269 +++--------------- 2 files changed, 37 insertions(+), 236 deletions(-) diff --git a/phuzzy/optimization/Alpha Opti Notebook.ipynb b/phuzzy/optimization/Alpha Opti Notebook.ipynb index ce769b1..0138919 100644 --- a/phuzzy/optimization/Alpha Opti Notebook.ipynb +++ b/phuzzy/optimization/Alpha Opti Notebook.ipynb @@ -423,7 +423,7 @@ } ], "source": [ - "z.simple_dataframe(round=2) # Default: round=None\n", + "z.compact_output(round=2) # Default: round=None\n", "z.df" ] }, @@ -657,7 +657,7 @@ } ], "source": [ - "z.extanded_dataframe(round=4) # Default: round=None\n", + "z.extanded_output(round=4) # Default: round=None\n", "z.df_extanded" ] }, diff --git a/phuzzy/optimization/alphaOpt.py b/phuzzy/optimization/alphaOpt.py index ba16117..72e8b3a 100644 --- a/phuzzy/optimization/alphaOpt.py +++ b/phuzzy/optimization/alphaOpt.py @@ -142,7 +142,13 @@ def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=N else: # Alpha-Level < 1 # if all bounds are Fuzzy-Intervalls - if 'shc_fuzzy_min' in locals(): + if 'shc_fuzzy_min' not in locals(): + shc_const_min = self._call_minimizer_shgo(bounds) + shc_const_max = self._call_maximizer_shgo(bounds) + + shc_fuzzy_min = self._find_result(shc_const_min) + shc_fuzzy_max = self._find_result(shc_const_max) + else: shc_fuzzy_min.bounds = bounds shc_fuzzy_min.iterate() shc_fuzzy_min.find_minima() @@ -150,14 +156,6 @@ def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=N shc_fuzzy_max.bounds = bounds shc_fuzzy_max.iterate() shc_fuzzy_max.find_minima() - else: - shc_const_min = self._call_minimizer_shgo(bounds) - shc_const_max = self._call_maximizer_shgo(bounds) - - #shc_fuzzy_min.construct_complex() - #shc_fuzzy_max.construct_complex() - shc_fuzzy_min = self._find_result(shc_const_min) - shc_fuzzy_max = self._find_result(shc_const_max) ## safe results in lists best_indi_min = shc_fuzzy_min.res.x @@ -192,201 +190,10 @@ def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=N self.zmax_values = self._safe_z_values(min_max='max', z_value_list=zmax_value_list) self.total_nfev = sum(self.nfev_list_min) + sum(self.nfev_list_max) - self.simple_dataframe() + self.compact_output() - def separat_minimization(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): - """ - Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate - the Fuzzy Objective Membershipfunction. - :param n: Number of Sampling Points / Individuals for the Optimization Algorithm - :param iters: Number of max. Iterations per Optimization Loop - :param optimizer: Selected Optimizer Strategy: "sobol" / "simplicial" - :param backup: Creates a Backup Folder saving the result of each Alpha Level Result - :param start_at: Start at certain Alpha Level (Counts starts from Alpha Level 1) - """ - - # Input Variables - self.n = n - self.iters = iters - self.optimizer = optimizer # simplicial / sobol - self.backup = backup - self.start_at = start_at - - zmin_value_list = [] - boundlist = [] - - if self.start_at is not None: self._cut_global_blounds() - - for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): - boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) - - with tqdm(total=len(boundlist)) as pbar: - for lvl, bounds in enumerate(boundlist): - comp_bounds = [] - - for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) - - if lvl == 0: # Alpha-Level = 1 - if self.start_at is None: - if all(comp_bounds) == True: # if all bounds are constants - ## calculate objective value - zmin = self.objective_function(bounds[:, 0]) - - ## safe values in list - zmin_value_list.append(np.array(zmin)) - best_indi_min = np.array(bounds[:, 0]) - nfev_min = np.array(0) - nit_min = np.array(0) - - elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants - ## prepare bounds / pop constants - bounds = self._pop_constants(comp_bounds, bounds) - - ## optimization routine - shc_const_min = self._call_minimizer_shgo(bounds) - shc_const_min = self._find_result(shc_const_min) - - ## safe results in lists - best_indi_min = self._safe_best_array(comp_bounds, shc_const_min.res) - nfev_min = shc_const_min.res.nfev - nit_min = shc_const_min.res.nit - zmin_value_list.append(shc_const_min.res.fun * (1)) - self.x_glob = [] - else: - shc_const_min = self._call_minimizer_shgo(bounds) - shc_const_min = self._find_result(shc_const_min) - - ## safe results in lists - best_indi_min = self._safe_best_array(comp_bounds, shc_const_min.res) - nfev_min = shc_const_min.res.nfev - nit_min = shc_const_min.res.nit - zmin_value_list.append(shc_const_min.res.fun * (1)) - - else: # Alpha-Level < 1 - # if all bounds are Fuzzy-Intervalls - if 'shc_fuzzy_min' in locals(): - shc_fuzzy_min.bounds = bounds - shc_fuzzy_min.iterate() - shc_fuzzy_min.find_minima() - else: - shc_const_min = self._call_minimizer_shgo(bounds) - shc_fuzzy_min = self._find_result(shc_const_min) - - ## safe results in lists - best_indi_min = shc_fuzzy_min.res.x - if lvl <= 1: - nfev_min = shc_const_min.res.nfev - else: - nfev_min = np.absolute((shc_const_min.res.nfev - np.sum(self.nfev_list_min[0:lvl-1]))) - nit_min = shc_const_min.res.nit - - zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) - - self.best_indi_list_min.append(best_indi_min) - self.nfev_list_min.append(nfev_min) - self.nit_list_min.append(nit_min) - pbar.update() - - self.zmin_values = self._safe_z_values(min_max='min', z_value_list=zmin_value_list) - - - def separat_maximization(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): - """ - Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate - the Fuzzy Objective Membershipfunction. - :param n: Number of Sampling Points / Individuals for the Optimization Algorithm - :param iters: Number of max. Iterations per Optimization Loop - :param optimizer: Selected Optimizer Strategy: "sobol" / "simplicial" - :param backup: Creates a Backup Folder saving the result of each Alpha Level Result - :param start_at: Start at certain Alpha Level (Counts starts from Alpha Level 1) - """ - - # Input Variables - self.n = n - self.iters = iters - self.optimizer = optimizer # simplicial / sobol - self.backup = backup - self.start_at = start_at - - zmax_value_list = [] - boundlist = [] - - if self.start_at is not None: self._cut_global_blounds() - - for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): - boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) - - with tqdm(total=len(boundlist)) as pbar: - for lvl, bounds in enumerate(boundlist): - comp_bounds = [] - for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) - if lvl == 0: # Alpha-Level = 1 - if self.start_at is None: - if all(comp_bounds) == True: # if all bounds are constants - ## calculate objective value - zmax = self.objective_function(bounds[:, 0]) - - ## safe values in list - zmax_value_list.append(np.array(zmax)) - best_indi_max = np.array(bounds[:, 0]) - nfev_max = np.array(0) - nit_max = np.array(0) - - elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants - ## prepare bounds / pop constants - bounds = self._pop_constants(comp_bounds, bounds) - - ## optimization routine - shc_const_max = self._call_maximizer_shgo(bounds) - shc_const_max = self._find_result(shc_const_max) - - ## safe results in lists - best_indi_max = self._safe_best_array(comp_bounds, shc_const_max.res) - nfev_max = shc_const_max.res.nfev - nit_max = shc_const_max.res.nit - - zmax_value_list.append(shc_const_max.res.fun * (-1)) - self.x_glob = [] - else: - shc_const_max = self._call_maximizer_shgo(bounds) - shc_const_max = self._find_result(shc_const_max) - - ## safe results in lists - best_indi_max = self._safe_best_array(comp_bounds, shc_const_max.res) - nfev_max = shc_const_max.res.nfev - nit_max = shc_const_max.res.nit - zmax_value_list.append(shc_const_max.res.fun * (-1)) - - else: # Alpha-Level < 1 - # if all bounds are Fuzzy-Intervalls - if 'shc_fuzzy_min' in locals(): - shc_fuzzy_max.bounds = bounds - shc_fuzzy_max.iterate() - shc_fuzzy_max.find_minima() - else: - shc_const_max = self._call_maximizer_shgo(bounds) - shc_fuzzy_max = self._find_result(shc_const_max) - - ## safe results in lists - best_indi_max = shc_fuzzy_max.res.x - if lvl <= 1: - nfev_max = shc_const_max.res.nfev - else: - nfev_max = np.absolute((shc_const_max.res.nfev - np.sum(self.nfev_list_max[0:lvl-1]))) - nit_max = shc_const_max.res.nit - - zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) - - self.best_indi_list_max.append(best_indi_max) - self.nfev_list_max.append(nfev_max) - self.nit_list_max.append(nit_max) - pbar.update() - - self.zmax_values = self._safe_z_values(min_max='max', z_value_list=zmax_value_list) - - - def simple_dataframe(self,round=None): + def compact_output(self, round=None): """ Returns Dataframe of Objective Memebership Function :param round: Round Values of Dataframe @@ -408,7 +215,7 @@ def simple_dataframe(self,round=None): self._df = self._df.round(round) - def extanded_dataframe(self,round=None): + def extanded_output(self,round=None): """ Create extanded Solution Dataframe of Objective :param round: Round Values of Dataframe @@ -559,8 +366,8 @@ def _objective_function(self, x): aeval.symtable['x'] = x return aeval.run(exprc) - - def _boundary_constraints(self, **kwargs): + @classmethod + def _boundary_constraints(**kwargs): """ Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton :param kwargs: Input Fuzzy Variables @@ -582,9 +389,9 @@ def _boundary_constraints(self, **kwargs): for key, value in kwargs.items(): # if number_of_alpha_levels are different if (len(set(list_of_n_alpha_levels)) == 1) == False: - max = np.max(list_of_n_alpha_levels) + max_value = np.max(list_of_n_alpha_levels) if isinstance(value, phuzzy.FuzzyNumber): - if value.number_of_alpha_levels < max: value.convert_df(alpha_levels=max) + if value.number_of_alpha_levels < max_value: value.convert_df(alpha_levels=max_value) filter_fuzzy_variables_dict[key] = value._df elif isinstance(value, phuzzy.FuzzyNumber): # if number_of_alpha_levels are the same @@ -593,15 +400,30 @@ def _boundary_constraints(self, **kwargs): # extract fuzzy values from dict and safe as DataArray fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) for k, v in filter_fuzzy_variables_dict.items()} - """ - if self.start_at is not None: - return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables')[:,0:self.start_at,:] - else: - return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') - """ return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') + @staticmethod + def _safe_z_values(min_max, z_value_list): + """ + Post Preparation for Results of Optimization Routines for creation of Fuzzy Dataframe + :param min_max: Define if Result is from a Minimization or Maximization + :param z_value_list: List of all Objective Value Results (for each Alpha Level) + :return: + z_value_list Adapted List of all Objective Value Results + """ + if min_max == 'min': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item < next_item: + z_value_list[i + 1] = current_item + elif min_max == 'max': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item > next_item: + z_value_list[i + 1] = current_item + else: + raise ValueError('Please define -min- or -max- in min_max') + return np.flip(z_value_list, axis=0) + def _cut_global_blounds(self): """ @@ -697,27 +519,6 @@ def _pop_constants(self, comp_bounds, bounds): bounds = np.delete(bounds, pop, 0) return bounds - @staticmethod - def _safe_z_values(min_max, z_value_list): - """ - Post Preparation for Results of Optimization Routines for creation of Fuzzy Dataframe - :param min_max: Define if Result is from a Minimization or Maximization - :param z_value_list: List of all Objective Value Results (for each Alpha Level) - :return: - z_value_list Adapted List of all Objective Value Results - """ - if min_max == 'min': - for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): - if current_item < next_item: - z_value_list[i + 1] = current_item - elif min_max == 'max': - for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): - if current_item > next_item: - z_value_list[i + 1] = current_item - else: - raise ValueError('Please define -min- or -max- in min_max') - return np.flip(z_value_list, axis=0) - def _call_backup(self,iteration): """ From d171c6c221efd3255762a07ad32758c33ad381ca Mon Sep 17 00:00:00 2001 From: Eugen Boos Date: Wed, 14 Nov 2018 13:14:06 +0100 Subject: [PATCH 09/11] Revised Alpha-Level-Optimization Signed-off-by: Eugen Boos --- phuzzy/optimization/Alpha Opti Notebook.ipynb | 58 +++--- phuzzy/optimization/__init__.py | 2 - phuzzy/optimization/alphaOpt.py | 181 +++++++++--------- 3 files changed, 123 insertions(+), 118 deletions(-) diff --git a/phuzzy/optimization/Alpha Opti Notebook.ipynb b/phuzzy/optimization/Alpha Opti Notebook.ipynb index 0138919..81d1264 100644 --- a/phuzzy/optimization/Alpha Opti Notebook.ipynb +++ b/phuzzy/optimization/Alpha Opti Notebook.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "collapsed": false }, @@ -24,7 +24,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -45,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -59,42 +59,42 @@ "name": "stderr", "output_type": "stream", "text": [ - "\r 17%|█▋ | 1/6 [00:00<00:01, 3.65it/s]" + "\r 17%|█▋ | 1/6 [00:00<00:01, 3.58it/s]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r 33%|███▎ | 2/6 [00:01<00:02, 1.86it/s]" + "\r 33%|███▎ | 2/6 [00:01<00:02, 1.74it/s]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r 50%|█████ | 3/6 [00:03<00:02, 1.02it/s]" + "\r 50%|█████ | 3/6 [00:03<00:03, 1.01s/it]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r 67%|██████▋ | 4/6 [00:05<00:02, 1.35s/it]" + "\r 67%|██████▋ | 4/6 [00:06<00:03, 1.67s/it]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r 83%|████████▎ | 5/6 [00:08<00:01, 1.75s/it]" + "\r 83%|████████▎ | 5/6 [00:10<00:02, 2.38s/it]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r100%|██████████| 6/6 [00:11<00:00, 2.21s/it]" + "\r100%|██████████| 6/6 [00:15<00:00, 3.12s/it]" ] }, { @@ -112,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -121,7 +121,7 @@ "Opti_Test(x:[[-3.51, 195], [59.4, 64.2]])" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -132,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "collapsed": false }, @@ -270,7 +270,7 @@ "" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -281,7 +281,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -417,7 +417,7 @@ "" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -429,7 +429,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "collapsed": false }, @@ -651,7 +651,7 @@ "" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -663,7 +663,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -672,7 +672,7 @@ "1168" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -683,7 +683,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "collapsed": true }, @@ -704,7 +704,7 @@ "True" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -715,7 +715,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "collapsed": false }, @@ -736,7 +736,7 @@ "75.41381950397155" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -749,7 +749,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -762,7 +762,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -776,21 +776,21 @@ "name": "stderr", "output_type": "stream", "text": [ - "\r 33%|███▎ | 1/3 [00:01<00:02, 1.24s/it]" + "\r 33%|███▎ | 1/3 [00:01<00:02, 1.29s/it]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r 67%|██████▋ | 2/3 [00:02<00:01, 1.22s/it]" + "\r 67%|██████▋ | 2/3 [00:02<00:01, 1.25s/it]" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "\r100%|██████████| 3/3 [00:04<00:00, 1.36s/it]" + "\r100%|██████████| 3/3 [00:04<00:00, 1.46s/it]" ] }, { @@ -816,7 +816,7 @@ "True" ] }, - "execution_count": 12, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py index f1bdfcb..2819609 100644 --- a/phuzzy/optimization/__init__.py +++ b/phuzzy/optimization/__init__.py @@ -43,8 +43,6 @@ z = alphaOpt.Alpha_Level_Optimization(**kwargs) z.calculation() - z.extanded_dataframe() - z.export() z.plot() plt.show() diff --git a/phuzzy/optimization/alphaOpt.py b/phuzzy/optimization/alphaOpt.py index 72e8b3a..020c24c 100644 --- a/phuzzy/optimization/alphaOpt.py +++ b/phuzzy/optimization/alphaOpt.py @@ -241,9 +241,9 @@ def extanded_output(self,round=None): 'r': self.zmax_values, 'best_indi_r': max_arr.tolist(), 'nfev_r':self.nfev_list_max, 'nit_r': self.nit_list_max}) else: - self.df_extanded = pd.DataFrame(data={'alpha': np.linspace(0, - np.linspace(0, 1.0, self.orig_number_of_alpha_lvls) - [self.orig_number_of_alpha_lvls-self.start_at], self.number_of_alpha_lvls), + self.df_extanded = pd.DataFrame(data={'alpha': + np.linspace(0, np.linspace(0, 1.0, self.orig_number_of_alpha_lvls) + [self.orig_number_of_alpha_lvls-self.start_at], self.number_of_alpha_lvls), 'l': self.zmin_values, 'best_indi_l': min_arr.tolist(), 'nfev_l': self.nfev_list_min, 'nit_l': self.nit_list_min, 'r': self.zmax_values, 'best_indi_r': max_arr.tolist(), @@ -366,64 +366,6 @@ def _objective_function(self, x): aeval.symtable['x'] = x return aeval.run(exprc) - @classmethod - def _boundary_constraints(**kwargs): - """ - Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton - :param kwargs: Input Fuzzy Variables - :return: 3D DataArray representing each Fuzzy Inputvariables Boundaries for each Alpha Level - prepared for the Optimization Routine - """ - filter_fuzzy_variables_dict = {} - list_of_n_alpha_levels = np.zeros(1, dtype='int') - - # check if number_of_alpha_levels is the same - for key, value in kwargs.items(): - if isinstance(value, phuzzy.FuzzyNumber): - if list_of_n_alpha_levels[0] == 0: - np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) - else: - list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) - - # extract fuzzy variables from kwargs and safe in dict - for key, value in kwargs.items(): - # if number_of_alpha_levels are different - if (len(set(list_of_n_alpha_levels)) == 1) == False: - max_value = np.max(list_of_n_alpha_levels) - if isinstance(value, phuzzy.FuzzyNumber): - if value.number_of_alpha_levels < max_value: value.convert_df(alpha_levels=max_value) - filter_fuzzy_variables_dict[key] = value._df - elif isinstance(value, phuzzy.FuzzyNumber): - # if number_of_alpha_levels are the same - filter_fuzzy_variables_dict[key] = value._df - - # extract fuzzy values from dict and safe as DataArray - fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) - for k, v in filter_fuzzy_variables_dict.items()} - - return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') - - @staticmethod - def _safe_z_values(min_max, z_value_list): - """ - Post Preparation for Results of Optimization Routines for creation of Fuzzy Dataframe - :param min_max: Define if Result is from a Minimization or Maximization - :param z_value_list: List of all Objective Value Results (for each Alpha Level) - :return: - z_value_list Adapted List of all Objective Value Results - """ - if min_max == 'min': - for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): - if current_item < next_item: - z_value_list[i + 1] = current_item - elif min_max == 'max': - for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): - if current_item > next_item: - z_value_list[i + 1] = current_item - else: - raise ValueError('Please define -min- or -max- in min_max') - return np.flip(z_value_list, axis=0) - def _cut_global_blounds(self): """ @@ -462,31 +404,6 @@ def _max_function_value(self, x): return -1 * (self._objective_function(x)) - def _find_result(self, shc): - """ - Post Calculation for Shgo-Optimization Algorithm - """ - shc.construct_complex() - if len(shc.LMC.xl_maps) > 0: - return shc - else: - lres = minimize(shc.func, shc.x_lowest, - **shc.minimizer_kwargs) - shc.res.nlfev += lres.nfev - try: - lres.fun = lres.fun[0] - except (IndexError, TypeError): - lres.fun - - shc.LMC[shc.x_lowest] - shc.LMC.add_res(shc.x_lowest, lres) - shc.sort_result() - # Lowest values used to report in case of failures - shc.f_lowest = shc.res.fun - shc.x_lowest = shc.res.x - return shc - - def _safe_best_array(self, comp_bounds, z_res): """ Post Preparation to extrapolate sampling Point with min/max Objective Value from Optimization Result @@ -532,7 +449,7 @@ def _call_backup(self,iteration): filepath = Path.cwd() / 'back_up' / cache_str if self.start_at is None: df_cache = pd.DataFrame(data={'alpha': np.linspace(np.linspace(0, 1.0, self.number_of_alpha_lvls) - [self.number_of_alpha_lvls-1-iteration], 1.0, iteration+1), + [self.number_of_alpha_lvls-1-iteration], 1.0, iteration+1), 'l': self.zmin_values, 'r': self.zmax_values}) else: @@ -545,10 +462,100 @@ def _call_backup(self,iteration): df_cache.to_csv(filepath, sep=';', encoding='utf8', index=None, header=True) + + @staticmethod + def _boundary_constraints(**kwargs): + """ + Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton + :param kwargs: Input Fuzzy Variables + :return: 3D DataArray representing each Fuzzy Inputvariables Boundaries for each Alpha Level + prepared for the Optimization Routine + """ + filter_fuzzy_variables_dict = {} + list_of_n_alpha_levels = np.zeros(1, dtype='int') + + # check if number_of_alpha_levels is the same + for key, value in kwargs.items(): + if isinstance(value, phuzzy.FuzzyNumber): + if list_of_n_alpha_levels[0] == 0: + np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) + else: + list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) + + + # extract fuzzy variables from kwargs and safe in dict + for key, value in kwargs.items(): + # if number_of_alpha_levels are different + if (len(set(list_of_n_alpha_levels)) == 1) == False: + max_value = np.max(list_of_n_alpha_levels) + if isinstance(value, phuzzy.FuzzyNumber): + if value.number_of_alpha_levels < max_value: value.convert_df(alpha_levels=max_value) + filter_fuzzy_variables_dict[key] = value._df + elif isinstance(value, phuzzy.FuzzyNumber): + # if number_of_alpha_levels are the same + filter_fuzzy_variables_dict[key] = value._df + + + # extract fuzzy values from dict and safe as DataArray + fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) + for k, v in filter_fuzzy_variables_dict.items()} + + return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') + + + @staticmethod + def _safe_z_values(min_max, z_value_list): + """ + Post Preparation for Results of Optimization Routines for creation of Fuzzy Dataframe + :param min_max: Define if Result is from a Minimization or Maximization + :param z_value_list: List of all Objective Value Results (for each Alpha Level) + :return: + z_value_list Adapted List of all Objective Value Results + """ + if min_max == 'min': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item < next_item: + z_value_list[i + 1] = current_item + elif min_max == 'max': + for (i, current_item), next_item in zip(enumerate(z_value_list), z_value_list[1:]): + if current_item > next_item: + z_value_list[i + 1] = current_item + else: + raise ValueError('Please define -min- or -max- in min_max') + return np.flip(z_value_list, axis=0) + + + @staticmethod + def _find_result(shc): + """ + Post Calculation for Shgo-Optimization Algorithm + """ + shc.construct_complex() + if len(shc.LMC.xl_maps) > 0: + return shc + else: + lres = minimize(shc.func, shc.x_lowest, + **shc.minimizer_kwargs) + shc.res.nlfev += lres.nfev + try: + lres.fun = lres.fun[0] + except (IndexError, TypeError): + lres.fun + + shc.LMC[shc.x_lowest] + shc.LMC.add_res(shc.x_lowest, lres) + shc.sort_result() + # Lowest values used to report in case of failures + shc.f_lowest = shc.res.fun + shc.x_lowest = shc.res.x + return shc + + @classmethod def from_str(cls, s): pass + def to_str(self): pass From 8d5e92366cace14439f33deafdcb645b4ae75785 Mon Sep 17 00:00:00 2001 From: Eugen Boos Date: Tue, 4 Dec 2018 10:19:37 +0100 Subject: [PATCH 10/11] Revised Alpha-Level-Optimization Signed-off-by: Eugen Boos --- phuzzy/fuzzification/__init__.py | 50 ++ phuzzy/fuzzification/data_fitting.py | 233 +++++++ phuzzy/mpl/plots.py | 16 + phuzzy/optimization/Alpha Opti Notebook.ipynb | 75 ++- .../optimization/Fuzzy Sensi Analysis.ipynb | 567 ++++++++++++++++++ phuzzy/optimization/__init__.py | 44 +- phuzzy/optimization/alphaOpt.py | 138 ++++- phuzzy/optimization/sensitivity_analysis.py | 284 +++++++++ tests/test_fuzzy analysis.ipynb | 138 +++++ tests/test_fuzzy_analysis.py | 7 + 10 files changed, 1533 insertions(+), 19 deletions(-) create mode 100644 phuzzy/fuzzification/__init__.py create mode 100644 phuzzy/fuzzification/data_fitting.py create mode 100644 phuzzy/optimization/Fuzzy Sensi Analysis.ipynb create mode 100644 phuzzy/optimization/sensitivity_analysis.py create mode 100644 tests/test_fuzzy analysis.ipynb diff --git a/phuzzy/fuzzification/__init__.py b/phuzzy/fuzzification/__init__.py new file mode 100644 index 0000000..c9c7d9a --- /dev/null +++ b/phuzzy/fuzzification/__init__.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +from shgo._shgo import SHGO + +import datetime +import os +import subprocess + +import phuzzy +from phuzzy.mpl import MPL_Mixin +from phuzzy.shapes import FuzzyNumber + +import matplotlib +import matplotlib.pyplot as plt +import matplotlib.rcsetup as rcsetup +from phuzzy.optimization import alphaOpt +from phuzzy.optimization import sensitivity_analysis + +from phuzzy.fuzzification import data_fitting +import math + +import numpy as np +import pandas as pd +import xarray as xr + +#from math import * + + + + + +if __name__ == "__main__": + + link = 'C:\\Users\\boos\\Desktop\\histotest.csv' + + kwargs = {'name': 'test', 'input_link': link} + + fuzzy_variable = data_fitting.New_Data_Fitting() + fuzzy_variable.create_fuzzy_variable(input_link=link) + histogram_df = fuzzy_variable.histogram_df + fuzzy_variable_i = fuzzy_variable.fuzzy_variable + + fig, ax = plt.subplots() + binsSize = histogram_df['widthR'].values[0]-histogram_df['widthL'].values[0] + ax.bar(x=histogram_df['center'].values.tolist(),height=histogram_df['absBinFrequencyNorm'].values.tolist(), + width=binsSize.tolist(),align='center',color='royalblue') + plt.show() + + + r = 1 diff --git a/phuzzy/fuzzification/data_fitting.py b/phuzzy/fuzzification/data_fitting.py new file mode 100644 index 0000000..488ecdd --- /dev/null +++ b/phuzzy/fuzzification/data_fitting.py @@ -0,0 +1,233 @@ +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +import phuzzy.mpl as phm + +from scipy import interpolate, optimize +from pandas._libs.testing import isna + + + + + + +class New_Data_Fitting(object): + + def __init__(self): + pass + + def create_fuzzy_variable(self, input_link=None, type='Triangle', number_of_alpha_levels=5, alpha_level_1_method= 'maxVal', + alpha_level_0_method='direct', name=None, bin_calc_method='scott', custom_bins=25): + + if input_link is None: raise ValueError('PLEASE ADD INPUT LINK') + if name is None: self.name = 'Input Data' + + input_df = self.read_input_csv(input_link=input_link) + self.histogram_df = self.create_histogram(input_df=input_df, bin_calc_method=bin_calc_method, custom_bins=custom_bins) + + alpha_lvl_0 = self.set_alpha_level_0(histogram_df=self.histogram_df, alpha_level_0_method=alpha_level_0_method) + alpha_lvl_1 = self.set_alpha_level_1(histogram_df=self.histogram_df,alpha_level_1_method=alpha_level_1_method) + + self.fuzzy_variable = self.fitting(type=type,number_of_alpha_levels=number_of_alpha_levels, + alpha_lvl_0=alpha_lvl_0,alpha_lvl_1=alpha_lvl_1) + + + #self.plot_data() + #r = 1 + + def plot_data(self): + + #phm.plot_bar(y=self.histogram_df['absBinFrequencyNorm'],x=self.histogram_df['center']) + + binsSize = self.histogram_df['widthR'].values[0]-self.histogram_df['widthL'].values[0] + plt.bar(height=self.histogram_df['absBinFrequencyNorm'].values,x=self.histogram_df['center'].values,width=binsSize) + self.fuzzy_variable.plot() + + plt.show() + + self.histogram_df['absBinFrequencyNorm'].plot.hist(grid=True, bins=20, rwidth=0.9, + color='#607c8e') + bins = np.concatenate((self.histogram_df['widthL'].values,self.histogram_df['widthR'].values[-1]),axis=None) + plt.hist2d(bins, self.histogram_df['absBinFrequencyNorm'], 'r--', linewidth=1) + + + def read_input_csv(self, input_link): + return pd.read_csv(input_link,sep=',',header=None) + + + def minimization_dist_function(self,xx): + if self.type == 'TruncGenNorm': + func = phm.TruncGenNorm(alpha0=self.histo_class.alpha0, alpha1=self.histo_class.alpha1, number_of_alpha_levels=self.set_number_of_alpha_levels, beta=xx[0]) + elif self.type == 'Superellipse': + func = phm.Superellipse(alpha0=self.histo_class.alpha0, alpha1=self.histo_class.alpha1, m= xx[0], n=xx[1], number_of_alpha_levels=self.set_number_of_alpha_levels) + elif self.type == 'TruncGenSkewNorm': + func = phm.TruncGenSkewNorm(alpha0=self.histo_class.alpha0, alpha1=self.histo_class.alpha1, number_of_alpha_levels=self.set_number_of_alpha_levels, a=xx[0]) + x_values = [] + alpha_values = [] + #for index_histo, row_histo in self.histo_class.histo_df.iterrows(): + for i in range(len(self.histo_class.histo_df)): + #x = row_histo['center'] + x = self.histo_class.histo_df.iloc[i]["center"] + x_values.append(x) + loop = 0 + if x < func._df.iloc[-1]["l"]: + for i in range(0,len(func._df)-1): + if x >= func._df.iloc[i]["l"] and x <= func._df.iloc[i+1]["l"] and loop == 0: + x_interpol = [func._df.iloc[i]["l"], func._df.iloc[i+1]["l"]] + y_interpol = [func._df.iloc[i]["alpha"], func._df.iloc[i+1]["alpha"]] + f = interpolate.interp1d(x_interpol, y_interpol) + alpha_x = f(x) + alpha_values.append(alpha_x.item(0)) + loop = 1 + elif x >= func._df.iloc[-1]["r"]: + for i in range(0,len(func._df)-1): + if x <= func._df.iloc[i]["r"] and x >= func._df.iloc[i+1]["r"] and loop == 0: + x_interpol = [func._df.iloc[i]["r"], func._df.iloc[i+1]["r"]] + y_interpol = [func._df.iloc[i]["alpha"], func._df.iloc[i+1]["alpha"]] + f = interpolate.interp1d(x_interpol, y_interpol) + alpha_x = f(x) + alpha_values.append(alpha_x.item(0)) + loop = 1 + else: + alpha_values.append(1.0) + #calc dist + alpha_values_hist = self.histo_class.histo_df['absBinFrequencyNorm'].values + alpha_values_plot = alpha_values + return sum(abs(alpha_values_plot-alpha_values_hist)) + + + def create_histogram(self,input_df,bin_calc_method,custom_bins=None): + + #Bins Size & Number of Bins Definition + if bin_calc_method == 'scott': + binSize = ((3.49 * input_df.values.std()) / (len(input_df))**(1/3)) + nbins = (int(round((input_df.values.max() - input_df.values.min()) / binSize))) + elif bin_calc_method == 'freedman': + binSize = ((2*((input_df.quantile(0.75) - input_df.quantile(0.25)).values)) / (len(input_df))**(1/3)).item(0) + nbins = (int(round((input_df.values.max() - input_df.values.min()) / binSize))) + elif bin_calc_method == 'custom': + nbins = custom_bins + binSize = (input_df.values.max() - input_df.values.min()) / nbins + elif bin_calc_method == 'rice': + nbins = int(round((2*len(input_df)**(1/3)))) #Rice Rule + binSize = (input_df.values.max() - input_df.values.min()) / nbins + + #Calculate Histogram Data + values = np.ravel((input_df._convert(datetime=True)._get_numeric_data())) + values = values[~isna(values)] + abs_bin_frequency, binsIntval = np.histogram(values, bins=nbins) + #abs_bin_frequency_norm = (abs_bin_frequency - abs_bin_frequency.min()) / (abs_bin_frequency.max() - abs_bin_frequency.min()) + abs_bin_frequency_norm = (abs_bin_frequency - 0.0) / (abs_bin_frequency.max() - 0.0) + + #Histo Array Pandas DataFrame creation + histo_array = np.concatenate((abs_bin_frequency,abs_bin_frequency_norm,binsIntval[0:-1],binsIntval[1:],0.5*(binsIntval[1:]+binsIntval[0:-1])),axis=None) + histo_array = histo_array.reshape(len(abs_bin_frequency),5).T + histogram_df = pd.DataFrame(columns=["absBinFrequency", "absBinFrequencyNorm", "widthL", "widthR","center"],data=histo_array, dtype=np.float) + return histogram_df + + + def set_alpha_level_1(self,histogram_df,alpha_level_1_method): + if alpha_level_1_method == 'maxVal': + maxValRow = histogram_df.loc[histogram_df['absBinFrequency'].idxmax()] + if histogram_df.loc[histogram_df['absBinFrequency'].idxmax()].name == 0: + maxMeanVal = maxValRow[2] + alpha1 = [maxMeanVal, maxMeanVal] + elif histogram_df.loc[histogram_df['absBinFrequency'].idxmax()].name == (len(histogram_df.index)-1): + maxMeanVal = maxValRow[3] + alpha1 = [maxMeanVal, maxMeanVal] + else: + maxMeanVal = maxValRow[4] + alpha1 = [maxMeanVal, maxMeanVal] + elif alpha_level_1_method == 'mean': + meanVal = histogram_df.mean() + alpha1 = [meanVal.values.item(0), meanVal.values.item(0)] + elif alpha_level_1_method == 'modus': + modusVal = histogram_df.mode() + if len(modusVal) == 1: + alpha1 = [modusVal.values.item(0), modusVal.values.item(0)] + else: + alpha1 = [modusVal.values.min(), modusVal.values.max()] + elif alpha_level_1_method == 'gnstd': + meanVal = histogram_df.mean() + stdVal = histogram_df.std() + alpha1 = [meanVal.values.item(0)-(0.50*stdVal.values.item(0)), meanVal.values.item(0)+(0.50*stdVal.values.item(0))] + return np.array(alpha1) + + + def set_alpha_level_0(self,histogram_df,alpha_level_0_method): + if alpha_level_0_method == 'direct': + alpha0L = histogram_df['widthL'].min() + alpha0R = histogram_df['widthR'].max() + elif alpha_level_0_method == 'saftyfactor': + binSize = histogram_df['widthR'][0]-histogram_df['widthL'][0] + alpha0L = histogram_df['widthL'].min() - 0.5*binSize + alpha0R = histogram_df['widthR'].max() + 0.5*binSize + return np.array([alpha0L, alpha0R]) + + + def fitting(self,type,number_of_alpha_levels,alpha_lvl_0,alpha_lvl_1): + + # Optimization Call + if type == 'TruncGenNorm': + res = optimize.minimize(self.minimization_dist_function, [1.0], method='Nelder-Mead', tol=1e-03,options={'disp': True}) + elif type == 'Superellipse': + res = optimize.minimize(self.minimization_dist_function, [1.0,1.0], method='Nelder-Mead', tol=1e-03,options={'disp': True}) + elif type == 'TruncGenSkewNorm': + res = optimize.minimize(self.minimization_dist_function, [1.0], method='Nelder-Mead', tol=1e-03,options={'disp': True}) + + # Fitting Functions & Plot + if type == 'TruncGenNorm': + fuzzy_var = phm.TruncGenNorm(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels, beta=res.x[0]) + #tgn.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) + elif type == 'Superellipse': + fuzzy_var = phm.Superellipse(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, m= res.x[0], n=res.x[1], number_of_alpha_levels=number_of_alpha_levels) + #se.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) + elif type == 'TruncGenSkewNorm': + fuzzy_var = phm.TruncGenSkewNorm(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels, a=res.x[0]) + #tgsn.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) + elif type == 'Triangle': + fuzzy_var = phm.Triangle(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels) + #tri.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) + elif type == 'Trapezoid': + fuzzy_var = phm.Trapezoid(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels) + #tra.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) + elif type == 'TruncNorm': + fuzzy_var = phm.TruncNorm(alpha0=alpha_lvl_0, number_of_alpha_levels=number_of_alpha_levels) + #tn.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) + return fuzzy_var + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phuzzy/mpl/plots.py b/phuzzy/mpl/plots.py index db0a376..c2cb89c 100644 --- a/phuzzy/mpl/plots.py +++ b/phuzzy/mpl/plots.py @@ -32,6 +32,7 @@ def plot_xy(x, y, height=100, width=200): return fig, axs + def plot_xyz(x, y, z, height=70, width=200): """plot two fuzzy numbers @@ -61,6 +62,7 @@ def plot_xyz(x, y, z, height=70, width=200): return fig, axs + def plot_xy_3d(x, y, height=200, width=200): """plot two fuzzy numbers @@ -156,6 +158,7 @@ def plot_3d(x, y, ax=None, show=False, height=200, width=200): return fig, ax + def plot_hist(x, ax=None, bins=None, normed=1, **kwargs): if bins is None: @@ -179,6 +182,19 @@ def plot_hist(x, ax=None, bins=None, normed=1, **kwargs): return fig, ax +""" +def plot_bar(x,y,ax=None, **kwargs): + + if ax is None: + fig, ax = plt.subplots(1, 1, figsize=(10,5)) + else: + fig = plt.gcf() + + ax.bar(x,y, label=kwargs.get("label"), color=kwargs.get("color", "r")) + + return fig, ax +""" + def plot_cdf(x, method="rossow", ax=None, bins=None, color=None, **kwargs): df=pd.DataFrame({"x":x}) diff --git a/phuzzy/optimization/Alpha Opti Notebook.ipynb b/phuzzy/optimization/Alpha Opti Notebook.ipynb index 81d1264..83473ae 100644 --- a/phuzzy/optimization/Alpha Opti Notebook.ipynb +++ b/phuzzy/optimization/Alpha Opti Notebook.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": { "collapsed": false }, @@ -13,11 +13,82 @@ "text": [ "no display found. Using non-interactive Agg backend\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\r 0%| | 0/11 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "rr = sensitivity_analysis.Fuzzy_Sensitivity_Analysis(**kwargs)\n", + "rr.lcefa(**kwargs)\n", + "rr.barchart_plot()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\rSensitivity Analysis: 0%| | 0/6 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "rr = sensitivity_analysis.Fuzzy_Sensitivity_Analysis(**kwargs)\n", + "rr.lcefa(error=True, **kwargs)\n", + "rr.barchart_plot()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py index 2819609..44f72d0 100644 --- a/phuzzy/optimization/__init__.py +++ b/phuzzy/optimization/__init__.py @@ -12,6 +12,8 @@ import matplotlib.pyplot as plt from phuzzy.optimization import alphaOpt +from phuzzy.optimization import sensitivity_analysis +import math import numpy as np import pandas as pd @@ -22,27 +24,43 @@ - if __name__ == "__main__": + """ + v1 = phuzzy.Triangle(alpha0=[1,4], alpha1=[2], number_of_alpha_levels=3) + v2 = phuzzy.Triangle(alpha0=[0, 4], alpha1=[1], number_of_alpha_levels=3) + v3 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[2], number_of_alpha_levels=3) + v4 = phuzzy.Triangle(alpha0=[0,4], alpha1=[2.5], number_of_alpha_levels=6) + v5 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[3], number_of_alpha_levels=3) + v6 = phuzzy.Triangle(alpha0=[1,5], alpha1=[3], number_of_alpha_levels=3) + obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)' + kwargs = {'var6': v6, 'var2': v2, 'var3': v3, + 'var4': v4,'var5': v5, 'var1': v1, + 'obj_function': obj_function} + + """ + """ + v1 = phuzzy.Uniform(alpha0=[-3.14159265359,3.14159265359], number_of_alpha_levels=5) + v2 = phuzzy.Uniform(alpha0=[-3.14159265359,3.14159265359], number_of_alpha_levels=5) + v3 = phuzzy.Uniform(alpha0=[-3.14159265359,3.14159265359], number_of_alpha_levels=5) - v1 = phuzzy.Triangle(alpha0=[0,4], alpha1=[1], number_of_alpha_levels=4) - v2 = phuzzy.Superellipse(alpha0=[-1, 2.], alpha1=None, m=1.0, n=.5, number_of_alpha_levels=4) - v3 = phuzzy.TruncGenNorm(alpha0=[1, 4], alpha1=[2, 3], number_of_alpha_levels=4, beta=3.) - v4 = phuzzy.Trapezoid(alpha0=[0, 4], alpha1=[2, 3], number_of_alpha_levels=8) - v5 = phuzzy.TruncNorm(alpha0=[1, 3], number_of_alpha_levels=4, name="y") - v6 = phuzzy.Triangle(alpha0=[1,4], alpha1=[3], number_of_alpha_levels=4) - - obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)' + obj_function = 'sin(x[0]) + 7*(asin(x[1])**2) + 0.1*(x[2]**4)*sin(x[0])' kwargs = {'var1': v1, 'var2': v2, 'var3': v3, - 'var4': v4,'var5': v5, 'var6': v6, 'obj_function': obj_function} + """ + """ + #z = alphaOpt.Alpha_Level_Optimization(**kwargs) + #z.calculation(progressbar_disable=True) + #z.plot() + #plt.show() - z = alphaOpt.Alpha_Level_Optimization(**kwargs) - z.calculation() - z.plot() + rr = sensitivity_analysis.Fuzzy_Sensitivity_Analysis(**kwargs) + rr.lcefa(error=False, **kwargs) + rr.barchart_plot() plt.show() + + """ diff --git a/phuzzy/optimization/alphaOpt.py b/phuzzy/optimization/alphaOpt.py index 020c24c..9b48ff8 100644 --- a/phuzzy/optimization/alphaOpt.py +++ b/phuzzy/optimization/alphaOpt.py @@ -50,7 +50,133 @@ def __repr__(self): self._df.iloc[-1].l, self._df.iloc[-1].r) - def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): + def calculation(self, n=60, iters=3, optimizer='sobol', progressbar_disable=False, backup=False, start_at=None): + """ + Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate + the Fuzzy Objective Membershipfunction. + :param n: Number of Sampling Points / Individuals for the Optimization Algorithm + :param iters: Number of max. Iterations per Optimization Loop + :param optimizer: Selected Optimizer Strategy: "sobol" / "simplicial" + :param backup: Creates a Backup Folder saving the result of each Alpha Level Result + :param start_at: Start at certain Alpha Level (Counts starts from Alpha Level 1) + """ + + # Input Variables + self.n = n + self.iters = iters + self.optimizer = optimizer # simplicial / sobol + self.backup = backup + self.start_at = start_at + + zmin_value_list = [] + zmax_value_list = [] + boundlist = [] + + if self.start_at is not None: self._cut_global_blounds() + + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + with tqdm(total=len(boundlist), desc='1st Loop', leave=True, disable=progressbar_disable) as pbar: + for lvl, bounds in enumerate(boundlist): + comp_bounds = [] + + for item_i, item_j in zip(bounds[:, 0], bounds[:, 1]): comp_bounds.extend([item_i == item_j]) + + if 'shc_fuzzy_min' not in locals(): + + if all(comp_bounds) == True: # if all bounds are constants + ## calculate objective value + zmin = self._objective_function(bounds[:, 0]) + + ## safe values in list + zmin_value_list.append(np.array(zmin)) + zmax_value_list.append(np.array(zmin)) + + best_indi_min = np.array(bounds[:, 0]) + best_indi_max = np.array(bounds[:, 0]) + nfev_min = np.array(0) + nfev_max = np.array(0) + nit_min = np.array(0) + nit_max = np.array(0) + + else: + if all(comp_bounds) == False and any(comp_bounds) == True: + bounds = self._pop_constants(comp_bounds, bounds) + + ## optimization routine + shc_const_min = self._call_minimizer_shgo(bounds) + shc_const_max = self._call_maximizer_shgo(bounds) + + if any(comp_bounds) == False: + shc_fuzzy_min = self._find_result(shc_const_min) + shc_fuzzy_max = self._find_result(shc_const_max) + + shc_const_min = self._find_result(shc_const_min) + shc_const_max = self._find_result(shc_const_max) + + ## safe results in lists + best_indi_min = self._safe_best_array(comp_bounds, shc_const_min.res) + best_indi_max = self._safe_best_array(comp_bounds, shc_const_max.res) + nfev_min = shc_const_min.res.nfev + nfev_max = shc_const_max.res.nfev + nit_min = shc_const_min.res.nit + nit_max = shc_const_max.res.nit + + zmin_value_list.append(shc_const_min.res.fun * (1)) + zmax_value_list.append(shc_const_max.res.fun * (-1)) + + self.x_glob = [] + + else: + + shc_fuzzy_min.bounds = bounds + shc_fuzzy_min.iterate() + shc_fuzzy_min.find_minima() + + shc_fuzzy_max.bounds = bounds + shc_fuzzy_max.iterate() + shc_fuzzy_max.find_minima() + + ## safe results in lists + best_indi_min = shc_fuzzy_min.res.x + best_indi_max = shc_fuzzy_max.res.x + if lvl <= 1: + nfev_min = shc_const_min.res.nfev + nfev_max = shc_const_max.res.nfev + else: + nfev_min = np.absolute((shc_const_min.res.nfev - np.sum(self.nfev_list_min[0:lvl-1]))) + nfev_max = np.absolute((shc_const_max.res.nfev - np.sum(self.nfev_list_max[0:lvl-1]))) + nit_min = shc_const_min.res.nit + nit_max = shc_const_max.res.nit + + zmin_value_list.append(shc_fuzzy_min.res.fun * (1)) + zmax_value_list.append(shc_fuzzy_max.res.fun * (-1)) + + + self.best_indi_list_min.append(best_indi_min) + self.best_indi_list_max.append(best_indi_max) + self.nfev_list_min.append(nfev_min) + self.nfev_list_max.append(nfev_max) + self.nit_list_min.append(nit_min) + self.nit_list_max.append(nit_max) + + + if self.backup == True: + self.zmin_values = self._safe_z_values(min_max='min', z_value_list=zmin_value_list) + self.zmax_values = self._safe_z_values(min_max='max', z_value_list=zmax_value_list) + self._call_backup(iteration=lvl) + + pbar.update() + + self.zmin_values = self._safe_z_values(min_max='min', z_value_list=zmin_value_list) + self.zmax_values = self._safe_z_values(min_max='max', z_value_list=zmax_value_list) + + self.total_nfev = sum(self.nfev_list_min) + sum(self.nfev_list_max) + self.compact_output() + + + def calculation_old(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): """ Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate the Fuzzy Objective Membershipfunction. @@ -87,7 +213,7 @@ def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=N if self.start_at is None: if all(comp_bounds) == True: # if all bounds are constants ## calculate objective value - zmin = self.objective_function(bounds[:, 0]) + zmin = self._objective_function(bounds[:, 0]) ## safe values in list zmin_value_list.append(np.array(zmin)) @@ -100,9 +226,11 @@ def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=N nit_min = np.array(0) nit_max = np.array(0) - elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants + #elif all(comp_bounds) == False and any(comp_bounds) == True: # if one or more bounds are constants ## prepare bounds / pop constants - bounds = self._pop_constants(comp_bounds, bounds) + else: # if one or more bounds are constants or all intervals + if all(comp_bounds) == False and any(comp_bounds) == True: + bounds = self._pop_constants(comp_bounds, bounds) ## optimization routine shc_const_min = self._call_minimizer_shgo(bounds) @@ -122,6 +250,8 @@ def calculation(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=N zmin_value_list.append(shc_const_min.res.fun * (1)) zmax_value_list.append(shc_const_max.res.fun * (-1)) self.x_glob = [] + + else: shc_const_min = self._call_minimizer_shgo(bounds) shc_const_max = self._call_maximizer_shgo(bounds) diff --git a/phuzzy/optimization/sensitivity_analysis.py b/phuzzy/optimization/sensitivity_analysis.py new file mode 100644 index 0000000..0890542 --- /dev/null +++ b/phuzzy/optimization/sensitivity_analysis.py @@ -0,0 +1,284 @@ +import numpy as np +import pandas as pd + +import phuzzy +import phuzzy.mpl as phm +from phuzzy.mpl import mix_mpl +from phuzzy.optimization import alphaOpt + +from tqdm import tqdm +import matplotlib.pyplot as plt + + + + +class Fuzzy_Sensitivity_Analysis(object): + + def __init__(self,**kwargs): + """ + :param kwargs: Inputvariables / Fuzzyvariables / Name (name) / Objective Function (obj_function) / Objective Link (obj_link) + """ + + # Define Bounds of Each Alpha Level + self.input_dict = kwargs + self.fuzzy_variables_dict = self._prepare_fuzzy_variables(**kwargs) + self.x_glob = [] + + # Filter Objective Function / Link and Safe it + if kwargs.get('obj_function') is not None: self.objective = kwargs.get('obj_function') + elif kwargs.get('obj_link') is not None: self.objective = kwargs.get('obj_link') + else: raise ValueError('PLEASE IMPORT OBJECTIVE') + + # Define Setup Parameters + if kwargs.get('name') is None: self.name = 'Fuzzy Objective Value' + else: self.name = kwargs.get('name') + + + def _prepare_fuzzy_variables(self, alpha_Level=None, **kwargs): + """ + Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton + :param kwargs: Input Fuzzy Variables + :return: 3D DataArray representing each Fuzzy Inputvariables Boundaries for each Alpha Level + prepared for the Optimization Routine + """ + filter_fuzzy_variables_dict = {} + list_of_n_alpha_levels = np.zeros(1, dtype='int') + + if alpha_Level is None: + # check if number_of_alpha_levels is the same + for key, value in kwargs.items(): + if isinstance(value, phuzzy.FuzzyNumber): + if list_of_n_alpha_levels[0] == 0: + np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) + else: + list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) + + if alpha_Level is None: + # extract fuzzy variables from kwargs and safe in dict + for key, value in kwargs.items(): + # if number_of_alpha_levels are different + if (len(set(list_of_n_alpha_levels)) == 1) == False: + max_value = np.max(list_of_n_alpha_levels) + if isinstance(value, phuzzy.FuzzyNumber): + if value.number_of_alpha_levels < max_value: value.convert_df(alpha_levels=max_value) + filter_fuzzy_variables_dict[key] = value._df + self.number_of_alpha_lvl = max_value + elif isinstance(value, phuzzy.FuzzyNumber): + # if number_of_alpha_levels are the same + filter_fuzzy_variables_dict[key] = value._df + self.number_of_alpha_lvl = value.number_of_alpha_levels + else: + for key, value in kwargs.items(): + if isinstance(value, phuzzy.FuzzyNumber): + value.convert_df(alpha_levels=alpha_Level) + filter_fuzzy_variables_dict[key] = value._df + self.number_of_alpha_lvl = alpha_Level + + return filter_fuzzy_variables_dict + + + def barchart_plot(self): + + + y_pos = np.arange(len(self.name_list)) + fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, sharex=False,figsize=(10,len(y_pos))) + width = 0.6 + width2 = 0.3 + + + if hasattr(self,'sensis_total_var') == True: + fig.suptitle('Average Local Cost Effectivness Fuzzy Analysis') + + ax1.set_title('Average Total Relative Effectivness') + ax1.set_yticks(y_pos) + ax1.set_yticklabels(self.name_list) + ax1.invert_yaxis() # labels read top-to-bottom + ax1.set_ylabel('Variables') + ax1.set_xlabel('Total Sensitivity') + ax1.set_axisbelow(True) + ax1.set_xlim(0,max(self.sensis_total)+0.1) + ax1.grid(b=True, which='major') + ax1.grid(b=True, which='minor') + formatted_sensis = [round(elem, 3) for elem in self.sensis_total] + for i, v in enumerate(formatted_sensis): + ax1.text(v+0.001, i-0.055, " "+str(v), color='black', va='center',fontweight='bold') + ax1.barh(y_pos, self.sensis_total, width, xerr=self.sensis_total_var, align='center', color='lightslategrey', ecolor='black') + + ax2.set_title('Average Absolute Left / Right Effectivness') + ax2.set_yticks(y_pos) + ax2.set_yticklabels(self.name_list) + ax2.invert_yaxis() # labels read top-to-bottom + ax2.set_ylabel('Variables') + ax2.set_xlabel('Relative Partial Sensitivity') + ax2.set_axisbelow(True) + ax2.set_xlim(0,max(max(self.sensis_l),max(self.sensis_r))+0.1) + ax2.grid(b=True, which='major') + ax2.grid(b=True, which='minor') + formatted_sensis_l = [round(elem, 3) for elem in self.sensis_l] + formatted_sensis_r = [round(elem, 3) for elem in self.sensis_r] + for (i_l, v_l),(i_r, v_r) in zip(enumerate(formatted_sensis_l),enumerate(formatted_sensis_r)): + ax2.text(v_l+0.001, i_l-0.5*width2-0.055, " "+str(v_l), color='black', va='center',fontweight='bold') + ax2.text(v_r+0.001, i_r+0.5*width2+0.055, " "+str(v_r), color='black', va='center',fontweight='bold') + ax2.barh(y_pos-0.5*width2, self.sensis_l, width2, xerr=self.sensis_l_var, color='SkyBlue', label='Left', ecolor='black') + ax2.barh(y_pos+0.5*width2, self.sensis_r, width2, xerr=self.sensis_r_var, color='IndianRed', label='Right', ecolor='black') + ax2.legend() + + else: + + fig.suptitle('Local Cost Effectivness Fuzzy Analysis') + + ax1.set_title('Total Relative Effectivness') + ax1.set_yticks(y_pos) + ax1.set_yticklabels(self.name_list) + ax1.invert_yaxis() # labels read top-to-bottom + ax1.set_ylabel('Variables') + ax1.set_xlabel('Total Sensitivity') + ax1.set_axisbelow(True) + ax1.set_xlim(left=0,right=max(self.sensis_total)+0.1) + ax1.grid(b=True, which='major') + ax1.grid(b=True, which='minor') + formatted_sensis = [round(elem, 3) for elem in self.sensis_total] + for i, v in enumerate(formatted_sensis): + ax1.text(v+0.001, i-0.055, " "+str(v), color='black', va='center',fontweight='bold') + ax1.barh(y_pos, self.sensis_total, width, align='center', color='lightslategrey') + + ax2.set_title('Absolute Left / Right Effectivness') + ax2.set_yticks(y_pos) + ax2.set_yticklabels(self.name_list) + ax2.invert_yaxis() # labels read top-to-bottom + ax2.set_ylabel('Variables') + ax2.set_xlabel('Relative Partial Sensitivity') + ax2.set_axisbelow(True) + ax2.set_xlim(0,max(max(self.sensis_l),max(self.sensis_r))+0.1) + ax2.grid(b=True, which='major') + ax2.grid(b=True, which='minor') + formatted_sensis_l = [round(elem, 3) for elem in self.sensis_l] + formatted_sensis_r = [round(elem, 3) for elem in self.sensis_r] + for (i_l, v_l),(i_r, v_r) in zip(enumerate(formatted_sensis_l),enumerate(formatted_sensis_r)): + ax2.text(v_l+0.001, i_l-0.5*width2-0.055, " "+str(v_l), color='black', va='center',fontweight='bold') + ax2.text(v_r+0.001, i_r+0.5*width2+0.055, " "+str(v_r), color='black', va='center',fontweight='bold') + ax2.barh(y_pos-0.5*width2, self.sensis_l, width2, color='SkyBlue', label='Left') + ax2.barh(y_pos+0.5*width2, self.sensis_r, width2, color='IndianRed', label='Right') + ax2.legend() + + plt.show() + + + def lcefa(self, error=False, lsa=None, **kwargs): + """ + Local cost effectivness fuzzy analysis + :return: + """ + + if error == False: + self.name_list, self.sensis_total, self.sensis_l, self.sensis_r = self.lcefa_calculation(**kwargs) + else: + sensi_total_dict = {} + sensi_l_dict = {} + sensi_r_dict = {} + #with tqdm(total=7,desc='Average Sensitivity Analysis',leave=True, disable=True) as pbar_glob: + for alpha_Level in range(3,9): + name_list, sensis_total, sensis_l, sensis_r = self.lcefa_calculation(alpha_Level=alpha_Level, lsa=lsa, leave=False,**kwargs,) + sensi_total_dict[str(alpha_Level)] = sensis_total + sensi_l_dict[str(alpha_Level)] = sensis_l + sensi_r_dict[str(alpha_Level)] = sensis_r + #pbar_glob.update() + + + self.name_list = name_list + self.sensi_total_df = pd.DataFrame.from_dict(sensi_total_dict) + self.sensi_l_df = pd.DataFrame.from_dict(sensi_l_dict) + self.sensi_r_df = pd.DataFrame.from_dict(sensi_r_dict) + + self.sensis_total = self.sensi_total_df.mean(axis=1).values + self.sensis_total_var = self.sensi_total_df.var(axis=1).values + self.sensis_l = self.sensi_l_df.mean(axis=1).values + self.sensis_l_var = self.sensi_l_df.var(axis=1).values + self.sensis_r = self.sensi_r_df.mean(axis=1).values + self.sensis_r_var = self.sensi_r_df.var(axis=1).values + + + def lcefa_calculation(self, alpha_Level=None, lsa=None, leave=False, **kwargs): + res_total = [] + res_l = [] + res_r = [] + name_list = [] + + s_sum = 0 + l_sum = 0 + r_sum = 0 + + if alpha_Level is not None: + self.fuzzy_variables_dict = self._prepare_fuzzy_variables(alpha_Level=alpha_Level, **kwargs) + + index = np.arange(len(self.fuzzy_variables_dict)) + + with tqdm(total=len(index),desc='Sensitivity Analysis',leave=leave) as pbar_loc: + for (var_i, values_i) in self.fuzzy_variables_dict.items(): + fvars = {} + name_list.append(var_i) + for (_, j) , (var_j, values_j) in zip(enumerate(index),self.fuzzy_variables_dict.items()): + if var_i == var_j: + fvars[var_j]=self.input_dict[var_i] + else: + if lsa is None: + y = phuzzy.Uniform(alpha0=[values_j['l'].iloc[0], values_j['r'].iloc[0]], + number_of_alpha_levels=self.number_of_alpha_lvl) + else: + y = phuzzy.Uniform(alpha0=[lsa[j],lsa[j]], number_of_alpha_levels=self.number_of_alpha_lvl) + + fvars[var_j]=y + + kwargs = {**self.input_dict , **fvars} + + z = alphaOpt.Alpha_Level_Optimization(**kwargs) + z.calculation(n=30,iters=2,progressbar_disable=True) + + E = 1. - (z.df['r']-z.df['l'])/(z.df['r'].iloc[0]-z.df['l'].iloc[0]) + full_length = abs(z.df['r']-z.df['l']) + E_l = abs(((z.df['l'].iloc[-1]-z.df['l'])/full_length)/(len(z.df)-1)) + E_r = abs(((z.df['r']-z.df['r'].iloc[-1])/full_length)/(len(z.df)-1)) + + z.plot() + + #del z + sensi_i = sum(E) + sensi_l = sum(E_l) + sensi_r = sum(E_r) + + s_sum += sensi_i + l_sum += sensi_l + r_sum += sensi_r + + res_total.append(sensi_i) + res_l.append(sensi_l) + res_r.append(sensi_r) + + pbar_loc.update() + + sensis_total = [] + sensis_l = [] + sensis_r = [] + + for i in range(len(res_total)): + sensis_total_j = res_total[i] / s_sum + sensis_l_j = res_l[i] + sensis_r_j = res_r[i] + + sensis_total.append(sensis_total_j) + sensis_l.append(sensis_l_j) + sensis_r.append(sensis_r_j) + + + """ + for i, z in enumerate(res_total): + sensi_j = z / s_sum + sensis_total.append(sensi_j) + """ + + return name_list, sensis_total, sensis_l, sensis_r + + + +if __name__ == "__main__": + pass diff --git a/tests/test_fuzzy analysis.ipynb b/tests/test_fuzzy analysis.ipynb new file mode 100644 index 0000000..aa25b4b --- /dev/null +++ b/tests/test_fuzzy analysis.ipynb @@ -0,0 +1,138 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import phuzzy\n", + "import phuzzy.analysis\n", + "import numpy as np\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(FuzzyAnalysis:'FuzzyAnalysis N.N.', dv=[TruncNorm(x:[[-6,2], [-2,-2]]), Triangle(y:[[-6,6], [6,6]]), Triangle(z:[[-6,6], [6,6]])]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x.sk=0.014\ny.sk=0.99\nz.sk=0\n" + ] + }, + { + "data": { + "text/plain": [ + "[0.01382664604097675, 0.9861733539590233, 0.0]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = 1.23\n", + "def f(x):\n", + " x1 = x[0]\n", + " x2 = x[1]\n", + " return (x1+1.15)**2+(x2+.4)**4 + a\n", + "\n", + "x = phuzzy.TruncNorm(alpha0=[-6, 2], name=\"x\", number_of_alpha_levels=2)\n", + "y = phuzzy.Triangle(alpha0=[-6, 6], alpha1=[6], name=\"y\", number_of_alpha_levels=2)\n", + "z = phuzzy.Triangle(alpha0=[-6, 6], alpha1=[6], name=\"z\", number_of_alpha_levels=2)\n", + "\n", + "pa = phuzzy.analysis.FuzzyAnalysis(designvars=[x, y, z], function=f)\n", + "print(pa)\n", + "\n", + "pa.lcefa()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(FuzzyAnalysis:'FuzzyAnalysis N.N.', dv=[TruncNorm(x:[[0,6.28], [3.14,3.14]]), Triangle(y:[[0,6.28], [6,6]])]\n" + ] + }, + { + "ename": "AttributeError", + "evalue": "'TruncNorm' object has no attribute 'sin'", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpa\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 12\u001b[1;33m \u001b[0msensibilities\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpa\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlcefa\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 13\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msensibilities\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 14\u001b[0m \u001b[1;32massert\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0misclose\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msk\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m.5\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\PycharmProjects\\phuzzy\\phuzzy\\analysis\\__init__.py\u001b[0m in \u001b[0;36mlcefa\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 94\u001b[0m \u001b[0mfvars\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 95\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 96\u001b[1;33m \u001b[0mz\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfunction\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfvars\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 97\u001b[0m \u001b[0mz\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdesignvars\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 98\u001b[0m \u001b[0mdflr\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mz\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdf\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"l\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"r\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m\u001b[0m in \u001b[0;36mf\u001b[1;34m(x)\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mx1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mx2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mx2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mphuzzy\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTruncNorm\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0malpha0\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"x\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnumber_of_alpha_levels\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mAttributeError\u001b[0m: 'TruncNorm' object has no attribute 'sin'" + ], + "output_type": "error" + } + ], + "source": [ + "def f(x):\n", + " x1 = x[0]\n", + " x2 = x[1]\n", + " return np.sin(x1) + np.sin(4*x2)\n", + "\n", + "x = phuzzy.TruncNorm(alpha0=[0, 2*np.pi], name=\"x\", number_of_alpha_levels=2)\n", + "y = phuzzy.Triangle(alpha0=[0, 2*np.pi], alpha1=[6], name=\"y\", number_of_alpha_levels=2)\n", + "\n", + "pa = phuzzy.analysis.FuzzyAnalysis(designvars=[x, y], function=f)\n", + "print(pa)\n", + "\n", + "sensibilities = pa.lcefa()\n", + "print(sensibilities)\n", + "assert np.isclose(x.sk, .5)\n", + "assert np.isclose(y.sk, .5)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/tests/test_fuzzy_analysis.py b/tests/test_fuzzy_analysis.py index 6c814f7..b674684 100644 --- a/tests/test_fuzzy_analysis.py +++ b/tests/test_fuzzy_analysis.py @@ -91,3 +91,10 @@ def f(x): print(sensibilities) assert np.isclose(x.sk, .5) assert np.isclose(y.sk, .5) + + + + + + +test_lcefa() From f809507fe8c828c13676344dc20ad2f103e8b302 Mon Sep 17 00:00:00 2001 From: Eugen Boos Date: Thu, 25 Apr 2019 14:53:59 +0200 Subject: [PATCH 11/11] Revised Alpha-Level-Optimization Signed-off-by: Eugen Boos --- doc/x:y.png | Bin 46934 -> 0 bytes docs/operations/x:y.png | Bin 46934 -> 0 bytes ipynb/fuzzy_plots.ipynb | 4 +- phuzzy/__init__.py | 1 + phuzzy/fuzzification/__init__.py | 45 +- phuzzy/fuzzification/data_fitting.py | 233 ----- phuzzy/fuzzification/fuzzy_fitting.py | 188 ++++ phuzzy/mpl/__init__.py | 18 +- phuzzy/optimization/Alpha Opti Notebook.ipynb | 929 ------------------ .../optimization/Fuzzy Sensi Analysis.ipynb | 567 ----------- phuzzy/optimization/__init__.py | 62 +- phuzzy/optimization/alphaOpt.py | 154 ++- phuzzy/optimization/function_constraints.py | 75 -- .../ipynb/Example_Alpha_Opt.ipynb | 879 +++++++++++++++++ .../ipynb/Example_Fuzzy_Sensi_Analysis.ipynb | 567 +++++++++++ phuzzy/optimization/sensitivity_analysis.py | 331 +++---- phuzzy/shapes/__init__.py | 7 +- phuzzy/shapes/superellipse.py | 1 - 18 files changed, 1941 insertions(+), 2120 deletions(-) delete mode 100644 doc/x:y.png delete mode 100644 docs/operations/x:y.png delete mode 100644 phuzzy/fuzzification/data_fitting.py create mode 100644 phuzzy/fuzzification/fuzzy_fitting.py delete mode 100644 phuzzy/optimization/Alpha Opti Notebook.ipynb delete mode 100644 phuzzy/optimization/Fuzzy Sensi Analysis.ipynb delete mode 100644 phuzzy/optimization/function_constraints.py create mode 100644 phuzzy/optimization/ipynb/Example_Alpha_Opt.ipynb create mode 100644 phuzzy/optimization/ipynb/Example_Fuzzy_Sensi_Analysis.ipynb diff --git a/doc/x:y.png b/doc/x:y.png deleted file mode 100644 index fb34baffb7f69a70f62e1ba1db1be04ae5c9f076..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46934 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 l1daIbBT2yF(f_B@YaDhd$Ff_!a|;k~sH= func._df.iloc[i]["l"] and x <= func._df.iloc[i+1]["l"] and loop == 0: - x_interpol = [func._df.iloc[i]["l"], func._df.iloc[i+1]["l"]] - y_interpol = [func._df.iloc[i]["alpha"], func._df.iloc[i+1]["alpha"]] - f = interpolate.interp1d(x_interpol, y_interpol) - alpha_x = f(x) - alpha_values.append(alpha_x.item(0)) - loop = 1 - elif x >= func._df.iloc[-1]["r"]: - for i in range(0,len(func._df)-1): - if x <= func._df.iloc[i]["r"] and x >= func._df.iloc[i+1]["r"] and loop == 0: - x_interpol = [func._df.iloc[i]["r"], func._df.iloc[i+1]["r"]] - y_interpol = [func._df.iloc[i]["alpha"], func._df.iloc[i+1]["alpha"]] - f = interpolate.interp1d(x_interpol, y_interpol) - alpha_x = f(x) - alpha_values.append(alpha_x.item(0)) - loop = 1 - else: - alpha_values.append(1.0) - #calc dist - alpha_values_hist = self.histo_class.histo_df['absBinFrequencyNorm'].values - alpha_values_plot = alpha_values - return sum(abs(alpha_values_plot-alpha_values_hist)) - - - def create_histogram(self,input_df,bin_calc_method,custom_bins=None): - - #Bins Size & Number of Bins Definition - if bin_calc_method == 'scott': - binSize = ((3.49 * input_df.values.std()) / (len(input_df))**(1/3)) - nbins = (int(round((input_df.values.max() - input_df.values.min()) / binSize))) - elif bin_calc_method == 'freedman': - binSize = ((2*((input_df.quantile(0.75) - input_df.quantile(0.25)).values)) / (len(input_df))**(1/3)).item(0) - nbins = (int(round((input_df.values.max() - input_df.values.min()) / binSize))) - elif bin_calc_method == 'custom': - nbins = custom_bins - binSize = (input_df.values.max() - input_df.values.min()) / nbins - elif bin_calc_method == 'rice': - nbins = int(round((2*len(input_df)**(1/3)))) #Rice Rule - binSize = (input_df.values.max() - input_df.values.min()) / nbins - - #Calculate Histogram Data - values = np.ravel((input_df._convert(datetime=True)._get_numeric_data())) - values = values[~isna(values)] - abs_bin_frequency, binsIntval = np.histogram(values, bins=nbins) - #abs_bin_frequency_norm = (abs_bin_frequency - abs_bin_frequency.min()) / (abs_bin_frequency.max() - abs_bin_frequency.min()) - abs_bin_frequency_norm = (abs_bin_frequency - 0.0) / (abs_bin_frequency.max() - 0.0) - - #Histo Array Pandas DataFrame creation - histo_array = np.concatenate((abs_bin_frequency,abs_bin_frequency_norm,binsIntval[0:-1],binsIntval[1:],0.5*(binsIntval[1:]+binsIntval[0:-1])),axis=None) - histo_array = histo_array.reshape(len(abs_bin_frequency),5).T - histogram_df = pd.DataFrame(columns=["absBinFrequency", "absBinFrequencyNorm", "widthL", "widthR","center"],data=histo_array, dtype=np.float) - return histogram_df - - - def set_alpha_level_1(self,histogram_df,alpha_level_1_method): - if alpha_level_1_method == 'maxVal': - maxValRow = histogram_df.loc[histogram_df['absBinFrequency'].idxmax()] - if histogram_df.loc[histogram_df['absBinFrequency'].idxmax()].name == 0: - maxMeanVal = maxValRow[2] - alpha1 = [maxMeanVal, maxMeanVal] - elif histogram_df.loc[histogram_df['absBinFrequency'].idxmax()].name == (len(histogram_df.index)-1): - maxMeanVal = maxValRow[3] - alpha1 = [maxMeanVal, maxMeanVal] - else: - maxMeanVal = maxValRow[4] - alpha1 = [maxMeanVal, maxMeanVal] - elif alpha_level_1_method == 'mean': - meanVal = histogram_df.mean() - alpha1 = [meanVal.values.item(0), meanVal.values.item(0)] - elif alpha_level_1_method == 'modus': - modusVal = histogram_df.mode() - if len(modusVal) == 1: - alpha1 = [modusVal.values.item(0), modusVal.values.item(0)] - else: - alpha1 = [modusVal.values.min(), modusVal.values.max()] - elif alpha_level_1_method == 'gnstd': - meanVal = histogram_df.mean() - stdVal = histogram_df.std() - alpha1 = [meanVal.values.item(0)-(0.50*stdVal.values.item(0)), meanVal.values.item(0)+(0.50*stdVal.values.item(0))] - return np.array(alpha1) - - - def set_alpha_level_0(self,histogram_df,alpha_level_0_method): - if alpha_level_0_method == 'direct': - alpha0L = histogram_df['widthL'].min() - alpha0R = histogram_df['widthR'].max() - elif alpha_level_0_method == 'saftyfactor': - binSize = histogram_df['widthR'][0]-histogram_df['widthL'][0] - alpha0L = histogram_df['widthL'].min() - 0.5*binSize - alpha0R = histogram_df['widthR'].max() + 0.5*binSize - return np.array([alpha0L, alpha0R]) - - - def fitting(self,type,number_of_alpha_levels,alpha_lvl_0,alpha_lvl_1): - - # Optimization Call - if type == 'TruncGenNorm': - res = optimize.minimize(self.minimization_dist_function, [1.0], method='Nelder-Mead', tol=1e-03,options={'disp': True}) - elif type == 'Superellipse': - res = optimize.minimize(self.minimization_dist_function, [1.0,1.0], method='Nelder-Mead', tol=1e-03,options={'disp': True}) - elif type == 'TruncGenSkewNorm': - res = optimize.minimize(self.minimization_dist_function, [1.0], method='Nelder-Mead', tol=1e-03,options={'disp': True}) - - # Fitting Functions & Plot - if type == 'TruncGenNorm': - fuzzy_var = phm.TruncGenNorm(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels, beta=res.x[0]) - #tgn.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) - elif type == 'Superellipse': - fuzzy_var = phm.Superellipse(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, m= res.x[0], n=res.x[1], number_of_alpha_levels=number_of_alpha_levels) - #se.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) - elif type == 'TruncGenSkewNorm': - fuzzy_var = phm.TruncGenSkewNorm(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels, a=res.x[0]) - #tgsn.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) - elif type == 'Triangle': - fuzzy_var = phm.Triangle(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels) - #tri.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) - elif type == 'Trapezoid': - fuzzy_var = phm.Trapezoid(alpha0=alpha_lvl_0, alpha1=alpha_lvl_1, number_of_alpha_levels=number_of_alpha_levels) - #tra.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) - elif type == 'TruncNorm': - fuzzy_var = phm.TruncNorm(alpha0=alpha_lvl_0, number_of_alpha_levels=number_of_alpha_levels) - #tn.plot(show=True, filepath="truncgennorm.png", title=True, input_df = self.histo_class) - return fuzzy_var - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/phuzzy/fuzzification/fuzzy_fitting.py b/phuzzy/fuzzification/fuzzy_fitting.py new file mode 100644 index 0000000..e7da6e0 --- /dev/null +++ b/phuzzy/fuzzification/fuzzy_fitting.py @@ -0,0 +1,188 @@ +import numpy as np +import pandas as pd +import scipy.stats as st + +import phuzzy.mpl as phm +import phuzzy.mpl.plots + +import warnings +import matplotlib.pyplot as plt +plt.style.use('seaborn') + + + + +class Data_Fitting(object): + + def __init__(self): + pass + + + def best_fit_distribution(self, data, number_of_alpha_levels=6, bins=False, bootstrap=False, ax=True, + filepath=None): + """ + Routine to determin automatically a suiting membership function to a given data set + + :param data: input array + :param number_of_alpha_levels: level of discritization of the membership function + :param bins: number of histogram bins + :param bootstrap: applying / not applying bootstrap algorithm + :param ax: plot command + :param filepath: safe plot + + :return: fuzzy parameter + """ + + """Model data by finding best fit distribution to data""" + + if bootstrap: + data = self._bootstrap(data) + + # Get histogram of original data + if bins: + y, x = np.histogram(data, bins=bins, density=True) + else: + y, x = np.histogram(data, bins='fd', density=True) + + y, x = np.histogram(data, density=True) + x = (x + np.roll(x, -1))[:-1] / 2.0 + DISTRIBUTIONS = [ + st.triang, + st.norm, + st.uniform + ] + # Best holders + best_distribution = st.triang + best_params = (0.0, 1.0) + best_sse = np.inf + dists = [] + # Estimate distribution parameters from data + for distribution in DISTRIBUTIONS: + # Try to fit the distribution + try: + # Ignore warnings from data that can't be fit + with warnings.catch_warnings(): + warnings.filterwarnings('ignore') + # fit dist to data + params = distribution.fit(data) + # Separate parts of parameters + arg = params[:-2] + loc = params[-2] + scale = params[-1] + # Calculate fitted PDF and error with fit in distribution + pdf = distribution.pdf(x, loc=loc, scale=scale, *arg) + sse = np.sum(np.power(y - pdf, 2.0)) + dist = distribution(loc=loc, scale=scale, *arg) + dists.append([dist, loc, scale, arg]) + # if axis pass in add to plot + #try: + # if ax: + # pd.Series(pdf, x).plot(ax=ax) + #except Exception: + # pass + # identify if this distribution is better + if best_sse > sse > 0: + best_distribution = distribution.name + best_params = params + best_sse = sse + except Exception: + pass + + x = np.linspace(data.min(),data.max(), 500) + + if best_distribution == 'norm': + dist, loc, scale, args = dists[0] + a = max(abs(loc-data.min()), abs(loc-data.max())) + fuzzy_var = phm.TruncNorm(alpha0=[loc-a, loc+a], alpha1=[data.mean()], + number_of_alpha_levels=number_of_alpha_levels) + #return (tgn, tgn.get_shape()) + + elif best_distribution == 'triang': + dist, loc, scale, args = dists[0] + y = dist.pdf(x) + y /= y.max() + df = pd.DataFrame({"x":x, "y":y}) + loc = df.loc[df.y.idxmax()].x + fuzzy_var = phm.Triangle(alpha0=[data.min(), data.max()], alpha1=[loc], + number_of_alpha_levels=number_of_alpha_levels) + #return (tria, tria.get_shape()) + + elif best_distribution == 'uniform': + dist, loc, scale, args = dists[1] + fuzzy_var = phm.Uniform(alpha0=[data.min(),data.max()], alpha1=[1.00,1.00], + number_of_alpha_levels=number_of_alpha_levels) + #return (uni, uni.get_shape()) + else: + raise ValueError + + + if ax: + fig, ax = plt.subplots(1,1, figsize=(8,5)) + x = np.linspace(data.min(),data.max(), 500) + y = dist.pdf(x) + y /= y.max() + df = pd.DataFrame({"x":x, "y":y}) + ax.plot(x,y, label="hist fit", color="g", lw=2, alpha=.8, ls="--") + ax.axvline(data.min(), dashes=[5,2,1,2], c="k", alpha=.5) + ax.axvline(data.max(), dashes=[5,2,1,2], c="k", alpha=.5) + ax.axvline(loc, dashes=[5,2,1,2], c="k", alpha=.5) + ax.scatter(data, np.ones_like(data)*(-.1), color="g", alpha=.4, label="data") + ax.set_ylabel(r"$\alpha$ [$-$]") + fuzzy_var_shape = fuzzy_var.get_shape() + ax.plot(fuzzy_var_shape.x, fuzzy_var_shape.alpha, label="Phuzzy Variable", alpha=.4, color="r") + + if bins: + phuzzy.mpl.plots.plot_hist(data, bins=bins, ax=ax, normed=True, color="b", + filled=True, alpha=.3, label='histo data') + else: + phuzzy.mpl.plots.plot_hist(data, ax=ax, bins='fd', normed=True, color="b", + filled=True, alpha=.3, label='histo data') + + if best_distribution == 'norm': ax.set_title('TruncNorm') + elif best_distribution == 'triang': ax.set_title('Triangle') + elif best_distribution == 'uniform': ax.set_title('Uniform') + + ax.legend(fancybox=True, framealpha=0.5, loc=1) + plt.show() + + if filepath: + fig.savefig(filepath, dpi=360) + + + return fuzzy_var + + + def _bootstrap(self,data): + """ + Bootstrapping Algorithm for stretching data + + :param data: Input Data + :return: Boostrapped Data + """ + xbar = np.zeros(shape=1000) + for i in range(1000): + sample = data[np.random.randint(0,len(data),size=len(data))] + xbar[i] = np.mean(sample) + np.append(xbar,data.min()) + np.append(xbar,data.max()) + return xbar + + + def fit_plot(self,data,fuzzy_var,dist): + + fig, ax = plt.subplots(1,1, figsize=(10,5)) + + x = np.linspace(data.min(),data.max(), 500) + y = dist.pdf(x) + y /= y.max() + df = pd.DataFrame({"x":x, "y":y}) + # pdf = make_pdf(st.norm, [loc, scale]+args) + ax.plot(x,y, label="hist fit", color="g", lw=2, alpha=.8, ls="--") + dist, loc, scale, args = dist[0] + + ax.axvline(data.min(), dashes=[5,2,1,2], c="k", alpha=.5) + ax.axvline(data.max(), dashes=[5,2,1,2], c="k", alpha=.5) + ax.axvline(loc, dashes=[5,2,1,2], c="k", alpha=.5) + ax.scatter(data, np.ones_like(data)*(-.1), color="g", alpha=.4, label="data") + + diff --git a/phuzzy/mpl/__init__.py b/phuzzy/mpl/__init__.py index a9fc346..9623554 100644 --- a/phuzzy/mpl/__init__.py +++ b/phuzzy/mpl/__init__.py @@ -10,6 +10,7 @@ import numpy as np import phuzzy + def extend_instance(obj, cls): """Apply mixins to a class instance after creation""" base_cls = obj.__class__ @@ -48,7 +49,7 @@ def plot(self, ax=None, filepath=None, show=False, xlim=None, labels=True, title if defuzzy is not None and labels is True: ax.annotate('%.3g' % defuzzy[0], xy=(defuzzy[0], (defuzzy[1]+0.018)), xycoords='data', - xytext=(-2, 2), textcoords='offset points', + xytext=(-2, -9), textcoords='offset points', horizontalalignment='right', verticalalignment='bottom', alpha=.4) @@ -69,17 +70,17 @@ def plot(self, ax=None, filepath=None, show=False, xlim=None, labels=True, title ax.set_xlabel('%s' % self.name) ax.set_ylabel(r'$\alpha$') ax.grid(c="gray", alpha=.5, lw=.5, dashes=[1, 3]) - ax.annotate('%.3g' % a0["l"], xy=(a0["l"], a0["alpha"]), xycoords='data', + ax.annotate('%.5g' % a0["l"], xy=(a0["l"], a0["alpha"]), xycoords='data', xytext=(-2, 2), textcoords='offset points', horizontalalignment='right', verticalalignment='bottom', alpha=.4) - ax.annotate('%.3g' % a0["r"], xy=(a0["r"], a0["alpha"]), xycoords='data', + ax.annotate('%.5g' % a0["r"], xy=(a0["r"], a0["alpha"]), xycoords='data', xytext=(2, 2), textcoords='offset points', horizontalalignment='left', verticalalignment='bottom', alpha=.4) a1 = self.alpha1 - ax.annotate('%.3g' % a1["l"], xy=(a1["l"], a1["alpha"]), xycoords='data', + ax.annotate('%.5g' % a1["l"], xy=(a1["l"], a1["alpha"]), xycoords='data', xytext=(-2, 2), textcoords='offset points', horizontalalignment='right', verticalalignment='bottom', alpha=.4) - ax.annotate('%.3g' % a1["r"], xy=(a1["r"], a1["alpha"]), xycoords='data', + ax.annotate('%.5g' % a1["r"], xy=(a1["r"], a1["alpha"]), xycoords='data', xytext=(2, 2), textcoords='offset points', horizontalalignment='left', verticalalignment='bottom', alpha=.4) dx = abs(self.alpha0["r"] - self.alpha0["l"]) @@ -98,7 +99,7 @@ def plot(self, ax=None, filepath=None, show=False, xlim=None, labels=True, title try: fig.tight_layout() if filepath: - fig.savefig(filepath, dpi=90) + fig.savefig(filepath, dpi=360) except UnboundLocalError: pass @@ -215,3 +216,8 @@ class Superellipse(phuzzy.Superellipse, MPL_Mixin): """Superellipse fuzzy number with matplotlib mixin""" def __init__(self, **kwargs): phuzzy.Superellipse.__init__(self, **kwargs) + +class Skewnorm(phuzzy.Skewnorm, MPL_Mixin): + """Superellipse fuzzy number with matplotlib mixin""" + def __init__(self, **kwargs): + phuzzy.Skewnorm.__init__(self, **kwargs) diff --git a/phuzzy/optimization/Alpha Opti Notebook.ipynb b/phuzzy/optimization/Alpha Opti Notebook.ipynb deleted file mode 100644 index 83473ae..0000000 --- a/phuzzy/optimization/Alpha Opti Notebook.ipynb +++ /dev/null @@ -1,929 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "no display found. Using non-interactive Agg backend\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\r 0%| | 0/11 [00:00\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
alphalr
00.0-3.510000195.109998
10.212.251661146.263084
20.416.409011119.703942
30.626.304469101.314470
40.839.43945583.907310
51.059.40000064.200000
\n", - "" - ], - "text/plain": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
alphalr
00.0-3.510000195.109998
10.212.251661146.263084
20.416.409011119.703942
30.626.304469101.314470
40.839.43945583.907310
51.059.40000064.200000
\n", - "
" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z.df" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
alphalr
00.0-3.51195.11
10.212.25146.26
20.416.41119.70
30.626.30101.31
40.839.4483.91
51.059.4064.20
\n", - "
" - ], - "text/plain": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
alphalr
00.0-3.51195.11
10.212.25146.26
20.416.41119.70
30.626.30101.31
40.839.4483.91
51.059.4064.20
\n", - "
" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z.compact_output(round=2) # Default: round=None\n", - "z.df" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
alphalbest_indi_lnfev_lnit_lrbest_indi_rnfev_rnit_r
00.0-3.5100[4.0, 2.0, 1.0, 0.1, 1.0, 1.0]173195.1100[1.0007, -0.0988, 4.0, 4.0, 3.0, 4.0]943
10.212.2517[0.2, 1.3292, 1.3676, 0.4, 1.356, 1.4]443146.2631[0.9999, -0.1, 3.6324, 3.8, 2.644, 3.8]123
20.416.4090[2.8, 1.0513, 1.5883, 0.8, 1.5425, 1.8]313119.7039[1.0, -0.0513, 3.4117, 3.6, 2.4575, 3.6]23
30.626.3045[2.2, 0.8381, 1.7581, 1.2, 1.6634, 2.2]893101.3145[1.0, 0.1619, 3.2419, 3.4, 2.3366, 3.4]1103
40.839.4395[0.8, 0.6584, 2.0072, 1.6, 1.7977, 2.6]196383.9073[0.9978, 0.3416, 2.9928, 3.2, 2.2023, 3.2]2043
51.059.4000[1.0, 0.5, 2.5, 2.0, 2.0, 3.0]183364.2000[1.0, 0.5, 2.5, 3.0, 2.0, 3.0]1863
\n", - "
" - ], - "text/plain": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
alphalbest_indi_lnfev_lnit_lrbest_indi_rnfev_rnit_r
00.0-3.5100[4.0, 2.0, 1.0, 0.1, 1.0, 1.0]173195.1100[1.0007, -0.0988, 4.0, 4.0, 3.0, 4.0]943
10.212.2517[0.2, 1.3292, 1.3676, 0.4, 1.356, 1.4]443146.2631[0.9999, -0.1, 3.6324, 3.8, 2.644, 3.8]123
20.416.4090[2.8, 1.0513, 1.5883, 0.8, 1.5425, 1.8]313119.7039[1.0, -0.0513, 3.4117, 3.6, 2.4575, 3.6]23
30.626.3045[2.2, 0.8381, 1.7581, 1.2, 1.6634, 2.2]893101.3145[1.0, 0.1619, 3.2419, 3.4, 2.3366, 3.4]1103
40.839.4395[0.8, 0.6584, 2.0072, 1.6, 1.7977, 2.6]196383.9073[0.9978, 0.3416, 2.9928, 3.2, 2.2023, 3.2]2043
51.059.4000[1.0, 0.5, 2.5, 2.0, 2.0, 3.0]183364.2000[1.0, 0.5, 2.5, 3.0, 2.0, 3.0]1863
\n", - "
" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z.extanded_output(round=4) # Default: round=None\n", - "z.df_extanded" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1168" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z.total_nfev" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": true - }, - "outputs": [ - { - "data": { - "image/png": "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gahJVqFQKASiJlmFQqEQyGU/yba2tmIymSgoKIj/uffee2dcc/ToUa688krsdjt1dXW8/vrrWVKb2YI56fDZz34Wm802ox8T+ymbur/97W9z9dVXk5uby/333z/jtdHRUT796U9TWFhIeXk5f/d3f5fW65nUeuutt5Kbmzujj7u7u7OiNRQK8fnPf541a9bgdDrZtGkT+/fvT1mLkbQK79cl7xmTnJaWFg3QhoaGkr4+ODioud1u7Xvf+54WDAa1733ve5rH45nzetF89atf1a688kqtu7tb6+7u1q688krtiSeeyIqWRP7zf/7P2pe//OU5X8+m7p/97Gfaz3/+c+3hhx/WPvKRj8x47TOf+Yx21113aUNDQ1pjY6NWVVWl/eAHP0j59UxqveWWW7R//Md/nPNrM6l1fHxce/zxx7WmpiZtenpae/311zW32629+OKLKWkxklbR/aom2QUm2aefflrbsmXLjLbNmzdr+/fvz4S8S6isrNSee+65+L+fffZZrbq6OitaEllokjWC7q997WszJq5AIKDZbDbtrbfeird94xvf0G6++eaUXs+kVk2bfzLIptYYH/3oR7XHH3/c0P06W6umie/Xy94uiHHFFVdQUVHBfffdx9mzZ+PtJ06coK6ubsa1dXV1nDhxItMSGRoaorOzc4aeuro62tvbF3Xyrd788Ic/xOPxsGXLFv7hH/4hXvLOqLobGxuZmpq6RFfsd7vQ69ngySefxOPxcNVVV/HDH/4w3p5trcFgkGPHjrFt2zbD92ui1hgi+3VZT7LhcJhgMDjnH03TKCkp4c0336SlpYWzZ89SU1PDHXfcwejoKHCxSE1igRq4WKQmdjBiJlmoYE42+dKXvkRjYyMDAwPs27ePb33rW3zrW98CjKt7fHwch8MxY2NL4u92odczzf/4H/+D5uZm+vr6+PrXv87u3bv5+c9/nnWtmqbx0EMPUVNTwwMPPGDofp2tFcT367KeZD/60Y+Sn58/55+2tjYKCgrYuXMnVqsVt9vN//yf/5NwOMxrr70GXCxSM/tpa2RkJCsFaoxcMGf79u2UlpaSk5PDddddx9/8zd/w05/+FDCu7oKCAiYmJmYEcIm/24VezzTXX389LpcLq9XKXXfdxV/8xV/M6ONsaNU0jS984Qs0Njbyi1/8ArPZbNh+TaYVxPfrsp5kf/Ob36Bd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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z.plot(show=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "75.41381950397155" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z.defuzzification(method = 'centroid') # mean / alpha_one / centroid\n", - "z.plot(show=True, defuzzy=z.determin_point,labels=True)\n", - "z.determin_objective\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Export Simple Dataframe as CSV\n", - "z.export_to_csv() # Default df='simple', filepath=None\n", - "\n", - "# Export Extanded Dataframe as CSV\n", - "z.export_to_csv(df='extended') # Default df='simple', filepath=None" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\r 0%| | 0/3 [00:00" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z.calculation(start_at=4)\n", - "z.plot(show=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.4" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/phuzzy/optimization/Fuzzy Sensi Analysis.ipynb b/phuzzy/optimization/Fuzzy Sensi Analysis.ipynb deleted file mode 100644 index af0c946..0000000 --- a/phuzzy/optimization/Fuzzy Sensi Analysis.ipynb +++ /dev/null @@ -1,567 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "no display found. Using non-interactive Agg backend\n" - ] - } - ], - "source": [ - "import phuzzy\n", - "from phuzzy.optimization import alphaOpt\n", - "from phuzzy.optimization import sensitivity_analysis\n", - "import matplotlib.pyplot as plt\n", - "\n", - "%matplotlib inline\n", - "plt.style.use('seaborn')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "v1 = phuzzy.Triangle(alpha0=[1,4], alpha1=[2], number_of_alpha_levels=3)\n", - "v2 = phuzzy.Triangle(alpha0=[0, 4], alpha1=[1], number_of_alpha_levels=3)\n", - "v3 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[2], number_of_alpha_levels=3)\n", - "v4 = phuzzy.Triangle(alpha0=[0,4], alpha1=[2.5], number_of_alpha_levels=6)\n", - "v5 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[3], number_of_alpha_levels=3)\n", - "v6 = phuzzy.Triangle(alpha0=[1,6], alpha1=[3], number_of_alpha_levels=3)\n", - "\n", - "obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)'\n", - "\n", - "kwargs = {'var1': v1, 'var2': v2, 'var3': v3,\n", - " 'var4': v4,'var5': v5, 'var6': v6,\n", - " 'obj_function': obj_function}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\rSensitivity Analysis: 0%| | 0/6 [00:00" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "\n", - "rr = sensitivity_analysis.Fuzzy_Sensitivity_Analysis(**kwargs)\n", - "rr.lcefa(**kwargs)\n", - "rr.barchart_plot()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\rSensitivity Analysis: 0%| | 0/6 [00:00" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "rr = sensitivity_analysis.Fuzzy_Sensitivity_Analysis(**kwargs)\n", - "rr.lcefa(error=True, **kwargs)\n", - "rr.barchart_plot()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "language": "python", - "name": "python2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/phuzzy/optimization/__init__.py b/phuzzy/optimization/__init__.py index 44f72d0..2863181 100644 --- a/phuzzy/optimization/__init__.py +++ b/phuzzy/optimization/__init__.py @@ -1,66 +1,52 @@ # -*- coding: utf-8 -*- - from shgo._shgo import SHGO - -import datetime -import os -import subprocess +from scipy.optimize import minimize import phuzzy from phuzzy.mpl import MPL_Mixin from phuzzy.shapes import FuzzyNumber -import matplotlib.pyplot as plt -from phuzzy.optimization import alphaOpt -from phuzzy.optimization import sensitivity_analysis -import math +from asteval import Interpreter +from pathlib import Path +#from tqdm import tqdm import numpy as np import pandas as pd import xarray as xr +from phuzzy.optimization import alphaOpt, sensitivity_analysis + +from SALib.sample import saltelli +from SALib.analyze import sobol #from math import * + if __name__ == "__main__": - """ - v1 = phuzzy.Triangle(alpha0=[1,4], alpha1=[2], number_of_alpha_levels=3) - v2 = phuzzy.Triangle(alpha0=[0, 4], alpha1=[1], number_of_alpha_levels=3) - v3 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[2], number_of_alpha_levels=3) - v4 = phuzzy.Triangle(alpha0=[0,4], alpha1=[2.5], number_of_alpha_levels=6) - v5 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[3], number_of_alpha_levels=3) - v6 = phuzzy.Triangle(alpha0=[1,5], alpha1=[3], number_of_alpha_levels=3) - obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)' - kwargs = {'var6': v6, 'var2': v2, 'var3': v3, - 'var4': v4,'var5': v5, 'var1': v1, - 'obj_function': obj_function} - - """ - """ - v1 = phuzzy.Uniform(alpha0=[-3.14159265359,3.14159265359], number_of_alpha_levels=5) - v2 = phuzzy.Uniform(alpha0=[-3.14159265359,3.14159265359], number_of_alpha_levels=5) - v3 = phuzzy.Uniform(alpha0=[-3.14159265359,3.14159265359], number_of_alpha_levels=5) + v1 = phuzzy.Triangle(alpha0=[1,4], alpha1=[2], name='v1', number_of_alpha_levels=3) + v2 = phuzzy.Triangle(alpha0=[0, 4], alpha1=[1], name='v2', number_of_alpha_levels=5) + v3 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[2], name='v3', number_of_alpha_levels=3) + v4 = phuzzy.Triangle(alpha0=[0,4], alpha1=[2.5], name='v4', number_of_alpha_levels=3) + v5 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[3], name='v5', number_of_alpha_levels=3) + v6 = phuzzy.Triangle(alpha0=[1,5], alpha1=[3], name='v6', number_of_alpha_levels=3) + + input = [v1,v2,v3,v4,v5,v6] + obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)' - obj_function = 'sin(x[0]) + 7*(asin(x[1])**2) + 0.1*(x[2]**4)*sin(x[0])' + kwargs = {'fuzzy_variables': input,'obj_function': obj_function} - kwargs = {'var1': v1, 'var2': v2, 'var3': v3, - 'obj_function': obj_function} - """ - """ #z = alphaOpt.Alpha_Level_Optimization(**kwargs) - #z.calculation(progressbar_disable=True) - #z.plot() - #plt.show() + #z.calculation() + p = phuzzy.Triangle(alpha0=[1,5], alpha1=[3], + number_of_alpha_levels=11, name='x') rr = sensitivity_analysis.Fuzzy_Sensitivity_Analysis(**kwargs) - rr.lcefa(error=False, **kwargs) - rr.barchart_plot() - plt.show() + rr.calculation(**kwargs) + rr.barchart_plot(plot=True) - """ diff --git a/phuzzy/optimization/alphaOpt.py b/phuzzy/optimization/alphaOpt.py index 9b48ff8..3929229 100644 --- a/phuzzy/optimization/alphaOpt.py +++ b/phuzzy/optimization/alphaOpt.py @@ -1,7 +1,6 @@ from shgo._shgo import SHGO from scipy.optimize import minimize -import phuzzy from phuzzy.mpl import MPL_Mixin from phuzzy.shapes import FuzzyNumber @@ -15,27 +14,54 @@ -class Alpha_Level_Optimization(FuzzyNumber, MPL_Mixin): +class Function(): + def __init__(self, function): + if isinstance(function, str): + self.aeval = Interpreter() + self.exprc = self.aeval.parse(function) + + def func(x): + self.aeval.symtable['x'] = x + return self.aeval.run(self.exprc) + self.func = func # here + + elif callable(function): + self.func = function + + def __call__(self, x): + return self.func(x) + + +class Alpha_Level_Optimization(FuzzyNumber, MPL_Mixin, Function): def __init__(self, **kwargs): """ - :param kwargs: Inputvariables / Fuzzyvariables / Name (name) / Objective Function (obj_function) / Objective Link (obj_link) + :param input_fuzzy_var_list: List of all Fuzzy Variables + :param var_names_list: List of Names of all Fuzzy Variables + :param kwargs: Inputvariables / Fuzzyvariables / Name (name) / Objective Function (obj_function) / Objective Link (obj_link) """ + # READ FUZZY INPUT VARIABLES + if kwargs.get('fuzzy_variables') is not None: input_fuzzy_var_list = kwargs.get('fuzzy_variables') + else: raise ValueError('PLEASE IMPORT FUZZY VARIABLES as -- fuzzy_variables --') + + # Check for identical number_of_alpha_levels and adapt + fuzzy_var_list = self._alpha_level_check(input_fuzzy_var_list) + # Define Bounds of Each Alpha Level - self.global_bounds_DataArray = self._boundary_constraints(**kwargs) - self.x_glob = [] + self.global_bounds_DataArray = self._boundary_constraints(fuzzy_var_list) + # Filter Objective Function / Link and Safe it - if kwargs.get('obj_function') is not None: self.objective = kwargs.get('obj_function') - elif kwargs.get('obj_link') is not None: self.objective = kwargs.get('obj_link') - else: raise ValueError('PLEASE IMPORT OBJECTIVE') + if kwargs.get('obj_function') is not None: self.objective = Function(kwargs.get('obj_function')) + else: raise ValueError('PLEASE IMPORT OBJECTIVE FUNCTION as -- obj_function --') - # Define Setup Parameters + # Setup Parameters if kwargs.get('name') is None: self.name = 'Fuzzy Objective Value' else: self.name = kwargs.get('name') - self.dim = self.global_bounds_DataArray['fuzzy_variables'].size + self.x_glob = [] + self.dim = self.global_bounds_DataArray['fuzzy_variable'].size self.number_of_alpha_lvls = self.global_bounds_DataArray['number_of_alpha_levels'].size self.best_indi_list_min = [] self.best_indi_list_max = [] @@ -46,11 +72,11 @@ def __init__(self, **kwargs): def __repr__(self): - return "{}(x:[[{:.3g}, {:.3g}], [{:.3g}, {:.3g}]])".format(self.name, self._df.iloc[0].l, self._df.iloc[0].r, - self._df.iloc[-1].l, self._df.iloc[-1].r) + return "{}(x:[[{:.3g}, {:.3g}], [{:.3g}, {:.3g}]])".format(self.name, self._df.iloc[0].l, self._df.iloc[0].r, + self._df.iloc[-1].l, self._df.iloc[-1].r) - def calculation(self, n=60, iters=3, optimizer='sobol', progressbar_disable=False, backup=False, start_at=None): + def main(self, n=50, iters=3, optimizer='sobol', progressbar_disable=False, backup=False, start_at=None): """ Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate the Fuzzy Objective Membershipfunction. @@ -176,7 +202,7 @@ def calculation(self, n=60, iters=3, optimizer='sobol', progressbar_disable=Fals self.compact_output() - def calculation_old(self, n=60, iters=3, optimizer='sobol', backup=False, start_at=None): + def _main_fast(self, n=250, iters=3, optimizer='sobol', backup=False, start_at=None): """ Main Routine calculating the Minimum and Maximum of the Objective on each Alpha Level to generate the Fuzzy Objective Membershipfunction. @@ -187,6 +213,9 @@ def calculation_old(self, n=60, iters=3, optimizer='sobol', backup=False, start_ :param start_at: Start at certain Alpha Level (Counts starts from Alpha Level 1) """ + ###################### STILL IN WORK ################################################## + + """ # Input Variables self.n = n self.iters = iters @@ -198,6 +227,18 @@ def calculation_old(self, n=60, iters=3, optimizer='sobol', backup=False, start_ zmax_value_list = [] boundlist = [] + for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): + boundlist.append(np.delete(self.global_bounds_DataArray.values[:, -i, :], 0, 1)) + + + bounds = boundlist[-1] + + shc_base_min = self._call_minimizer_shgo(bounds) + shc_base_max = self._call_maximizer_shgo(bounds) + + r = 1 + + if self.start_at is not None: self._cut_global_blounds() for i in range(1, self.global_bounds_DataArray['number_of_alpha_levels'].size + 1): @@ -321,6 +362,7 @@ def calculation_old(self, n=60, iters=3, optimizer='sobol', backup=False, start_ self.total_nfev = sum(self.nfev_list_min) + sum(self.nfev_list_max) self.compact_output() + """ def compact_output(self, round=None): @@ -382,7 +424,7 @@ def extanded_output(self,round=None): if round is not None: self.df_extanded = self.df_extanded.round(round) - def export_to_csv(self, df = 'simple' , filepath= None): + def export_to_csv(self, df='simple', filepath= None): """ Export Dataframe as CSV :param df Define Dataframe-Type which is to be exported simple / extended @@ -407,7 +449,7 @@ def export_to_csv(self, df = 'simple' , filepath= None): self.df_extanded.to_csv(filepath+self.name+datatype_str, sep=';', encoding='utf8', index=None, header=True) - def defuzzification(self, method = 'mean'): + def defuzzification(self, method='mean'): """ Defuzzyfication of Uncertain Objective :param method: Select Method of Defuzzyfication - alpha_one / mean / centroid @@ -491,11 +533,12 @@ def _objective_function(self, x): :param x: Input Variable :return: Function Value of Objective """ - aeval = Interpreter() - exprc = aeval.parse(self.objective) - aeval.symtable['x'] = x - return aeval.run(exprc) - + #aeval = Interpreter() + #exprc = aeval.parse(self.objective) + #aeval.symtable['x'] = x + #return aeval.run(exprc) + return self.objective(x) + def _cut_global_blounds(self): """ @@ -504,7 +547,7 @@ def _cut_global_blounds(self): if self.start_at is not None: self.orig_number_of_alpha_lvls = self.number_of_alpha_lvls self.global_bounds_DataArray = self.global_bounds_DataArray[:,0:self.orig_number_of_alpha_lvls-self.start_at+1,:] - self.dim = self.global_bounds_DataArray['fuzzy_variables'].size + self.dim = self.global_bounds_DataArray['fuzzy_variable'].size self.number_of_alpha_lvls = self.global_bounds_DataArray['number_of_alpha_levels'].size else: raise ValueError('Please select starting Alpha Level or keep variable "start_at=None"') @@ -594,43 +637,51 @@ def _call_backup(self,iteration): @staticmethod - def _boundary_constraints(**kwargs): + def _alpha_level_check(input_fuzzy_var_list): """ - Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton - :param kwargs: Input Fuzzy Variables - :return: 3D DataArray representing each Fuzzy Inputvariables Boundaries for each Alpha Level - prepared for the Optimization Routine + Checks if all Fuzzy Input Variables have the same alpha Level Discretization. + If not, adapt all Variables to the highes alpha Level. + + :param input_fuzzy_var_list: List of all Fuzzy Input Variables + :return: List of all Fuzzy Input Variables """ - filter_fuzzy_variables_dict = {} - list_of_n_alpha_levels = np.zeros(1, dtype='int') + alpha_array = np.zeros(shape=(len(input_fuzzy_var_list))) - # check if number_of_alpha_levels is the same - for key, value in kwargs.items(): - if isinstance(value, phuzzy.FuzzyNumber): - if list_of_n_alpha_levels[0] == 0: - np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) - else: - list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) + for i, fuzzy_var in enumerate(input_fuzzy_var_list): + alpha_array[i] = fuzzy_var.number_of_alpha_levels + if np.all(alpha_array == alpha_array[0]): + pass + else: + alvl_max = np.max(alpha_array) + index = np.argmax(alpha_array) + for i, fuzzy_var in enumerate(input_fuzzy_var_list): + if i != index: + fuzzy_var.convert_df(alpha_levels=alvl_max) + input_fuzzy_var_list[i] = fuzzy_var + return input_fuzzy_var_list - # extract fuzzy variables from kwargs and safe in dict - for key, value in kwargs.items(): - # if number_of_alpha_levels are different - if (len(set(list_of_n_alpha_levels)) == 1) == False: - max_value = np.max(list_of_n_alpha_levels) - if isinstance(value, phuzzy.FuzzyNumber): - if value.number_of_alpha_levels < max_value: value.convert_df(alpha_levels=max_value) - filter_fuzzy_variables_dict[key] = value._df - elif isinstance(value, phuzzy.FuzzyNumber): - # if number_of_alpha_levels are the same - filter_fuzzy_variables_dict[key] = value._df + @staticmethod + def _boundary_constraints(input_fuzzy_var_list): + """ + Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton + :param kwargs: Input Fuzzy Variables + :return: 3D DataArray representing each Fuzzy Inputvariables Boundaries for each Alpha Level + prepared for the Optimization Routine + """ - # extract fuzzy values from dict and safe as DataArray - fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) - for k, v in filter_fuzzy_variables_dict.items()} + df_list = [] + var_names_list = [] + for i, fuzzy_var in enumerate(input_fuzzy_var_list): + df_list.append(fuzzy_var.df) + var_names_list.append(fuzzy_var.name) + fuzzy_array = np.array([df.values for df in df_list]) + alpha_levels = np.linspace(1,len(fuzzy_array[0,:]),len(fuzzy_array[0,:])) + head = ['alpha','l','r'] + dims=['fuzzy_variable','number_of_alpha_levels','alpha_level_bounds'] - return xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') + return xr.DataArray(fuzzy_array,coords=[var_names_list, alpha_levels, head],dims=dims) @staticmethod @@ -691,6 +742,5 @@ def to_str(self): - if __name__ == "__main__": pass diff --git a/phuzzy/optimization/function_constraints.py b/phuzzy/optimization/function_constraints.py deleted file mode 100644 index b2d55b9..0000000 --- a/phuzzy/optimization/function_constraints.py +++ /dev/null @@ -1,75 +0,0 @@ -import numpy as np - - - -class ObjFunction(object): - def __init__(self): - self.x_glob = [] - - def min_function_value(self, x): - if isinstance(self.x_glob, np.ndarray): - for row in self.x_glob: - x = np.insert(x, (row[0].astype(int)), row[1]) - return self.objective_function(x) - - def max_function_value(self, x): - if isinstance(self.x_glob, np.ndarray): - for row in self.x_glob: - x = np.insert(x, (row[0].astype(int)), row[1]) - return -1 * (self.objective_function(x)) - - def objective_function(self, x): - return -1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - (x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2) - - -class Constraints(object): - def __init__(self, bound=True, **kwargs): - """ - Optimization Constraints - """ - if bound == True: - self.boundary_constraints(**kwargs) - - def boundary_constraints(self, **kwargs): - - filter_fuzzy_variables_dict = {} - list_of_n_alpha_levels = np.zeros(1, dtype='int') - - # check if number_of_alpha_levels is the same - for key, value in kwargs.items(): - if isinstance(value, phuzzy.FuzzyNumber): - if list_of_n_alpha_levels[0] == 0: - np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) - else: - list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) - - # extract fuzzy variables from kwargs and safe in dict - for key, value in kwargs.items(): - # if number_of_alpha_levels are different - if (len(set(list_of_n_alpha_levels)) == 1) == False: - max = np.max(list_of_n_alpha_levels) - if isinstance(value, phuzzy.FuzzyNumber): - if value.number_of_alpha_levels < max: value.convert_df(alpha_levels=max) - filter_fuzzy_variables_dict[key] = value._df - elif isinstance(value, phuzzy.FuzzyNumber): - # if number_of_alpha_levels are the same - filter_fuzzy_variables_dict[key] = value._df - - # extract fuzzy values from dict and safe as DataArray - fuzzy_variables = {k: xr.DataArray(v, dims=['number_of_alpha_levels', 'alpha_level_bounds']) - for k, v in filter_fuzzy_variables_dict.items()} - - self.global_bounds_DataArray = xr.Dataset(fuzzy_variables).to_array(dim='fuzzy_variables') - - def inequality_constraints(self): - - # cons = ({'type': 'ineq', 'fun': g1}, #>= - # {'type': 'ineq', 'fun': g2}, - # {'type': 'eq', 'fun': h1}) - pass - - def equality_constraints(self): - # cons = ({'type': 'ineq', 'fun': g1}, #>= - # {'type': 'ineq', 'fun': g2}, - # {'type': 'eq', 'fun': h1}) - pass diff --git a/phuzzy/optimization/ipynb/Example_Alpha_Opt.ipynb b/phuzzy/optimization/ipynb/Example_Alpha_Opt.ipynb new file mode 100644 index 0000000..c7fa3a8 --- /dev/null +++ b/phuzzy/optimization/ipynb/Example_Alpha_Opt.ipynb @@ -0,0 +1,879 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "no display found. Using non-interactive Agg backend\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\boos\\PycharmProjects\\phuzzy\\phuzzy\\mpl\\__init__.py:7: UserWarning: \nThis call to matplotlib.use() has no effect because the backend has already\nbeen chosen; matplotlib.use() must be called *before* pylab, matplotlib.pyplot,\nor matplotlib.backends is imported for the first time.\n\nThe backend was *originally* set to 'module://ipykernel.pylab.backend_inline' by the following code:\n File \"C:\\ProgramData\\Anaconda3\\lib\\runpy.py\", line 193, in _run_module_as_main\n \"__main__\", mod_spec)\n File \"C:\\ProgramData\\Anaconda3\\lib\\runpy.py\", line 85, in _run_code\n exec(code, run_globals)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel_launcher.py\", line 16, in \n app.launch_new_instance()\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\traitlets\\config\\application.py\", line 658, in launch_instance\n app.start()\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel\\kernelapp.py\", line 505, in start\n self.io_loop.start()\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\platform\\asyncio.py\", line 132, in start\n self.asyncio_loop.run_forever()\n File \"C:\\ProgramData\\Anaconda3\\lib\\asyncio\\base_events.py\", line 421, in run_forever\n self._run_once()\n File \"C:\\ProgramData\\Anaconda3\\lib\\asyncio\\base_events.py\", line 1431, in _run_once\n handle._run()\n File \"C:\\ProgramData\\Anaconda3\\lib\\asyncio\\events.py\", line 145, in _run\n self._callback(*self._args)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\ioloop.py\", line 758, in _run_callback\n ret = callback()\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\stack_context.py\", line 300, in null_wrapper\n return fn(*args, **kwargs)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 1233, in inner\n self.run()\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 1147, in run\n yielded = self.gen.send(value)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel\\kernelbase.py\", line 370, in dispatch_queue\n yield self.process_one()\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 346, in wrapper\n runner = Runner(result, future, yielded)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 1080, in __init__\n self.run()\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 1147, in run\n yielded = self.gen.send(value)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel\\kernelbase.py\", line 357, in process_one\n yield gen.maybe_future(dispatch(*args))\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 326, in wrapper\n yielded = next(result)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel\\kernelbase.py\", line 267, in dispatch_shell\n yield gen.maybe_future(handler(stream, idents, msg))\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 326, in wrapper\n yielded = next(result)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel\\kernelbase.py\", line 534, in execute_request\n user_expressions, allow_stdin,\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\tornado\\gen.py\", line 326, in wrapper\n yielded = next(result)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel\\ipkernel.py\", line 294, in do_execute\n res = shell.run_cell(code, store_history=store_history, silent=silent)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\ipykernel\\zmqshell.py\", line 536, in run_cell\n return super(ZMQInteractiveShell, self).run_cell(*args, **kwargs)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\IPython\\core\\interactiveshell.py\", line 2819, in run_cell\n raw_cell, store_history, silent, shell_futures)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\IPython\\core\\interactiveshell.py\", line 2845, in _run_cell\n return runner(coro)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\IPython\\core\\async_helpers.py\", line 67, in _pseudo_sync_runner\n coro.send(None)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\IPython\\core\\interactiveshell.py\", line 3020, in run_cell_async\n interactivity=interactivity, compiler=compiler, result=result)\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\IPython\\core\\interactiveshell.py\", line 3185, in run_ast_nodes\n if (yield from self.run_code(code, result)):\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\IPython\\core\\interactiveshell.py\", line 3267, in run_code\n exec(code_obj, self.user_global_ns, self.user_ns)\n File \"\", line 1, in \n import phuzzy\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\phuzzy\\__init__.py\", line 23, in \n from phuzzy.shapes.skewnorm import Skewnorm\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\phuzzy\\shapes\\skewnorm.py\", line 21, in \n import matplotlib.pyplot as plt\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\matplotlib\\pyplot.py\", line 71, in \n from matplotlib.backends import pylab_setup\n File \"C:\\Users\\boos\\PycharmProjects\\phuzzy\\venv\\lib\\site-packages\\matplotlib\\backends\\__init__.py\", line 16, in \n line for line in traceback.format_stack()\n\n\n matplotlib.use('Agg')\n" + ] + } + ], + "source": [ + "import phuzzy\n", + "from phuzzy.optimization import alphaOpt\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "plt.style.use('seaborn')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "v1 = phuzzy.Triangle(alpha0=[1,4], alpha1=[2], name='v1', number_of_alpha_levels=3)\n", + "v2 = phuzzy.Triangle(alpha0=[0, 4], alpha1=[1], name='v2', number_of_alpha_levels=5)\n", + "v3 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[2], name='v3', number_of_alpha_levels=3)\n", + "v4 = phuzzy.Triangle(alpha0=[0,4], alpha1=[2.5], name='v4', number_of_alpha_levels=3)\n", + "v5 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[3], name='v5', number_of_alpha_levels=3)\n", + "v6 = phuzzy.Triangle(alpha0=[1,5], alpha1=[3], name='v6', number_of_alpha_levels=3)\n", + "fuzzy_input_variables = [v1,v2,v3,v4,v5,v6]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\r1st Loop: 0%| | 0/5 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.00-15.909987451.10000
10.25-1.671875327.15625
20.5018.712500230.21250
30.7550.503125155.95625
41.00100.450000100.45000
\n", + "" + ], + "text/plain": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.00-15.909987451.10000
10.25-1.671875327.15625
20.5018.712500230.21250
30.7550.503125155.95625
41.00100.450000100.45000
\n", + "
" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.df" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.00-15.91451.10
10.25-1.67327.16
20.5018.71230.21
30.7550.50155.96
41.00100.45100.45
\n", + "
" + ], + "text/plain": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalr
00.00-15.91451.10
10.25-1.67327.16
20.5018.71230.21
30.7550.50155.96
41.00100.45100.45
\n", + "
" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.compact_output(round=2) # Default: round=None\n", + "z_string.df" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalbest_indi_lnfev_lnit_lrbest_indi_rnfev_rnit_r
00.00-15.9100[4.0, 4.0, 1.0, 0.1036, 1.0, 1.0]263451.1000[1.0, 0.0, 4.0, 4.0, 4.0, 5.0]183
10.25-1.6719[3.5, 3.25, 1.25, 0.625, 1.5, 1.5]1323327.1562[1.25, 0.25, 3.5, 3.625, 3.75, 4.5]1323
20.5018.7125[3.0, 2.5, 1.5, 1.25, 2.0, 2.0]2323230.2125[1.5, 0.5, 3.0, 3.25, 3.5, 4.0]2323
30.7550.5031[2.5, 1.75, 1.75, 1.875, 2.5, 2.5]1663155.9562[1.75, 0.75, 2.5, 2.875, 3.25, 3.5]1663
41.00100.4500[2.0, 1.0, 2.0, 2.5, 3.0, 3.0]00100.4500[2.0, 1.0, 2.0, 2.5, 3.0, 3.0]00
\n", + "
" + ], + "text/plain": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphalbest_indi_lnfev_lnit_lrbest_indi_rnfev_rnit_r
00.00-15.9100[4.0, 4.0, 1.0, 0.1036, 1.0, 1.0]263451.1000[1.0, 0.0, 4.0, 4.0, 4.0, 5.0]183
10.25-1.6719[3.5, 3.25, 1.25, 0.625, 1.5, 1.5]1323327.1562[1.25, 0.25, 3.5, 3.625, 3.75, 4.5]1323
20.5018.7125[3.0, 2.5, 1.5, 1.25, 2.0, 2.0]2323230.2125[1.5, 0.5, 3.0, 3.25, 3.5, 4.0]2323
30.7550.5031[2.5, 1.75, 1.75, 1.875, 2.5, 2.5]1663155.9562[1.75, 0.75, 2.5, 2.875, 3.25, 3.5]1663
41.00100.4500[2.0, 1.0, 2.0, 2.5, 3.0, 3.0]00100.4500[2.0, 1.0, 2.0, 2.5, 3.0, 3.0]00
\n", + "
" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.extanded_output(round=4) # Default: round=None\n", + "z_string.df_extanded\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1104" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.total_nfev" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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wACef/55/P73v8epU6ewceNGAMDGjRuxd+9ebNiwAdu3b0d1dTWWLVsGAKiursYtt9yC3/zmN7j++utRVVWF3bt3w2azBd/z6aefxvXXX4/169fjJz/5Ce666y689NJLEakbiRxqsiRsdXV1MBqN0/5ZrVAocNttt+H1118HABw/fhwVFRU4deoU9u7di7179+LkyZPYtWsXtm7diq1bt+KFF16I6Ph8Ph927twJpVKJt956Cy+++CIaGxvxi1/8AsDougYWiwXvvvsu3nnnHWi1Wjz55JMoKirCU089BYlEgrq6OixZsmTO99qyZQsef/xxfP/738fhw4fR0tICuVyOhx56CAsXLsSdd96JHTt2YO3atXjvvfeC33fx4kW8+eabeOqpp6Yc02AwYGhoCMePH8fzzz+PU6dO4fnnnwcAvPjii/jjH/+IZ555BidOnEBKSgrq6+sjVDkSSdRkSdj6+/sBABkZGdO+rtfrg/ssW7YMX/nKVyCTybBx40Z85jOfwdGjRwUdX319PS5duoS9e/dCo9EgIyMDu3fvxj/+8Q94vV7I5XI0Nzfj2LFjGBgYwCOPPIKHHnoorPf61re+hSeeeAJutxu//OUvceutt2Ljxo149tlnZ/2+W265BUlJSUhJSZn29XvvvRcKhQKFhYWorKxEa2srAODw4cP40pe+hLKyMsjlcnz7299Genp6WGMnwpLGegCEXXq9HgDQ3d2NBQsWTHm9q6sruM/ChQsnvJabm4umpiZBx9fV1QWv14sbbrhhwnaRSISenh7s3LkTCoUCf/3rX7F3714UFRVh9+7d2LRpU1jvd9NNN+Gmm24CMDqL4I033sAjjzyClJQUbNu2bdrvmekfKGD0ES86nS74tVQqhc/nAwD09vYiOzt7wr7jvybxg85kSdjWrFkDvV4fvL46nt1ux6uvvorNmzcDGG0K43V2dgavXwolKysLGo0Gp06dCq6d+t577+HIkSPIy8vDpUuXsHnzZhw+fBgnT57Erbfeivvvv5/zgxQvXryIFStWoKenJ7itoKAAX//613HDDTfg/PnzM36vSCQK62fLyclBd3d38Gu/34++vr6wjkWERU2WhE0mk+HnP/85nn32Wezbtw8DAwPw+XxobGzEN77xDSiVStxzzz0ARoOhl156CT6fDydOnMDx48eDQZdcLsfIyEjEx7d69WpkZmbif//3f+FwOGCz2bB3797gUxOee+457NmzB4ODg9BqtUhJSYFGo4FcLodcLoff7w+p4ZaWlqKsrAy7d+9GQ0MDAoEAbDYb3n77bXz00UfBM+NI/px33nknnnvuOTQ1NcHj8WD//v0YGBiIyLFJZFGTJbxs3LgRf/3rX9HS0oLbb78da9aswXe+8x2sWbMGzz//PJKTkwEAZWVlePvtt1FVVYVf/OIX+NWvfoWVK1cCAD772c+itrYWt9xyS0THJpfL8fTTT8NgMODmm2/Gpz71KVitVjz99NMQi8V44IEHkJeXh1tvvRUVFRV4+eWXsX//fsjlcixduhSrVq3C9ddfP+dMB5FIhN/97ndYtWoVdu/ejYqKCtxwww3405/+hF//+teoqqoCANx8880wGo249tprgzMcwrV161Zs374dO3bswA033IDBwUFkZWVBJpPxOi6JPFq0mwhu3759OHXqFA4dOhTroSSMpqYmpKamIicnBwAQCASwdu1a7Nu3D+vWrYvx6Mh4dCZLCIPef/993HfffRgaGoLP58Mf//hHSCQSrFq1KtZDI5PQ7AISl4aGhvDpT396xtd1Oh3++c9/RmUsu3btQnV19Yyv//a3v8WGDRuiMpYxX/nKV9DR0YEtW7bA6XSirKwMv/vd76Y844zEHl0uIIQQAdHlAkIIERA1WUIIERA1WUIIERA1WUIIERA1WUIIERA1WUIIERA1WUIIERA1WUIIEdD/B0AzHbb8QVguAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.plot(show=True, filepath=\"z_plot.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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9uxZ7N27F01NTWhsbMQXvvAFPPbYY7Db7RH9/0ceeQS//vWvg68bGxuDK5HmYtu2bWhsbERjYyNWrFiBFStWBF9v27Yt5s8D+D9TNFvRO51OPPLII7jxxhvR0NCAjRs34jvf+c60KlUHDx7E/fffP+s5jh07FlzmSmQOJLIEL95991187Wtfw7Jly3D48GGcPHkSjz32GE6dOoV/+Id/iKg2q9FonPa6tbU1IrF59dVX0draitbWVuzcuRM7duwIvn711Vdj/kwAYDab4Xa7Iz7+wQcfxOnTp/H73/8ep06dwptvvgmdToevfe1rwRiMjY1hrrU/TU1NEf1xIYQFiSwRM263G/fddx/27NmDu+66CzqdDgzDYMmSJfjNb34Dl8uFp59+Gk888QTuvPNOfPe730VjYyO2bt2KF154AYC/ItQrr7yCV155BbfeeisA/zLPY8eOxaWPIyMj+Nd//Vds3rwZ1113HR566CG4XC4AgNVqxd13342mpiZs2bIF//zP/4y+vj50d3fjW9/6FliWRWNjIy5evDjvdU6ePInPfvazqKioAABoNBrce++9uP766zE2Noa//OUv+O1vf4vjx4/juuuuAwBcd911uP/++7F582bs2rULR48exfLlywEAR48exU033YQnn3wS1157LZqamnDPPffAZrMFr/nMM8/g2muvxaZNm/DjH/8Yt99+O1566aW4xI2IHySyRMy0trbCYDCE/Votl8uxfft2vPHGGwCAI0eOYO3atTh+/Djuv/9+3H///fjkk0+wd+9e7NixAzt27MDzzz8f1/6xLIs9e/ZAoVDg7bffxgsvvID29nb8/Oc/B+Cva2A2m/Hee+/h3XffhUajwVNPPYWamhr85je/gVgsRmtrK5YsWTLvtbZt24bHHnsM9957L1588UV0dnZCJpPhZz/7GRYuXIjbbrsNu3f//+3dS0hUXxzA8e+kcw0mp0QnNSlrE06gI06phDOYZtJE0qaFbVwYQT7Kxo2rWRZJFjSIYS7MQLCB7CFCoYESCZMbIR1UcmH5HpyFj6Ic/S/kf9F/+X9Mc7P+/D67c8/j/u4sfnM493BPKZmZmfT29qr9hoeHefnyJffu3ftmzPHxcQKBAN3d3Xg8HrxeLx6PB4DHjx/T3NzM/fv36enpwWg0MjAwEKZfToSTJFkRstnZWQDi4uK+W28ymdQ2R44coaSkBL1ej91u59SpUzx79kzT+AYGBhgZGcHlcmEwGIiLi8PpdPLo0SNWVlZQFIXR0VE6Ojrw+/3U1tZy48aNkO515coV7t69y5cvX6irq8PhcGC322lpafnbfgUFBezatQuj0fjd+oqKCqKiojhw4ABHjx5lbGwMgPb2doqLizGbzSiKwtWrV4mNjQ0pdqGtyO0OQPy+TCYTAJOTkyQnJ39TPzExobY5ePDgprp9+/bh8/k0jW9iYoKVlRVsNtum6zqdjqmpKS5fvkxUVBStra24XC4OHTqE0+nk5MmTId0vNzeX3NxcYH0XwYsXL6itrcVoNHLu3Lnv9tnqDwrWj3iJiYlRy5GRkQSDQQCmp6dJSEjY1HZjWfw6ZCYrQma1WjGZTOr66kbLy8t0dnZSWFgIrCeFjT5+/KiuX2olPj4eg8GA1+tVv53a29vLkydPSEpKYmRkhMLCQtrb2+nr68PhcFBVVfWfD1IcHh4mNTWVqakp9dr+/fu5ePEiNpuNwcHBLfvqdLqQni0xMZHJyUm1vLq6yszMTEhjCW1JkhUh0+v1XL9+nZaWFtxuN36/n2AwyNDQEJcuXWLnzp2UlZUB6y+Gnj59SjAYpKenh+7ubvVFl6IoLCwshD2+9PR09u7dy61bt/j06RNLS0u4XC711IS2tjZqamqYn59n9+7dGI1GDAYDiqKgKAqrq6v/KuEePnwYs9mM0+nk3bt3rK2tsbS0RFdXF2/fvlVnxuF8zvPnz9PW1obP5+Pr1680NDTg9/vDMrYIL0my4ofY7XZaW1t5//49RUVFWK1Wrl27htVqxePxEB0dDYDZbKarq4usrCxu3rzJ7du3SUtLA+D06dP09/dTUFAQ1tgURaGxsZHx8XHy8/M5ceIEi4uLNDY2smPHDqqrq0lKSsLhcJCRkcHz589paGhAURRSUlKwWCzk5OT8404HnU5HU1MTFosFp9NJRkYGNpuNBw8ecOfOHbKysgDIz89nbm6OY8eOqTscQnX27FkuXLhAaWkpNpuN+fl54uPj0ev1PzSuCD/5aLfQnNvtxuv18vDhw+0O5X/D5/OxZ88eEhMTAVhbWyMzMxO32012dvY2Ryc2kpmsEL+h169fU1lZSSAQIBgM0tzcTEREBBaLZbtDE38huwvELykQCJCXl7dlfUxMDK9evfopsZSXl/PmzZst6+vr6zl+/PhPieVPJSUlfPjwgTNnzvD582fMZjNNTU3fnHEmtp8sFwghhIZkuUAIITQkSVYIITQkSVYIITQkSVYIITQkSVYIITQkSVYIITQkSVYIITQkSVYIITT0B1vsnIQxfD14AAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.defuzzification(method = 'centroid') # mean / alpha_one / centroid\n", + "z_string.plot(show=True, defuzzy=z_string.determin_point,labels=True, filepath=\"z_centroid_plot.png\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "# Export Simple Dataframe as CSV\n", + "z_string.export_to_csv() # Default df='simple', filepath=None\n", + "\n", + "# Export Extanded Dataframe as CSV\n", + "z_string.export_to_csv(df='extended') # Default df='simple', filepath=None" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.defuzzification(method = 'mean') # mean / alpha_one / centroid\n", + "z_string.plot(show=True, defuzzy=z_string.determin_point,labels=True, filepath=\"z_mean_plot.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\r1st Loop: 0%| | 0/2 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z_string.calculation(start_at=4)\n", + "z_string.plot(show=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.4" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/phuzzy/optimization/ipynb/Example_Fuzzy_Sensi_Analysis.ipynb b/phuzzy/optimization/ipynb/Example_Fuzzy_Sensi_Analysis.ipynb new file mode 100644 index 0000000..183ab0f --- /dev/null +++ b/phuzzy/optimization/ipynb/Example_Fuzzy_Sensi_Analysis.ipynb @@ -0,0 +1,567 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import phuzzy\n", + "from phuzzy.optimization import alphaOpt\n", + "from phuzzy.optimization.sensitivity_analysis import Fuzzy_Sensitivity_Analysis\n", + "import matplotlib.pyplot as plt\n", + "\n", + "%matplotlib inline\n", + "plt.style.use('seaborn')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "v1 = phuzzy.Triangle(alpha0=[1,4], alpha1=[2], name='v1', number_of_alpha_levels=3)\n", + "v2 = phuzzy.Triangle(alpha0=[0, 4], alpha1=[1], name='v2', number_of_alpha_levels=5)\n", + "v3 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[2], name='v3', number_of_alpha_levels=3)\n", + "v4 = phuzzy.Triangle(alpha0=[0,4], alpha1=[2.5], name='v4', number_of_alpha_levels=6)\n", + "v5 = phuzzy.Triangle(alpha0=[1, 4], alpha1=[3], name='v5', number_of_alpha_levels=3)\n", + "v6 = phuzzy.Triangle(alpha0=[1,5], alpha1=[3], name='v6', number_of_alpha_levels=3)\n", + "\n", + "fuzzy_input_variables = [v1,v2,v3,v4,v5,v6]\n", + "obj_function = '-1*((x[0] - 1) ** 2 + (x[1] + .1) ** 2 + .1 - (x[2] + 2) ** 2 - ' \\\n", + " '(x[3] - 0.1) ** 2 - (x[4] * x[5]) ** 2)'\n", + "\n", + "name = 'Sensi_Test'\n", + "\n", + "kwargs = {'fuzzy_variables': fuzzy_input_variables, \n", + " 'obj_function': obj_function, 'name': name}" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\rSensitivity Analysis: 0%| | 0/6 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fuzzySensi = Fuzzy_Sensitivity_Analysis(**kwargs)\n", + "fuzzySensi.main(**kwargs)\n", + "fig, ax = fuzzySensi.barchart_plot()\n", + "plt.plot()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\rSensitivity Analysis: 0%| | 0/6 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fuzzySensi = Fuzzy_Sensitivity_Analysis(**kwargs)\n", + "fuzzySensi.main(error=True, **kwargs)\n", + "fig, ax = fuzzySensi.barchart_plot()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/phuzzy/optimization/sensitivity_analysis.py b/phuzzy/optimization/sensitivity_analysis.py index 0890542..4e5bd9c 100644 --- a/phuzzy/optimization/sensitivity_analysis.py +++ b/phuzzy/optimization/sensitivity_analysis.py @@ -2,9 +2,7 @@ import pandas as pd import phuzzy -import phuzzy.mpl as phm -from phuzzy.mpl import mix_mpl -from phuzzy.optimization import alphaOpt +from phuzzy.optimization.alphaOpt import Alpha_Level_Optimization from tqdm import tqdm import matplotlib.pyplot as plt @@ -14,178 +12,73 @@ class Fuzzy_Sensitivity_Analysis(object): - def __init__(self,**kwargs): + def __init__(self, **kwargs): """ + :param input_fuzzy_var_list: List of all Fuzzy Variables + :param var_names_list: List of Names of all Fuzzy Variables :param kwargs: Inputvariables / Fuzzyvariables / Name (name) / Objective Function (obj_function) / Objective Link (obj_link) """ + # READ FUZZY INPUT VARIABLES + if kwargs.get('fuzzy_variables') is not None: input_fuzzy_var_list = kwargs.get('fuzzy_variables') + else: raise ValueError('PLEASE IMPORT FUZZY VARIABLES as -- fuzzy_variables --') + + # Check for identical number_of_alpha_levels and adapt + self.fuzzy_var_list = Alpha_Level_Optimization._alpha_level_check(input_fuzzy_var_list) + # Define Bounds of Each Alpha Level - self.input_dict = kwargs - self.fuzzy_variables_dict = self._prepare_fuzzy_variables(**kwargs) - self.x_glob = [] + self.global_bounds_DataArray = Alpha_Level_Optimization._boundary_constraints(self.fuzzy_var_list) - # Filter Objective Function / Link and Safe it - if kwargs.get('obj_function') is not None: self.objective = kwargs.get('obj_function') - elif kwargs.get('obj_link') is not None: self.objective = kwargs.get('obj_link') - else: raise ValueError('PLEASE IMPORT OBJECTIVE') + # Setup Parameters + self.number_of_alpha_lvl = self.global_bounds_DataArray['number_of_alpha_levels'].size + self.x_glob = [] - # Define Setup Parameters if kwargs.get('name') is None: self.name = 'Fuzzy Objective Value' else: self.name = kwargs.get('name') - def _prepare_fuzzy_variables(self, alpha_Level=None, **kwargs): + def main(self, search='quick', error=False, progressbar_disable = False, lsa=None, **kwargs): """ - Calculating the Optimization Boundaries based on the Fuzzy Variables Membership Funciton - :param kwargs: Input Fuzzy Variables - :return: 3D DataArray representing each Fuzzy Inputvariables Boundaries for each Alpha Level - prepared for the Optimization Routine + Calculate Fuzzy Sensitivity of Fuzzy Variables + + :param search: Search Precision of Optimization Routine (quick / default / deep) + :param error: include calculation of possible error margin + :param progressbar_disable: disable progressbar + :param lsa: local search algorithm (instead of uniform fuzzy variables it uses + deterministic variables to calculate the sensitivity at a certain Point) + :param kwargs: kwargs + :return: """ - filter_fuzzy_variables_dict = {} - list_of_n_alpha_levels = np.zeros(1, dtype='int') - - if alpha_Level is None: - # check if number_of_alpha_levels is the same - for key, value in kwargs.items(): - if isinstance(value, phuzzy.FuzzyNumber): - if list_of_n_alpha_levels[0] == 0: - np.put(list_of_n_alpha_levels, 0, value.number_of_alpha_levels) - else: - list_of_n_alpha_levels = np.append(list_of_n_alpha_levels, value.number_of_alpha_levels) - - if alpha_Level is None: - # extract fuzzy variables from kwargs and safe in dict - for key, value in kwargs.items(): - # if number_of_alpha_levels are different - if (len(set(list_of_n_alpha_levels)) == 1) == False: - max_value = np.max(list_of_n_alpha_levels) - if isinstance(value, phuzzy.FuzzyNumber): - if value.number_of_alpha_levels < max_value: value.convert_df(alpha_levels=max_value) - filter_fuzzy_variables_dict[key] = value._df - self.number_of_alpha_lvl = max_value - elif isinstance(value, phuzzy.FuzzyNumber): - # if number_of_alpha_levels are the same - filter_fuzzy_variables_dict[key] = value._df - self.number_of_alpha_lvl = value.number_of_alpha_levels - else: - for key, value in kwargs.items(): - if isinstance(value, phuzzy.FuzzyNumber): - value.convert_df(alpha_levels=alpha_Level) - filter_fuzzy_variables_dict[key] = value._df - self.number_of_alpha_lvl = alpha_Level - - return filter_fuzzy_variables_dict + if search == "quick": + self.n = 15 + self.iters = 2 + elif search == "default": + self.n = 30 + self.iters = 3 + elif search == 'deep': + self.n = 60 + self.iters = 4 - def barchart_plot(self): - - - y_pos = np.arange(len(self.name_list)) - fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, sharex=False,figsize=(10,len(y_pos))) - width = 0.6 - width2 = 0.3 - - - if hasattr(self,'sensis_total_var') == True: - fig.suptitle('Average Local Cost Effectivness Fuzzy Analysis') - - ax1.set_title('Average Total Relative Effectivness') - ax1.set_yticks(y_pos) - ax1.set_yticklabels(self.name_list) - ax1.invert_yaxis() # labels read top-to-bottom - ax1.set_ylabel('Variables') - ax1.set_xlabel('Total Sensitivity') - ax1.set_axisbelow(True) - ax1.set_xlim(0,max(self.sensis_total)+0.1) - ax1.grid(b=True, which='major') - ax1.grid(b=True, which='minor') - formatted_sensis = [round(elem, 3) for elem in self.sensis_total] - for i, v in enumerate(formatted_sensis): - ax1.text(v+0.001, i-0.055, " "+str(v), color='black', va='center',fontweight='bold') - ax1.barh(y_pos, self.sensis_total, width, xerr=self.sensis_total_var, align='center', color='lightslategrey', ecolor='black') - - ax2.set_title('Average Absolute Left / Right Effectivness') - ax2.set_yticks(y_pos) - ax2.set_yticklabels(self.name_list) - ax2.invert_yaxis() # labels read top-to-bottom - ax2.set_ylabel('Variables') - ax2.set_xlabel('Relative Partial Sensitivity') - ax2.set_axisbelow(True) - ax2.set_xlim(0,max(max(self.sensis_l),max(self.sensis_r))+0.1) - ax2.grid(b=True, which='major') - ax2.grid(b=True, which='minor') - formatted_sensis_l = [round(elem, 3) for elem in self.sensis_l] - formatted_sensis_r = [round(elem, 3) for elem in self.sensis_r] - for (i_l, v_l),(i_r, v_r) in zip(enumerate(formatted_sensis_l),enumerate(formatted_sensis_r)): - ax2.text(v_l+0.001, i_l-0.5*width2-0.055, " "+str(v_l), color='black', va='center',fontweight='bold') - ax2.text(v_r+0.001, i_r+0.5*width2+0.055, " "+str(v_r), color='black', va='center',fontweight='bold') - ax2.barh(y_pos-0.5*width2, self.sensis_l, width2, xerr=self.sensis_l_var, color='SkyBlue', label='Left', ecolor='black') - ax2.barh(y_pos+0.5*width2, self.sensis_r, width2, xerr=self.sensis_r_var, color='IndianRed', label='Right', ecolor='black') - ax2.legend() - else: - - fig.suptitle('Local Cost Effectivness Fuzzy Analysis') - - ax1.set_title('Total Relative Effectivness') - ax1.set_yticks(y_pos) - ax1.set_yticklabels(self.name_list) - ax1.invert_yaxis() # labels read top-to-bottom - ax1.set_ylabel('Variables') - ax1.set_xlabel('Total Sensitivity') - ax1.set_axisbelow(True) - ax1.set_xlim(left=0,right=max(self.sensis_total)+0.1) - ax1.grid(b=True, which='major') - ax1.grid(b=True, which='minor') - formatted_sensis = [round(elem, 3) for elem in self.sensis_total] - for i, v in enumerate(formatted_sensis): - ax1.text(v+0.001, i-0.055, " "+str(v), color='black', va='center',fontweight='bold') - ax1.barh(y_pos, self.sensis_total, width, align='center', color='lightslategrey') - - ax2.set_title('Absolute Left / Right Effectivness') - ax2.set_yticks(y_pos) - ax2.set_yticklabels(self.name_list) - ax2.invert_yaxis() # labels read top-to-bottom - ax2.set_ylabel('Variables') - ax2.set_xlabel('Relative Partial Sensitivity') - ax2.set_axisbelow(True) - ax2.set_xlim(0,max(max(self.sensis_l),max(self.sensis_r))+0.1) - ax2.grid(b=True, which='major') - ax2.grid(b=True, which='minor') - formatted_sensis_l = [round(elem, 3) for elem in self.sensis_l] - formatted_sensis_r = [round(elem, 3) for elem in self.sensis_r] - for (i_l, v_l),(i_r, v_r) in zip(enumerate(formatted_sensis_l),enumerate(formatted_sensis_r)): - ax2.text(v_l+0.001, i_l-0.5*width2-0.055, " "+str(v_l), color='black', va='center',fontweight='bold') - ax2.text(v_r+0.001, i_r+0.5*width2+0.055, " "+str(v_r), color='black', va='center',fontweight='bold') - ax2.barh(y_pos-0.5*width2, self.sensis_l, width2, color='SkyBlue', label='Left') - ax2.barh(y_pos+0.5*width2, self.sensis_r, width2, color='IndianRed', label='Right') - ax2.legend() - - plt.show() - - - def lcefa(self, error=False, lsa=None, **kwargs): - """ - Local cost effectivness fuzzy analysis - :return: - """ - - if error == False: - self.name_list, self.sensis_total, self.sensis_l, self.sensis_r = self.lcefa_calculation(**kwargs) + if not error: + self.sensis_total, self.sensis_l, self.sensis_r = \ + self._sensitivity_rotuine(progressbar_disable = progressbar_disable, **kwargs) else: sensi_total_dict = {} sensi_l_dict = {} sensi_r_dict = {} #with tqdm(total=7,desc='Average Sensitivity Analysis',leave=True, disable=True) as pbar_glob: for alpha_Level in range(3,9): - name_list, sensis_total, sensis_l, sensis_r = self.lcefa_calculation(alpha_Level=alpha_Level, lsa=lsa, leave=False,**kwargs,) + sensis_total, sensis_l, sensis_r =\ + self._sensitivity_rotuine(alpha_Level=alpha_Level, progressbar_disable = progressbar_disable, lsa=lsa, + leave=False,**kwargs) sensi_total_dict[str(alpha_Level)] = sensis_total sensi_l_dict[str(alpha_Level)] = sensis_l sensi_r_dict[str(alpha_Level)] = sensis_r #pbar_glob.update() - self.name_list = name_list self.sensi_total_df = pd.DataFrame.from_dict(sensi_total_dict) self.sensi_l_df = pd.DataFrame.from_dict(sensi_l_dict) self.sensi_r_df = pd.DataFrame.from_dict(sensi_r_dict) @@ -198,50 +91,143 @@ def lcefa(self, error=False, lsa=None, **kwargs): self.sensis_r_var = self.sensi_r_df.var(axis=1).values - def lcefa_calculation(self, alpha_Level=None, lsa=None, leave=False, **kwargs): + def barchart_plot(self, plot=False): + + y_pos = np.arange(self.global_bounds_DataArray['fuzzy_variable'].size) + fig, ax = plt.subplots(nrows=1, ncols=2, sharex=False,figsize=(10,len(y_pos))) + width = 0.6 + width2 = 0.3 + + if hasattr(self,'sensis_total_var') == True: + fig.suptitle('Average Fuzzy Sensitivity Analysis') + ax[0].set_title('Average Total Relative Sensitivity') + ax[0].set_yticks(y_pos) + ax[0].set_yticklabels(self.global_bounds_DataArray['fuzzy_variable'].values) + ax[0].invert_yaxis() # labels read top-to-bottom + ax[0].set_ylabel('Variables') + ax[0].set_xlabel('Total Sensitivity') + ax[0].set_axisbelow(True) + ax[0].set_xlim(0,max(self.sensis_total)+0.1) + ax[0].grid(b=True, which='major') + ax[0].grid(b=True, which='minor') + formatted_sensis = [round(elem, 3) for elem in self.sensis_total] + for i, v in enumerate(formatted_sensis): + ax[0].text(v+0.001, i-0.055, " "+str(v), color='black', va='center',fontweight='bold') + ax[0].barh(y_pos, self.sensis_total, width, xerr=self.sensis_total_var, align='center', color='lightslategrey', ecolor='black') + ax[1].set_title('Average Absolute Left / Right Sensitivity') + ax[1].set_yticks(y_pos) + ax[1].set_yticklabels(self.global_bounds_DataArray['fuzzy_variable'].values) + ax[1].invert_yaxis() # labels read top-to-bottom + ax[1].set_ylabel('Variables') + ax[1].set_xlabel('Relative Partial Sensitivity') + ax[1].set_axisbelow(True) + ax[1].set_xlim(0,max(max(self.sensis_l),max(self.sensis_r))+0.1) + ax[1].grid(b=True, which='major') + ax[1].grid(b=True, which='minor') + formatted_sensis_l = [round(elem, 3) for elem in self.sensis_l] + formatted_sensis_r = [round(elem, 3) for elem in self.sensis_r] + for (i_l, v_l),(i_r, v_r) in zip(enumerate(formatted_sensis_l),enumerate(formatted_sensis_r)): + ax[1].text(v_l+0.001, i_l-0.5*width2-0.055, " "+str(v_l), color='black', va='center',fontweight='bold') + ax[1].text(v_r+0.001, i_r+0.5*width2+0.055, " "+str(v_r), color='black', va='center',fontweight='bold') + ax[1].barh(y_pos-0.5*width2, self.sensis_l, width2, xerr=self.sensis_l_var, color='SkyBlue', label='Left', ecolor='black') + ax[1].barh(y_pos+0.5*width2, self.sensis_r, width2, xerr=self.sensis_r_var, color='IndianRed', label='Right', ecolor='black') + ax[1].legend(fancybox=True, framealpha=0.5) + + else: + + fig.suptitle('Fuzzy Sensitivity Analysis') + ax[0].set_title('Total Relative Sensitivity') + ax[0].set_yticks(y_pos) + ax[0].set_yticklabels(self.global_bounds_DataArray['fuzzy_variable'].values) + ax[0].invert_yaxis() # labels read top-to-bottom + ax[0].set_ylabel('Variables') + ax[0].set_xlabel('Total Sensitivity') + ax[0].set_axisbelow(True) + ax[0].set_xlim(left=0,right=max(self.sensis_total)+0.1) + ax[0].grid(b=True, which='major') + ax[0].grid(b=True, which='minor') + formatted_sensis = [round(elem, 3) for elem in self.sensis_total] + for i, v in enumerate(formatted_sensis): + ax[0].text(v+0.001, i-0.055, " "+str(v), color='black', va='center',fontweight='bold') + ax[0].barh(y_pos, self.sensis_total, width, align='center', color='lightslategrey') + ax[1].set_title('Absolute Left / Right Sensitivity') + ax[1].set_yticks(y_pos) + ax[1].set_yticklabels(self.global_bounds_DataArray['fuzzy_variable'].values) + ax[1].invert_yaxis() # labels read top-to-bottom + ax[1].set_ylabel('Variables') + ax[1].set_xlabel('Relative Partial Sensitivity') + ax[1].set_axisbelow(True) + ax[1].set_xlim(0,max(max(self.sensis_l),max(self.sensis_r))+0.1) + ax[1].grid(b=True, which='major') + ax[1].grid(b=True, which='minor') + formatted_sensis_l = [round(elem, 3) for elem in self.sensis_l] + formatted_sensis_r = [round(elem, 3) for elem in self.sensis_r] + for (i_l, v_l),(i_r, v_r) in zip(enumerate(formatted_sensis_l),enumerate(formatted_sensis_r)): + ax[1].text(v_l+0.001, i_l-0.5*width2-0.055, " "+str(v_l), color='black', va='center',fontweight='bold') + ax[1].text(v_r+0.001, i_r+0.5*width2+0.055, " "+str(v_r), color='black', va='center',fontweight='bold') + ax[1].barh(y_pos-0.5*width2, self.sensis_l, width2, color='SkyBlue', label='Left') + ax[1].barh(y_pos+0.5*width2, self.sensis_r, width2, color='IndianRed', label='Right') + ax[1].legend(fancybox=True, framealpha=0.5) + + + if plot: plt.show() + return fig, ax + + + def _sensitivity_rotuine(self, alpha_Level=None, progressbar_disable = False, lsa=None, leave=False, **kwargs): res_total = [] res_l = [] res_r = [] - name_list = [] s_sum = 0 l_sum = 0 r_sum = 0 if alpha_Level is not None: - self.fuzzy_variables_dict = self._prepare_fuzzy_variables(alpha_Level=alpha_Level, **kwargs) + self.fuzzy_variables_dict= self._change_alpha_level(alpha_Level=alpha_Level) + self.global_bounds_DataArray = Alpha_Level_Optimization._boundary_constraints(self.fuzzy_var_list) + self.number_of_alpha_lvl = self.global_bounds_DataArray['number_of_alpha_levels'].size - index = np.arange(len(self.fuzzy_variables_dict)) + index = np.arange(len(self.global_bounds_DataArray)) - with tqdm(total=len(index),desc='Sensitivity Analysis',leave=leave) as pbar_loc: - for (var_i, values_i) in self.fuzzy_variables_dict.items(): - fvars = {} - name_list.append(var_i) - for (_, j) , (var_j, values_j) in zip(enumerate(index),self.fuzzy_variables_dict.items()): - if var_i == var_j: - fvars[var_j]=self.input_dict[var_i] + with tqdm(total=len(index), desc='Sensitivity Analysis', disable = progressbar_disable, leave=leave) as pbar_loc: + + for i in range(len(index)): + name_i = self.global_bounds_DataArray['fuzzy_variable'].values[i] + df_i = self.global_bounds_DataArray.data[i] + fuzzy_var_list_new = [] + names_new = [] + + for j in range(len(index)): + name_j = self.global_bounds_DataArray['fuzzy_variable'].values[j] + df_j = self.global_bounds_DataArray.data[j] + + if name_i == name_j: + fuzzy_var_list_new.append(self.fuzzy_var_list[i]) + names_new.append(name_i) else: if lsa is None: - y = phuzzy.Uniform(alpha0=[values_j['l'].iloc[0], values_j['r'].iloc[0]], + y = phuzzy.Uniform(alpha0=[df_j[0][1], df_j[0][2]], number_of_alpha_levels=self.number_of_alpha_lvl) else: y = phuzzy.Uniform(alpha0=[lsa[j],lsa[j]], number_of_alpha_levels=self.number_of_alpha_lvl) - fvars[var_j]=y + fuzzy_var_list_new.append(y) + + #names_new.append(name_j) + #kwargs = {**self.input_dict , **fvars} + #kwargs = {self.input_dict ,fvars} - kwargs = {**self.input_dict , **fvars} + kwargs['fuzzy_variables'] = fuzzy_var_list_new - z = alphaOpt.Alpha_Level_Optimization(**kwargs) - z.calculation(n=30,iters=2,progressbar_disable=True) + z = Alpha_Level_Optimization(**kwargs) + z.main(n=self.n,iters=self.iters, progressbar_disable=True, backup=False) E = 1. - (z.df['r']-z.df['l'])/(z.df['r'].iloc[0]-z.df['l'].iloc[0]) full_length = abs(z.df['r']-z.df['l']) E_l = abs(((z.df['l'].iloc[-1]-z.df['l'])/full_length)/(len(z.df)-1)) E_r = abs(((z.df['r']-z.df['r'].iloc[-1])/full_length)/(len(z.df)-1)) - z.plot() - - #del z sensi_i = sum(E) sensi_l = sum(E_l) sensi_r = sum(E_r) @@ -270,14 +256,15 @@ def lcefa_calculation(self, alpha_Level=None, lsa=None, leave=False, **kwargs): sensis_r.append(sensis_r_j) - """ - for i, z in enumerate(res_total): - sensi_j = z / s_sum - sensis_total.append(sensi_j) - """ + return sensis_total, sensis_l, sensis_r - return name_list, sensis_total, sensis_l, sensis_r + def _change_alpha_level(self, alpha_Level): + input_fuzzy_var_list = self.fuzzy_var_list + for i, fuzzy_var in enumerate(self.fuzzy_var_list): + fuzzy_var.convert_df(alpha_levels=alpha_Level) + input_fuzzy_var_list[i] = fuzzy_var + return input_fuzzy_var_list if __name__ == "__main__": diff --git a/phuzzy/shapes/__init__.py b/phuzzy/shapes/__init__.py index 3d65651..4d82a9c 100644 --- a/phuzzy/shapes/__init__.py +++ b/phuzzy/shapes/__init__.py @@ -816,6 +816,7 @@ def get_alpha_from_value(self, x): shape = self.get_shape() return np.interp(x, shape.x, shape.alpha) + class Triangle(FuzzyNumber): """triange fuzzy number""" @@ -907,7 +908,7 @@ def cdf(self, x, **kwargs): def to_str(self): if len(self.df) > 0: - return "tri[{:.3g}, {:.3g}, {:.3g}]".format(self.df.iloc[0].l, self.df.iloc[0].r, self.df.iloc[-1].l) + return "tri[{:.5g}, {:.5g}, {:.5g}]".format(self.df.iloc[0].l, self.df.iloc[0].r, self.df.iloc[-1].l) else: return "tri[nan, nan, nan]" @@ -985,7 +986,7 @@ def cdf(self, x, **kwargs): def to_str(self): if len(self.df) > 0: - return "trap[{:.3g}, {:.3g}, {:.3g}, {:.3g}]".format(self.df.iloc[0].l, self.df.iloc[0].r, + return "trap[{:.5g}, {:.5g}, {:.5g}, {:.5g}]".format(self.df.iloc[0].l, self.df.iloc[0].r, self.df.iloc[-1].l, self.df.iloc[-1].r) else: return "trap[nan, nan, nan, nan]" @@ -1045,7 +1046,7 @@ def cdf(self, x, **kwargs): return np.select(condlist, choicelist) def to_str(self): - return "Uniform[{:.4g},{:.4g}]".format(self.alpha0.l, self.alpha0.r) + return "Uniform[{:.5g},{:.5g}]".format(self.alpha0.l, self.alpha0.r) # @classmethod # def from_str(cls, s): diff --git a/phuzzy/shapes/superellipse.py b/phuzzy/shapes/superellipse.py index 8f902b5..b709948 100644 --- a/phuzzy/shapes/superellipse.py +++ b/phuzzy/shapes/superellipse.py @@ -14,7 +14,6 @@ """ - from phuzzy.shapes import FuzzyNumber import numpy as np import pandas as pd