├── pyDecision ├── __init__.py ├── util │ └── __init__.py ├── compare │ └── __init__.py └── algorithm │ ├── psi_m.py │ ├── rsw.py │ ├── entropy.py │ ├── roc.py │ ├── rrw.py │ ├── bwm_s.py │ ├── critic.py │ ├── merec.py │ ├── cilos.py │ ├── ahp.py │ ├── fuzzy_ahp.py │ ├── fuzzy_merec.py │ ├── seca.py │ ├── saw.py │ ├── borda.py │ ├── piv.py │ ├── spotis.py │ ├── psi.py │ ├── anp.py │ ├── fucom.py │ ├── idocriw.py │ ├── smart.py │ ├── cradis.py │ ├── macbeth.py │ ├── fuzzy_critic.py │ ├── rov.py │ ├── copras.py │ ├── ocra.py │ ├── gra.py │ ├── moora.py │ ├── moosra.py │ ├── oreste.py │ ├── bwm.py │ ├── mairca.py │ ├── aras.py │ ├── topsis.py │ ├── wings.py │ ├── mara.py │ ├── mabac.py │ ├── edas.py │ ├── codas.py │ ├── cocoso.py │ ├── copeland.py │ ├── todim.py │ ├── fuzzy_ahp_ppf.py │ ├── marcos.py │ ├── dematel.py │ ├── wisp.py │ ├── rafsi.py │ ├── fuzzy_aras.py │ ├── e_tri_nb.py │ ├── fuzzy_moora.py │ ├── vikor.py │ ├── lmaw.py │ ├── __init__.py │ ├── e_tri_c.py │ ├── maut.py │ ├── fuzzy_dematel.py │ ├── fuzzy_ocra.py │ ├── waspas.py │ ├── fuzzy_topsis.py │ ├── e_tri_nc.py │ ├── fuzzy_copras.py │ ├── p_iv.py │ ├── multimoora.py │ ├── fuzzy_edas.py │ ├── opa.py │ ├── fuzzy_waspas.py │ ├── regime.py │ ├── fuzzy_fucom.py │ └── fuzzy_bwm.py ├── LICENSE └── setup.py /pyDecision/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pyDecision/util/__init__.py: -------------------------------------------------------------------------------- 1 | from .ga import genetic_algorithm 2 | from .LLM import ask_chatgpt_corr, ask_chatgpt_rank, ask_chatgpt_weights 3 | -------------------------------------------------------------------------------- /pyDecision/compare/__init__.py: -------------------------------------------------------------------------------- 1 | from .compare import compare_ranks_crisp, compare_ranks_fuzzy, compare_weights, compare_weights_fuzzy, plot_rank_freq, corr_viz 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2022 by Valdecy Pereira 2 | 3 | pyDecision is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | pyDecision is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with pyDecision. If not, see . 15 | -------------------------------------------------------------------------------- /pyDecision/algorithm/psi_m.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: MPSI (Modified Preference Selection Index) 9 | def mpsi_method(dataset, criterion_type): 10 | X = np.copy(dataset)/1.0 11 | for j in range(0, X.shape[1]): 12 | if (criterion_type[j] == 'max'): 13 | X[:,j] = X[:,j] / np.max(X[:,j]) 14 | else: 15 | X[:,j] = np.min(X[:,j]) / X[:,j] 16 | R = np.mean(X, axis = 0) 17 | Z = np.sum((X - R)**2, axis = 0) 18 | I = Z/np.sum(Z) 19 | return I 20 | 21 | ############################################################################### -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from pathlib import Path 3 | 4 | this_directory = Path(__file__).parent 5 | long_description = (this_directory / 'README.md').read_text() 6 | 7 | setup( 8 | name='pydecision', 9 | version='4.8.8', 10 | license='GNU', 11 | author='Valdecy Pereira', 12 | author_email='valdecy.pereira@gmail.com', 13 | url='https://github.com/Valdecy/pyDecisions', 14 | packages=find_packages(), 15 | install_requires=[ 16 | 'llmx', 17 | 'matplotlib', 18 | 'numpy', 19 | 'openai', 20 | 'pandas', 21 | 'scikit-learn', 22 | 'scipy' 23 | ], 24 | description='A MCDA Library Incorporating a Large Language Model to Enhance Decision Analysis', 25 | long_description=long_description, 26 | long_description_content_type='text/markdown', 27 | ) 28 | -------------------------------------------------------------------------------- /pyDecision/algorithm/rsw.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import re 6 | 7 | ############################################################################### 8 | 9 | # Function: RSW (Rank Summed Weight) 10 | def rsw_method(criteria_rank): 11 | 12 | ################################################ 13 | 14 | def extract_number(text): 15 | match = re.search(r'\d+', text) 16 | return int(match.group()) if match else None 17 | 18 | ################################################ 19 | 20 | N = len(criteria_rank) 21 | x = np.zeros(N) 22 | for i in range(0, x.shape[0]): 23 | x[i] = ( 2 * (N - (i+1) + 1) ) / ( N * (N + 1) ) 24 | x = x/np.sum(x) 25 | idx = sorted(range(0, len(criteria_rank)), key = lambda x: extract_number(criteria_rank[x])) 26 | x = x[idx] 27 | return x 28 | 29 | ############################################################################### 30 | -------------------------------------------------------------------------------- /pyDecision/algorithm/entropy.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import itertools 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Entropy 10 | def entropy_method(dataset, criterion_type): 11 | X = np.copy(dataset)/1.0 12 | for j in range(0, X.shape[1]): 13 | if (criterion_type[j] == 'max'): 14 | X[:,j] = X[:,j] / np.sum(X[:,j]) 15 | else: 16 | X[:,j] = (1 / (X[:,j] + 1e-9)) / np.sum(1 / (X[:,j] + 1e-9)) 17 | X = np.abs(X) 18 | H = np.zeros((X.shape)) 19 | for j, i in itertools.product(range(H.shape[1]), range(H.shape[0])): 20 | if (X[i, j]): 21 | H[i, j] = X[i, j] * np.log(X[i, j] + 1e-9) 22 | h = np.sum(H, axis = 0) * (-1 * ((np.log(H.shape[0] + 1e-9)) ** (-1))) 23 | d = 1 - h 24 | d = d + 1e-9 25 | w = d / (np.sum(d)) 26 | return w 27 | 28 | ############################################################################### 29 | -------------------------------------------------------------------------------- /pyDecision/algorithm/roc.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import re 6 | 7 | ############################################################################### 8 | 9 | # Function: ROC (Rank Ordered Centroid) 10 | def roc_method(criteria_rank): 11 | 12 | ################################################ 13 | 14 | def extract_number(text): 15 | match = re.search(r'\d+', text) 16 | return int(match.group()) if match else None 17 | 18 | ################################################ 19 | 20 | x = np.zeros(len(criteria_rank)) 21 | for i in range(0, x.shape[0]): 22 | for j in range(i, x.shape[0]): 23 | x[i] = x[i] + 1/(j+1) 24 | x = x/len(criteria_rank) 25 | x = x/np.sum(x) 26 | idx = sorted(range(0, len(criteria_rank)), key = lambda x: extract_number(criteria_rank[x])) 27 | x = x[idx] 28 | return x 29 | 30 | ############################################################################### 31 | -------------------------------------------------------------------------------- /pyDecision/algorithm/rrw.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import re 6 | 7 | ############################################################################### 8 | 9 | # Function: RRW (Rank Reciprocal Weighting) 10 | def rrw_method(criteria_rank): 11 | 12 | ################################################ 13 | 14 | def extract_number(text): 15 | match = re.search(r'\d+', text) 16 | return int(match.group()) if match else None 17 | 18 | ################################################ 19 | 20 | S = 0 21 | x = np.zeros(len(criteria_rank)) 22 | for i in range(0, x.shape[0]): 23 | S = S + 1/(i+1) 24 | for i in range(0, x.shape[0]): 25 | x[i] = 1 / ( (i+1) * S) 26 | x = x/np.sum(x) 27 | idx = sorted(range(0, len(criteria_rank)), key = lambda x: extract_number(criteria_rank[x])) 28 | x = x[idx] 29 | return x 30 | 31 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/bwm_s.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Simplified BWM 9 | def simplified_bw_method(mic, lic, alpha = 0.5,verbose = True): 10 | ib = np.argmin(mic) 11 | iw = np.argmin(lic) 12 | wb = [ 1 for item in mic] 13 | ww = [ 1 for item in lic] 14 | div = 0 15 | for i in range(0, mic.shape[0]): 16 | a = mic[i] 17 | div = div + 1/a 18 | wb[ib] = 1/div 19 | for i in range(0, mic.shape[0]): 20 | if (i != ib): 21 | wb[i] = wb[ib]/mic[i] 22 | ww[iw] = 1/np.sum(lic) 23 | for i in range(0, lic.shape[0]): 24 | if (i != iw): 25 | ww[i] = lic[i]*ww[iw] 26 | w = [alpha*wb[i] + (1 - alpha)*ww[i] for i in range(0, mic.shape[0])] 27 | cr = sum([abs(wb[i] - ww[i]) for i in range(0, mic.shape[0])]) 28 | if (verbose == True): 29 | print('CR:', np.round(cr, 4)) 30 | return cr, w 31 | 32 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/critic.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: CRITIC (CRiteria Importance Through Intercriteria Correlation) 9 | def critic_method(dataset, criterion_type): 10 | X = np.copy(dataset)/1.0 11 | best = np.zeros(X.shape[1]) 12 | worst = np.zeros(X.shape[1]) 13 | for i in range(0, dataset.shape[1]): 14 | if (criterion_type[i] == 'max'): 15 | best[i] = np.max(X[:, i]) 16 | worst[i] = np.min(X[:, i]) 17 | else: 18 | best[i] = np.min(X[:, i]) 19 | worst[i] = np.max(X[:, i]) 20 | for j in range(0, X.shape[1]): 21 | X[:,j] = ( X[:,j] - worst[j] ) / ( best[j] - worst[j] + 1e-10) 22 | std = (np.sum((X - X.mean(axis = 0))**2, axis = 0)/(X.shape[0] - 1))**(1/2) 23 | sim_mat = np.corrcoef(X.T) 24 | sim_mat = np.nan_to_num(sim_mat) 25 | conflict = np.sum(1 - sim_mat, axis = 1) 26 | infor = std*conflict 27 | weights = infor/np.sum(infor) 28 | return weights 29 | 30 | ############################################################################### 31 | -------------------------------------------------------------------------------- /pyDecision/algorithm/merec.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: MEREC (MEthod based on the Removal Effects of Criteria) 9 | def merec_method(dataset, criterion_type): 10 | X = np.copy(dataset)/1.0 11 | for j in range(0, X.shape[1]): 12 | if (criterion_type[j] == 'max'): 13 | divisor = np.min(X[:,j]) 14 | if (divisor == 0): 15 | divisor = 1e-9 16 | X[:,j] = divisor / (X[:,j] + 1e-9) 17 | else: 18 | divisor = np.max(X[:,j]) 19 | if (divisor == 0): 20 | divisor = 1e-9 21 | X[:,j] = X[:,j] / (divisor + 1e-9) 22 | S = np.log(1 + (1/X.shape[1] * np.sum(np.abs(np.log(X)), axis = 1))) 23 | R = np.zeros(X.shape) 24 | for j in range(0, X.shape[1]): 25 | Z = np.delete(X, j, axis = 1) 26 | R[:, j] = np.log(1 + (1/X.shape[1] * np.sum(np.abs(np.log(Z)), axis = 1))) 27 | E = np.sum(np.abs(R.T - S), axis = 1) 28 | E = E / np.sum(E) 29 | return E 30 | 31 | ############################################################################### 32 | -------------------------------------------------------------------------------- /pyDecision/algorithm/cilos.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | from scipy.linalg import null_space 7 | 8 | ############################################################################### 9 | 10 | # Function: CILOS (Criterion Impact LOSs) 11 | def cilos_method(dataset, criterion_type): 12 | X = np.copy(dataset)/1.0 13 | for j in range(X.shape[1]): 14 | divisor = np.min(X[:, j]) if criterion_type[j] == 'max' else np.max(X[:, j]) 15 | if (divisor == 0): 16 | X[:, j] = 1e-9 17 | else: 18 | X[:, j] = X[:, j] / divisor 19 | sum_X_j = np.sum(X[:, j]) 20 | if (sum_X_j == 0): 21 | X[:, j] = 1e-9 22 | else: 23 | X[:, j] = X[:, j] / sum_X_j 24 | for j in range(X.shape[1]): 25 | unique_vals = np.unique(X[:, j]) 26 | if (len(unique_vals) == 1): 27 | X[:, j] = X[:, j] + np.random.uniform(low=1e-2, high=1e-1, size=X[:, j].shape) 28 | A = X[np.argmax(X, axis = 0)] 29 | P = (np.diag(A) - A) / np.diag(A) 30 | F = P - np.diag(np.sum(P, axis = 0)) 31 | q = null_space(F) 32 | q = (q / np.sum(q)).flatten() 33 | return q 34 | 35 | ############################################################################### 36 | -------------------------------------------------------------------------------- /pyDecision/algorithm/ahp.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | from functools import reduce 6 | 7 | ############################################################################### 8 | 9 | # Function: AHP 10 | def ahp_method(dataset, wd = 'm'): 11 | inc_rat = np.array([0, 0, 0, 0.58, 0.9, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49, 1.51, 1.48, 1.56, 1.57, 1.59]) 12 | X = np.copy(dataset) 13 | weights = np.zeros(X.shape[1]) 14 | if (wd == 'm' or wd == 'mean'): 15 | weights = np.mean(X/np.sum(X, axis = 0), axis = 1) 16 | vector = np.sum(X*weights, axis = 1)/weights 17 | lamb_max = np.mean(vector) 18 | elif (wd == 'g' or wd == 'geometric'): 19 | for i in range (0, X.shape[1]): 20 | weights[i] = reduce( (lambda x, y: x * y), X[i,:])**(1/X.shape[1]) 21 | weights = weights/np.sum(weights) 22 | vector = np.sum(X*weights, axis = 1)/weights 23 | lamb_max = np.mean(vector) 24 | elif (wd == 'me' or wd == 'max_eigen'): 25 | eigenvalues, eigenvectors = np.linalg.eig(X) 26 | eigenvalues_real = np.real(eigenvalues) 27 | lamb_max_index = np.argmax(eigenvalues_real) 28 | lamb_max = eigenvalues_real[lamb_max_index] 29 | principal_eigenvector = np.real(eigenvectors[:, lamb_max_index]) 30 | weights = principal_eigenvector / principal_eigenvector.sum() 31 | cons_ind = (lamb_max - X.shape[1])/(X.shape[1] - 1) 32 | rc = cons_ind/inc_rat[X.shape[1]] 33 | return weights, rc 34 | 35 | ############################################################################### 36 | -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_ahp.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Fuzzy AHP 9 | def fuzzy_ahp_method(dataset): 10 | row_sum = [] 11 | s_row = [] 12 | f_w = [] 13 | d_w = [] 14 | inc_rat = np.array([0, 0, 0, 0.58, 0.9, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49, 1.51, 1.48, 1.56, 1.57, 1.59]) 15 | X = [(item[0] + 4*item[1] + item[2])/6 for i in range(0, len(dataset)) for item in dataset[i] ] 16 | X = np.asarray(X) 17 | X = np.reshape(X, (len(dataset), len(dataset))) 18 | for i in range(0, len(dataset)): 19 | a, b, c = 1, 1, 1 20 | for j in range(0, len(dataset[i])): 21 | d, e, f = dataset[i][j] 22 | a, b, c = a*d, b*e, c*f 23 | row_sum.append( (a, b, c) ) 24 | L, M, U = 0, 0, 0 25 | for i in range(0, len(row_sum)): 26 | a, b, c = row_sum[i] 27 | a, b, c = a**(1/len(dataset)), b**(1/len(dataset)), c**(1/len(dataset)) 28 | s_row.append( ( a, b, c ) ) 29 | L = L + a 30 | M = M + b 31 | U = U + c 32 | for i in range(0, len(s_row)): 33 | a, b, c = s_row[i] 34 | a, b, c = a*(U**-1), b*(M**-1), c*(L**-1) 35 | f_w.append( ( a, b, c ) ) 36 | d_w.append( (a + b + c)/3 ) 37 | n_w = [item/sum(d_w) for item in d_w] 38 | vector = np.sum(X*n_w, axis = 1)/n_w 39 | lamb_max = np.mean(vector) 40 | cons_ind = (lamb_max - X.shape[1])/(X.shape[1] - 1) 41 | rc = cons_ind/inc_rat[X.shape[1]] 42 | return f_w, d_w, n_w, rc 43 | 44 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_merec.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Fuzzy MEREC (Fuzzy MEthod based on the Removal Effects of Criteria) 9 | def fuzzy_merec_method(dataset, criterion_type): 10 | X_a = np.zeros((len(dataset), len(dataset[0]))) 11 | X_b = np.zeros((len(dataset), len(dataset[0]))) 12 | X_c = np.zeros((len(dataset), len(dataset[0]))) 13 | X = np.zeros((len(dataset), len(dataset[0]))) 14 | S_ = np.zeros((len(dataset), len(dataset[0]))) 15 | for j in range(0, X_a.shape[1]): 16 | for i in range(0, X_a.shape[0]): 17 | a, b, c = dataset[i][j] 18 | X_a[i,j] = a 19 | X_b[i,j] = b 20 | X_c[i,j] = c 21 | for j in range(0, X_a.shape[1]): 22 | if (criterion_type[j] == 'max'): 23 | X_a[:, j] = X_a[:, j] / np.max(X_c[:, j]) 24 | X_b[:, j] = X_b[:, j] / np.max(X_c[:, j]) 25 | X_c[:, j] = X_c[:, j] / np.max(X_c[:, j]) 26 | else: 27 | X_a[:, j] = np.min(X_a[:, j]) / X_a[:, j] 28 | X_b[:, j] = np.min(X_a[:, j]) / X_b[:, j] 29 | X_c[:, j] = np.min(X_a[:, j]) / X_c[:, j] 30 | for i in range(0, X.shape[0]): 31 | for j in range(0, X.shape[1]): 32 | X[i,j] = (X_a[i,j] + 4*X_b[i,j] + X_c[i,j])/6 33 | S = (1/X.shape[1]) * np.sum(np.log(1 - X), axis = 1) 34 | for j in range(0, X.shape[1]): 35 | idx = [item for item in list(range(0, X.shape[1])) if item != j] 36 | S_[:, j] = (1/X.shape[1]) * np.sum(np.log(1 - X[:,idx]), axis = 1) 37 | D = np.sum(abs(S_ - S.reshape(-1,1)), axis = 0) 38 | D = D/np.sum(D) 39 | return D 40 | 41 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/seca.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import warnings 6 | warnings.filterwarnings('ignore', message = 'delta_grad == 0.0. Check if the approximated') 7 | warnings.filterwarnings('ignore', message = 'Values in x were outside bounds during a minimize step, clipping to bounds') 8 | 9 | from scipy.optimize import minimize, Bounds, LinearConstraint 10 | 11 | ############################################################################### 12 | 13 | 14 | # Function: SECA (Simultaneous Evaluation of Criteria and Alternatives) 15 | def seca_method(dataset, criterion_type, beta = 3): 16 | X = np.copy(dataset)/1.0 17 | N = X.shape[1] 18 | for j in range(0, N): 19 | if (criterion_type[j] == 'max'): 20 | X[:,j] = np.min(X[:,j]) / X[:,j] 21 | else: 22 | X[:,j] = X[:,j] / np.max(X[:,j]) 23 | std = (np.sum((X - X.mean())**2, axis = 0)/(X.shape[0] - 1))**(1/2) 24 | std = std/np.sum(std) 25 | sim_mat = np.corrcoef(X.T) 26 | sim_mat = np.sum(1 - sim_mat, axis = 1) 27 | sim_mat = sim_mat/np.sum(sim_mat) 28 | 29 | ################################################ 30 | 31 | def target_function(variables): 32 | Lmb_a = np.min(np.sum(X * variables, axis = 0)) 33 | Lmb_b = np.sum((variables - std)**2, axis = 0) 34 | Lmb_c = np.sum((variables - sim_mat)**2, axis = 0) 35 | Lmb = Lmb_a - beta*(Lmb_b + Lmb_c) 36 | return -Lmb 37 | 38 | ################################################ 39 | 40 | np.random.seed(42) 41 | variables = np.random.uniform(low = 0.001, high = 1.0, size = N) 42 | variables = variables / np.sum(variables) 43 | bounds = Bounds(0.0001, 1.0) 44 | constraints = LinearConstraint(np.ones(N), 1, 1) 45 | results = minimize(target_function, variables, method = 'SLSQP', constraints = constraints, bounds = bounds) 46 | weights = results.x 47 | return weights 48 | 49 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/saw.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | ############################################################################### 9 | 10 | # Function: Rank 11 | def ranking(flow): 12 | rank_xy = np.zeros((flow.shape[0], 2)) 13 | for i in range(0, rank_xy.shape[0]): 14 | rank_xy[i, 0] = 0 15 | rank_xy[i, 1] = flow.shape[0]-i 16 | for i in range(0, rank_xy.shape[0]): 17 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 18 | for i in range(0, rank_xy.shape[0]-1): 19 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 20 | axes = plt.gca() 21 | axes.set_xlim([-1, +1]) 22 | ymin = np.amin(rank_xy[:,1]) 23 | ymax = np.amax(rank_xy[:,1]) 24 | if (ymin < ymax): 25 | axes.set_ylim([ymin, ymax]) 26 | else: 27 | axes.set_ylim([ymin-1, ymax+1]) 28 | plt.axis('off') 29 | plt.show() 30 | return 31 | 32 | # Function: SAW 33 | def saw_method(dataset, criterion_type, weights, graph = True, verbose = True): 34 | X = np.copy(dataset)/1.0 35 | for i in range(0, X.shape[1]): 36 | if ( criterion_type[i] == 'max'): 37 | X[:,i] = (X[:,i] / np.max(X[:,i]))*weights[i] 38 | else: 39 | X[:,i] = (np.min(X[:,i]) / X[:,i])*weights[i] 40 | Y = np.sum(X, axis = 1) 41 | flow = np.copy(Y) 42 | flow = np.reshape(flow, (Y.shape[0], 1)) 43 | flow = np.insert(flow, 0, list(range(1, Y.shape[0]+1)), axis = 1) 44 | if (verbose == True): 45 | for i in range(0, flow.shape[0]): 46 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 47 | if (graph == True): 48 | flow = flow[np.argsort(flow[:, 1])] 49 | flow = flow[::-1] 50 | ranking(flow) 51 | return flow 52 | 53 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/borda.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: Borda 32 | def borda_method(dataset, criterion_type, graph = True, verbose = True): 33 | X = np.zeros((dataset.shape[0], dataset.shape[1])) 34 | for j in range(0, dataset.shape[1]): 35 | if (criterion_type[j] == 'max'): 36 | X[:,j] = np.argsort(np.argsort(-dataset[:,j]))+1 37 | else: 38 | X[:,j] = np.argsort(np.argsort(dataset[:,j]))+1 39 | total = np.sum(X, axis = 1) 40 | if (verbose == True): 41 | for i in range(0, total.shape[0]): 42 | print('a' + str(i+1) + ': ' + str(round(total[i], 2))) 43 | if ( graph == True): 44 | flow = np.copy(total) 45 | flow = np.reshape(flow, (total.shape[0], 1)) 46 | flow = np.insert(flow, 0, list(range(1, total.shape[0]+1)), axis = 1) 47 | flow = flow[np.argsort(flow[:, 1])] 48 | ranking(flow) 49 | return total 50 | 51 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/piv.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: PIV (Proximity Indexed Value) 32 | def piv_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | for j in range(0, X.shape[1]): 35 | X[:,j] = (X[:,j] / (np.sum(X[:,j]**2))**(1/2))*weights[j] 36 | for j in range(0, X.shape[1]): 37 | if (criterion_type[j] == 'max'): 38 | X[:,j] = np.max(X[:,j]) - X[:,j] 39 | else: 40 | X[:,j] = X[:,j] - np.min(X[:,j]) 41 | D = np.sum(X, axis = 1) 42 | if (verbose == True): 43 | for i in range(0, D.shape[0]): 44 | print('a' + str(i+1) + ': ' + str(round(D[i], 2))) 45 | if ( graph == True): 46 | flow = np.copy(D) 47 | flow = np.reshape(flow, (D.shape[0], 1)) 48 | flow = np.insert(flow, 0, list(range(1, D.shape[0]+1)), axis = 1) 49 | flow = flow[np.argsort(flow[:, 1])] 50 | ranking(flow) 51 | return D 52 | 53 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/spotis.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: SPOTIS (Stable Preference Ordering Towards Ideal Solution) 32 | def spotis_method(dataset, criterion_type, weights, s_min,s_max, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | S = np.zeros(X.shape[1]) 35 | for j in range(0, X.shape[1]): 36 | if (criterion_type[j] == 'max'): 37 | S[j] = s_max[j] 38 | else: 39 | S[j] = s_min[j] 40 | X = abs(X - S) / abs(np.array(s_max) - np.array(s_min) + 0.0000000000000001) 41 | X = X * weights 42 | D = np.sum(X, axis = 1) 43 | if (verbose == True): 44 | for i in range(0, D.shape[0]): 45 | print('a' + str(i+1) + ': ' + str(round(D[i], 2))) 46 | if ( graph == True): 47 | flow = np.copy(D) 48 | flow = np.reshape(flow, (D.shape[0], 1)) 49 | flow = np.insert(flow, 0, list(range(1, D.shape[0]+1)), axis = 1) 50 | flow = flow[np.argsort(flow[:, 1])] 51 | ranking(flow) 52 | return D 53 | 54 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/psi.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: PSI (Preference Selection Index) 32 | def psi_method(dataset, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | for j in range(0, X.shape[1]): 35 | if (criterion_type[j] == 'max'): 36 | X[:,j] = X[:,j] / np.max(X[:,j]) 37 | else: 38 | X[:,j] = np.min(X[:,j]) / X[:,j] 39 | R = np.mean(X, axis = 0) 40 | Z = (X - R)**2 41 | PV = np.sum(Z, axis = 0) 42 | T = 1 - PV 43 | P = T/np.sum(T) 44 | I = np.sum(X * P, axis = 1) 45 | if (verbose == True): 46 | for i in range(0, I.shape[0]): 47 | print('a' + str(i+1) + ': ' + str(round(I[i], 2))) 48 | if ( graph == True): 49 | flow = np.copy(I) 50 | flow = np.reshape(flow, (I.shape[0], 1)) 51 | flow = np.insert(flow, 0, list(range(1, I.shape[0]+1)), axis = 1) 52 | flow = flow[np.argsort(flow[:, 1])] 53 | flow = flow[::-1] 54 | ranking(flow) 55 | return I 56 | 57 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/anp.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Normalization 9 | def normalize_matrix(W, zero_column_policy = "keep"): 10 | W = np.array(W, dtype = float) 11 | col_sums = W.sum(axis = 0) 12 | W_norm = W.copy() 13 | n_rows, _ = W.shape 14 | nonzero_mask = col_sums != 0 15 | zero_mask = ~nonzero_mask 16 | W_norm[:, nonzero_mask] = W_norm[:, nonzero_mask] / col_sums[nonzero_mask] 17 | if np.any(zero_mask): 18 | if zero_column_policy == "uniform": 19 | W_norm[:, zero_mask] = 1.0 / n_rows 20 | return W_norm 21 | 22 | ############################################################################### 23 | 24 | # Function: ANP 25 | def anp_method(W, max_iter = 100, tol = 1e-12, cesaro = True): 26 | W = np.array(W, dtype = float) 27 | W = normalize_matrix(W, zero_column_policy = "keep") 28 | rows, cols = W.shape 29 | if rows != cols: 30 | raise ValueError(f"Input matrix must be square. Got {rows}x{cols}.") 31 | if (cesaro == True): 32 | W_power = W.copy() 33 | cumulative_sum = W.copy() 34 | current_mean = W.copy() 35 | for k in range(2, max_iter + 1): 36 | W_power = W_power @ W 37 | cumulative_sum = cumulative_sum + W_power 38 | new_mean = cumulative_sum / k 39 | if np.allclose(new_mean, current_mean, atol = tol): 40 | L = new_mean.copy() 41 | L[np.abs(L) < tol] = 0.0 42 | print(f"Cesaro mean converged at iteration k = {k}") 43 | return L 44 | current_mean = new_mean 45 | L = current_mean.copy() 46 | L[np.abs(L) < tol] = 0.0 47 | else: 48 | M_prev = W.copy() 49 | L = W.copy() 50 | for k in range(0, max_iter): 51 | L = L @ W 52 | if np.allclose(L, M_prev, atol = tol): 53 | return L 54 | M_prev = L 55 | return L 56 | 57 | ############################################################################### 58 | -------------------------------------------------------------------------------- /pyDecision/algorithm/fucom.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import re 6 | import warnings 7 | warnings.filterwarnings('ignore', message = 'delta_grad == 0.0. Check if the approximated') 8 | warnings.filterwarnings('ignore', message = 'Values in x were outside bounds during a minimize step, clipping to bounds') 9 | 10 | from scipy.optimize import minimize, Bounds, LinearConstraint 11 | 12 | ############################################################################### 13 | 14 | # Function: FUCOM (Full Consistency Method) 15 | def fucom_method(criteria_rank, criteria_priority, sort_criteria = True, verbose = True): 16 | 17 | ################################################ 18 | 19 | def extract_number(text): 20 | match = re.search(r'\d+', text) 21 | return int(match.group()) if match else None 22 | 23 | def target_function(variables): 24 | variables = np.array(variables) 25 | ratios_1 = variables[:-1] / variables[1:] 26 | target_ratios_1 = np.array(criteria_priority[1:]) / np.array(criteria_priority[:-1]) 27 | chi_1 = np.abs(ratios_1 - target_ratios_1) 28 | ratios_2 = variables[:-2] / variables[2:] 29 | target_ratios_2 = np.array(criteria_priority[2:]) / np.array(criteria_priority[:-2]) 30 | chi_2 = np.abs(ratios_2 - target_ratios_2) 31 | chi = np.hstack((chi_1, chi_2)) 32 | return np.max(chi) 33 | 34 | ################################################ 35 | 36 | np.random.seed(42) 37 | variables = np.random.uniform(low = 0.001, high = 1.0, size = len(criteria_priority)) 38 | variables = variables / np.sum(variables) 39 | bounds = Bounds(0.0001, 1.0) 40 | constraints = LinearConstraint(np.ones(len(criteria_priority)), 1, 1) 41 | results = minimize(target_function, variables, method = 'SLSQP', constraints = constraints, bounds = bounds) 42 | weights = results.x 43 | if (sort_criteria == True): 44 | idx = sorted(range(0, len(criteria_rank)), key = lambda x: extract_number(criteria_rank[x])) 45 | weights = results.x[idx] 46 | if (verbose == True): 47 | print('Chi:', np.round(results.fun, 4)) 48 | return weights 49 | 50 | ############################################################################### 51 | -------------------------------------------------------------------------------- /pyDecision/algorithm/idocriw.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | from scipy.optimize import minimize, Bounds 7 | 8 | ############################################################################### 9 | 10 | # Function: IDOCRIW (Integrated Determination of Objective CRIteria Weights) 11 | def idocriw_method(dataset, criterion_type, verbose = True): 12 | X = np.copy(dataset)/1.0 13 | X = X/X.sum(axis = 0) 14 | X_ln = np.zeros(X.shape[1]) 15 | X_r = np.copy(dataset)/1.0 16 | for j in range(0, X.shape[1]): 17 | adj_col = np.where(X[:, j] == 0, 1e-9, X[:, j]) 18 | X_ln[j] = np.sum(adj_col * np.log(adj_col)) 19 | X_ln[j] = X_ln[j]*(-1/np.log(X.shape[1])) 20 | d = 1 - X_ln 21 | w = d/np.sum(d) 22 | for i in range(0, len(criterion_type)): 23 | if (criterion_type[i] == 'min'): 24 | X_r[:,i] = dataset[:,i].min() / X_r[:,i] 25 | X_r = X_r/X_r.sum(axis = 0) 26 | a_max = X_r.max(axis = 0) 27 | A = np.zeros((dataset.shape[1], dataset.shape[1])) 28 | np.fill_diagonal(A, a_max) 29 | for k in range(0, a_max.shape[0]): 30 | i, _ = np.where(X_r == a_max[k]) 31 | i = i[0] 32 | for j in range(0, A.shape[1]): 33 | A[k, j] = X_r[i, j] 34 | a_max_ = A.max(axis = 0) 35 | P = np.copy(A) 36 | for j in range(0, P.shape[1]): 37 | P[:,j] = (-P[:,j] + a_max_[j])/a_max[j] 38 | WP = np.copy(P) 39 | np.fill_diagonal(WP, -P.sum(axis = 0)) 40 | 41 | ################################################ 42 | def target_function(variables): 43 | WP_s = np.copy(WP) 44 | for i in range(0, WP.shape[0]): 45 | for j in range(0, WP.shape[1]): 46 | if (WP_s[i, j] != 0): 47 | WP_s[i, j] = WP_s[i, j]*variables[j] 48 | total = np.sum((WP_s.sum(axis = 1))) 49 | return total 50 | ################################################ 51 | 52 | variables = np.ones(WP.shape[1]) 53 | bounds = Bounds([0.0000001]*len(variables), [1]*len(variables)) 54 | results = minimize(target_function, variables, method = 'L-BFGS-B', bounds = bounds) 55 | weights = results.x 56 | weights = weights * w 57 | weights = weights / np.sum(weights) 58 | return weights 59 | 60 | ############################################################################### 61 | -------------------------------------------------------------------------------- /pyDecision/algorithm/smart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | ############################################################################### 9 | 10 | # Function: Rank 11 | def ranking(flow): 12 | rank_xy = np.zeros((flow.shape[0], 2)) 13 | for i in range(0, rank_xy.shape[0]): 14 | rank_xy[i, 0] = 0 15 | rank_xy[i, 1] = flow.shape[0]-i 16 | for i in range(0, rank_xy.shape[0]): 17 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 18 | for i in range(0, rank_xy.shape[0]-1): 19 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 20 | axes = plt.gca() 21 | axes.set_xlim([-1, +1]) 22 | ymin = np.amin(rank_xy[:,1]) 23 | ymax = np.amax(rank_xy[:,1]) 24 | if (ymin < ymax): 25 | axes.set_ylim([ymin, ymax]) 26 | else: 27 | axes.set_ylim([ymin-1, ymax+1]) 28 | plt.axis('off') 29 | plt.show() 30 | return 31 | 32 | # Function: SMART 33 | def smart_method(dataset, grades, lower, upper, criterion_type, graph = True, verbose = True): 34 | w = np.copy(grades)/1.0 35 | for i in range(0, w.shape[0]): 36 | w[i] = (2**(1/2))**w[i] 37 | w = w/np.sum(w) 38 | X = np.copy(dataset)/1.0 39 | for i in range(0, X.shape[1]): 40 | if ( criterion_type[i] == 'max'): 41 | X[:,i] = 4 + np.log2( ((dataset[:,i] - lower[i] ) / (upper[i] - lower[i]))*(64) ) 42 | else: 43 | X[:,i] = 10 - np.log2( ((dataset[:,i] - lower[i] ) / (upper[i] - lower[i]))*(64) ) 44 | Y = np.sum(X*w, axis = 1) 45 | flow = np.copy(Y) 46 | flow = np.reshape(flow, (Y.shape[0], 1)) 47 | flow = np.insert(flow, 0, list(range(1, Y.shape[0]+1)), axis = 1) 48 | if (verbose == True): 49 | for i in range(0, flow.shape[0]): 50 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 51 | if (graph == True): 52 | flow = flow[np.argsort(flow[:, 1])] 53 | flow = flow[::-1] 54 | ranking(flow) 55 | return flow 56 | 57 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/cradis.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: CRADIS (Compromise Ranking of Alternatives from Distance to Ideal Solution) 32 | def cradis_method(dataset, criterion_type, weights, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | for j in range(0, X.shape[1]): 35 | if (criterion_type[j] == 'max'): 36 | X[:,j] = np.min(X[:,j]) / X[:,j] 37 | else: 38 | X[:,j] = X[:,j] / np.max(X[:,j]) 39 | X = X * weights 40 | Sp = np.sum(np.max(X) - X, axis = 1) + 0.0000000000000001 41 | Sm = np.sum(X - np.min(X), axis = 1) 42 | Sop = np.sum(np.max(X) - np.max(X, axis = 0)) 43 | Som = np.sum(np.max(X, axis = 0) - np.min(X)) 44 | Kp = Sop / Sp 45 | Km = Sm / Som 46 | Q = (Kp + Km) / 2 47 | if (verbose == True): 48 | for i in range(0, Q.shape[0]): 49 | print('a' + str(i+1) + ': ' + str(round(Q[i], 2))) 50 | if ( graph == True): 51 | flow = np.copy(Q) 52 | flow = np.reshape(flow, (Q.shape[0], 1)) 53 | flow = np.insert(flow, 0, list(range(1, Q.shape[0]+1)), axis = 1) 54 | flow = flow[np.argsort(flow[:, 1])] 55 | ranking(flow) 56 | return Q 57 | 58 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/macbeth.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: MACBETH (Measuring Attractiveness by a Categorical Based Evaluation TecHnique) 32 | def macbeth_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | best = np.zeros(X.shape[1]) 35 | worst = np.zeros(X.shape[1]) 36 | for j in range(0, X.shape[1]): 37 | if (criterion_type[j] == 'max'): 38 | best[j] = np.max(X[:, j]) 39 | worst[j] = np.min(X[:, j]) 40 | else: 41 | best[j] = np.min(X[:, j]) 42 | worst[j] = np.max(X[:, j]) 43 | X = (X - worst) / (best - worst + 0.0000000000000001) 44 | X = X * weights 45 | V = np.sum(X, axis = 1) 46 | if (verbose == True): 47 | for i in range(0, V.shape[0]): 48 | print('a' + str(i+1) + ': ' + str(round(V[i], 2))) 49 | if ( graph == True): 50 | flow = np.copy(V) 51 | flow = np.reshape(flow, (V.shape[0], 1)) 52 | flow = np.insert(flow, 0, list(range(1, V.shape[0]+1)), axis = 1) 53 | flow = flow[np.argsort(flow[:, 1])] 54 | flow = flow[::-1] 55 | ranking(flow) 56 | return V 57 | 58 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_critic.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Fuzzy CRITIC (Fuzzy CRiteria Importance Through Intercriteria Correlation) 9 | def fuzzy_critic_method(dataset, criterion_type): 10 | X_a = np.array([[triplet[0] for triplet in row] for row in dataset]) 11 | X_b = np.array([[triplet[1] for triplet in row] for row in dataset]) 12 | X_c = np.array([[triplet[2] for triplet in row] for row in dataset]) 13 | min_a = X_a.min(axis = 0) 14 | min_b = X_b.min(axis = 0) 15 | min_c = X_c.min(axis = 0) 16 | max_a = X_a.max(axis = 0) 17 | max_b = X_b.max(axis = 0) 18 | max_c = X_c.max(axis = 0) 19 | R = np.zeros((X_a.shape)) 20 | for j in range(0, X_a.shape[1]): 21 | for i in range(0, X_a.shape[0]): 22 | if (criterion_type[j] == 'max'): 23 | p1 = (X_a[i, j]**2)*(min_a[j]**2) + (X_b[i, j]**2)*(min_b[j]**2) + (X_c[i, j]**2)*(min_c[j]**2) 24 | p2 = np.max((X_a[i, j]**4, min_a[j]**4)) + np.max((X_b[i, j]**4, min_b[j]**4)) + np.max((X_c[i, j]**4, min_c[j]**4)) 25 | p = p1/p2 26 | q1 = (max_a[j]**2)*(min_a[j]**2) + (max_b[j]**2)*(min_b[j]**2) + (max_c[j]**2)*(min_c[j]**2) 27 | q2 = np.max((max_a[j]**4, min_a[j]**4)) + np.max((max_b[j]**4, min_b[j]**4)) + np.max((max_c[j]**4, min_c[j]**4)) 28 | q = q1/q2 29 | R[i, j] = (1 - p)/(1 - q) 30 | else: 31 | p1 = (X_a[i, j]**2)*(max_a[j]**2) + (X_b[i, j]**2)*(max_b[j]**2) + (X_c[i, j]**2)*(max_c[j]**2) 32 | p2 = np.max((X_a[i, j]**4, max_a[j]**4)) + np.max((X_b[i, j]**4, max_b[j]**4)) + np.max((X_c[i, j]**4, max_c[j]**4)) 33 | p = p1/p2 34 | q1 = (max_a[j]**2)*(min_a[j]**2) + (max_b[j]**2)*(min_b[j]**2) + (max_c[j]**2)*(min_c[j]**2) 35 | q2 = np.max((max_a[j]**4, min_a[j]**4)) + np.max((max_b[j]**4, min_b[j]**4)) + np.max((max_c[j]**4, min_c[j]**4)) 36 | q = q1/q2 37 | R[i, j] = (1 - p)/(1 - q) 38 | std = (np.sum((R - R.mean())**2, axis = 0)/(R.shape[0] - 1))**(1/2) 39 | sim_mat = np.corrcoef(R.T) 40 | conflict = np.sum(1 - sim_mat, axis = 1) 41 | infor = std*conflict 42 | weights = infor/np.sum(infor) 43 | return weights 44 | 45 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/rov.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: ROV (Range Of Value) 32 | def rov_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | D = 0 35 | weights = weights/np.sum(weights) 36 | for j in range(0, X.shape[1]): 37 | if (criterion_type[j] == 'max'): 38 | if (np.max(X[:,j]) == np.min(X[:,j])): 39 | D = 1 40 | else: 41 | D = np.max(X[:,j]) - np.min(X[:,j]) 42 | X[:,j] = ( X[:,j] - np.min(X[:,j]) ) / D 43 | else: 44 | if (np.max(X[:,j]) == np.min(X[:,j])): 45 | D = 1 46 | else: 47 | D = np.max(X[:,j]) - np.min(X[:,j]) 48 | X[:,j] = ( np.max(X[:,j]) - X[:,j] ) / D 49 | u = np.sum(X * weights, axis = 1) 50 | if (verbose == True): 51 | for i in range(0, u.shape[0]): 52 | print('a' + str(i+1) + ': ' + str(round(u[i], 2))) 53 | if ( graph == True): 54 | flow = np.copy(u) 55 | flow = np.reshape(flow, (u.shape[0], 1)) 56 | flow = np.insert(flow, 0, list(range(1, u.shape[0]+1)), axis = 1) 57 | flow = flow[np.argsort(flow[:, 1])] 58 | flow = flow[::-1] 59 | ranking(flow) 60 | return u 61 | 62 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/copras.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: COPRAS (Complex Proportional Assessment) 32 | def copras_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | X = X/np.sum(X, axis = 0) 35 | X = X*weights 36 | s_p = np.zeros(X.shape[0]) 37 | s_m = np.zeros(X.shape[0]) 38 | s_d = np.zeros(X.shape[0]) 39 | q_i = np.zeros(X.shape[0]) 40 | u_i = np.zeros(X.shape[0]) 41 | id1 = [i for i, j in enumerate(criterion_type) if j == 'max'] 42 | id2 = [i for i, j in enumerate(criterion_type) if j == 'min'] 43 | if (len(id1) > 0): 44 | s_p = np.sum(X[:,id1], axis = 1) 45 | q_i = s_p 46 | if (len(id2) > 0): 47 | s_m = np.sum(X[:,id2], axis = 1) 48 | s_d = np.min(s_m)/s_m 49 | q_i = s_p + (np.min(s_m)*np.sum(s_m))/(s_m*np.sum(s_d)) 50 | u_i = q_i/np.max(q_i) 51 | flow = np.copy(u_i) 52 | flow = np.reshape(flow, (u_i.shape[0], 1)) 53 | flow = np.insert(flow, 0, list(range(1, u_i.shape[0]+1)), axis = 1) 54 | if (verbose == True): 55 | for i in range(0, flow.shape[0]): 56 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 57 | if (graph == True): 58 | flow = flow[np.argsort(flow[:, 1])] 59 | flow = flow[::-1] 60 | ranking(flow) 61 | return flow -------------------------------------------------------------------------------- /pyDecision/algorithm/ocra.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: OCRA (Operational Competitiveness RAting) 32 | def ocra_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | I = np.zeros(X.shape[0]) 35 | O = np.zeros(X.shape[0]) 36 | weights = np.array(weights) 37 | for j in range(0, X.shape[1]): 38 | if (criterion_type[j] == 'max'): 39 | A = (X[:,j] - np.min(X[:,j])) / np.min(X[:,j]) 40 | for k in range(0, A.shape[0]): 41 | A[k] = A[k] * weights[j] 42 | O = O + A 43 | else: 44 | B = (np.max(X[:,j]) - X[:,j]) / np.min(X[:,j]) 45 | for k in range(0, B.shape[0]): 46 | B[k] = B[k] * weights[j] 47 | I = I + B 48 | O = O - np.min(O) 49 | I = I - np.min(I) 50 | r = (I + O) - np.min(I + O) 51 | if (verbose == True): 52 | for i in range(0, r.shape[0]): 53 | print('a' + str(i+1) + ': ' + str(round(r[i], 2))) 54 | if ( graph == True): 55 | flow = np.copy(r) 56 | flow = np.reshape(flow, (r.shape[0], 1)) 57 | flow = np.insert(flow, 0, list(range(1, r.shape[0]+1)), axis = 1) 58 | flow = flow[np.argsort(flow[:, 1])] 59 | flow = flow[::-1] 60 | ranking(flow) 61 | return r 62 | 63 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/gra.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: GRA (Grey Relational Analysis) 32 | def gra_method(dataset, criterion_type, weights, epsilon = 0.5, graph = True, verbose = True): 33 | x = np.zeros((dataset.shape[0], dataset.shape[1]), dtype = float) 34 | for j in range(0, dataset.shape[1]): 35 | if (criterion_type[j] == 'max'): 36 | x[:,j] = ( dataset[:,j] - np.min(dataset[:,j]) ) / ( np.max(dataset[:,j]) - np.min(dataset[:,j]) + 0.0000000000000001) 37 | else: 38 | x[:,j] = ( np.max(dataset[:,j]) - dataset[:,j] ) / ( np.max(dataset[:,j]) - np.min(dataset[:,j]) + 0.0000000000000001) 39 | deviation_sequence = 1 - x 40 | gra_coefficient = epsilon/(deviation_sequence + epsilon) 41 | gra_grade = np.sum(gra_coefficient*weights, axis = 1) / dataset.shape[0] 42 | if (verbose == True): 43 | for i in range(0, gra_grade.shape[0]): 44 | print('a' + str(i+1) + ': ' + str(round(gra_grade[i], 4))) 45 | if ( graph == True): 46 | flow = np.copy(gra_grade) 47 | flow = np.reshape(flow, (gra_grade.shape[0], 1)) 48 | flow = np.insert(flow, 0, list(range(1, gra_grade.shape[0]+1)), axis = 1) 49 | flow = flow[np.argsort(flow[:, 1])] 50 | flow = flow[::-1] 51 | ranking(flow) 52 | return gra_grade 53 | 54 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/moora.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: MOORA (Multi-objective Optimization on the basis of Ratio Analysis) 32 | def moora_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | best = np.zeros(X.shape[1]) 35 | for i in range(0, X.shape[1]): 36 | if ( criterion_type[i] == 'max'): 37 | best[i] = np.max(X[:,i]) 38 | else: 39 | best[i] = np.min(X[:,i]) 40 | root = (np.sum(X**2, axis = 0))**(1/2) 41 | X = X/root 42 | X = X*weights 43 | id1 = [i for i, j in enumerate(criterion_type) if j == 'max'] 44 | id2 = [i for i, j in enumerate(criterion_type) if j == 'min'] 45 | s_p = np.zeros(X.shape[0]) 46 | s_m = np.zeros(X.shape[0]) 47 | Y = np.zeros(X.shape[0]) 48 | if (len(id1) > 0): 49 | s_p = np.sum(X[:,id1], axis = 1) 50 | if (len(id2) > 0): 51 | s_m = np.sum(X[:,id2], axis = 1) 52 | Y = s_p - s_m 53 | flow = np.copy(Y) 54 | flow = np.reshape(flow, (Y.shape[0], 1)) 55 | flow = np.insert(flow, 0, list(range(1, Y.shape[0]+1)), axis = 1) 56 | if (verbose == True): 57 | for i in range(0, flow.shape[0]): 58 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 59 | if (graph == True): 60 | flow = flow[np.argsort(flow[:, 1])] 61 | flow = flow[::-1] 62 | ranking(flow) 63 | return flow -------------------------------------------------------------------------------- /pyDecision/algorithm/moosra.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: MOOSRA (Multi-objective Optimisation on the Basis of Simple Ratio Analysis) 32 | def moosra_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | best = np.zeros(X.shape[1]) 35 | for i in range(0, X.shape[1]): 36 | if ( criterion_type[i] == 'max'): 37 | best[i] = np.max(X[:,i]) 38 | else: 39 | best[i] = np.min(X[:,i]) 40 | root = (np.sum(X**2, axis = 0))**(1/2) 41 | X = X/root 42 | X = X*weights 43 | id1 = [i for i, j in enumerate(criterion_type) if j == 'max'] 44 | id2 = [i for i, j in enumerate(criterion_type) if j == 'min'] 45 | s_p = np.zeros(X.shape[0]) 46 | s_m = np.zeros(X.shape[0]) 47 | Y = np.zeros(X.shape[0]) 48 | if (len(id1) > 0): 49 | s_p = np.sum(X[:,id1], axis = 1) 50 | if (len(id2) > 0): 51 | s_m = np.sum(X[:,id2], axis = 1) 52 | Y = s_p/s_m 53 | flow = np.copy(Y) 54 | flow = np.reshape(flow, (Y.shape[0], 1)) 55 | flow = np.insert(flow, 0, list(range(1, Y.shape[0]+1)), axis = 1) 56 | if (verbose == True): 57 | for i in range(0, flow.shape[0]): 58 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 59 | if (graph == True): 60 | flow = flow[np.argsort(flow[:, 1])] 61 | flow = flow[::-1] 62 | ranking(flow) 63 | return flow -------------------------------------------------------------------------------- /pyDecision/algorithm/oreste.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | from scipy.stats import rankdata 8 | 9 | ############################################################################### 10 | 11 | # Function: Rank 12 | def ranking(flow): 13 | rank_xy = np.zeros((flow.shape[0], 2)) 14 | for i in range(0, rank_xy.shape[0]): 15 | rank_xy[i, 0] = 0 16 | rank_xy[i, 1] = flow.shape[0]-i 17 | for i in range(0, rank_xy.shape[0]): 18 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 19 | for i in range(0, rank_xy.shape[0]-1): 20 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 21 | axes = plt.gca() 22 | axes.set_xlim([-1, +1]) 23 | ymin = np.amin(rank_xy[:,1]) 24 | ymax = np.amax(rank_xy[:,1]) 25 | if (ymin < ymax): 26 | axes.set_ylim([ymin, ymax]) 27 | else: 28 | axes.set_ylim([ymin-1, ymax+1]) 29 | plt.axis('off') 30 | plt.show() 31 | return 32 | 33 | # Function: ORESTE (Organisation Rangement Et SynThèsE de données relationnelles) 34 | def oreste_method(dataset, weights, criterion_type, alpha = 0.4, graph = True, verbose = True): 35 | X = np.copy(dataset)/1.0 36 | w = rankdata(-np.array(weights), method = 'min') 37 | r_ind = np.zeros((X.shape)) 38 | for j in range(0, X.shape[1]): 39 | if (criterion_type[j] == 'max'): 40 | X[:,j] = rankdata(-X[:,j], method = 'min') 41 | else: 42 | X[:,j] = rankdata(X[:,j], method = 'min') 43 | for i in range(0, r_ind.shape[0]): 44 | for j in range(0, r_ind.shape[1]): 45 | r_ind[i, j] = alpha*X[i, j] + (1 - alpha)*w[j] 46 | ranked = rankdata(r_ind.flatten(), method = 'min').reshape(r_ind.shape) 47 | total = np.sum(ranked, axis = 1) 48 | if (verbose == True): 49 | for i in range(0, total.shape[0]): 50 | print('a' + str(i+1) + ': ' + str(round(total[i], 2))) 51 | if ( graph == True): 52 | flow = np.copy(total) 53 | flow = np.reshape(flow, (total.shape[0], 1)) 54 | flow = np.insert(flow, 0, list(range(1, total.shape[0]+1)), axis = 1) 55 | flow = flow[np.argsort(flow[:, 1])] 56 | ranking(flow) 57 | return total 58 | 59 | ############################################################################### 60 | -------------------------------------------------------------------------------- /pyDecision/algorithm/bwm.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import warnings 6 | warnings.filterwarnings('ignore', message = 'delta_grad == 0.0. Check if the approximated') 7 | 8 | from scipy.optimize import minimize, Bounds, LinearConstraint 9 | 10 | ############################################################################### 11 | 12 | # Function: BWM 13 | def bw_method(mic, lic, eps_penalty = 1, verbose = True): 14 | cr = [] 15 | mx = np.max(mic) 16 | if (mx == 1): 17 | cr = 1 18 | else: 19 | for i in range(0, mic.shape[0]): 20 | cr.append((mic[i] * lic[i] - mx)/(mx**2 - mx)) 21 | cr = np.max(cr) 22 | threshold = [0, 0, 0, 0.1667, 0.1898, 0.2306, 0.2643, 0.2819, 0.2958, 0.3062] 23 | if (verbose == True): 24 | if (cr <= threshold[mx]): 25 | print('CR:', np.round(cr, 4), '(The Consistency Level is Acceptable)') 26 | else: 27 | print('CR:', np.round(cr, 4), '(The Consistency Level is Not Acceptable)') 28 | 29 | ################################################ 30 | def target_function(variables): 31 | eps = variables[-1] 32 | wx = variables[np.argmin(mic)] 33 | wy = variables[np.argmin(lic)] 34 | cons_1 = [] 35 | cons_2 = [] 36 | penalty = 0 37 | for i in range(0, mic.shape[0]): 38 | cons_1.append(wx - mic[i] * variables[i]) 39 | cons_1.extend([-item for item in cons_1]) 40 | for i in range(0, lic.shape[0]): 41 | cons_2.append(variables[i] - lic[i] * wy) 42 | cons_2.extend([-item for item in cons_2]) 43 | cons = cons_1 + cons_2 44 | for item in cons: 45 | if (item > eps): 46 | penalty = penalty + (item - eps) * 1 47 | penalty = penalty + eps * eps_penalty 48 | return penalty 49 | ################################################ 50 | 51 | np.random.seed(42) 52 | variables = np.random.uniform(low = 0.001, high = 1.0, size = mic.shape[0]) 53 | variables = variables / np.sum(variables) 54 | variables = np.append(variables, [0]) 55 | bounds = Bounds([0]*mic.shape[0] + [0], [1]*mic.shape[0] + [1]) 56 | w_cons = LinearConstraint(np.append(np.ones(mic.shape[0]), [0]), [1], [1]) 57 | results = minimize(target_function, variables, method = 'trust-constr', bounds = bounds, constraints = [w_cons]) 58 | weights = results.x[:-1] 59 | if (verbose == True): 60 | print('Epsilon Value:', np.round(results.x[-1], 4)) 61 | return weights 62 | 63 | ############################################################################### 64 | -------------------------------------------------------------------------------- /pyDecision/algorithm/mairca.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: MAIRCA (Multi-Attributive Ideal-Real Comparative Analysis) 32 | def mairca_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | p = (1 / X.shape[0]) 35 | Tp = np.ones((X.shape)) 36 | Tr = np.ones((X.shape)) 37 | for j in range(X.shape[1]): 38 | Tp[:, j] = p * weights[j] 39 | D = 0 40 | for j in range(0, X.shape[1]): 41 | if (criterion_type[j] == 'max'): 42 | if (np.max(X[:,j]) == np.min(X[:,j])): 43 | D = 1 44 | else: 45 | D = np.max(X[:,j]) - np.min(X[:,j]) 46 | Tr[:,j] = Tp[:, j] * ( X[:,j] - np.min(X[:,j]) ) / D 47 | else: 48 | if (np.max(X[:,j]) == np.min(X[:,j])): 49 | D = 1 50 | else: 51 | D = np.min(X[:,j]) - np.max(X[:,j]) 52 | Tr[:,j] = Tp[:, j] * ( X[:,j] - np.max(X[:,j]) ) / D 53 | G = Tp - Tr 54 | G = np.sum(G, axis = 1) 55 | if (verbose == True): 56 | for i in range(0, G.shape[0]): 57 | print('a' + str(i+1) + ': ' + str(round(G[i], 2))) 58 | if ( graph == True): 59 | flow = np.copy(G) 60 | flow = np.reshape(flow, (G.shape[0], 1)) 61 | flow = np.insert(flow, 0, list(range(1, G.shape[0]+1)), axis = 1) 62 | flow = flow[np.argsort(flow[:, 1])] 63 | ranking(flow) 64 | return G 65 | 66 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/aras.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: ARAS (Additive Ratio Assessment) 32 | def aras_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | bst = np.zeros(X.shape[1]) 35 | bsm = np.zeros(X.shape[1]) 36 | for j in range(0, X.shape[1]): 37 | if ( criterion_type[j] == 'max'): 38 | bst[j] = np.max(X[:, j]) 39 | bsm[j] = bst[j] + np.sum(X[:, j]) 40 | elif ( criterion_type[j] == 'min'): 41 | bst[j] = 1/np.min(X[:, j]) 42 | X[:,j] = 1/X[:, j] 43 | bsm[j] = bst[j] + np.sum(X[:, j]) 44 | for j in range(0, X.shape[1]): 45 | bst[j] = bst[j]/ bsm[j] 46 | for i in range(0, X.shape[0]): 47 | X[i, j] = X[i, j]/ bsm[j] 48 | X = X * weights 49 | bst = bst * weights 50 | n_0 = np.sum(bst) 51 | n_i = np.sum(X, axis = 1) 52 | k_i = n_i/n_0 53 | flow = np.copy(k_i) 54 | flow = np.reshape(flow, (k_i.shape[0], 1)) 55 | flow = np.insert(flow, 0, list(range(1, k_i.shape[0]+1)), axis = 1) 56 | if (verbose == True): 57 | for i in range(0, flow.shape[0]): 58 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 59 | if (graph == True): 60 | flow = flow[np.argsort(flow[:, 1])] 61 | flow = flow[::-1] 62 | ranking(flow) 63 | return flow 64 | 65 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/topsis.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: TOPSIS 32 | def topsis_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset) 34 | w = np.copy(weights) 35 | sum_cols = np.sum(X*X, axis = 0) 36 | sum_cols = sum_cols**(1/2) 37 | r_ij = X/sum_cols 38 | v_ij = r_ij*w 39 | p_ideal_A = np.zeros(X.shape[1]) 40 | n_ideal_A = np.zeros(X.shape[1]) 41 | for i in range(0, dataset.shape[1]): 42 | if (criterion_type[i] == 'max'): 43 | p_ideal_A[i] = np.max(v_ij[:, i]) 44 | n_ideal_A[i] = np.min(v_ij[:, i]) 45 | else: 46 | p_ideal_A[i] = np.min(v_ij[:, i]) 47 | n_ideal_A[i] = np.max(v_ij[:, i]) 48 | p_s_ij = (v_ij - p_ideal_A)**2 49 | p_s_ij = np.sum(p_s_ij, axis = 1)**(1/2) 50 | n_s_ij = (v_ij - n_ideal_A)**2 51 | n_s_ij = np.sum(n_s_ij, axis = 1)**(1/2) 52 | c_i = n_s_ij / ( p_s_ij + n_s_ij ) 53 | if (verbose == True): 54 | for i in range(0, c_i.shape[0]): 55 | print('a' + str(i+1) + ': ' + str(round(c_i[i], 2))) 56 | if ( graph == True): 57 | flow = np.copy(c_i) 58 | flow = np.reshape(flow, (c_i.shape[0], 1)) 59 | flow = np.insert(flow, 0, list(range(1, c_i.shape[0]+1)), axis = 1) 60 | flow = flow[np.argsort(flow[:, 1])] 61 | flow = flow[::-1] 62 | ranking(flow) 63 | return c_i 64 | 65 | ############################################################################### 66 | -------------------------------------------------------------------------------- /pyDecision/algorithm/wings.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | ############################################################################### 9 | 10 | # Function: WINGS (Weighted Influence Non-linear Gauge System) 11 | def wings_method(dataset, size_x = 10, size_y = 10): 12 | D = dataset 13 | C = D/np.sum(D) 14 | I = np.eye(dataset.shape[0]) 15 | T = np.dot(C, np.linalg.inv( I - C )) 16 | c_i = np.sum(T, axis = 0) 17 | r_i = np.sum(T, axis = 1) 18 | r_plus_c = r_i + c_i 19 | r_minus_c = r_i - c_i 20 | weights = r_plus_c/np.sum(r_plus_c) 21 | plt.figure(figsize = [size_x, size_y]) 22 | plt.style.use('ggplot') 23 | for i in range(0, dataset.shape[0]): 24 | if (r_minus_c[i] >= 0 and r_plus_c[i] >= np.mean(r_plus_c)): 25 | plt.text(r_plus_c[i], r_minus_c[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.7, 1.0, 0.7),)) 26 | print('g'+str(i+1)+': Quadrant I') 27 | elif (r_minus_c[i] >= 0 and r_plus_c[i] < np.mean(r_plus_c)): 28 | plt.text(r_plus_c[i], r_minus_c[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (1.0, 1.0, 0.7),)) 29 | print('g'+str(i+1)+': Quadrant II') 30 | elif (r_minus_c[i] < 0 and r_plus_c[i] < np.mean(r_plus_c)): 31 | plt.text(r_plus_c[i], r_minus_c[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (1.0, 0.7, 0.7),)) 32 | print('g'+str(i+1)+': Quadrant III') 33 | else: 34 | plt.text(r_plus_c[i], r_minus_c[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.7, 0.7, 1.0),)) 35 | print('g'+str(i+1)+': Quadrant IV') 36 | axes = plt.gca() 37 | xmin = np.amin(r_plus_c) 38 | if (xmin > 0): 39 | xmin = 0 40 | xmax = np.amax(r_plus_c) 41 | if (xmax < 0): 42 | xmax = 0 43 | axes.set_xlim([xmin-1, xmax+1]) 44 | ymin = np.amin(r_minus_c) 45 | if (ymin > 0): 46 | ymin = 0 47 | ymax = np.amax(r_minus_c) 48 | if (ymax < 0): 49 | ymax = 0 50 | axes.set_ylim([ymin-1, ymax+1]) 51 | plt.axvline(x = np.mean(r_plus_c), linewidth = 0.9, color = 'r', linestyle = 'dotted') 52 | plt.axhline(y = 0, linewidth = 0.9, color = 'r', linestyle = 'dotted') 53 | plt.xlabel('(R + C)') 54 | plt.ylabel('(R - C)') 55 | plt.show() 56 | return r_plus_c, r_minus_c, weights 57 | 58 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/mara.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: MARA (Magnitude of the Area for the Ranking of Alternatives) 32 | def mara_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | for j in range(0, X.shape[1]): 35 | if (criterion_type[j] == 'max'): 36 | X[:,j] = X[:,j] / np.max(X[:,j]) 37 | else: 38 | X[:,j] = np.min(X[:,j]) / X[:,j] 39 | X = X * weights 40 | opt = np.max(X, axis = 0) 41 | S_k = 0 42 | S_L = 0 43 | T_k = np.zeros(X.shape[0]) 44 | T_L = np.zeros(X.shape[0]) 45 | for j in range(0, X.shape[1]): 46 | if (criterion_type[j] == 'max'): 47 | S_k = S_k + opt[j] 48 | for i in range(0, X.shape[0]): 49 | T_k[i] = T_k[i] + X[i, j] 50 | else: 51 | S_L = S_L + opt[j] 52 | for i in range(0, X.shape[0]): 53 | T_L[i] = T_L[i] + X[i, j] 54 | f_opt = (S_L - S_k)/2 + S_k 55 | f_i = (T_L - T_k)/2 + T_k 56 | M = f_opt - f_i 57 | if (verbose == True): 58 | for i in range(0, M.shape[0]): 59 | print('a' + str(i+1) + ': ' + str(round(M[i], 2))) 60 | if ( graph == True): 61 | flow = np.copy(M) 62 | flow = np.reshape(flow, (M.shape[0], 1)) 63 | flow = np.insert(flow, 0, list(range(1, M.shape[0]+1)), axis = 1) 64 | flow = flow[np.argsort(flow[:, 1])] 65 | ranking(flow) 66 | return M 67 | 68 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/mabac.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: MABAC (Multi-Attributive Border Approximation area Comparison) 32 | def mabac_method(dataset, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | X_r = np.copy(dataset)/1.0 35 | X_q = np.copy(dataset)/1.0 36 | for i in range(0, X.shape[0]): 37 | for j in range(0, X.shape[1]): 38 | fct = 0 39 | if (criterion_type[j] == 'max'): 40 | if ((max(X[:,j]) - min(X[:,j])) != 0): 41 | fct = (X[i,j] - min(X[:,j]))/(max(X[:,j]) - min(X[:,j])) 42 | else: 43 | if ((min(X[:,j]) - max(X[:,j])) != 0): 44 | fct = (X[i,j] - max(X[:,j]))/(min(X[:,j]) - max(X[:,j])) 45 | X_r[i,j] = (1/X.shape[0])*(1 + fct) 46 | for i in range(0, X.shape[0]): 47 | for j in range(0, X.shape[1]): 48 | X_q[i,j] = X_r[i,j] - np.prod(X_r[:,j]**(1/X.shape[0])) 49 | rank = np.sum(X_q, axis = 1) 50 | if (verbose == True): 51 | for i in range(0, rank.shape[0]): 52 | print('a' + str(i+1) + ': ' + str(round(rank[i], 4))) 53 | if ( graph == True): 54 | flow = np.copy(rank) 55 | flow = np.reshape(flow, (rank.shape[0], 1)) 56 | flow = np.insert(flow, 0, list(range(1, rank.shape[0]+1)), axis = 1) 57 | flow = flow[np.argsort(flow[:, 1])] 58 | flow = flow[::-1] 59 | ranking(flow) 60 | return rank 61 | 62 | ############################################################################### 63 | -------------------------------------------------------------------------------- /pyDecision/algorithm/edas.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | ############################################################################### 9 | 10 | # Function: Rank 11 | def ranking(flow): 12 | rank_xy = np.zeros((flow.shape[0], 2)) 13 | for i in range(0, rank_xy.shape[0]): 14 | rank_xy[i, 0] = 0 15 | rank_xy[i, 1] = flow.shape[0]-i 16 | for i in range(0, rank_xy.shape[0]): 17 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 18 | for i in range(0, rank_xy.shape[0]-1): 19 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 20 | axes = plt.gca() 21 | axes.set_xlim([-1, +1]) 22 | ymin = np.amin(rank_xy[:,1]) 23 | ymax = np.amax(rank_xy[:,1]) 24 | if (ymin < ymax): 25 | axes.set_ylim([ymin, ymax]) 26 | else: 27 | axes.set_ylim([ymin-1, ymax+1]) 28 | plt.axis('off') 29 | plt.show() 30 | return 31 | 32 | # Function: EDAS 33 | def edas_method(dataset, criterion_type, weights, graph = True, verbose = True): 34 | col_mean = np.mean(dataset, axis = 0) 35 | pda = np.zeros((dataset.shape[0], dataset.shape[1])) 36 | nda = np.zeros((dataset.shape[0], dataset.shape[1])) 37 | for i in range(0, dataset.shape[0]): 38 | for j in range(0, dataset.shape[1]): 39 | if (criterion_type[j] == 'max'): 40 | pda[i,j] = max(0, dataset[i,j] - col_mean[j]) / col_mean[j] 41 | nda[i,j] = max(0, -dataset[i,j] + col_mean[j]) / col_mean[j] 42 | else: 43 | pda[i,j] = max(0, -dataset[i,j] + col_mean[j]) / col_mean[j] 44 | nda[i,j] = max(0, dataset[i,j] - col_mean[j]) / col_mean[j] 45 | w_pda = pda*weights 46 | w_nda = nda*weights 47 | s_p = np.sum(w_pda , axis = 1) 48 | s_n = np.sum(w_nda , axis = 1) 49 | n_s_p = s_p/max(s_p) 50 | n_s_n = 1 - s_n/max(s_n) 51 | a_s = (1/2)*(n_s_p + n_s_n) 52 | if (verbose == True): 53 | for i in range(0, a_s.shape[0]): 54 | print('a' + str(i+1) + ': ' + str(round(a_s[i], 4))) 55 | if ( graph == True): 56 | flow = np.copy(a_s) 57 | flow = np.reshape(flow, (a_s.shape[0], 1)) 58 | flow = np.insert(flow, 0, list(range(1, a_s.shape[0]+1)), axis = 1) 59 | flow = flow[np.argsort(flow[:, 1])] 60 | flow = flow[::-1] 61 | ranking(flow) 62 | return a_s 63 | 64 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/codas.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: CODAS (Combinative Distance-based Assessment) 32 | def codas_method(dataset, weights, criterion_type, lmbd = 0.02, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | bst = np.zeros(X.shape[1]) 35 | r_m = np.zeros((X.shape[0], X.shape[0])) 36 | for j in range(0, X.shape[1]): 37 | if ( criterion_type[j] == 'max'): 38 | bst[j] = np.max(X[:, j]) 39 | elif ( criterion_type[j] == 'min'): 40 | bst[j] = np.min(X[:, j]) 41 | for j in range(0, X.shape[1]): 42 | for i in range(0, X.shape[0]): 43 | if ( criterion_type[j] == 'max'): 44 | X[i, j] = X[i, j]/bst[j] 45 | elif ( criterion_type[j] == 'min'): 46 | X[i, j] = bst[j]/X[i, j] 47 | X = X * weights 48 | n_i = np.min(X, axis = 0) 49 | e_i = np.sum( (X - n_i)**2, axis = 1)**(1/2) 50 | t_i = np.sum( abs(X - n_i), axis = 1) 51 | for j in range(0, r_m.shape[1]): 52 | for i in range(0, r_m.shape[0]): 53 | r_m[i, j] = (e_i[i] - e_i[j]) + lmbd*( (e_i[i] - e_i[j]) * (t_i[i] - t_i[j]) ) 54 | h_i = np.sum(r_m, axis = 1) 55 | flow = np.copy(h_i) 56 | flow = np.reshape(flow, (h_i.shape[0], 1)) 57 | flow = np.insert(flow, 0, list(range(1, h_i.shape[0]+1)), axis = 1) 58 | if (verbose == True): 59 | for i in range(0, flow.shape[0]): 60 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 61 | if (graph == True): 62 | flow = flow[np.argsort(flow[:, 1])] 63 | flow = flow[::-1] 64 | ranking(flow) 65 | return flow -------------------------------------------------------------------------------- /pyDecision/algorithm/cocoso.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: COCOSO (COmbined COmpromise SOlution) 32 | def cocoso_method(dataset, criterion_type, weights, L = 0.5, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | best = np.zeros(X.shape[1]) 35 | worst = np.zeros(X.shape[1]) 36 | for i in range(0, dataset.shape[1]): 37 | if (criterion_type[i] == 'max'): 38 | best[i] = np.max(X[:, i]) 39 | worst[i] = np.min(X[:, i]) 40 | else: 41 | best[i] = np.min(X[:, i]) 42 | worst[i] = np.max(X[:, i]) 43 | for j in range(0, X.shape[1]): 44 | X[:,j] = ( X[:,j] - worst[j] ) / ( best[j] - worst[j] + 0.0000000000000001) 45 | S = np.sum(X * weights, axis = 1) 46 | P = np.sum(X ** weights, axis = 1) 47 | if (np.min(S) == 0): 48 | S = S + 1 49 | if (np.min(P) == 0): 50 | P = P + 1 51 | ksi_a = (P + S) / np.sum(P + S, axis = 0) 52 | ksi_b = (S / np.min(S)) + (P / np.min(P)) 53 | ksi_c = (L * S + (1 - L) * P) / (L * np.max(S) + (1 - L) * np.max(P)) 54 | ksi = np.power(ksi_a * ksi_b * ksi_c, 1/3) + 1/3 * (ksi_a + ksi_b + ksi_c) 55 | if (verbose == True): 56 | for i in range(0, ksi.shape[0]): 57 | print('a' + str(i+1) + ': ' + str(round(ksi[i], 2))) 58 | if ( graph == True): 59 | flow = np.copy(ksi) 60 | flow = np.reshape(flow, (ksi.shape[0], 1)) 61 | flow = np.insert(flow, 0, list(range(1, ksi.shape[0]+1)), axis = 1) 62 | flow = flow[np.argsort(flow[:, 1])] 63 | flow = flow[::-1] 64 | ranking(flow) 65 | return ksi 66 | 67 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/copeland.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: Copeland 32 | def copeland_method(dataset, criterion_type, graph = True, verbose = True): 33 | X = np.zeros((dataset.shape[0], dataset.shape[0])) 34 | for i in range(0, dataset.shape[0]): 35 | for k in range(0, dataset.shape[0]): 36 | if (i != k): 37 | for j in range(0, dataset.shape[1]): 38 | if (criterion_type[j] == 'max'): 39 | if (dataset[i, j] > dataset[k, j]): 40 | X[i,k] = X[i,k] + 1 41 | if (dataset[i, j] == dataset[k, j]): 42 | X[i,k] = X[i,k] + 0 43 | if (dataset[i, j] < dataset[k, j]): 44 | X[i,k] = X[i,k] - 1 45 | else: 46 | if (dataset[i, j] > dataset[k, j]): 47 | X[i,k] = X[i,k] - 1 48 | if (dataset[i, j] == dataset[k, j]): 49 | X[i,k] = X[i,k] + 0 50 | if (dataset[i, j] < dataset[k, j]): 51 | X[i,k] = X[i,k] + 1 52 | total = np.sum(X, axis = 1) 53 | if (verbose == True): 54 | for i in range(0, total.shape[0]): 55 | print('a' + str(i+1) + ': ' + str(round(total[i], 2))) 56 | if ( graph == True): 57 | flow = np.copy(total) 58 | flow = np.reshape(flow, (total.shape[0], 1)) 59 | flow = np.insert(flow, 0, list(range(1, total.shape[0]+1)), axis = 1) 60 | flow = flow[np.argsort(flow[:, 1])] 61 | flow = flow[::-1] 62 | ranking(flow) 63 | return total 64 | 65 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/todim.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: TODIM (TOmada de Decisao Interativa e Multicriterio - Interactive and Multicriteria Decision Making) 32 | def todim_method(dataset, criterion_type, weights, teta = 1, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | for j in range(0, X.shape[1]): 35 | if (criterion_type[j] == 'max'): 36 | X[:,j] = X[:,j] / np.sum(X[:,j]) 37 | else: 38 | X[:,j] = (1/X[:,j]) / np.sum(1/X[:,j]) 39 | weights = weights/np.max(weights) 40 | D = np.zeros((X.shape[0], X.shape[0])) 41 | for i in range(0, D.shape[0]): 42 | for j in range(0, D.shape[1]): 43 | if (i != j): 44 | for k in range(0, X.shape[1]): 45 | p_i = X[i, k] 46 | p_j = X[j, k] 47 | if (p_i - p_j > 0): 48 | D[i, j] = D[i, j] + (weights[k]*(p_i - p_j) / np.sum(weights))**(1/2) 49 | elif (p_i - p_j == 0): 50 | D[i, j] = D[i, j] + 0 51 | else: 52 | D[i, j] = D[i, j] + (-1/teta)*(np.sum(weights)*(p_j - p_i)/weights[k])**(1/2) 53 | r = np.sum(D, axis = 1) 54 | r = (r - np.min(r)) / (np.max(r) - np.min(r)) 55 | if (verbose == True): 56 | for i in range(0, r.shape[0]): 57 | print('a' + str(i+1) + ': ' + str(round(r[i], 2))) 58 | if ( graph == True): 59 | flow = np.copy(r) 60 | flow = np.reshape(flow, (r.shape[0], 1)) 61 | flow = np.insert(flow, 0, list(range(1, r.shape[0]+1)), axis = 1) 62 | flow = flow[np.argsort(flow[:, 1])] 63 | flow = flow[::-1] 64 | ranking(flow) 65 | return r 66 | 67 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_ahp_ppf.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # PPF AHP (Proportional Picture Fuzzy sets combined with the Analytic Hierarchy Process) 9 | def ppf_ahp_method(comparison_matrix): 10 | 11 | inc_rat = np.array([0, 0, 0, 0.58, 0.9, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49, 1.51, 1.48, 1.56, 1.57, 1.59]) 12 | 13 | ################################################ 14 | def ppf_to_triple(comparison_matrix): 15 | triple_matrix = [] 16 | for row in comparison_matrix: 17 | triple_row = [] 18 | for k1, k2 in row: 19 | if (k1 == 0 and k2 == 0): 20 | triple_row.append((1.0, 0.0, 0.0)) 21 | else: 22 | pi = 1 / (1 + k1 + k2) 23 | mu = k1 * pi 24 | theta = k2 * pi 25 | triple_row.append((mu, pi, theta)) 26 | triple_matrix.append(triple_row) 27 | return triple_matrix 28 | 29 | def triple_to_crisp(triple_matrix): 30 | crisp_matrix = np.zeros((len(triple_matrix), len(triple_matrix))) 31 | for i, row in enumerate(triple_matrix): 32 | for j, (mu, pi, theta) in enumerate(row): 33 | if (i == j): 34 | crisp_matrix[i, j] = 1.0 35 | else: 36 | score = 10 * (mu - pi/2 - theta) 37 | score_n = 1 / (10 * (theta - pi/2 - mu)) 38 | if (score > 0): 39 | crisp_matrix[i, j] = score 40 | else: 41 | crisp_matrix[i, j] = score_n 42 | return crisp_matrix 43 | 44 | def normalize_matrix(crisp_matrix): 45 | n_matrix = np.abs(crisp_matrix) / crisp_matrix.sum(axis = 0) 46 | return n_matrix 47 | 48 | def consistency_ratio(crisp_matrix): 49 | eigenvalues, eigenvectors = np.linalg.eig(crisp_matrix) 50 | eigenvalues_real = np.real(eigenvalues) 51 | lamb_max_index = np.argmax(eigenvalues_real) 52 | lamb_max = eigenvalues_real[lamb_max_index] 53 | cons_ind = (lamb_max - crisp_matrix.shape[1]) / (crisp_matrix.shape[1] - 1) 54 | rc = cons_ind / inc_rat[crisp_matrix.shape[1]] 55 | return rc 56 | 57 | def calculate_weights(n_matrix): 58 | weights = n_matrix.mean(axis = 1) 59 | return weights 60 | ################################################ 61 | 62 | triple_matrix = ppf_to_triple(comparison_matrix) 63 | crisp_matrix = triple_to_crisp(triple_matrix) 64 | n_matrix = normalize_matrix(crisp_matrix) 65 | weights = calculate_weights(n_matrix) 66 | weights = weights/np.sum(weights) 67 | rc = consistency_ratio(crisp_matrix) 68 | return weights, rc 69 | 70 | ############################################################################### 71 | -------------------------------------------------------------------------------- /pyDecision/algorithm/marcos.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: MARCOS (Measurement of Alternatives and Ranking according to COmpromise Solution) 32 | def marcos_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | best = np.zeros(X.shape[1]) 35 | worst = np.zeros(X.shape[1]) 36 | weights = np.array(weights) 37 | for i in range(0, dataset.shape[1]): 38 | if (criterion_type[i] == 'max'): 39 | best[i] = np.max(X[:, i]) 40 | worst[i] = np.min(X[:, i]) 41 | else: 42 | best[i] = np.min(X[:, i]) 43 | worst[i] = np.max(X[:, i]) 44 | for j in range(0, X.shape[1]): 45 | if (criterion_type[j] == 'max'): 46 | X[:,j] = X[:,j] / best[j] 47 | worst[j] = worst[j] / best[j] 48 | best[j] = best[j] / best[j] 49 | else: 50 | X[:,j] = best[j] / X[:,j] 51 | worst[j] = best[j] / worst[j] 52 | best[j] = best[j] / best[j] 53 | best = np.array(best) 54 | worst = np.array(worst) 55 | for i in range(0, X.shape[1]): 56 | best[i] = best[i] * weights[i] 57 | worst[i] = worst[i] * weights[i] 58 | V = X * weights 59 | S = V.sum(axis = 1) 60 | k_n = S / np.sum(worst) 61 | k_p = S / np.sum(best) 62 | f_k_n = k_p / (k_p + k_n) 63 | f_k_p = k_n / (k_p + k_n) 64 | f_k = (k_p + k_n) / (1 + ((1 - f_k_p) / f_k_p) + ((1 - f_k_n) / f_k_n)) 65 | if (verbose == True): 66 | for i in range(0, f_k.shape[0]): 67 | print('a' + str(i+1) + ': ' + str(round(f_k[i], 2))) 68 | if ( graph == True): 69 | flow = np.copy(f_k) 70 | flow = np.reshape(flow, (f_k.shape[0], 1)) 71 | flow = np.insert(flow, 0, list(range(1, f_k.shape[0]+1)), axis = 1) 72 | flow = flow[np.argsort(flow[:, 1])] 73 | flow = flow[::-1] 74 | ranking(flow) 75 | return f_k 76 | 77 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/dematel.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | ############################################################################### 9 | 10 | # Function: DEMATEL 11 | def dematel_method(dataset, size_x = 10, size_y = 10): 12 | row_sum = np.sum(dataset, axis = 1) 13 | max_sum = np.max(row_sum) 14 | X = dataset/max_sum 15 | Y = np.linalg.inv(np.identity(dataset.shape[0]) - X) 16 | T = np.matmul (X, Y) 17 | D = np.sum(T, axis = 1) 18 | R = np.sum(T, axis = 0) 19 | D_plus_R = D + R # Most Importante Criteria 20 | D_minus_R = D - R # +Influencer Criteria, - Influenced Criteria 21 | weights = D_plus_R/np.sum(D_plus_R) 22 | print('QUADRANT I has the Most Important Criteria (Prominence: High, Relation: High)') 23 | print('QUADRANT II has Important Criteira that can be Improved by Other Criteria (Prominence: Low, Relation: High)') 24 | print('QUADRANT III has Criteria that are not Important (Prominence: Low, Relation: Low)') 25 | print('QUADRANT IV has Important Criteria that cannot be Improved by Other Criteria (Prominence: High, Relation: Low)') 26 | print('') 27 | plt.figure(figsize = [size_x, size_y]) 28 | plt.style.use('ggplot') 29 | for i in range(0, dataset.shape[0]): 30 | if (D_minus_R[i] >= 0 and D_plus_R[i] >= np.mean(D_plus_R)): 31 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.7, 1.0, 0.7),)) 32 | print('g'+str(i+1)+': Quadrant I') 33 | elif (D_minus_R[i] >= 0 and D_plus_R[i] < np.mean(D_plus_R)): 34 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (1.0, 1.0, 0.7),)) 35 | print('g'+str(i+1)+': Quadrant II') 36 | elif (D_minus_R[i] < 0 and D_plus_R[i] < np.mean(D_plus_R)): 37 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (1.0, 0.7, 0.7),)) 38 | print('g'+str(i+1)+': Quadrant III') 39 | else: 40 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.7, 0.7, 1.0),)) 41 | print('g'+str(i+1)+': Quadrant IV') 42 | axes = plt.gca() 43 | xmin = np.amin(D_plus_R) 44 | if (xmin > 0): 45 | xmin = 0 46 | xmax = np.amax(D_plus_R) 47 | if (xmax < 0): 48 | xmax = 0 49 | axes.set_xlim([xmin-1, xmax+1]) 50 | ymin = np.amin(D_minus_R) 51 | if (ymin > 0): 52 | ymin = 0 53 | ymax = np.amax(D_minus_R) 54 | if (ymax < 0): 55 | ymax = 0 56 | axes.set_ylim([ymin-1, ymax+1]) 57 | plt.axvline(x = np.mean(D_plus_R), linewidth = 0.9, color = 'r', linestyle = 'dotted') 58 | plt.axhline(y = 0, linewidth = 0.9, color = 'r', linestyle = 'dotted') 59 | plt.xlabel('Prominence (D + R)') 60 | plt.ylabel('Relation (D - R)') 61 | plt.show() 62 | return D_plus_R, D_minus_R, weights 63 | 64 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/wisp.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: WISP (Integrated Simple Weighted Sum Product) 32 | def wisp_method(dataset, criterion_type, weights, simplified = False, graph = True, verbose = True): 33 | weights = [item/sum(weights) for item in weights] 34 | X = np.copy(dataset)/1.0 35 | best = np.max(X, axis = 0) 36 | X = X / ( best + 0.0000000000000001) 37 | X = X * weights 38 | v_p = np.zeros((X.shape[0])) 39 | v_m = np.zeros((X.shape[0])) 40 | w_p = np.ones( (X.shape[0])) 41 | w_m = np.ones( (X.shape[0])) 42 | for i in range(0, X.shape[0]): 43 | for j in range(0, X.shape[1]): 44 | if (criterion_type[j] == 'max'): 45 | v_p[i] = v_p[i] + X[i, j] 46 | w_p[i] = w_p[i] * X[i, j] 47 | else: 48 | v_m[i] = v_m[i] + X[i, j] 49 | w_m[i] = w_m[i] * X[i, j] 50 | u_wsd = v_p - v_m 51 | u_wpd = w_p - w_m 52 | if ('min' not in criterion_type): 53 | u_wsr = v_p 54 | u_wpr = w_p 55 | elif ('max' not in criterion_type): 56 | u_wsr = 1/v_m 57 | u_wpr = 1/w_m 58 | else: 59 | u_wsr = v_p / (v_m ) 60 | u_wpr = w_p / (w_m ) 61 | n_wsd = (1 + u_wsd) / (1 + np.max(u_wsd)) 62 | n_wpd = (1 + u_wpd) / (1 + np.max(u_wpd)) 63 | n_wsr = (1 + u_wsr) / (1 + np.max(u_wsr)) 64 | n_wpr = (1 + u_wpr) / (1 + np.max(u_wpr)) 65 | if (simplified == False): 66 | u = (n_wsd + n_wpd + n_wsr + n_wpr) / 4 67 | else: 68 | u = (n_wsd + n_wpr) / 2 69 | if (verbose == True): 70 | for i in range(0, u.shape[0]): 71 | print('a' + str(i+1) + ': ' + str(round(u[i], 2))) 72 | if ( graph == True): 73 | flow = np.copy(u) 74 | flow = np.reshape(flow, (u.shape[0], 1)) 75 | flow = np.insert(flow, 0, list(range(1, u.shape[0]+1)), axis = 1) 76 | flow = flow[np.argsort(flow[:, 1])] 77 | flow = flow[::-1] 78 | ranking(flow) 79 | return u 80 | 81 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/rafsi.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: RAFSI (Ranking of Alternatives through Functional mapping of criterion sub-intervals into a Single Interval) 32 | def rafsi_method(dataset, weights, criterion_type, ideal = [], anti_ideal = [], n_i = 1, n_k = 6, graph = True, verbose = True): 33 | X = np.copy(dataset)/1.0 34 | coef = np.zeros((2, X.shape[1])) 35 | best = np.zeros(X.shape[1]) 36 | worst = np.zeros(X.shape[1]) 37 | for j in range(0, X.shape[1]): 38 | if (criterion_type[j] == 'max'): 39 | if (len(ideal) == 0): 40 | best[j] = np.max(X[:,j])*2 41 | else: 42 | best[j] = ideal[j] 43 | if (len(anti_ideal) == 0): 44 | worst[j] = np.min(X[:,j])*0.5 45 | else: 46 | worst[j] = anti_ideal[j] 47 | else: 48 | if (len(anti_ideal) == 0): 49 | best[j] = np.min(X[:,j])*0.5 50 | else: 51 | best[j] = anti_ideal[j] 52 | if (len(ideal) == 0): 53 | worst[j] = np.max(X[:,j])*2 54 | else: 55 | worst[j] = ideal[j] 56 | coef[0, j] = (n_k - n_i)/(best[j] - worst[j]) 57 | coef[1, j] = (best[j]*n_i - worst[j]*n_k)/(best[j] - worst[j]) 58 | S = X * coef[0, :] + coef[1,:] 59 | A = np.mean((n_i, n_k)) 60 | H = 2/(n_i**-1 + n_k**-1) 61 | for j in range(0, X.shape[1]): 62 | if (criterion_type[j] == 'max'): 63 | S[:,j] = S[:,j]/(2*A) 64 | else: 65 | S[:,j] = H/(2*S[:,j]) 66 | V = np.sum(S*weights, axis = 1) 67 | flow = np.copy(V) 68 | flow = np.reshape(flow, (V.shape[0], 1)) 69 | flow = np.insert(flow, 0, list(range(1, V.shape[0]+1)), axis = 1) 70 | if (verbose == True): 71 | for i in range(0, flow.shape[0]): 72 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 73 | if (graph == True): 74 | flow = flow[np.argsort(flow[:, 1])] 75 | flow = flow[::-1] 76 | ranking(flow) 77 | return V 78 | 79 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_aras.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: FARAS (Fuzzy Additive Ratio Assessment) 32 | def fuzzy_aras_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X_a = np.zeros((len(dataset), len(dataset[0]))) 34 | X_b = np.zeros((len(dataset), len(dataset[0]))) 35 | X_c = np.zeros((len(dataset), len(dataset[0]))) 36 | weights_a = np.zeros(len(weights[0])) 37 | weights_b = np.zeros(len(weights[0])) 38 | weights_c = np.zeros(len(weights[0])) 39 | for j in range(0, X_a.shape[1]): 40 | weights_a[j] = weights[0][j][0] 41 | weights_b[j] = weights[0][j][1] 42 | weights_c[j] = weights[0][j][2] 43 | for i in range(0, X_a.shape[0]): 44 | a, b, c = dataset[i][j] 45 | X_a[i,j] = a 46 | X_b[i,j] = b 47 | X_c[i,j] = c 48 | for j in range(0, X_a.shape[1]): 49 | if (criterion_type[j] == 'max'): 50 | X_a[:, j] = X_a[:, j] / np.sum(X_a[:, j]) 51 | X_b[:, j] = X_b[:, j] / np.sum(X_b[:, j]) 52 | X_c[:, j] = X_c[:, j] / np.sum(X_c[:, j]) 53 | else: 54 | X_a[:, j] = (1 / X_a[:, j]) / np.sum((1 / X_a[:, j])) 55 | X_b[:, j] = (1 / X_b[:, j]) / np.sum((1 / X_b[:, j])) 56 | X_c[:, j] = (1 / X_c[:, j]) / np.sum((1 / X_c[:, j])) 57 | for j in range(0, X_a.shape[1]): 58 | X_a[:, j] = X_a[:, j] * weights_a[j] 59 | X_b[:, j] = X_b[:, j] * weights_b[j] 60 | X_c[:, j] = X_c[:, j] * weights_c[j] 61 | S_a = np.sum(X_a, axis = 1) 62 | S_b = np.sum(X_b, axis = 1) 63 | S_c = np.sum(X_c, axis = 1) 64 | S = (1/3)*(S_a + S_b + S_c) 65 | Q = S/np.max(S) 66 | if (verbose == True): 67 | for i in range(0, Q.shape[0]): 68 | print('a' + str(i+1) + ': ' + str(round(Q[i], 2))) 69 | if ( graph == True): 70 | flow = np.copy(Q) 71 | flow = np.reshape(flow, (Q.shape[0], 1)) 72 | flow = np.insert(flow, 0, list(range(1, Q.shape[0]+1)), axis = 1) 73 | flow = flow[np.argsort(flow[:, 1])] 74 | flow = flow[::-1] 75 | ranking(flow) 76 | return Q 77 | 78 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/e_tri_nb.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Credibility 9 | def credibility(x, y, w, q, p, v): 10 | x = np.asarray(x, dtype = float) 11 | y = np.asarray(y, dtype = float) 12 | w = np.asarray(w, dtype = float) 13 | q = np.asarray(q, dtype = float) 14 | p = np.asarray(p, dtype = float) 15 | v = np.asarray(v, dtype = float) 16 | d = y - x 17 | c = np.zeros_like(d, dtype = float) 18 | mask_full = d <= q 19 | c[mask_full] = 1.0 20 | mask_int = (~mask_full) & (d < p) 21 | c[mask_int] = (p[mask_int] - d[mask_int]) / (p[mask_int] - q[mask_int]) 22 | C = (w * c).sum() / w.sum() 23 | D = np.zeros_like(d, dtype = float) 24 | mask_full_dis = d >= v 25 | D[mask_full_dis] = 1.0 26 | mask_int_dis = (d > p) & (~mask_full_dis) 27 | D[mask_int_dis] = (d[mask_int_dis] - p[mask_int_dis]) / (v[mask_int_dis] - p[mask_int_dis]) 28 | sigma = C 29 | if C < 1.0: 30 | for Dj in D: 31 | if Dj > C: 32 | sigma *= (1 - Dj) / (1 - C) 33 | return float(sigma) 34 | 35 | # Function: Profiles 36 | def relations_x_Bk(x, Bk, w, q, p, v, lam): 37 | Bk = np.asarray(Bk, dtype = float) 38 | n_prof = Bk.shape[0] 39 | if n_prof == 0: 40 | return False, False 41 | 42 | sig_xb = np.zeros(n_prof) 43 | sig_bx = np.zeros(n_prof) 44 | for j in range(0, n_prof): 45 | sig_xb[j] = credibility(x, Bk[j], w, q, p, v) 46 | sig_bx[j] = credibility(Bk[j], x, w, q, p, v) 47 | 48 | S_xb = sig_xb >= lam 49 | S_bx = sig_bx >= lam 50 | xP_b = S_xb & (~S_bx) 51 | bP_x = S_bx & (~S_xb) 52 | xS_Bk = S_xb.any() and (not bP_x.any()) 53 | BkP_x = bP_x.any() and (not xP_b.any()) 54 | return xS_Bk, BkP_x 55 | 56 | ############################################################################### 57 | 58 | # Function: Electre Tri - nB 59 | def electre_tri_nb(perf_matrix, B_sets, w, q, p, v, lam = 0.7): 60 | X = np.asarray(perf_matrix, dtype = float) 61 | n_alt, m = X.shape 62 | M = len(B_sets) - 1 63 | xS_Bk = np.zeros((n_alt, M+1), dtype = bool) 64 | BkP_x = np.zeros((n_alt, M+1), dtype = bool) 65 | for i in range(0, n_alt): 66 | x = X[i] 67 | for k in range(0, M+1): 68 | s, p_rel = relations_x_Bk(x, B_sets[k], w, q, p, v, lam) 69 | xS_Bk[i, k] = s 70 | BkP_x[i, k] = p_rel 71 | 72 | C_pc = np.ones(n_alt, dtype = int) 73 | 74 | for i in range(0, n_alt): 75 | for k in range(M, 0, -1): 76 | k_minus = k - 1 77 | cond1 = xS_Bk[i, k_minus] 78 | cond2 = True 79 | if k_minus > 0: 80 | cond2 = not BkP_x[i, :k_minus].any() 81 | if cond1 and cond2: 82 | C_pc[i] = k 83 | break 84 | C_pd = np.ones(n_alt, dtype = int) 85 | for i in range(0, n_alt): 86 | assigned = False 87 | for k in range(1, M+1): 88 | cond1 = BkP_x[i, k] 89 | cond2 = True 90 | if k < M: 91 | cond2 = not xS_Bk[i, k+1:].any() 92 | if cond1 and cond2: 93 | C_pd[i] = k 94 | assigned = True 95 | break 96 | if not assigned: 97 | C_pd[i] = 1 98 | return C_pc, C_pd 99 | 100 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_moora.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: Fuzzy MOORA (Multi-objective Optimization on the basis of Ratio Analysis) 32 | def fuzzy_moora_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X_a = np.zeros((len(dataset), len(dataset[0]))) 34 | X_b = np.zeros((len(dataset), len(dataset[0]))) 35 | X_c = np.zeros((len(dataset), len(dataset[0]))) 36 | S_a = np.zeros((len(dataset))) 37 | S_b = np.zeros((len(dataset))) 38 | S_c = np.zeros((len(dataset))) 39 | R_a = np.zeros((len(dataset))) 40 | R_b = np.zeros((len(dataset))) 41 | R_c = np.zeros((len(dataset))) 42 | weights_a = np.zeros(len(weights[0])) 43 | weights_b = np.zeros(len(weights[0])) 44 | weights_c = np.zeros(len(weights[0])) 45 | for j in range(0, X_a.shape[1]): 46 | weights_a[j] = weights[0][j][0] 47 | weights_b[j] = weights[0][j][1] 48 | weights_c[j] = weights[0][j][2] 49 | for i in range(0, X_a.shape[0]): 50 | a, b, c = dataset[i][j] 51 | X_a[i,j] = a 52 | X_b[i,j] = b 53 | X_c[i,j] = c 54 | for j in range(0, X_a.shape[1]): 55 | X_a[:, j] = X_a[:, j] / np.sum(X_a[:, j]**2 + X_b[:, j]**2 + X_c[:, j]**2)**(1/2) 56 | X_b[:, j] = X_b[:, j] / np.sum(X_a[:, j]**2 + X_b[:, j]**2 + X_c[:, j]**2)**(1/2) 57 | X_c[:, j] = X_c[:, j] / np.sum(X_a[:, j]**2 + X_b[:, j]**2 + X_c[:, j]**2)**(1/2) 58 | for j in range(0, X_a.shape[1]): 59 | X_a[:, j] = X_a[:, j] * weights_a[j] 60 | X_b[:, j] = X_b[:, j] * weights_b[j] 61 | X_c[:, j] = X_c[:, j] * weights_c[j] 62 | for i in range(0, X_a.shape[0]): 63 | for j in range(0, X_a.shape[1]): 64 | if (criterion_type[j] == 'max'): 65 | S_a[i] = S_a[i] + X_a[i, j] 66 | S_b[i] = S_b[i] + X_b[i, j] 67 | S_c[i] = S_c[i] + X_c[i, j] 68 | else: 69 | R_a[i] = R_a[i] + X_a[i, j] 70 | R_b[i] = R_b[i] + X_b[i, j] 71 | R_c[i] = R_c[i] + X_c[i, j] 72 | S = ( (1/3)*( (S_a - R_a) + (S_b - R_b) + (S_c - R_c) ) )**(1/2) 73 | if (verbose == True): 74 | for i in range(0, S.shape[0]): 75 | print('a' + str(i+1) + ': ' + str(round(S[i], 3))) 76 | if (graph == True): 77 | flow = np.copy(S) 78 | flow = np.reshape(flow, (S.shape[0], 1)) 79 | flow = np.insert(flow, 0, list(range(1, S.shape[0]+1)), axis = 1) 80 | flow = flow[np.argsort(flow[:, 1])] 81 | flow = flow[::-1] 82 | ranking(flow) 83 | return S -------------------------------------------------------------------------------- /pyDecision/algorithm/vikor.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: VIKOR 32 | def vikor_method(dataset, weights, criterion_type, strategy_coefficient = 0.5, graph = True, verbose = True): 33 | X = np.copy(dataset) 34 | w = np.copy(weights) 35 | best = np.zeros(X.shape[1]) 36 | worst = np.zeros(X.shape[1]) 37 | for i in range(0, dataset.shape[1]): 38 | if (criterion_type[i] == 'max'): 39 | best[i] = np.max(X[:, i]) 40 | worst[i] = np.min(X[:, i]) 41 | else: 42 | best[i] = np.min(X[:, i]) 43 | worst[i] = np.max(X[:, i]) 44 | s_i = w * ( abs(best - X) / (abs(best - worst) + 0.0000000000000001) ) 45 | r_i = np.max(s_i, axis = 1) 46 | s_i = np.sum(s_i, axis = 1) 47 | s_best = np.min(s_i) 48 | s_worst = np.max(s_i) 49 | r_best = np.min(r_i) 50 | r_worst = np.max(r_i) 51 | q_i = strategy_coefficient*( (s_i - s_best) / (s_worst - s_best) ) + (1 - strategy_coefficient)*( (r_i - r_best) / (r_worst - r_best) ) 52 | dq = 1 /(X.shape[0] - 1) 53 | flow_s = np.copy(s_i) 54 | flow_s = np.reshape(flow_s, (s_i.shape[0], 1)) 55 | flow_s = np.insert(flow_s, 0, list(range(1, s_i.shape[0]+1)), axis = 1) 56 | flow_s = flow_s[np.argsort(flow_s[:, 1])] 57 | flow_r = np.copy(r_i) 58 | flow_r = np.reshape(flow_r, (r_i.shape[0], 1)) 59 | flow_r = np.insert(flow_r, 0, list(range(1, r_i.shape[0]+1)), axis = 1) 60 | flow_r = flow_r[np.argsort(flow_r[:, 1])] 61 | flow_q = np.copy(q_i) 62 | flow_q = np.reshape(flow_q, (q_i.shape[0], 1)) 63 | flow_q = np.insert(flow_q, 0, list(range(1, q_i.shape[0]+1)), axis = 1) 64 | flow_q = flow_q[np.argsort(flow_q[:, 1])] 65 | condition_1 = False 66 | condition_2 = False 67 | if (flow_q[1, 1] - flow_q[0, 1] >= dq): 68 | condition_1 = True 69 | if (flow_q[0,0] == flow_s[0,0] or flow_q[0,0] == flow_r[0,0]): 70 | condition_2 = True 71 | solution = np.copy(flow_q) 72 | if (condition_1 == True and condition_2 == False): 73 | solution = np.copy(flow_q[0:2,:]) 74 | elif (condition_1 == False and condition_2 == True): 75 | for i in range(solution.shape[0] -1, -1, -1): 76 | if(solution[i, 1] - solution[0, 1] >= dq): 77 | solution = np.delete(solution, i, axis = 0) 78 | if (verbose == True): 79 | for i in range(0, solution.shape[0]): 80 | print('a' + str(i+1) + ': ' + str(round(solution[i, 0], 2))) 81 | if ( graph == True): 82 | ranking(solution) 83 | return flow_s, flow_r, flow_q, solution 84 | 85 | ############################################################################### 86 | -------------------------------------------------------------------------------- /pyDecision/algorithm/lmaw.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | ############################################################################### 32 | 33 | # Function: LMAW (Logarithm Methodology of Additive Weights) 34 | def lmaw_method(performance_matrix, weights, criterion_type, graph = True, verbose = True): 35 | performance_matrix = performance_matrix.astype(np.float64) 36 | m, n = performance_matrix.shape 37 | weights = np.asarray(weights, dtype = np.float64).reshape(1, n) 38 | weights = weights/np.sum(weights) 39 | eps = np.finfo(np.float64).eps 40 | col_max = np.max(performance_matrix, axis = 0) 41 | col_min = np.min(performance_matrix, axis = 0) 42 | standardized_matrix = np.empty_like(performance_matrix) 43 | for j in range(n): 44 | if (criterion_type[j] == 'max'): 45 | denom = col_max[j] if np.abs(col_max[j]) > eps else eps 46 | standardized_matrix[:, j] = (performance_matrix[:, j] + col_max[j]) / denom 47 | else: 48 | denom = np.where(np.abs(performance_matrix[:, j]) < eps, eps, performance_matrix[:, j]) 49 | standardized_matrix[:, j] = (performance_matrix[:, j] + col_min[j]) / denom 50 | standardized_matrix = np.where(standardized_matrix <= 0, eps, standardized_matrix) 51 | log_std = np.log(standardized_matrix) 52 | prod_g = np.prod(standardized_matrix, axis = 0) 53 | safe_prod_g = np.where(prod_g <= 0, eps, prod_g) 54 | log_prod = np.log(safe_prod_g) 55 | log_prod = np.where(np.abs(log_prod) < eps, eps, log_prod) 56 | phi_matrix = log_std / log_prod 57 | phi_w = np.power(phi_matrix, weights) 58 | two_minus_phi_w = np.power(2 - phi_matrix, weights) 59 | denominator = two_minus_phi_w + phi_w 60 | denominator = np.where(np.abs(denominator) < eps, eps, denominator) 61 | weighted_matrix = (2 * phi_w) / denominator 62 | ranking_scores = np.sum(weighted_matrix, axis = 1) 63 | if (verbose == True): 64 | for i in range(0, ranking_scores .shape[0]): 65 | print('a' + str(i+1) + ': ' + str(round(ranking_scores [i], 4))) 66 | if ( graph == True): 67 | flow = np.copy(ranking_scores) 68 | flow = np.reshape(flow, (ranking_scores .shape[0], 1)) 69 | flow = np.insert(flow, 0, list(range(1, ranking_scores .shape[0]+1)), axis = 1) 70 | flow = flow[np.argsort(flow[:, 1])] 71 | flow = flow[::-1] 72 | ranking(flow) 73 | return ranking_scores 74 | 75 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/__init__.py: -------------------------------------------------------------------------------- 1 | from .ahp import ahp_method 2 | from .anp import anp_method 3 | from .aras import aras_method 4 | from .borda import borda_method 5 | from .bwm import bw_method 6 | from .bwm_s import simplified_bw_method 7 | from .cilos import cilos_method 8 | from .cocoso import cocoso_method 9 | from .codas import codas_method 10 | from .copeland import copeland_method 11 | from .copras import copras_method 12 | from .cpp_tri import cpp_tri_method 13 | from .cradis import cradis_method 14 | from .critic import critic_method 15 | from .dematel import dematel_method 16 | from .e_i import electre_i 17 | from .e_i_s import electre_i_s 18 | from .e_i_v import electre_i_v 19 | from .e_ii import electre_ii 20 | from .e_iii import electre_iii 21 | from .e_iv import electre_iv 22 | from .e_tri_b import electre_tri_b 23 | from .e_tri_nb import electre_tri_nb 24 | from .e_tri_c import electre_tri_c 25 | from .e_tri_nc import electre_tri_nc 26 | from .edas import edas_method 27 | from .entropy import entropy_method 28 | from .flowsort import flowsort_method 29 | from .fucom import fucom_method 30 | from .fuzzy_ahp import fuzzy_ahp_method 31 | from .fuzzy_ahp_ppf import ppf_ahp_method 32 | from .fuzzy_aras import fuzzy_aras_method 33 | from .fuzzy_bwm import fuzzy_bw_method 34 | from .fuzzy_copras import fuzzy_copras_method 35 | from .fuzzy_critic import fuzzy_critic_method 36 | from .fuzzy_dematel import fuzzy_dematel_method 37 | from .fuzzy_edas import fuzzy_edas_method 38 | from .fuzzy_fucom import fuzzy_fucom_method 39 | from .fuzzy_merec import fuzzy_merec_method 40 | from .fuzzy_moora import fuzzy_moora_method 41 | from .fuzzy_ocra import fuzzy_ocra_method 42 | from .fuzzy_topsis import fuzzy_topsis_method 43 | from .fuzzy_vikor import fuzzy_vikor_method 44 | from .fuzzy_waspas import fuzzy_waspas_method 45 | from .gra import gra_method 46 | from .idocriw import idocriw_method 47 | from .lmaw import lmaw_method 48 | from .mabac import mabac_method 49 | from .macbeth import macbeth_method 50 | from .mairca import mairca_method 51 | from .mara import mara_method 52 | from .marcos import marcos_method 53 | from .maut import maut_method 54 | from .merec import merec_method 55 | from .moora import moora_method 56 | from .moosra import moosra_method 57 | from .multimoora import multimoora_method 58 | from .ocra import ocra_method 59 | from .opa import opa_method 60 | from .oreste import oreste_method 61 | from .p_ec import ec_promethee, solution_p_ranking, plot_rank_freq, find_column_modes 62 | from .p_i import promethee_i 63 | from .p_ii import promethee_ii 64 | from .p_iii import promethee_iii 65 | from .p_iv import promethee_iv 66 | from .p_v import promethee_v 67 | from .p_vi import promethee_vi 68 | from .p_xgaia import promethee_gaia 69 | from .piv import piv_method 70 | from .psi import psi_method 71 | from .psi_m import mpsi_method 72 | from .rafsi import rafsi_method 73 | from .regime import regime_method 74 | from .roc import roc_method 75 | from .rov import rov_method 76 | from .rrw import rrw_method 77 | from .rsw import rsw_method 78 | from .saw import saw_method 79 | from .seca import seca_method 80 | from .smart import smart_method 81 | from .spotis import spotis_method 82 | from .todim import todim_method 83 | from .topsis import topsis_method 84 | from .utadis_i import utadis_i_method, predict_classes_new 85 | from .utadis_ii import utadis_ii_method 86 | from .utadis_iii import utadis_iii_method 87 | from .vikor import vikor_method, ranking 88 | from .waspas import waspas_method 89 | from .wisp import wisp_method 90 | from .wings import wings_method 91 | -------------------------------------------------------------------------------- /pyDecision/algorithm/e_tri_c.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Matrices 9 | def _tri_c_r_matrices(performance_matrix, C, W, Q, P, V = None): 10 | A = np.array(performance_matrix, dtype = float) 11 | B = np.array(C, dtype = float) 12 | m, n = A.shape 13 | hB = B.shape[0] 14 | W = np.array(W, dtype = float) 15 | W = W / W.sum() 16 | Q = np.array(Q, dtype = float) 17 | P = np.array(P, dtype = float) 18 | if V is not None and len(V) > 0: 19 | V = np.array(V, dtype = float) 20 | use_veto = True 21 | else: 22 | V = None 23 | use_veto = False 24 | 25 | def c(a, b): 26 | d = a - b 27 | if use_veto: 28 | if np.any(-d >= V): 29 | return 0.0 30 | C_I = np.abs(d) <= Q 31 | C_P = d > P 32 | C_Q = (d > Q) & (d <= P) 33 | C_Q_rev = (-d > Q) & (-d <= P) 34 | s = W[C_I | C_Q | C_P].sum() 35 | u = (d + P) / (P - Q) 36 | s = s + (W[C_Q_rev] * u[C_Q_rev]).sum() 37 | return float(s) 38 | 39 | r_ab = np.zeros((m, hB)) 40 | r_ba = np.zeros((m, hB)) 41 | 42 | for a_idx in range(0, m): 43 | for h in range(0, hB): 44 | a_vec = A[a_idx] 45 | b_vec = B[h] 46 | r_ab[a_idx, h] = c(a_vec, b_vec) 47 | r_ba[a_idx, h] = c(b_vec, a_vec) 48 | return r_ab, r_ba 49 | 50 | ############################################################################### 51 | 52 | # Function: Electre Tri-C 53 | def electre_tri_c(performance_matrix, W = [], Q = [], P = [], V = [], C = [], cut_level = 0.6, verbose = True, tol = 1e-9): 54 | A = np.array(performance_matrix, dtype = float) 55 | B = np.array(C, dtype = float) 56 | m, n = A.shape 57 | n_profiles = B.shape[0] 58 | q = n_profiles - 2 59 | r_ab, r_ba = _tri_c_r_matrices(A, B, W, Q, P, V) 60 | 61 | def q_select(a_idx, h_idx): 62 | return min(r_ab[a_idx, h_idx], r_ba[a_idx, h_idx]) 63 | 64 | lowest_classes = [] 65 | highest_classes = [] 66 | 67 | for a in range(0, m): 68 | t = None 69 | for h in range(q + 1, -1, -1): 70 | if r_ab[a, h] >= cut_level - tol: 71 | t = h 72 | break 73 | if t is None: 74 | t = 0 75 | if t == q: 76 | desc_cat = q 77 | elif 0 < t < q: 78 | if q_select(a, t) > q_select(a, t + 1) + tol: 79 | desc_cat = t 80 | else: 81 | desc_cat = t + 1 82 | elif t == 0: 83 | desc_cat = 1 84 | else: 85 | desc_cat = q 86 | 87 | k_idx = None 88 | for h in range(0, q + 2): 89 | if r_ba[a, h] >= cut_level - tol: 90 | k_idx = h 91 | break 92 | if k_idx is None: 93 | k_idx = q + 1 94 | if k_idx == 1: 95 | asc_cat = 1 96 | elif 1 < k_idx < (q + 1): 97 | if q_select(a, k_idx) > q_select(a, k_idx - 1) + tol: 98 | asc_cat = k_idx 99 | else: 100 | asc_cat = k_idx - 1 101 | elif k_idx == (q + 1): 102 | asc_cat = q 103 | else: 104 | asc_cat = 1 105 | 106 | low = min(desc_cat, asc_cat) 107 | high = max(desc_cat, asc_cat) 108 | lowest_classes.append(low) 109 | highest_classes.append(high) 110 | if verbose: 111 | print(f'a{a+1}: [C{low}, C{high}]') 112 | return lowest_classes, highest_classes 113 | 114 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/maut.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Code Contributor: Sabir Mohammedi Taieb - Université Abdelhamid Ibn Badis Mostaganem 4 | 5 | # Required Libraries 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | 9 | ############################################################################### 10 | 11 | # Function: Rank 12 | def ranking(flow): 13 | rank_xy = np.zeros((flow.shape[0], 2)) 14 | for i in range(0, rank_xy.shape[0]): 15 | rank_xy[i, 0] = 0 16 | rank_xy[i, 1] = flow.shape[0]-i 17 | for i in range(0, rank_xy.shape[0]): 18 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 19 | for i in range(0, rank_xy.shape[0]-1): 20 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 21 | axes = plt.gca() 22 | axes.set_xlim([-1, +1]) 23 | ymin = np.amin(rank_xy[:,1]) 24 | ymax = np.amax(rank_xy[:,1]) 25 | if (ymin < ymax): 26 | axes.set_ylim([ymin, ymax]) 27 | else: 28 | axes.set_ylim([ymin-1, ymax+1]) 29 | plt.axis('off') 30 | plt.show() 31 | return 32 | 33 | ############################################################################### 34 | 35 | # Function: Marginal Utility Exp 36 | def u_exp(x): 37 | y = (np.exp(x**2)-1)/1.72 38 | return y 39 | 40 | # Function: Marginal Utility Step 41 | def u_step(x, op): 42 | y = np.ceil(op*x)/op 43 | return y 44 | 45 | # Function: Marginal Utility Log10 46 | def u_log(x): 47 | y = np.log10(9*x+1) 48 | return y 49 | 50 | # Function: Marginal Utility LN 51 | def u_ln(x): 52 | y = np.log((np.exp(1)-1)*x+1) 53 | return y 54 | 55 | # Function: Marginal Utility Quadratic 56 | def u_quad(x): 57 | y = (2*x-1)**2 58 | return y 59 | 60 | ############################################################################### 61 | 62 | # Function: MAUT 63 | def maut_method(dataset, weights, criterion_type, utility_functions, step_size = 1, graph = True, verbose = True): 64 | X = np.copy(dataset)/1.0 65 | for j in range(0, X.shape[1]): 66 | if (criterion_type[j] == 'max'): 67 | X[:, j] = (X[:,j] - np.min(X[:, j]))/(np.max(X[:, j]) - np.min(X[:, j]) + 0.0000000000000001) 68 | else: 69 | X[:, j] = 1 + (np.min(X[:, j])- X[:, j])/(np.max(X[:, j]) - np.min(X[: ,j])+ 0.0000000000000001) 70 | for i in range(0, X.shape[1]): 71 | if (utility_functions[i] == 'exp'): 72 | ArrExp = np.vectorize(u_exp) 73 | X[:, i] = ArrExp(X[:, i]) 74 | elif (utility_functions[i] == 'step'): 75 | ArrStep = np.vectorize(u_step) 76 | X[:, i] = ArrStep(X[:, i], step_size) 77 | elif (utility_functions[i] == 'quad'): 78 | ArrQuad = np.vectorize(u_quad) 79 | X[:, i] = ArrQuad(X[:, i]) 80 | elif (utility_functions[i] == 'log'): 81 | ArrLog = np.vectorize(u_log) 82 | X[:, i] = ArrLog(X[:, i]) 83 | elif (utility_functions[i] == 'ln'): 84 | ArrLn = np.vectorize(u_ln) 85 | X[:, i] = ArrLn(X[:, i]) 86 | for i in range(0, X.shape[1]): 87 | X[:, i] = X[:, i]*weights[i] 88 | Y = np.sum(X, axis = 1) 89 | flow = np.copy(Y) 90 | flow = np.reshape(flow, (Y.shape[0], 1)) 91 | flow = np.insert(flow, 0, list(range(1, Y.shape[0]+1)), axis = 1) 92 | if (verbose == True): 93 | for i in range(0, flow.shape[0]): 94 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 95 | if (graph == True): 96 | flow = flow[np.argsort(flow[:, 1])] 97 | flow = flow[::-1] 98 | ranking(flow) 99 | return flow 100 | 101 | ############################################################################### 102 | -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_dematel.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | ############################################################################### 9 | 10 | # Function: Fuzzy DEMATEL 11 | def fuzzy_dematel_method(dataset, size_x = 10, size_y = 10): 12 | X_a = np.zeros((len(dataset), len(dataset))) 13 | X_b = np.zeros((len(dataset), len(dataset))) 14 | X_c = np.zeros((len(dataset), len(dataset))) 15 | m_a = np.ones ((len(dataset), len(dataset))) # min 16 | m_c = np.zeros((len(dataset), len(dataset))) # max 17 | for i in range(0, len(dataset)): 18 | for j in range(0, len(dataset)): 19 | a, b, c = dataset[i][j] 20 | X_a[i,j] = a 21 | X_b[i,j] = b 22 | X_c[i,j] = c 23 | if (a < m_a[i,j]): 24 | m_a[i,j] = a 25 | if (c > m_c[i,j]): 26 | m_c[i,j] = c 27 | m_a = np.min(m_a, axis = 1) 28 | m_c = np.max(m_c, axis = 1) 29 | X_a = (X_a - m_a) / (m_c - m_a) 30 | X_b = (X_b - m_a) / (m_c - m_a) 31 | X_c = (X_c - m_a) / (m_c - m_a) 32 | L = X_b / (1 + X_b - X_a) 33 | R = X_c / (1 + X_c - X_b) 34 | W = (L * (1 - L) + R * R) / (1 - L + R) 35 | Z = m_a + W * (m_c - m_a) 36 | X = Z/np.max(np.sum(Z, axis = 1)) 37 | Y = np.linalg.inv(np.identity(X.shape[0]) - X) 38 | T = np.matmul(X, Y) 39 | D = np.sum(T, axis = 1) 40 | R = np.sum(T, axis = 0) 41 | D_plus_R = D + R 42 | D_minus_R = D - R 43 | weights = (D_plus_R - D_minus_R)/(np.sum(D_plus_R + D_minus_R)) 44 | print('QUADRANT I has the Most Important Criteria (Prominence: High, Relation: High)') 45 | print('QUADRANT II has Important Criteira that can be Improved by Other Criteria (Prominence: Low, Relation: High)') 46 | print('QUADRANT III has Criteria that are not Important (Prominence: Low, Relation: Low)') 47 | print('QUADRANT IV has Important Criteria that cannot be Improved by Other Criteria (Prominence: High, Relation: Low)') 48 | print('') 49 | plt.figure(figsize = [size_x, size_y]) 50 | plt.style.use('ggplot') 51 | for i in range(0, len(dataset)): 52 | if (D_minus_R[i] >= 0 and D_plus_R[i] >= np.mean(D_plus_R)): 53 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.7, 1.0, 0.7),)) 54 | print('g'+str(i+1)+': Quadrant I') 55 | elif (D_minus_R[i] >= 0 and D_plus_R[i] < np.mean(D_plus_R)): 56 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (1.0, 1.0, 0.7),)) 57 | print('g'+str(i+1)+': Quadrant II') 58 | elif (D_minus_R[i] < 0 and D_plus_R[i] < np.mean(D_plus_R)): 59 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (1.0, 0.7, 0.7),)) 60 | print('g'+str(i+1)+': Quadrant III') 61 | else: 62 | plt.text(D_plus_R[i], D_minus_R[i], 'g'+str(i+1), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.7, 0.7, 1.0),)) 63 | print('g'+str(i+1)+': Quadrant IV') 64 | axes = plt.gca() 65 | xmin = np.amin(D_plus_R) 66 | if (xmin > 0): 67 | xmin = 0 68 | xmax = np.amax(D_plus_R) 69 | if (xmax < 0): 70 | xmax = 0 71 | axes.set_xlim([xmin-1, xmax+1]) 72 | ymin = np.amin(D_minus_R) 73 | if (ymin > 0): 74 | ymin = 0 75 | ymax = np.amax(D_minus_R) 76 | if (ymax < 0): 77 | ymax = 0 78 | axes.set_ylim([ymin-1, ymax+1]) 79 | plt.axvline(x = np.mean(D_plus_R), linewidth = 0.9, color = 'r', linestyle = 'dotted') 80 | plt.axhline(y = 0, linewidth = 0.9, color = 'r', linestyle = 'dotted') 81 | plt.xlabel('Prominence (D + R)') 82 | plt.ylabel('Relation (D - R)') 83 | plt.show() 84 | return D_plus_R, D_minus_R, weights 85 | 86 | ############################################################################### 87 | -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_ocra.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: Fuzzy OCRA (Operational Competitiveness RAting) 32 | def fuzzy_ocra_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X_a = np.zeros((len(dataset), len(dataset[0]))) 34 | X_b = np.zeros((len(dataset), len(dataset[0]))) 35 | X_c = np.zeros((len(dataset), len(dataset[0]))) 36 | I_a = np.zeros((len(dataset))) 37 | I_b = np.zeros((len(dataset))) 38 | I_c = np.zeros((len(dataset))) 39 | O_a = np.zeros((len(dataset))) 40 | O_b = np.zeros((len(dataset))) 41 | O_c = np.zeros((len(dataset))) 42 | P_a = np.zeros((len(dataset))) 43 | P_b = np.zeros((len(dataset))) 44 | P_c = np.zeros((len(dataset))) 45 | weights_a = np.zeros(len(weights[0])) 46 | weights_b = np.zeros(len(weights[0])) 47 | weights_c = np.zeros(len(weights[0])) 48 | for j in range(0, X_a.shape[1]): 49 | weights_a[j] = weights[0][j][0] 50 | weights_b[j] = weights[0][j][1] 51 | weights_c[j] = weights[0][j][2] 52 | for i in range(0, X_a.shape[0]): 53 | a, b, c = dataset[i][j] 54 | X_a[i,j] = a 55 | X_b[i,j] = b 56 | X_c[i,j] = c 57 | for i in range(0, X_a.shape[0]): 58 | for j in range(0, X_a.shape[1]): 59 | if (criterion_type[j] == 'max'): 60 | O_a[i] = O_a[i] + weights_a[j] * (X_a[i, j] - np.min(X_a[:, j])) / np.min(X_a[:, j]) 61 | O_b[i] = O_b[i] + weights_b[j] * (X_b[i, j] - np.min(X_b[:, j])) / np.min(X_b[:, j]) 62 | O_c[i] = O_c[i] + weights_c[j] * (X_c[i, j] - np.min(X_c[:, j])) / np.min(X_c[:, j]) 63 | else: 64 | I_a[i] = I_a[i] + weights_a[j] * (np.max(X_a[:, j]) - X_a[i, j]) / np.min(X_a[:, j]) 65 | I_b[i] = I_b[i] + weights_b[j] * (np.max(X_b[:, j]) - X_b[i, j]) / np.min(X_b[:, j]) 66 | I_c[i] = I_c[i] + weights_c[j] * (np.max(X_c[:, j]) - X_c[i, j]) / np.min(X_c[:, j]) 67 | min_i_a = np.min(I_a) 68 | min_i_b = np.min(I_b) 69 | min_i_c = np.min(I_c) 70 | min_o_a = np.min(O_a) 71 | min_o_b = np.min(O_b) 72 | min_o_c = np.min(O_c) 73 | I_a = I_a - min_i_a 74 | I_b = I_b - min_i_b 75 | I_c = I_c - min_i_c 76 | O_a = O_a - min_o_a 77 | O_b = O_b - min_o_b 78 | O_c = O_c - min_o_c 79 | P_a = I_a + O_a - np.min(I_a + O_a) 80 | P_b = I_b + O_b - np.min(I_b + O_b) 81 | P_c = I_c + O_c - np.min(I_c + O_c) 82 | P = (P_a + P_b + P_c) / 3 83 | if (verbose == True): 84 | for i in range(0, P.shape[0]): 85 | print('a' + str(i+1) + ': ' + str(round(P[i], 3))) 86 | if (graph == True): 87 | flow = np.copy(P) 88 | flow = np.reshape(flow, (P.shape[0], 1)) 89 | flow = np.insert(flow, 0, list(range(1, P.shape[0]+1)), axis = 1) 90 | flow = flow[np.argsort(flow[:, 1])] 91 | flow = flow[::-1] 92 | ranking(flow) 93 | return P -------------------------------------------------------------------------------- /pyDecision/algorithm/waspas.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking_m(flow_1, flow_2, flow_3): 11 | rank_xy = np.zeros((flow_1.shape[0] + 1, 6)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = -1 14 | rank_xy[i, 1] = flow_1.shape[0]-i+1 15 | rank_xy[i, 2] = 0 16 | rank_xy[i, 3] = flow_2.shape[0]-i+1 17 | rank_xy[i, 4] = 1 18 | rank_xy[i, 5] = flow_3.shape[0]-i+1 19 | plt.text(rank_xy[0, 0], rank_xy[0, 1], 'WSM', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 20 | plt.text(rank_xy[0, 2], rank_xy[0, 3], 'WPM', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 21 | plt.text(rank_xy[0, 4], rank_xy[0, 5], 'WASPAS', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 22 | for i in range(1, rank_xy.shape[0]): 23 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow_1[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = "round", ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 24 | plt.text(rank_xy[i, 2], rank_xy[i, 3], 'a' + str(int(flow_2[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 25 | plt.text(rank_xy[i, 4], rank_xy[i, 5], 'a' + str(int(flow_3[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 26 | for i in range(1, rank_xy.shape[0]-1): 27 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 28 | plt.arrow(rank_xy[i, 2], rank_xy[i, 3], rank_xy[i+1, 2] - rank_xy[i, 2], rank_xy[i+1, 3] - rank_xy[i, 3], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 29 | plt.arrow(rank_xy[i, 4], rank_xy[i, 5], rank_xy[i+1, 4] - rank_xy[i, 4], rank_xy[i+1, 5] - rank_xy[i, 5], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 30 | axes = plt.gca() 31 | axes.set_xlim([-2, +2]) 32 | ymin = np.amin(rank_xy[:,1]) 33 | ymax = np.amax(rank_xy[:,1]) 34 | if (ymin < ymax): 35 | axes.set_ylim([ymin, ymax]) 36 | else: 37 | axes.set_ylim([ymin-1, ymax+1]) 38 | plt.axis('off') 39 | plt.show() 40 | return 41 | 42 | # Function: WASPAS 43 | def waspas_method(dataset, criterion_type, weights, lambda_value, graph = True): 44 | x = np.zeros((dataset.shape[0], dataset.shape[1]), dtype = float) 45 | for j in range(0, dataset.shape[1]): 46 | if (criterion_type[j] == 'max'): 47 | x[:,j] = 1 + ( dataset[:,j] - np.min(dataset[:,j]) ) / ( np.max(dataset[:,j]) - np.min(dataset[:,j]) ) 48 | else: 49 | x[:,j] = 1 + ( np.max(dataset[:,j]) - dataset[:,j] ) / ( np.max(dataset[:,j]) - np.min(dataset[:,j]) ) 50 | wsm = np.sum(x*weights, axis = 1) 51 | wpm = np.prod(x**weights, axis = 1) 52 | waspas = (lambda_value)*wsm + (1 - lambda_value)*wpm 53 | flow_1 = np.copy(wsm) 54 | flow_1 = np.reshape(flow_1, (wsm.shape[0], 1)) 55 | flow_1 = np.insert(flow_1, 0, list(range(1, wsm.shape[0]+1)), axis = 1) 56 | flow_2 = np.copy(wpm) 57 | flow_2 = np.reshape(flow_2, (wpm.shape[0], 1)) 58 | flow_2 = np.insert(flow_2, 0, list(range(1, wpm.shape[0]+1)), axis = 1) 59 | flow_3 = np.copy(waspas) 60 | flow_3 = np.reshape(flow_3, (waspas.shape[0], 1)) 61 | flow_3 = np.insert(flow_3, 0, list(range(1, waspas.shape[0]+1)), axis = 1) 62 | if (graph == True): 63 | ranking_m(flow_1[np.argsort(flow_1[:, 1])[::-1]], flow_2[np.argsort(flow_2[:, 1])[::-1]], flow_3[np.argsort(flow_3[:, 1])[::-1]]) 64 | return wsm, wpm, waspas 65 | 66 | ############################################################################### 67 | 68 | -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_topsis.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import copy 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | ############################################################################### 9 | 10 | # Function: Rank 11 | def ranking(flow): 12 | rank_xy = np.zeros((flow.shape[0], 2)) 13 | for i in range(0, rank_xy.shape[0]): 14 | rank_xy[i, 0] = 0 15 | rank_xy[i, 1] = flow.shape[0]-i 16 | for i in range(0, rank_xy.shape[0]): 17 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 18 | for i in range(0, rank_xy.shape[0]-1): 19 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 20 | axes = plt.gca() 21 | axes.set_xlim([-1, +1]) 22 | ymin = np.amin(rank_xy[:,1]) 23 | ymax = np.amax(rank_xy[:,1]) 24 | if (ymin < ymax): 25 | axes.set_ylim([ymin, ymax]) 26 | else: 27 | axes.set_ylim([ymin-1, ymax+1]) 28 | plt.axis('off') 29 | plt.show() 30 | return 31 | 32 | # Function: Fuzzy TOPSIS 33 | def fuzzy_topsis_method(dataset, weights, criterion_type, graph = True, verbose = True): 34 | r_ij = copy.deepcopy(dataset) 35 | v_ij = copy.deepcopy(dataset) 36 | p_ideal_A = copy.deepcopy(weights) 37 | n_ideal_A = copy.deepcopy(weights) 38 | dist_p = np.zeros( (len(dataset), len(dataset[0])) ) 39 | dist_n = np.zeros( (len(dataset), len(dataset[0])) ) 40 | for j in range(0, len(dataset[0])): 41 | c_star = -float('inf') 42 | a_minus = float('inf') 43 | for i in range(0, len(dataset)): 44 | a, b, c = dataset[i][j] 45 | if (c >= c_star and criterion_type[j] == 'max'): 46 | c_star = c 47 | if (a <= a_minus and criterion_type[j] == 'min'): 48 | a_minus = a 49 | if (criterion_type[j] == 'max'): 50 | for i in range(0, len(r_ij)): 51 | a, b, c = r_ij[i][j] 52 | r_ij[i][j] = (a/c_star, b/c_star, c/c_star) 53 | else: 54 | for i in range(0, len(r_ij)): 55 | a, b, c = r_ij[i][j] 56 | r_ij[i][j] = (a_minus/c, a_minus/b, a_minus/a) 57 | for i in range(0, len(r_ij)): 58 | a, b, c = r_ij[i][j] 59 | d, e, f = weights[0][j] 60 | v_ij[i][j] = (a*d, b*e, c*f) 61 | d, e, f = v_ij[0][j] 62 | x, y, z = v_ij[0][j] 63 | for i in range(0, len(v_ij)): 64 | a, b, c = v_ij[i][j] 65 | if (a > d): 66 | d = a 67 | if (b > e): 68 | e = b 69 | if (c > f): 70 | f = c 71 | if (a < x): 72 | x = a 73 | if (b < y): 74 | y = b 75 | if (c < z): 76 | z = c 77 | p_ideal_A[0][j] = (d, e, f) 78 | n_ideal_A[0][j] = (x, y, z) 79 | for i in range(0, dist_p.shape[0]): 80 | for j in range(0, dist_p.shape[1]): 81 | a, b, c = v_ij[i][j] 82 | x, y, z = p_ideal_A[0][j] 83 | d, e, f = n_ideal_A[0][j] 84 | dist_p[i][j] = ( (1/dist_p.shape[1])* ( (a-x)**2 + (b-y)**2 + (c-z)**2 ) )**(1/2) 85 | dist_n[i][j] = ( (1/dist_n.shape[1])* ( (a-d)**2 + (b-e)**2 + (c-f)**2 ) )**(1/2) 86 | d_plus = np.sum(dist_p, axis = 1) 87 | d_minus = np.sum(dist_n, axis = 1) 88 | c_i = d_minus / (d_minus + d_plus) 89 | if (verbose == True): 90 | for i in range(0, c_i.shape[0]): 91 | print('a' + str(i+1) + ': ' + str(round(c_i[i], 4))) 92 | if ( graph == True): 93 | flow = np.copy(c_i) 94 | flow = np.reshape(flow, (c_i.shape[0], 1)) 95 | flow = np.insert(flow, 0, list(range(1, c_i.shape[0]+1)), axis = 1) 96 | flow = flow[np.argsort(flow[:, 1])] 97 | flow = flow[::-1] 98 | ranking(flow) 99 | return c_i 100 | 101 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/e_tri_nc.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | 6 | ############################################################################### 7 | 8 | # Function: Matrices 9 | def _tri_nc_r_matrices(performance_matrix, B_list, W, Q, P, V = None): 10 | A = np.array(performance_matrix, dtype = float) 11 | m, n = A.shape 12 | W = np.array(W, dtype = float) 13 | W = W / W.sum() 14 | Q = np.array(Q, dtype = float) 15 | P = np.array(P, dtype = float) 16 | 17 | if V is not None and len(V) > 0: 18 | V = np.array(V, dtype = float) 19 | use_veto = True 20 | else: 21 | V = None 22 | use_veto = False 23 | 24 | def c(a, b): 25 | d = a - b 26 | if use_veto: 27 | if np.any(-d >= V): 28 | return 0.0 29 | C_I = np.abs(d) <= Q 30 | C_P = d > P 31 | C_Q = (d > Q) & (d <= P) 32 | C_Q_rev = (-d > Q) & (-d <= P) 33 | s = W[C_I | C_Q | C_P].sum() 34 | u = (d + P) / (P - Q) 35 | s = s + (W[C_Q_rev] * u[C_Q_rev]).sum() 36 | return float(s) 37 | 38 | if isinstance(B_list, np.ndarray): 39 | if B_list.ndim != 2: 40 | raise ValueError("When using numpy array for C/B, it must be 2D.") 41 | subsets = [B_list[h:h+1, :] for h in range(B_list.shape[0])] 42 | else: 43 | subsets = [np.atleast_2d(np.array(Bh, dtype=float)) for Bh in B_list] 44 | 45 | hB = len(subsets) 46 | r_ab = np.zeros((m, hB)) 47 | r_ba = np.zeros((m, hB)) 48 | 49 | for a_idx in range(0, m): 50 | a_vec = A[a_idx] 51 | for h, Bh in enumerate(subsets): 52 | best_ab = 0.0 53 | best_ba = 0.0 54 | for b_vec in Bh: 55 | cab = c(a_vec, b_vec) 56 | cba = c(b_vec, a_vec) 57 | if cab > best_ab: 58 | best_ab = cab 59 | if cba > best_ba: 60 | best_ba = cba 61 | r_ab[a_idx, h] = best_ab 62 | r_ba[a_idx, h] = best_ba 63 | return r_ab, r_ba 64 | 65 | ############################################################################### 66 | 67 | # Function: Electre Tri - nC 68 | def electre_tri_nc(performance_matrix, W = [], Q = [], P = [], V = [], C = None, cut_level = 0.6, verbose = True, tol = 1e-9): 69 | A = np.array(performance_matrix, dtype = float) 70 | m, n = A.shape 71 | num_subsets = len(C) 72 | if num_subsets < 3: 73 | raise ValueError("There must be at least 3 subsets of reference actions (B0, B1..Bq, Bq+1).") 74 | q = num_subsets - 2 75 | r_ab, r_ba = _tri_nc_r_matrices(A, C, W, Q, P, V) 76 | 77 | def q_select(a_idx, h_idx): 78 | return min(r_ab[a_idx, h_idx], r_ba[a_idx, h_idx]) 79 | 80 | lowest_classes = [] 81 | highest_classes = [] 82 | 83 | for a in range(m): 84 | t = None 85 | for h in range(q + 1, -1, -1): 86 | if r_ab[a, h] >= cut_level - tol: 87 | t = h 88 | break 89 | if t is None: 90 | t = 0 91 | if t == q: 92 | desc_cat = q 93 | elif 0 < t < q: 94 | if q_select(a, t) > q_select(a, t + 1) + tol: 95 | desc_cat = t 96 | else: 97 | desc_cat = t + 1 98 | elif t == 0: 99 | desc_cat = 1 100 | else: 101 | desc_cat = q 102 | 103 | k_idx = None 104 | for h in range(0, q + 2): 105 | if r_ba[a, h] >= cut_level - tol: 106 | k_idx = h 107 | break 108 | if k_idx is None: 109 | k_idx = q + 1 110 | if k_idx == 1: 111 | asc_cat = 1 112 | elif 1 < k_idx < (q + 1): 113 | if q_select(a, k_idx) > q_select(a, k_idx - 1) + tol: 114 | asc_cat = k_idx 115 | else: 116 | asc_cat = k_idx - 1 117 | elif k_idx == (q + 1): 118 | asc_cat = q 119 | else: 120 | asc_cat = 1 121 | low = min(desc_cat, asc_cat) 122 | high = max(desc_cat, asc_cat) 123 | lowest_classes.append(low) 124 | highest_classes.append(high) 125 | if verbose: 126 | print(f'a{a+1}: [C{low}, C{high}]') 127 | return lowest_classes, highest_classes 128 | 129 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_copras.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking(flow): 11 | rank_xy = np.zeros((flow.shape[0], 2)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = 0 14 | rank_xy[i, 1] = flow.shape[0]-i 15 | for i in range(0, rank_xy.shape[0]): 16 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 17 | for i in range(0, rank_xy.shape[0]-1): 18 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 19 | axes = plt.gca() 20 | axes.set_xlim([-1, +1]) 21 | ymin = np.amin(rank_xy[:,1]) 22 | ymax = np.amax(rank_xy[:,1]) 23 | if (ymin < ymax): 24 | axes.set_ylim([ymin, ymax]) 25 | else: 26 | axes.set_ylim([ymin-1, ymax+1]) 27 | plt.axis('off') 28 | plt.show() 29 | return 30 | 31 | # Function: Fuzzy COPRAS (Complex Proportional Assessment) 32 | def fuzzy_copras_method(dataset, weights, criterion_type, graph = True, verbose = True): 33 | X_a = np.zeros((len(dataset), len(dataset[0]))) 34 | X_b = np.zeros((len(dataset), len(dataset[0]))) 35 | X_c = np.zeros((len(dataset), len(dataset[0]))) 36 | weights_a = np.zeros(len(weights[0])) 37 | weights_b = np.zeros(len(weights[0])) 38 | weights_c = np.zeros(len(weights[0])) 39 | for j in range(0, X_a.shape[1]): 40 | weights_a[j] = weights[0][j][0] 41 | weights_b[j] = weights[0][j][1] 42 | weights_c[j] = weights[0][j][2] 43 | for i in range(0, X_a.shape[0]): 44 | a, b, c = dataset[i][j] 45 | X_a[i,j] = a 46 | X_b[i,j] = b 47 | X_c[i,j] = c 48 | for j in range(0, X_a.shape[1]): 49 | #if (criterion_type[j] == 'max'): 50 | X_a[:, j] = X_a[:, j] / np.max(X_c[:, j]) 51 | X_b[:, j] = X_b[:, j] / np.max(X_c[:, j]) 52 | X_c[:, j] = X_c[:, j] / np.max(X_c[:, j]) 53 | #else: 54 | #X_a[:, j] = np.min(X_a[:, j]) / X_a[:, j] 55 | #X_b[:, j] = np.min(X_a[:, j]) / X_b[:, j] 56 | #X_c[:, j] = np.min(X_a[:, j]) / X_c[:, j] 57 | for j in range(0, X_a.shape[1]): 58 | X_a[:, j] = X_a[:, j] * weights_a[j] 59 | X_b[:, j] = X_b[:, j] * weights_b[j] 60 | X_c[:, j] = X_c[:, j] * weights_c[j] 61 | S_p_a = np.zeros((X_a.shape[0])) 62 | S_m_a = np.zeros((X_a.shape[0])) 63 | S_p_b = np.zeros((X_a.shape[0])) 64 | S_m_b = np.zeros((X_a.shape[0])) 65 | S_p_c = np.zeros((X_a.shape[0])) 66 | S_m_c = np.zeros((X_a.shape[0])) 67 | for i in range(0, X_a.shape[0]): 68 | for j in range(0, X_a.shape[1]): 69 | if (criterion_type[j] == 'max'): 70 | S_p_a[i] = S_p_a[i] + X_a[i, j] 71 | S_p_b[i] = S_p_b[i] + X_b[i, j] 72 | S_p_c[i] = S_p_c[i] + X_c[i, j] 73 | else: 74 | S_m_a[i] = S_m_a[i] + X_a[i, j] 75 | S_m_b[i] = S_m_b[i] + X_b[i, j] 76 | S_m_c[i] = S_m_c[i] + X_c[i, j] 77 | Q = np.zeros((X_a.shape[0])) 78 | Q_a = np.zeros((X_a.shape[0])) 79 | Q_b = np.zeros((X_a.shape[0])) 80 | Q_c = np.zeros((X_a.shape[0])) 81 | for i in range(0, X_a.shape[0]): 82 | if (np.sum(S_m_a) == 0): 83 | D_m_a = 1 84 | else: 85 | D_m_a = S_m_a[i] * np.sum(1 / S_m_a) 86 | if (np.sum(S_m_b) == 0): 87 | D_m_b = 1 88 | else: 89 | D_m_b = S_m_b[i] * np.sum(1 / S_m_b) 90 | if (np.sum(S_m_c) == 0): 91 | D_m_c = 1 92 | else: 93 | D_m_c = S_m_c[i] * np.sum(1 / S_m_c) 94 | Q_a[i] = S_p_a[i] + np.sum(S_m_a) / D_m_a 95 | Q_b[i] = S_p_b[i] + np.sum(S_m_b) / D_m_b 96 | Q_c[i] = S_p_c[i] + np.sum(S_m_c) / D_m_c 97 | for i in range(0, X_a.shape[0]): 98 | Q[i] = Q_a[i] + ( (Q_c[i] - Q_a[i]) + (Q_b[i] - Q_a[i]) ) / 3 99 | Q = Q/np.max(Q) 100 | if (verbose == True): 101 | for i in range(0, Q.shape[0]): 102 | print('a' + str(i+1) + ': ' + str(round(Q[i], 3))) 103 | if (graph == True): 104 | flow = np.copy(Q) 105 | flow = np.reshape(flow, (Q.shape[0], 1)) 106 | flow = np.insert(flow, 0, list(range(1, Q.shape[0]+1)), axis = 1) 107 | flow = flow[np.argsort(flow[:, 1])] 108 | flow = flow[::-1] 109 | ranking(flow) 110 | return Q -------------------------------------------------------------------------------- /pyDecision/algorithm/p_iv.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import math 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | from scipy.integrate import quad 9 | 10 | ############################################################################### 11 | 12 | # Function: Distance Matrix 13 | def distance_matrix(dataset, criteria = 0): 14 | distance_array = np.zeros(shape = (dataset.shape[0],dataset.shape[0])) 15 | for i in range(0, distance_array.shape[0]): 16 | for j in range(0, distance_array.shape[1]): 17 | distance_array[i,j] = dataset[i, criteria] - dataset[j, criteria] 18 | return distance_array 19 | 20 | # Optimized Integration 21 | def integration_preference_degree(dataset, W, Q, S, P, F): 22 | pd_array = np.zeros((dataset.shape[0], dataset.shape[0])) 23 | 24 | ############################################################################### 25 | 26 | def preference_function(distance, Fk, Qk, Pk, Sk): 27 | if (Fk == 't1'): 28 | return 1 if distance > 0 else 0 29 | elif (Fk == 't2'): 30 | return 1 if distance > Qk else 0 31 | elif (Fk == 't3'): 32 | return distance / Pk if 0 < distance <= Pk else (1 if distance > Pk else 0) 33 | elif (Fk == 't4'): 34 | return 0.5 if Qk < distance <= Pk else (1 if distance > Pk else 0) 35 | elif (Fk == 't5'): 36 | return (distance - Qk) / (Pk - Qk) if Qk < distance <= Pk else (1 if distance > Pk else 0) 37 | elif (Fk == 't6'): 38 | return 1 - math.exp(-(distance**2) / (2 * Sk**2)) if distance > 0 else 0 39 | else: 40 | return 0 41 | 42 | ############################################################################### 43 | 44 | for k in range(0, dataset.shape[1]): 45 | distances = distance_matrix(dataset, criteria = k) 46 | for i in range(0, distances.shape[0]): 47 | for j in range(0, distances.shape[1]): 48 | if (i != j): 49 | distance = distances[i, j] 50 | if (distance > 0): 51 | area, _ = quad(preference_function, 0, distance, args = (F[k], Q[k], P[k], S[k])) 52 | pd_array[i, j] = pd_array[i, j] + W[k] * area 53 | 54 | pd_array = pd_array/sum(W) 55 | return pd_array 56 | 57 | # Function: Rank 58 | def ranking(flow): 59 | rank_xy = np.zeros((flow.shape[0], 2)) 60 | for i in range(0, rank_xy.shape[0]): 61 | rank_xy[i, 0] = 0 62 | rank_xy[i, 1] = flow.shape[0]-i 63 | for i in range(0, rank_xy.shape[0]): 64 | if (flow[i,1] >= 0): 65 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.5, 0.8, 1.0),)) 66 | else: 67 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12,ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (1.0, 0.8, 0.8),)) 68 | for i in range(0, rank_xy.shape[0]-1): 69 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 70 | axes = plt.gca() 71 | xmin = np.amin(rank_xy[:,0]) 72 | xmax = np.amax(rank_xy[:,0]) 73 | axes.set_xlim([xmin-1, xmax+1]) 74 | ymin = np.amin(rank_xy[:,1]) 75 | ymax = np.amax(rank_xy[:,1]) 76 | if (ymin < ymax): 77 | axes.set_ylim([ymin, ymax]) 78 | else: 79 | axes.set_ylim([ymin-1, ymax+1]) 80 | plt.axis('off') 81 | plt.show() 82 | return 83 | 84 | ############################################################################### 85 | 86 | # Function: Promethee IV 87 | def promethee_iv(dataset, W, Q, S, P, F, sort = True, steps = 0.001, topn = 0, graph = False, verbose = True): 88 | pd_matrix = integration_preference_degree(dataset, W, Q, S, P, F) 89 | flow_plus = np.sum(pd_matrix, axis = 1)/(pd_matrix.shape[0] - 1) 90 | flow_minus = np.sum(pd_matrix, axis = 0)/(pd_matrix.shape[0] - 1) 91 | flow = flow_plus - flow_minus 92 | flow = np.reshape(flow, (pd_matrix.shape[0], 1)) 93 | flow = np.insert(flow, 0, list(range(1, pd_matrix.shape[0]+1)), axis = 1) 94 | if (sort == True or graph == True): 95 | flow = flow[np.argsort(flow[:, 1])] 96 | flow = flow[::-1] 97 | if (topn > 0): 98 | if (topn > pd_matrix.shape[0]): 99 | topn = pd_matrix.shape[0] 100 | if (verbose == True): 101 | for i in range(0, topn): 102 | print('a' + str(int(flow[i,0])) + ': ' + str(round(flow[i,1], 3))) 103 | if (graph == True): 104 | ranking(flow) 105 | return flow 106 | 107 | ############################################################################### 108 | -------------------------------------------------------------------------------- /pyDecision/algorithm/multimoora.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Rank 10 | def ranking_m(flow_1, flow_2, flow_3): 11 | rank_xy = np.zeros((flow_1.shape[0] + 1, 6)) 12 | for i in range(0, rank_xy.shape[0]): 13 | rank_xy[i, 0] = -1 14 | rank_xy[i, 1] = flow_1.shape[0]-i+1 15 | rank_xy[i, 2] = 0 16 | rank_xy[i, 3] = flow_2.shape[0]-i+1 17 | rank_xy[i, 4] = 1 18 | rank_xy[i, 5] = flow_3.shape[0]-i+1 19 | plt.text(rank_xy[0, 0], rank_xy[0, 1], 'MOORA', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 20 | plt.text(rank_xy[0, 2], rank_xy[0, 3], 'MOORA RP', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 21 | plt.text(rank_xy[0, 4], rank_xy[0, 5], 'MULTIMOORA', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 22 | for i in range(1, rank_xy.shape[0]): 23 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow_1[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = "round", ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 24 | plt.text(rank_xy[i, 2], rank_xy[i, 3], 'a' + str(int(flow_2[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 25 | plt.text(rank_xy[i, 4], rank_xy[i, 5], 'a' + str(int(flow_3[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 26 | for i in range(1, rank_xy.shape[0]-1): 27 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 28 | plt.arrow(rank_xy[i, 2], rank_xy[i, 3], rank_xy[i+1, 2] - rank_xy[i, 2], rank_xy[i+1, 3] - rank_xy[i, 3], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 29 | plt.arrow(rank_xy[i, 4], rank_xy[i, 5], rank_xy[i+1, 4] - rank_xy[i, 4], rank_xy[i+1, 5] - rank_xy[i, 5], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 30 | axes = plt.gca() 31 | axes.set_xlim([-2, +2]) 32 | ymin = np.amin(rank_xy[:,1]) 33 | ymax = np.amax(rank_xy[:,1]) 34 | if (ymin < ymax): 35 | axes.set_ylim([ymin, ymax]) 36 | else: 37 | axes.set_ylim([ymin-1, ymax+1]) 38 | plt.axis('off') 39 | plt.show() 40 | return 41 | 42 | # Function: MULTIMOORA (Multi-objective Optimization on the basis of Ratio Analisys Multiplicative Form) 43 | def multimoora_method(dataset, criterion_type, graph = True): 44 | X = np.copy(dataset)/1.0 45 | root = (np.sum(X**2, axis = 0))**(1/2) 46 | X = X/root 47 | best = np.zeros(X.shape[1]) 48 | Y1 = np.zeros(X.shape[0]) # MOORA 49 | Y2 = np.zeros(X.shape[0]) # MOORA Reference Point 50 | Y3 = np.zeros(X.shape[0]) # MULTIMOORA 51 | id1 = [i for i, j in enumerate(criterion_type) if j == 'max'] 52 | id2 = [i for i, j in enumerate(criterion_type) if j == 'min'] 53 | s_p = np.zeros(X.shape[0]) 54 | s_m = np.zeros(X.shape[0]) 55 | if (len(id1) > 0): 56 | s_p = np.sum(X[:,id1], axis = 1) 57 | if (len(id2) > 0): 58 | s_m = np.sum(X[:,id2], axis = 1) 59 | Y1 = s_p - s_m 60 | for i in range(0, X.shape[1]): 61 | if ( criterion_type[i] == 'max'): 62 | best[i] = np.max(X[:,i]) 63 | else: 64 | best[i] = np.min(X[:,i]) 65 | Y2 = np.max(np.absolute(X - best), axis = 1) 66 | if ( criterion_type[0] == 'max'): 67 | Y3 = np.copy(dataset[:,0]) 68 | else: 69 | Y3 = 1/np.copy(dataset[:,0]) 70 | for i in range(0, dataset.shape[0]): 71 | for j in range(1, dataset.shape[1]): 72 | if ( criterion_type[j] == 'max'): 73 | Y3[i] = Y3[i]*dataset[i,j] 74 | else: 75 | Y3[i] = Y3[i]/dataset[i,j] 76 | Y1 = Y1/np.max(Y1) 77 | Y2 = Y2/np.max(Y2) 78 | Y3 = Y3/np.max(Y3) 79 | flow_1 = np.copy(Y1) 80 | flow_1 = np.reshape(flow_1, (Y1.shape[0], 1)) 81 | flow_1 = np.insert(flow_1, 0, list(range(1, Y1.shape[0]+1)), axis = 1) 82 | flow_2 = np.copy(Y2) 83 | flow_2 = np.reshape(flow_2, (Y2.shape[0], 1)) 84 | flow_2 = np.insert(flow_2, 0, list(range(1, Y2.shape[0]+1)), axis = 1) 85 | flow_3 = np.copy(Y3) 86 | flow_3 = np.reshape(flow_3, (Y3.shape[0], 1)) 87 | flow_3 = np.insert(flow_3, 0, list(range(1, Y3.shape[0]+1)), axis = 1) 88 | if (graph == True): 89 | ranking_m(flow_1[np.argsort(flow_1[:, 1])[::-1]], flow_2[np.argsort(flow_2[:, 1])], flow_3[np.argsort(flow_3[:, 1])[::-1]]) 90 | return flow_1, flow_2, flow_3 -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_edas.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | ############################################################################### 9 | 10 | # Function: Rank 11 | def ranking(flow): 12 | rank_xy = np.zeros((flow.shape[0], 2)) 13 | for i in range(0, rank_xy.shape[0]): 14 | rank_xy[i, 0] = 0 15 | rank_xy[i, 1] = flow.shape[0]-i 16 | for i in range(0, rank_xy.shape[0]): 17 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 18 | for i in range(0, rank_xy.shape[0]-1): 19 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 20 | axes = plt.gca() 21 | axes.set_xlim([-1, +1]) 22 | ymin = np.amin(rank_xy[:,1]) 23 | ymax = np.amax(rank_xy[:,1]) 24 | if (ymin < ymax): 25 | axes.set_ylim([ymin, ymax]) 26 | else: 27 | axes.set_ylim([ymin-1, ymax+1]) 28 | plt.axis('off') 29 | plt.show() 30 | return 31 | 32 | # Function: Fuzzy EDAS 33 | def fuzzy_edas_method(dataset, criterion_type, weights, graph = True, verbose = True): 34 | pda_A = np.zeros((len(dataset), len(dataset[0]) )) 35 | nda_A = np.zeros((len(dataset), len(dataset[0]) )) 36 | pda_B = np.zeros((len(dataset), len(dataset[0]) )) 37 | nda_B = np.zeros((len(dataset), len(dataset[0]) )) 38 | pda_C = np.zeros((len(dataset), len(dataset[0]) )) 39 | nda_C = np.zeros((len(dataset), len(dataset[0]) )) 40 | dataset_A = np.zeros((len(dataset), len(dataset[0]) )) 41 | dataset_B = np.zeros((len(dataset), len(dataset[0]) )) 42 | dataset_C = np.zeros((len(dataset), len(dataset[0]) )) 43 | weights_A = np.zeros(len(weights[0])) 44 | weights_B = np.zeros(len(weights[0])) 45 | weights_C = np.zeros(len(weights[0])) 46 | for j in range(0, dataset_A.shape[1]): 47 | weights_A[j] = weights[0][j][0] 48 | weights_B[j] = weights[0][j][1] 49 | weights_C[j] = weights[0][j][2] 50 | for i in range(0, dataset_A.shape[0]): 51 | a, b, c = dataset[i][j] 52 | dataset_A[i, j] = a 53 | dataset_B[i, j] = b 54 | dataset_C[i, j] = c 55 | col_mean_A = np.mean(dataset_A, axis = 0) 56 | col_mean_B = np.mean(dataset_B, axis = 0) 57 | col_mean_C = np.mean(dataset_C, axis = 0) 58 | for i in range(0, dataset_A.shape[0]): 59 | for j in range(0, dataset_A.shape[1]): 60 | if (criterion_type[j] == 'max'): 61 | pda_A[i,j] = max(0, dataset_A[i,j] - col_mean_A[j]) / col_mean_A[j] 62 | nda_A[i,j] = max(0, -dataset_A[i,j] + col_mean_A[j]) / col_mean_A[j] 63 | pda_B[i,j] = max(0, dataset_B[i,j] - col_mean_B[j]) / col_mean_B[j] 64 | nda_B[i,j] = max(0, -dataset_B[i,j] + col_mean_B[j]) / col_mean_B[j] 65 | pda_C[i,j] = max(0, dataset_C[i,j] - col_mean_C[j]) / col_mean_C[j] 66 | nda_C[i,j] = max(0, -dataset_C[i,j] + col_mean_C[j]) / col_mean_C[j] 67 | else: 68 | pda_A[i,j] = max(0, -dataset_A[i,j] + col_mean_A[j]) / col_mean_A[j] 69 | nda_A[i,j] = max(0, dataset_A[i,j] - col_mean_A[j]) / col_mean_A[j] 70 | pda_B[i,j] = max(0, -dataset_B[i,j] + col_mean_B[j]) / col_mean_B[j] 71 | nda_B[i,j] = max(0, dataset_B[i,j] - col_mean_B[j]) / col_mean_B[j] 72 | pda_C[i,j] = max(0, -dataset_C[i,j] + col_mean_C[j]) / col_mean_C[j] 73 | nda_C[i,j] = max(0, dataset_C[i,j] - col_mean_C[j]) / col_mean_C[j] 74 | w_pda_A = pda_A*weights_A 75 | w_pda_B = pda_B*weights_B 76 | w_pda_C = pda_C*weights_C 77 | w_nda_A = nda_A*weights_A 78 | w_nda_B = nda_B*weights_B 79 | w_nda_C = nda_C*weights_C 80 | s_p_A = np.sum(w_pda_A, axis = 1) 81 | s_p_B = np.sum(w_pda_B, axis = 1) 82 | s_p_C = np.sum(w_pda_C, axis = 1) 83 | s_n_A = np.sum(w_nda_A, axis = 1) 84 | s_n_B = np.sum(w_nda_B, axis = 1) 85 | s_n_C = np.sum(w_nda_C, axis = 1) 86 | n_s_p_A = s_p_A/max(s_p_A) 87 | n_s_p_B = s_p_B/max(s_p_C) 88 | n_s_p_C = s_p_C/max(s_p_B) 89 | n_s_n_A = 1 - s_n_A/max(s_n_A) 90 | n_s_n_B = 1 - s_n_B/max(s_n_B) 91 | n_s_n_C = 1 - s_n_C/max(s_n_C) 92 | a_s_A = (1/2)*(n_s_p_A + n_s_n_A) 93 | a_s_B = (1/2)*(n_s_p_B + n_s_n_B) 94 | a_s_C = (1/2)*(n_s_p_C + n_s_n_C) 95 | a_s = (1/3)*(a_s_A + a_s_B + a_s_C) 96 | if (verbose == True): 97 | for i in range(0, a_s.shape[0]): 98 | print('a' + str(i+1) + ': ' + str(round(a_s[i], 4))) 99 | if ( graph == True): 100 | flow = np.copy(a_s) 101 | flow = np.reshape(flow, (a_s.shape[0], 1)) 102 | flow = np.insert(flow, 0, list(range(1, a_s.shape[0]+1)), axis = 1) 103 | flow = flow[np.argsort(flow[:, 1])] 104 | flow = flow[::-1] 105 | ranking(flow) 106 | return a_s 107 | 108 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/opa.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | from scipy.linalg import block_diag 8 | from scipy.optimize import linprog 9 | 10 | ############################################################################### 11 | 12 | # Function: Rank 13 | def ranking(flow): 14 | rank_xy = np.zeros((flow.shape[0], 2)) 15 | for i in range(0, rank_xy.shape[0]): 16 | rank_xy[i, 0] = 0 17 | rank_xy[i, 1] = flow.shape[0]-i 18 | for i in range(0, rank_xy.shape[0]): 19 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow[i,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 20 | for i in range(0, rank_xy.shape[0]-1): 21 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 22 | axes = plt.gca() 23 | axes.set_xlim([-1, +1]) 24 | ymin = np.amin(rank_xy[:,1]) 25 | ymax = np.amax(rank_xy[:,1]) 26 | if (ymin < ymax): 27 | axes.set_ylim([ymin, ymax]) 28 | else: 29 | axes.set_ylim([ymin-1, ymax+1]) 30 | plt.axis('off') 31 | plt.show() 32 | return 33 | 34 | # Function: OPA (Ordinal Priority Approach) 35 | def opa_method(experts_rank = [], experts_rank_criteria = [], experts_rank_alternatives = [], graph = True, verbose = True): 36 | experts = len(experts_rank) 37 | criteria = len(experts_rank_criteria[0]) 38 | alternatives = len(experts_rank_alternatives[0]) 39 | experts_rc = np.vstack(experts_rank_criteria) 40 | experts_ra = np.vstack(experts_rank_alternatives) 41 | C = [] 42 | index_temp = 0 43 | 44 | for e in range(experts): 45 | experts_ra_temp = experts_ra[e * alternatives:(e + 1) * alternatives, :] 46 | for i in range(criteria): 47 | index_temp = index_temp + 1 48 | mini_A = np.zeros((alternatives, alternatives)) 49 | for j in range(alternatives): 50 | if (j == alternatives - 1): 51 | index = np.where(experts_ra_temp[:, i] == alternatives)[0] 52 | mini_A[j, index] = experts_rank[e] * experts_rc[e, i] * (j + 1) 53 | break 54 | for k in range(j, j + 2): 55 | index = np.where(experts_ra_temp[:, i] == (k + 1))[0] 56 | if (k == j): 57 | mini_A[j, index] = experts_rank[e] * experts_rc[e, i] * (j + 1) 58 | elif (k == j + 1): 59 | mini_A[j, index] = -(experts_rank[e] * experts_rc[e, i] * (j + 1)) 60 | C.append(mini_A) 61 | 62 | A = block_diag(*C) 63 | A = np.hstack([np.ones((A.shape[0], 1)), A]) 64 | f = -np.hstack([1, np.zeros(experts * criteria * alternatives)]) 65 | A_ineq = A 66 | b_ineq = np.zeros(A.shape[0]) 67 | A_eq = np.hstack([0, np.ones(A.shape[1] - 1)]).reshape(1, -1) 68 | b_eq = np.array([1]) 69 | lb = [-np.inf] + [0] * (A.shape[1] - 1) 70 | result = linprog(f, A_ub = A_ineq, b_ub = b_ineq, A_eq = A_eq, b_eq = b_eq, bounds = [(lb[i], None) for i in range(len(lb))], method = 'highs') 71 | if (result.success): 72 | x = result.x 73 | x_weight = x[1:] 74 | w_experts = np.split(x_weight, experts) 75 | w_e = [] 76 | if (verbose == True): 77 | print('Weights - Experts') 78 | for i, w in enumerate(w_experts, 1): 79 | if (verbose == True): 80 | print(f'Expert {i}: {np.sum(w):.4f}') 81 | w_e.append(np.sum(w)) 82 | w_criteria_mat = np.zeros((experts, criteria)) 83 | for i in range(0, experts): 84 | w_criteria = np.split(w_experts[i], criteria) 85 | for j in range(0, criteria): 86 | w_criteria_mat[i, j] = np.sum(w_criteria[j]) 87 | w_c = [] 88 | for i in range(0, criteria): 89 | w_c.append(np.sum(w_criteria_mat[:, i], axis = 0)) 90 | if (verbose == True): 91 | print('') 92 | print('Weights - Criteria') 93 | if (verbose == True): 94 | for i in range(0, len(w_c)): 95 | print(f'g{i+1}: {w_c[i]:.4f}') 96 | w_a = [] 97 | if (verbose == True): 98 | print('') 99 | print('Weights - Alternatives') 100 | for i in range(0, alternatives): 101 | index = np.arange(i, experts * criteria * alternatives, alternatives) 102 | if (verbose == True): 103 | print(f'a{i + 1}: {np.sum(x_weight[index]):.4f}') 104 | w_a.append(np.sum(x_weight[index])) 105 | else: 106 | print('Optimization failed.') 107 | if ( graph == True): 108 | a_s = np.array(w_a) 109 | flow = np.copy(a_s) 110 | flow = np.reshape(flow, (a_s.shape[0], 1)) 111 | flow = np.insert(flow, 0, list(range(1, a_s.shape[0]+1)), axis = 1) 112 | flow = flow[np.argsort(flow[:, 1])] 113 | flow = flow[::-1] 114 | ranking(flow) 115 | return w_e, w_c, w_a 116 | 117 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_waspas.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import copy 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | ############################################################################### 9 | 10 | # Function: Rank 11 | def ranking_m(flow_1, flow_2, flow_3): 12 | rank_xy = np.zeros((flow_1.shape[0] + 1, 6)) 13 | for i in range(0, rank_xy.shape[0]): 14 | rank_xy[i, 0] = -1 15 | rank_xy[i, 1] = flow_1.shape[0]-i+1 16 | rank_xy[i, 2] = 0 17 | rank_xy[i, 3] = flow_2.shape[0]-i+1 18 | rank_xy[i, 4] = 1 19 | rank_xy[i, 5] = flow_3.shape[0]-i+1 20 | plt.text(rank_xy[0, 0], rank_xy[0, 1], 'F-WSM', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 21 | plt.text(rank_xy[0, 2], rank_xy[0, 3], 'F-WPM', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 22 | plt.text(rank_xy[0, 4], rank_xy[0, 5], 'F-WASPAS', size = 12, ha = 'center', va = 'center', color = 'white', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0, 0, 0),)) 23 | for i in range(1, rank_xy.shape[0]): 24 | plt.text(rank_xy[i, 0], rank_xy[i, 1], 'a' + str(int(flow_1[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = "round", ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 25 | plt.text(rank_xy[i, 2], rank_xy[i, 3], 'a' + str(int(flow_2[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 26 | plt.text(rank_xy[i, 4], rank_xy[i, 5], 'a' + str(int(flow_3[i-1,0])), size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 27 | for i in range(1, rank_xy.shape[0]-1): 28 | plt.arrow(rank_xy[i, 0], rank_xy[i, 1], rank_xy[i+1, 0] - rank_xy[i, 0], rank_xy[i+1, 1] - rank_xy[i, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 29 | plt.arrow(rank_xy[i, 2], rank_xy[i, 3], rank_xy[i+1, 2] - rank_xy[i, 2], rank_xy[i+1, 3] - rank_xy[i, 3], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 30 | plt.arrow(rank_xy[i, 4], rank_xy[i, 5], rank_xy[i+1, 4] - rank_xy[i, 4], rank_xy[i+1, 5] - rank_xy[i, 5], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 31 | axes = plt.gca() 32 | axes.set_xlim([-2, +2]) 33 | ymin = np.amin(rank_xy[:,1]) 34 | ymax = np.amax(rank_xy[:,1]) 35 | if (ymin < ymax): 36 | axes.set_ylim([ymin, ymax]) 37 | else: 38 | axes.set_ylim([ymin-1, ymax+1]) 39 | plt.axis('off') 40 | plt.show() 41 | return 42 | 43 | # Function: F-WASPAS 44 | def fuzzy_waspas_method(dataset, criterion_type, weights, graph = True): 45 | x = copy.deepcopy(dataset) 46 | max_values = [max(max(outer_list[i]) for outer_list in dataset) for i in range(0, len(dataset[0]))] 47 | min_values = [min(min(outer_list[i]) for outer_list in dataset) for i in range(0, len(dataset[0]))] 48 | for i in range(0, len(dataset)): 49 | for j in range(0, len(dataset[0])): 50 | if (criterion_type[j] == 'max'): 51 | a, b, c = x[i][j] 52 | d, e, f = weights[0][j] 53 | a, b, c = (a/max_values[j])*d, (b/max_values[j])*e, (c/max_values[j])*f 54 | x[i][j] = (a, b, c) 55 | else: 56 | a, b, c = x[i][j] 57 | d, e, f = weights[0][j] 58 | a, b, c = (min_values[j]/a)*d, (min_values[j]/b)*e, (min_values[j]/c)*f 59 | x[i][j] = (a, b, c) 60 | sums_dataset = [] 61 | prod_dataset = [] 62 | for row in dataset: 63 | sums_row = [] 64 | prod_row = [] 65 | for inner_list in row: 66 | sum_value = sum(inner_list)/3 67 | prd_value = np.prod(inner_list)/3 68 | sums_row.append([sum_value]) 69 | prod_row.append([prd_value]) 70 | sums_dataset.append(sums_row) 71 | prod_dataset.append(prod_row) 72 | prod_dataset = np.array(prod_dataset) 73 | rows_sums_q = np.sum(prod_dataset, axis = 1) 74 | f_wpm = [i[0] for i in rows_sums_q] 75 | sums_dataset = np.array(sums_dataset) 76 | rows_sums_p = np.sum(sums_dataset, axis = 1) 77 | f_wsm = [i[0] for i in rows_sums_p] 78 | lmbd = sum(rows_sums_p)[0]/ (sum(rows_sums_q)[0] + sum(rows_sums_p)[0]) 79 | f_waspas = [lmbd*f_wsm[i] + (1 - lmbd)*f_wpm[i] for i in range(0, len(f_wsm))] 80 | if (graph == True): 81 | flow_1 = np.array(f_wsm) 82 | flow_1 = np.reshape(flow_1, (len(f_wsm), 1)) 83 | flow_1 = np.insert(flow_1, 0, list(range(1, len(f_wsm)+1)), axis = 1) 84 | flow_2 = np.array(f_wpm) 85 | flow_2 = np.reshape(flow_2, (len(f_wsm), 1)) 86 | flow_2 = np.insert(flow_2, 0, list(range(1, len(f_wsm)+1)), axis = 1) 87 | flow_3 = np.array(f_waspas) 88 | flow_3 = np.reshape(flow_3, (len(f_wsm), 1)) 89 | flow_3 = np.insert(flow_3, 0, list(range(1,len(f_wsm)+1)), axis = 1) 90 | ranking_m(flow_1[np.argsort(flow_1[:, 1])[::-1]], flow_2[np.argsort(flow_2[:, 1])[::-1]], flow_3[np.argsort(flow_3[:, 1])[::-1]]) 91 | return f_wsm, f_wpm, f_waspas 92 | 93 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/regime.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | ############################################################################### 8 | 9 | # Function: Pre-Order Rank 10 | def po_ranking(po_string): 11 | alts = list(range(1, po_string.shape[0] + 1)) 12 | alts = ['a' + str(alt) for alt in alts] 13 | for i in range (po_string.shape[0] - 1, -1, -1): 14 | for j in range (po_string.shape[1] -1, -1, -1): 15 | if (po_string[i,j] == 'I'): 16 | po_string = np.delete(po_string, i, axis = 0) 17 | po_string = np.delete(po_string, i, axis = 1) 18 | alts[j] = str(alts[j] + "; " + alts[i]) 19 | del alts[i] 20 | break 21 | graph = {} 22 | for i in range(po_string.shape[0]): 23 | if (len(alts[i]) == 0): 24 | graph[alts[i]] = i 25 | else: 26 | graph[alts[i][ :2]] = i 27 | graph[alts[i][-2:]] = i 28 | po_matrix = np.zeros((po_string.shape[0], po_string.shape[1])) 29 | for i in range (0, po_string.shape[0]): 30 | for j in range (0, po_string.shape[1]): 31 | if (po_string[i,j] == 'P+'): 32 | po_matrix[i,j] = 1 33 | col_sum = np.sum(po_matrix, axis = 1) 34 | alts_rank = [x for _, x in sorted(zip(col_sum, alts))] 35 | if (np.sum(col_sum) != 0): 36 | alts_rank.reverse() 37 | graph_rank = {} 38 | for i in range(po_string.shape[0]): 39 | if (len(alts_rank[i]) == 0): 40 | graph_rank[alts_rank[i]] = i 41 | else: 42 | graph_rank[alts_rank[i][ :2]] = i 43 | graph_rank[alts_rank[i][-2:]] = i 44 | rank = np.copy(po_matrix) 45 | for i in range(0, po_matrix.shape[0]): 46 | for j in range(0, po_matrix.shape[1]): 47 | if (po_matrix[i,j] == 1): 48 | rank[i,:] = np.clip(rank[i,:] - rank[j,:], 0, 1) 49 | rank_xy = np.zeros((len(alts_rank), 2)) 50 | for i in range(0, rank_xy.shape[0]): 51 | rank_xy[i, 0] = 0 52 | if (len(alts_rank) - np.sum(~rank.any(1)) != 0): 53 | rank_xy[i, 1] = len(alts_rank) - np.sum(~rank.any(1)) 54 | else: 55 | rank_xy[i, 1] = 1 56 | for i in range(0, len(alts_rank) - 1): 57 | i1 = int(graph[alts_rank[ i ][:2]]) 58 | i2 = int(graph[alts_rank[i+1][:2]]) 59 | if (po_string[i1,i2] == 'P+'): 60 | rank_xy[i+1,1] = rank_xy[i+1,1] - 1 61 | for j in range(i+2, rank_xy.shape[0]): 62 | rank_xy[j,1] = rank_xy[i+1,1] 63 | if (po_string[i1,i2] == 'R'): 64 | rank_xy[i+1,0] = rank_xy[i,0] + 1 65 | for i in range(0, rank_xy.shape[0]): 66 | plt.text(rank_xy[i, 0], rank_xy[i, 1], alts_rank[i], size = 12, ha = 'center', va = 'center', bbox = dict(boxstyle = 'round', ec = (0.0, 0.0, 0.0), fc = (0.8, 1.0, 0.8),)) 67 | for i in range(0, len(alts_rank)): 68 | alts_rank[i] = alts_rank[i][:2] 69 | for i in range(0, rank.shape[0]): 70 | for j in range(0, rank.shape[1]): 71 | k1 = int(graph_rank[list(graph.keys())[list(graph.values()).index(i)]]) 72 | k2 = int(graph_rank[list(graph.keys())[list(graph.values()).index(j)]]) 73 | if (rank[i, j] == 1): 74 | plt.arrow(rank_xy[k1, 0], rank_xy[k1, 1], rank_xy[k2, 0] - rank_xy[k1, 0], rank_xy[k2, 1] - rank_xy[k1, 1], head_width = 0.01, head_length = 0.2, overhang = 0.0, color = 'black', linewidth = 0.9, length_includes_head = True) 75 | axes = plt.gca() 76 | xmin = np.amin(rank_xy[:,0]) 77 | xmax = np.amax(rank_xy[:,0]) 78 | axes.set_xlim([xmin-1, xmax+1]) 79 | ymin = np.amin(rank_xy[:,1]) 80 | ymax = np.amax(rank_xy[:,1]) 81 | if (ymin < ymax): 82 | axes.set_ylim([ymin, ymax]) 83 | else: 84 | axes.set_ylim([ymin-1, ymax+1]) 85 | plt.axis('off') 86 | plt.show() 87 | return 88 | 89 | # Function: Regime 90 | def regime_method(dataset, weights, criterion_type): 91 | X = np.copy(dataset)/1.0 92 | weights = weights/np.sum(weights) 93 | g_ind = np.zeros((X.shape[0], X.shape[0])) 94 | for i in range(0, g_ind.shape[0]): 95 | for k in range(0, g_ind.shape[0]): 96 | for j in range(0, X.shape[1]): 97 | if (i!= k): 98 | if (criterion_type[j] == 'max'): 99 | if (X[i, j] >= X[k, j]): 100 | g_ind[i, k] = g_ind[i, k] + weights[j] 101 | else: 102 | g_ind[i, k] = g_ind[i, k] - weights[j] 103 | else: 104 | if (X[i, j] < X[k, j]): 105 | g_ind[i, k] = g_ind[i, k] + weights[j] 106 | else: 107 | g_ind[i, k] = g_ind[i, k] - weights[j] 108 | cp_matrix = np.empty((X.shape[0], X.shape[0]), dtype = 'U25') 109 | cp_matrix.fill('-') 110 | for i in range(0, cp_matrix.shape[0]): 111 | for j in range(0, cp_matrix.shape[0]): 112 | if (i != j): 113 | if (g_ind[i, j] > 0): 114 | cp_matrix[i,j] = 'P+' 115 | if (g_ind[i, j] == 0 or g_ind[i, j] == g_ind[j, i]): 116 | cp_matrix[i,j] = 'I' 117 | po_ranking(cp_matrix) 118 | return cp_matrix 119 | 120 | ############################################################################### -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_fucom.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import re 6 | import warnings 7 | warnings.filterwarnings('ignore', message = 'delta_grad == 0.0. Check if the approximated') 8 | warnings.filterwarnings('ignore', message = 'Values in x were outside bounds during a minimize step, clipping to bounds') 9 | 10 | from scipy.optimize import minimize, Bounds, LinearConstraint, NonlinearConstraint 11 | 12 | ############################################################################### 13 | 14 | # Function: Fuzzy FUCOM (Full Consistency Method) 15 | def fuzzy_fucom_method(criteria_rank, criteria_priority, n_starts = 250, sort_criteria = True, verbose = True): 16 | 17 | ################################################ 18 | 19 | def extract_number(text): 20 | match = re.search(r'\d+', text) 21 | return int(match.group()) if match else None 22 | 23 | def generate_ordered_triplets(num_criteria): 24 | variables = np.zeros(3 * num_criteria) 25 | for i in range(0, num_criteria): 26 | x1 = np.random.uniform(low = 0.0001, high = 1.0) 27 | x2 = np.random.uniform(low = x1, high = 1.0) 28 | x3 = np.random.uniform(low = x2, high = 1.0) 29 | variables[3 * i] = x1 30 | variables[3 * i + 1] = x2 31 | variables[3 * i + 2] = x3 32 | fuzzy_set = [(variables[i], variables[i + 1], variables[i + 2]) for i in range(0, len(variables), 3)] 33 | weights = np.array([(a + 4 * b + c) / 6 for a, b, c in fuzzy_set]) 34 | total = np.sum(weights) 35 | scale_fac = 1 / total 36 | variables = variables * scale_fac 37 | return variables 38 | 39 | ################################################ 40 | 41 | def target_function(variables): 42 | fuzzy_set = [(variables[i], variables[i + 1], variables[i + 2]) for i in range(0, len(variables), 3)] 43 | skip = 1 44 | pairs_1 = [(i, i + skip) for i in range(len(fuzzy_set) - skip)] 45 | comparative_imp = [] 46 | for i, j in pairs_1: 47 | a, b, c = criteria_priority[j] 48 | d, e, f = criteria_priority[i] 49 | comparative_imp.append((a/f, b/e, c/d)) 50 | pairs_2 = [(i, i + skip) for i in range(len(comparative_imp) - skip)] 51 | for i, j in pairs_2: 52 | a, b, c = comparative_imp[i] 53 | d, e, f = comparative_imp[j] 54 | comparative_imp.append((a*d, b*e, c*f)) 55 | chi = [] 56 | skip = 2 57 | pairs_3 = [(i, i + skip) for i in range(len(fuzzy_set) - skip)] 58 | pairs = pairs_1 + pairs_3 59 | count = 0 60 | for i, j in pairs: 61 | a, b, c = fuzzy_set[i] 62 | d, e, f = fuzzy_set[j] 63 | x, y, z = comparative_imp[count] 64 | count = count + 1 65 | chi.append( abs((a / f) - x) ) 66 | chi.append( abs((b / e) - y) ) 67 | chi.append( abs((c / d) - z) ) 68 | return np.max(chi) 69 | 70 | def weights_constraint(variables): 71 | fuzzy_set = [(variables[i], variables[i + 1], variables[i + 2]) for i in range(0, len(variables), 3)] 72 | w = [(a + 4 * b + c) / 6 for a, b, c in fuzzy_set] 73 | return np.sum(w) 74 | 75 | ################################################ 76 | 77 | lower_bounds = [] 78 | upper_bounds = [] 79 | for i in range(0, len(criteria_priority) * 3, 3): 80 | lower_bounds = lower_bounds + [0.0001, 0.0001, 0.0001] 81 | upper_bounds = upper_bounds + [1, 1, 1] 82 | bounds = Bounds(lower_bounds, upper_bounds) 83 | constraints_1 = NonlinearConstraint(weights_constraint, 1, 1) 84 | const_matrix = [] 85 | constraint_lb = [] 86 | constraint_ub = [] 87 | for i in range(0, len(criteria_priority) * 3, 3): 88 | row = np.zeros(len(criteria_priority) * 3) 89 | row[i] = -1 90 | row[i + 1] = 1 91 | const_matrix.append(row) 92 | constraint_lb.append(0) 93 | constraint_ub.append(np.inf) 94 | row = np.zeros(len(criteria_priority)*3) 95 | row[i + 1] = -1 96 | row[i + 2] = 1 97 | const_matrix.append(row) 98 | constraint_lb.append(0) 99 | constraint_ub.append(np.inf) 100 | constraints_2 = LinearConstraint(const_matrix, constraint_lb, constraint_ub) 101 | chi = np.inf 102 | solution = None 103 | for i in range(0, n_starts): 104 | if (i == 0): 105 | guess = generate_ordered_triplets(len(criteria_priority)) 106 | else: 107 | guess = solution 108 | result = minimize(target_function, guess, method = 'SLSQP', constraints = [constraints_1, constraints_2], bounds = bounds) 109 | if (result.fun < chi): 110 | chi = result.fun 111 | solution = result.x 112 | f_weights = [(solution[i], solution[i + 1], solution[i + 2]) for i in range(0, len(solution), 3)] 113 | weights = [(a + 4 * b + c) / 6 for a, b, c in f_weights] 114 | if (sort_criteria == True): 115 | idx = sorted(range(0, len(criteria_rank)), key = lambda x: extract_number(criteria_rank[x])) 116 | f_weights = [f_weights[i] for i in idx] 117 | weights = [ weights[i] for i in idx] 118 | if (verbose == True): 119 | print('Chi:', np.round(chi, 4)) 120 | return f_weights, weights 121 | 122 | ############################################################################### 123 | -------------------------------------------------------------------------------- /pyDecision/algorithm/fuzzy_bwm.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | 3 | # Required Libraries 4 | import numpy as np 5 | import warnings 6 | warnings.filterwarnings('ignore', message = 'delta_grad == 0.0. Check if the approximated') 7 | warnings.filterwarnings('ignore', message = 'Values in x were outside bounds during a minimize step, clipping to bounds') 8 | 9 | from scipy.optimize import minimize, Bounds, NonlinearConstraint 10 | 11 | ############################################################################### 12 | 13 | # Function: Fuzzy BWM 14 | def fuzzy_bw_method(mic, lic, eps_penalty = 1, verbose = True): 15 | priority_tuples = [(7/2, 4, 9/2), (5/2, 3, 7/2), (3/2, 2, 5/2), (2/3, 1, 3/2), (1, 1, 1)] 16 | ci = [8.04, 6.69, 5.29, 3.8, 3.0 ] 17 | tuple_to_ci = dict(zip(priority_tuples, ci)) 18 | 19 | ############################################### 20 | 21 | def find_index(criteria_list, priority_tuples): 22 | for tup in priority_tuples: 23 | if tup in criteria_list: 24 | return criteria_list.index(tup) 25 | return None 26 | 27 | def generate_ordered_triplets(num_criteria): 28 | variables = np.zeros(3 * num_criteria) 29 | for i in range(0, num_criteria): 30 | x1 = np.random.uniform(low = 0.0001, high = 1.0) 31 | x2 = np.random.uniform(low = x1, high = 1.0) 32 | x3 = np.random.uniform(low = x2, high = 1.0) 33 | variables[3 * i] = x1 34 | variables[3 * i + 1] = x2 35 | variables[3 * i + 2] = x3 36 | fuzzy_set = [(variables[i], variables[i + 1], variables[i + 2]) for i in range(0, len(variables), 3)] 37 | weights = np.array([(a + 4 * b + c) / 6 for a, b, c in fuzzy_set]) 38 | total = np.sum(weights) 39 | scale_fac = 1 / total 40 | variables = variables * scale_fac 41 | return variables 42 | 43 | ############################################### 44 | 45 | ib = find_index(mic, priority_tuples) 46 | iw = find_index(lic, priority_tuples) 47 | ci_value = tuple_to_ci.get(mic[ib]) 48 | pairs_w = [(iw, i) for i in range(0, len(lic)) if i != iw] 49 | pairs_b = [(i, ib) for i in range(0, len(mic)) if i != ib and i != iw] 50 | 51 | ################################################ 52 | 53 | def operation(wv, eps, vector, idx_a = 2, idx_b = 0, idx_m = 0): 54 | a, b, c = wv[idx_a] 55 | d, e, f = wv[idx_b] 56 | fn = (a - vector[idx_m][0]*f - eps*f, b - vector[idx_m][1]*e - eps*e, c - vector[idx_m][2]*d - eps*d) 57 | return fn 58 | 59 | def target_function(variables): 60 | eps = variables[-1] 61 | cn1 = [] 62 | wv = [(1, 1, 1) for item in mic] 63 | penalty = 0 64 | j = 0 65 | for i in range(0, len(wv)): 66 | wv[i] = (variables[j], variables[j+1], variables[j+2]) 67 | j = j + 3 68 | for i in range(0, len(pairs_w)): 69 | a, b, c = operation(wv = wv, eps = eps, vector = mic, idx_a = pairs_w[i][0], idx_b = pairs_w[i][1], idx_m = i) 70 | cn1.append( a) 71 | cn1.append( b) 72 | cn1.append( c) 73 | cn1.append(-a) 74 | cn1.append(-b) 75 | cn1.append(-c) 76 | for i in range(0, len(pairs_b)): 77 | a, b, c = operation(wv = wv, eps = eps, vector = lic, idx_a = pairs_b[i][0], idx_b = pairs_b[i][1], idx_m = i) 78 | cn1.append( a) 79 | cn1.append( b) 80 | cn1.append( c) 81 | cn1.append(-a) 82 | cn1.append(-b) 83 | cn1.append(-c) 84 | for item in cn1: 85 | if (item > eps): 86 | penalty = penalty + (item - eps) * 1 87 | penalty = penalty + eps * eps_penalty 88 | return penalty 89 | 90 | def LMU_constraint(variables): 91 | constraints = [] 92 | for i in range(0, len(variables) - 1, 3): 93 | L, m, u = variables[i], variables[i+1], variables[i+2] 94 | constraints.append(L) 95 | constraints.append(m - L) 96 | constraints.append(u - m) 97 | return constraints 98 | 99 | def weights_constraint(variables): 100 | fuzzy_set = [(variables[i], variables[i + 1], variables[i + 2]) for i in range(0, len(variables)-1, 3)] 101 | w = [(a + 4 * b + c) / 6 for a, b, c in fuzzy_set] 102 | return np.sum(w) 103 | 104 | constraint_1 = NonlinearConstraint(weights_constraint, 1, 1) 105 | constraint_2 = {'type': 'ineq', 'fun': LMU_constraint} 106 | constraints = [constraint_1, constraint_2] 107 | 108 | ################################################ 109 | 110 | np.random.seed(42) 111 | bounds = Bounds([0]*len(mic)*3 + [0], [1]*len(mic)*3 + [1]) 112 | n_starts = 50 113 | solution = None 114 | obj_fun = np.inf 115 | for i in range(0, n_starts): 116 | if (i == 0): 117 | guess = generate_ordered_triplets(len(mic)) 118 | guess = np.append(guess, [0]) 119 | else: 120 | guess = solution 121 | 122 | results = minimize(target_function, guess, method = 'trust-constr', bounds = bounds, constraints = constraints) 123 | if (results.fun < obj_fun): 124 | obj_fun = results.fun 125 | solution = results.x 126 | f_weights = [(solution[i], solution[i + 1], solution[i + 2]) for i in range(0, len(solution)-1, 3)] 127 | weights = [(a + 4 * b + c) / 6 for a, b, c in f_weights] 128 | if (verbose == True): 129 | print('Epsilon Value:', np.round(results.x[-1], 4)) 130 | print('CR: ', np.round(results.x[-1]/ci_value , 4)) 131 | return results.x[-1], results.x[-1]/ci_value, f_weights, weights 132 | 133 | ############################################################################### 134 | --------------------------------------------------------------------------------