From 1619adb3f33e37698886212c16a8deea837a55e8 Mon Sep 17 00:00:00 2001 From: bahadirfyildirim Date: Fri, 17 Nov 2023 22:44:23 +0300 Subject: [PATCH] add OCRA method --- README.md | 63 ++++++++++---------- src/JMcDM.jl | 6 ++ src/mcdm.jl | 3 + src/ocra.jl | 152 +++++++++++++++++++++++++++++++++++++++++++++++ test/testmcdm.jl | 43 ++++++++++++++ 5 files changed, 236 insertions(+), 31 deletions(-) create mode 100644 src/ocra.jl diff --git a/README.md b/README.md index d5d6456..a65000d 100644 --- a/README.md +++ b/README.md @@ -94,39 +94,40 @@ Please check out the reference manual [here](https://jbytecode.github.io/JMcDM/) ### MCDM Tools -- TOPSIS (Technique for Order Preference by Similarity to Ideal Solutions) -- ELECTRE (Elimination and Choice Translating Reality) -- DEMATEL (The Decision Making Trial and Evaluation Laboratory) -- MOORA Reference (Multi-Objective Optimization By Ratio Analysis) -- MOORA Ratio -- VIKOR (VlseKriterijumska Optimizcija I Kaompromisno Resenje in Serbian) - AHP (Analytic Hierarchy Process) -- DEA (Data Envelopment Analysis) -- GRA (Grey Relational Analysis) -- Non-dominated Sorting -- SAW (Simple Additive Weighting) (aka WSM) - ARAS (Additive Ratio Assessment) -- WPM (Weighted Product Model) -- WASPAS (Weighted Aggregated Sum Product ASsessment) -- EDAS (Evaluation based on Distance from Average Solution) -- MARCOS (Measurement Alternatives and Ranking according to COmpromise Solution) -- MABAC (Multi-Attributive Border Approximation area Comparison) -- MAIRCA (Multi Attributive Ideal-Real Comparative Analysis) -- COPRAS (COmplex PRoportional ASsessment) -- PROMETHEE (Preference Ranking Organization METHod for Enrichment of Evaluations) - CoCoSo (Combined Compromise Solution) -- CRITIC (CRiteria Importance Through Intercriteria Correlation) -- Entropy - CODAS (COmbinative Distance-based ASsessment) - Copeland (For combining multiple ordering results) -- SD Method for determining weights of criteria -- ROV (Range of Value) Method -- PSI (Preference Selection Index) Method -- MOOSRA (Multi-Objective Optimization on the basis of Simple Ratio Analysis) Method +- COPRAS (COmplex PRoportional ASsessment) +- CRITIC (CRiteria Importance Through Intercriteria Correlation) +- DEA (Data Envelopment Analysis) +- DEMATEL (The Decision Making Trial and Evaluation Laboratory) +- EDAS (Evaluation based on Distance from Average Solution) +- ELECTRE (Elimination and Choice Translating Reality) +- Entropy +- GRA (Grey Relational Analysis) +- LOPCOW (LOgarithmic Percentage Change-driven Objective Weighting) +- MABAC (Multi-Attributive Border Approximation area Comparison) +- MAIRCA (Multi Attributive Ideal-Real Comparative Analysis) +- MARCOS (Measurement Alternatives and Ranking according to COmpromise Solution) - MEREC (MEthod based on the Removal Effects of Criteria) for determining weights +- MOORA Ratio +- MOORA Reference (Multi-Objective Optimization By Ratio Analysis) +- MOOSRA (Multi-Objective Optimization on the basis of Simple Ratio Analysis) Method +- Non-dominated Sorting +- OCRA (Operational Competitiveness RAting) - PIV (Proximity Indexed Value) method +- PROMETHEE (Preference Ranking Organization METHod for Enrichment of Evaluations) +- PSI (Preference Selection Index) Method +- ROV (Range of Value) Method +- SAW (Simple Additive Weighting) (aka WSM) +- SD Method for determining weights of criteria - SECA (Simultaneous Evaluation of Criteria and Alternatives) -- LOPCOW (LOgarithmic Percentage Change-driven Objective Weighting) +- TOPSIS (Technique for Order Preference by Similarity to Ideal Solutions) +- VIKOR (VlseKriterijumska Optimizcija I Kaompromisno Resenje in Serbian) +- WASPAS (Weighted Aggregated Sum Product ASsessment) +- WPM (Weighted Product Model) ### SCDM Tools @@ -145,18 +146,18 @@ Please check out the reference manual [here](https://jbytecode.github.io/JMcDM/) - Game solver for zero sum games ## Unimplemented methods -- UTA -- MAUT -- STEM -- PAPRIKA - ANP (Analytical Network Process) +- COMET - Goal Programming - MACBETH -- COMET -- SWARA +- MAUT - ORESTE +- PAPRIKA - SMAA +- STEM +- SWARA - TODIM +- UTA - will be updated soon. diff --git a/src/JMcDM.jl b/src/JMcDM.jl index c6aa545..51110d5 100755 --- a/src/JMcDM.jl +++ b/src/JMcDM.jl @@ -113,6 +113,7 @@ include("psi.jl") include("moosra.jl") include("merec.jl") include("lopcow.jl") +include("ocra.jl") include("summary.jl") @@ -155,6 +156,7 @@ import .AHP: ahp, ahp_consistency, ahp_RI, AHPResult, AHPConsistencyResult import .MEREC: merec, MERECResult, MERECMethod import .PIV: piv, PIVResult, PIVMethod import .LOPCOW: lopcow, LOPCOWResult, LOPCOWMethod +import .OCRA: ocra, OCRAResult, OCRAMethod import .SCDM: LaplaceResult, MaximinResult, MaximaxResult, MinimaxResult, MiniminResult import .SCDM: SavageResult, HurwiczResult, MLEResult, ExpectedRegretResult @@ -196,6 +198,8 @@ export ROVMethod export MERECMethod export PIVMethod export LOPCOWMethod +export OCRAMethod + export MCDMSetting @@ -230,6 +234,7 @@ export MoosraResult export MERECResult export PIVResult export LOPCOWResult +export OCRAResult #  export SCDM types export SCDMResult @@ -283,6 +288,7 @@ export moosra export merec export piv export lopcow +export ocra #  export SCDM tools export laplace diff --git a/src/mcdm.jl b/src/mcdm.jl index 14aff48..ce8b15a 100644 --- a/src/mcdm.jl +++ b/src/mcdm.jl @@ -36,6 +36,7 @@ julia> subtypes(MCDMMethod) MarcosMethod MooraMethod MoosraMethod + OCRAMethod PIVMethod PSIMethod PrometheeMethod @@ -110,6 +111,8 @@ function mcdm( merec(df, fns) elseif method isa LOPCOWMethod lopcow(df, fns) + elseif method isa OCRAMethod + ocra(df, w, fns) elseif method isa PIVMethod piv(df, w, fns) else diff --git a/src/ocra.jl b/src/ocra.jl new file mode 100644 index 0000000..64bf79c --- /dev/null +++ b/src/ocra.jl @@ -0,0 +1,152 @@ +module OCRA + +export ocra, OCRAResult, OCRAMethod + +import ..MCDMMethod, ..MCDMResult, ..MCDMSetting + +using ..Utilities + +struct OCRAResult <: MCDMResult + decisionMatrix::Matrix + weights::Array{Float64,1} + scores::Vector + ranking::Array{Int64,1} + bestIndex::Int64 +end + +""" + ocra(decisionMat, weights, fns) + +Apply ORCA (Operational Competitiveness RAting) for a given matrix and weights. + +# Arguments: + - `decisionMat::Matrix`: m × n matrix of objective values for n alternatives and m criteria + - `weights::Array{Float64, 1}`: n-vector of weights that sum up to 1.0. If the sum of weights is not 1.0, it is automatically normalized. + - `fns::Array{<:Function, 1}`: n-vector of functions to be applied on the columns. + +# Description +ocra() applies the OCRA method to rank m alternatives subject to n criteria which are supposed to be +either maximized or minimized. + +# Output +- `::OCRAResult`: OCRAResult object that holds multiple outputs including scores, rankings, and best index. + +# Examples +```julia-repl +julia> decMat = [ + 8.0 16.0 1.5 1.2 4200.0 5.0 5.0 314.0 185.0; + 8.0 16.0 1.0 1.3 4200.0 5.0 4.0 360.0 156.0; + 10.1 16.0 2.0 1.3 4060.0 5.0 3.0 503.0 160.0; + 10.1 8.0 1.0 1.5 5070.0 2.0 4.0 525.0 200.0; + 10.0 16.0 2.0 1.2 6350.0 5.0 3.0 560.0 190.0; + 10.1 16.0 1.0 1.2 5500.0 2.0 2.0 521.0 159.0; + 10.1 64.0 2.0 1.7 5240.0 5.0 3.0 770.0 199.0; + 7.0 32.0 1.0 1.8 3000.0 3.0 4.0 364.0 157.0; + 10.1 16.0 1.0 1.3 3540.0 5.0 3.0 510.0 171.0; + 9.7 16.0 2.0 1.83 7500.0 6.0 2.0 550.0 170.0 + ] +10×9 Matrix{Float64}: + 8.0 16.0 1.5 1.2 4200.0 5.0 5.0 314.0 185.0 + 8.0 16.0 1.0 1.3 4200.0 5.0 4.0 360.0 156.0 + 10.1 16.0 2.0 1.3 4060.0 5.0 3.0 503.0 160.0 + 10.1 8.0 1.0 1.5 5070.0 2.0 4.0 525.0 200.0 + 10.0 16.0 2.0 1.2 6350.0 5.0 3.0 560.0 190.0 + 10.1 16.0 1.0 1.2 5500.0 2.0 2.0 521.0 159.0 + 10.1 64.0 2.0 1.7 5240.0 5.0 3.0 770.0 199.0 + 7.0 32.0 1.0 1.8 3000.0 3.0 4.0 364.0 157.0 + 10.1 16.0 1.0 1.3 3540.0 5.0 3.0 510.0 171.0 + 9.7 16.0 2.0 1.83 7500.0 6.0 2.0 550.0 170.0 + +julia> weights =[0.167, 0.039, 0.247, 0.247, 0.116, 0.02, 0.056, 0.027, 0.081]; + +julia> fns = [maximum,maximum,maximum,maximum,maximum,maximum,maximum,minimum,minimum]; + +julia> result = ocra(decmat, weights, fns); + +julia> result.scores +10-element Vector{Float64}: + 0.14392093908214929 + 0.024106550710436096 + 0.27342011595623067 + 0.04297916544177691 + 0.31851953804157623 + 0.0024882426914910674 + 0.5921715172301161 + 0.11390289470614312 + 0.0 + 0.47874854984718046 + +julia> result.bestIndex +7 + +``` + +# References + +- Parkan, C. (1994). Operational competitiveness ratings of production units. Managerial and Decision Economics, 15(3), 201–221. doi:10.1002/mde.4090150303  +- Parkan, C. (2003). Measuring the effect of a new point of sale system on the performance of drugstore operations. Computers & Operations Research, 30(5), 729–744. doi:10.1016/s0305-0548(02)00047-3  +- Kundakcı, N. (2017). An Integrated Multi-Criteria Decision Making Approach for Tablet Computer Selection. European Journal of Multidisciplinary Studies, 2(5), 31-43. + +""" +function ocra( + decisionMat::Matrix, + weights::Array{Float64,1}, + fns::Array{F,1}; +)::OCRAResult where {F<:Function} + + row, col = size(decisionMat) + w = unitize(weights) + zerotype = eltype(decisionMat) + I1 = zeros(zerotype, row) + I2 = zeros(zerotype, row) + O1 = zeros(zerotype, row) + O2 = zeros(zerotype, row) + scores = zeros(zerotype, row) + + colMax = colmaxs(decisionMat) + colMin = colmins(decisionMat) + + for i = 1:row + for j = 1:col + if fns[j] == minimum + I1[i] += w[j]*(colMax[j] - decisionMat[i,j])/colMin[j] + else + O1[i] += w[j]*(decisionMat[i,j] - colMin[j])/colMin[j] + end + end + end + + I2 = I1 .- minimum(I1) + O2 = O1 .- minimum(O1) + scores = I2 .+ O2 + scores = scores .- minimum(scores) + + rankings = sortperm(scores) + + bestIndex = rankings |> last + + result = OCRAResult(decisionMat, w, scores, rankings, bestIndex) + + return result +end + +""" + ocra(setting) + +Apply OCRA (Operational Competitiveness RAting) for a given matrix and weights. + +# Arguments: + - `setting::MCDMSetting`: MCDMSetting object. + +# Description +ocra() applies the OCRA method to rank m alternatives subject to n criteria which are supposed to be +either maximized or minimized. + +# Output +- `::OCRAResult`: OCRAResult object that holds multiple outputs including scores, rankings, and best index. +""" +function ocra(setting::MCDMSetting)::OCRAResult + ocra(setting.df, setting.weights, setting.fns) +end + +end # end of module OCRA diff --git a/test/testmcdm.jl b/test/testmcdm.jl index c700248..50d5331 100644 --- a/test/testmcdm.jl +++ b/test/testmcdm.jl @@ -1472,4 +1472,47 @@ @test result2 isa LOPCOWResult @test result2.w == result.w end + + @testset "OCRA" begin + tol = 0.0001 + decisionMat = [ + 8.0 16.0 1.5 1.2 4200.0 5.0 5.0 314.0 185.0; + 8.0 16.0 1.0 1.3 4200.0 5.0 4.0 360.0 156.0; + 10.1 16.0 2.0 1.3 4060.0 5.0 3.0 503.0 160.0; + 10.1 8.0 1.0 1.5 5070.0 2.0 4.0 525.0 200.0; + 10.0 16.0 2.0 1.2 6350.0 5.0 3.0 560.0 190.0; + 10.1 16.0 1.0 1.2 5500.0 2.0 2.0 521.0 159.0; + 10.1 64.0 2.0 1.7 5240.0 5.0 3.0 770.0 199.0; + 7.0 32.0 1.0 1.8 3000.0 3.0 4.0 364.0 157.0; + 10.1 16.0 1.0 1.3 3540.0 5.0 3.0 510.0 171.0; + 9.7 16.0 2.0 1.83 7500.0 6.0 2.0 550.0 170.0 + ] + fns = [maximum,maximum,maximum,maximum,maximum,maximum,maximum,minimum,minimum] + weights =[0.167, 0.039, 0.247, 0.247, 0.116, 0.02, 0.056, 0.027, 0.081] + + result = ocra(decisionMat, weights, fns) + @test result isa OCRAResult + @test isapprox( + result.scores, + [ + 0.1439209390821490, + 0.0241065507104361, + 0.2734201159562310, + 0.0429791654417769, + 0.3185195380415760, + 0.0024882426914911, + 0.5921715172301160, + 0.1139028947061430, + 0.0000000000000000, + 0.4787485498471800, + ], + atol = tol, + ) + + setting = MCDMSetting(decisionMat, weights, fns) + result2 = ocra(setting) + @test result2 isa OCRAResult + @test result2.scores == result.scores + end + end