More weighting methods: CRITIC, PIPRECIA, generic and interval-valued AHP, DEMATEL¶
Weighting covers AHP, Buckley fuzzy AHP, SWARA and entropy. This page adds
five ways to get weights, all returning a
WeightingResult (or a result that converts to
one), so they plug straight into any ranking method:
| Method | Function | Input | Kind |
|---|---|---|---|
| CRITIC | critic |
decision matrix | objective |
| PIPRECIA | piprecia |
relative importances, crisp or TFN |
subjective |
| Generic fuzzy AHP | ahp_fuzzy_numbers |
comparison matrix of any one fuzzy number kind | subjective |
| Interval-valued AHP | ahp_interval_valued |
comparison matrix of one IVQROFN kind |
subjective |
| DEMATEL | dematel |
direct-influence matrix, crisp or fuzzy | structural |
CRITIC¶
CRITIC (Diakoulaki, Mavrotas and Papayannakis 1995) is objective like entropy, but rewards criteria for conflict with the others as well as for variation. Each column is scaled to \([0, 1]\) with the best value at 1, \(r_{ij} = (x_{ij} - x^-_j) / (x^+_j - x^-_j)\), where \(x^+_j\) is the largest value of a benefit criterion and the smallest of a cost criterion. With the population standard deviation \(\sigma_j\) of \(r_{\cdot j}\) and the Pearson correlation \(\rho_{jk}\) of two scaled columns, the information carried by criterion \(j\) is
A criterion gets weight for varying a lot (large \(\sigma_j\)) and for conflicting with the
others (low \(\rho_{jk}\)). The weights do not depend on whether \(\sigma_j\) uses \(m\) or
\(m - 1\) in the denominator (the factor cancels), and they are unchanged by a positive
scaling and a shift of any column. A constant column has no scale and no correlation:
it gets weight 0 and is left out of the other columns' correlation sums, so adding one
changes no other weight. extras holds std, correlation and information.
Sourcing
CRITIC has no published golden in the tests. The method is checked against
hand-derived cases (the derivations are in tests/test_critic_piprecia.py), not against
a worked example from the paper.
from bulanik.mcdm import critic
data = [[120, 8, 7], [100, 7, 5], [110, 9, 6], [130, 6, 9]]
types = ["cost", "benefit", "benefit"]
r = critic(data, ["price", "quality", "delivery"], criteria_types=types)
print({k: round(v, 3) for k, v in r.weights.items()}, r.ranking)
print({k: round(v, 3) for k, v in r.extras["std"].items()})
print({k: round(v, 2) for k, v in r.extras["correlation"]["price"].items()}) # delivery conflicts with price
c = critic([[1, 5, 3], [2, 4, 3], [3, 3, 3]], ["a", "b", "constant"])
print({k: round(v, 3) for k, v in c.weights.items()}) # the constant column weighs 0
{'price': 0.315, 'quality': 0.26, 'delivery': 0.425} ('delivery', 'price', 'quality')
{'price': 0.373, 'quality': 0.373, 'delivery': 0.37}
{'price': 1.0, 'quality': 0.4, 'delivery': -0.98}
{'a': 0.5, 'b': 0.5, 'constant': 0.0}
PIPRECIA¶
PIPRECIA (Stanujkic et al. 2017) is a subjective method like SWARA, with two differences: the criteria need not be sorted, and the judgements are ratios. The judgement \(s_j\) for \(j \ge 2\) compares criterion \(j\) with the one before it: \(s_j > 1\) if \(C_j\) is more important, \(s_j = 1\) if equal, \(s_j < 1\) if less. Then
With TFN judgements the method is the fully fuzzy PIPRECIA of Stevic et al. (2018) with
the usual triangular arithmetic: \(\tilde k_j = (2, 2, 2) - \tilde s_j\),
\(\tilde q_j = \tilde q_{j-1} \oslash \tilde k_j\) and
\(\tilde w_j = \tilde q_j \oslash \sum_k \tilde q_k\). The crisp weights are the fuzzy
weights scored with score (the graded mean \((l + 4m + u)/6\) by default, as in the source)
and normalised to sum 1, and fuzzy_weights holds the fuzzy ones. The valid domain is \(0 < s_j < 2\) (a ratio of importances; a TFN needs
\(s^l > 0\) and \(s^u < 2\)): a crisp \(s_j \le 0\) or \(s_j \ge 2\) raises, naming the index.
The inverse pass. With s_inverse the method follows Stevic et al. (2018) and
Dalic et al. (2020): the same criteria are judged again from the penultimate one
backwards. \(s'_j\) compares criterion \(j\) with criterion \(j + 1\) (\(j = 1, \dots, n - 1\),
so s_inverse has \(n - 1\) entries in the order of criteria, not reversed). Then
\(k'_n = 1\), \(k'_j = 2 - s'_j\), \(q'_n = 1\), \(q'_j = q'_{j+1} / k'_j\) and
\(w'_j = q'_j / \sum_k q'_k\). Each of \(w_j\) and \(w'_j\) is scored, and the final weight is
their mean \((w_j + w'_j)/2\). The source does not renormalise, and for fuzzy input that
mean need not sum to 1; bulanik renormalises the weights to sum 1, which leaves their
ranking unchanged. extras then holds forward and inverse (the scored vectors before
averaging, as printed in the source) and, for TFN input, fuzzy_inverse;
fuzzy_weights stays the forward pass.
from bulanik import TFN
from bulanik.mcdm import piprecia
names = ["a", "b", "c"]
r = piprecia([1.2, 0.9], names) # b is more important than a, c less than b
print({k: round(v, 3) for k, v in r.weights.items()}, r.operators)
both = piprecia([1.2, 0.9], names, s_inverse=[1.1, 0.7])
print({k: round(v, 3) for k, v in both.weights.items()}, both.operators["inverse"])
print({k: round(v, 3) for k, v in both.extras["forward"].items()},
{k: round(v, 3) for k, v in both.extras["inverse"].items()})
f = piprecia([TFN(1.1, 1.15, 1.2), TFN(0.8, 0.9, 1.0)], names)
print({k: round(v, 3) for k, v in f.weights.items()}, f.operators["score"])
w = f.fuzzy_weights["b"]
print(round(w.l, 3), round(w.m, 3), round(w.u, 3))
{'a': 0.295, 'b': 0.369, 'c': 0.336} {'score': 'crisp', 'inverse': 'none'}
{'a': 0.311, 'b': 0.331, 'c': 0.358} mean_of_forward_and_inverse
{'a': 0.295, 'b': 0.369, 'c': 0.336} {'a': 0.326, 'b': 0.293, 'c': 0.381}
{'a': 0.307, 'b': 0.362, 'c': 0.331} graded_mean
0.317 0.362 0.412
Generic fuzzy AHP¶
fuzzy_ahp is Buckley's method for triangular
numbers. ahp_fuzzy_numbers runs AHP over a
comparison matrix of any one number kind and rung: interval-valued, orthopair,
neutrosophic or interval type-2. Row \(i\) is aggregated with equal weights \(1/n\) by
wg (the fuzzy geometric mean
\(\tilde r_i = (\bigotimes_j \tilde a_{ij})^{1/n}\), the default) or
wa, the row number is scored, \(s_i = \mathrm{score}(\tilde r_i)\),
and the weights are
This differs from Buckley. He first normalises fuzzily,
\(\tilde w_i = \tilde r_i \otimes (\sum_k \tilde r_k)^{-1}\), and defuzzifies afterwards;
here the row number is defuzzified first and the crisp scores are normalised. The generic
form needs no fuzzy division, which is why it works for every kind. The matrix has order
at most 10, and fuzzy_weights holds the aggregated row numbers.
The consistency ratio is Saaty's. With consistency_matrix (typically the crisp Saaty
values of the linguistic terms) it is that matrix's ratio, recorded as
"saaty_ri_on_given_matrix"; otherwise, if every entry's score is positive, it is computed
on the matrix of entry scores ("saaty_ri_on_scores"); otherwise it is None ("none").
The row scores must be positive, so an orthopair kind needs score="normalized".
Use score=\"normalized\" for orthopair and interval-valued kinds
Their default score is the signed difference \(\mu - \nu\), which is not a ratio scale.
A signed row score raises, but whenever every row score happens to be positive it is
silently used as a ratio scale, and the weights can differ a lot from those of
score="normalized". Pass score="normalized" for IFN, PFN, IVIFN and the like,
and do not rely on the default.
from bulanik import IVIFN, TFN
from bulanik.mcdm import ahp_fuzzy_numbers
names = ["cost", "quality", "speed"]
m = [[TFN(1, 1, 1), TFN(2, 3, 4), TFN(4, 5, 6)],
[TFN(1/4, 1/3, 1/2), TFN(1, 1, 1), TFN(1, 2, 3)],
[TFN(1/6, 1/5, 1/4), TFN(1/3, 1/2, 1), TFN(1, 1, 1)]]
r = ahp_fuzzy_numbers(m, names)
print({k: round(v, 3) for k, v in r.weights.items()}, round(r.consistency_ratio, 3))
print(r.operators)
one = IVIFN(0.5, 0.5, 0.5, 0.5) # "equally important"
iv = [[one, IVIFN(0.7, 0.8, 0.1, 0.2)], [IVIFN(0.1, 0.2, 0.7, 0.8), one]]
try:
ahp_fuzzy_numbers(iv, ["a", "b"]) # the default score is signed
except ValueError as error:
print(error)
r = ahp_fuzzy_numbers(iv, ["a", "b"], score="normalized")
print({k: round(v, 3) for k, v in r.weights.items()}, r.operators["score"])
{'cost': 0.641, 'quality': 0.231, 'speed': 0.129} 0.093
{'weights': 'row_wg', 'ops': 'algebraic', 'score': 'centroid', 'consistency': 'saaty_ri_on_scores'}
ahp_fuzzy_numbers needs positive row scores, got [0.26366971781362525, -0.3783196677978017]; try score="normalized"
{'a': 0.67, 'b': 0.33} normalized
Interval-valued AHP¶
ahp_interval_valued takes a comparison
matrix of one interval-valued orthopair kind, \(([\mu^L, \mu^U], [\nu^L, \nu^U])\) of rung
\(q\): IVIFN, IVPFN,
IVFFN or a general IVQROFN. It
works on the interval endpoints directly rather than on a row number. Both triangles are
filled by the decision maker, reciprocity is not required, and the diagonal is taken as
given, so a scale's "equal" term may be whatever that scale says.
method="multiplicative" takes any \(q\) and is the default for \(q \ge 2\) (Karasan,
Ilbahar and Kahraman 2019; Alkan and Kahraman 2023 for \(q = 3\); the form for a general \(q\) is
this library's generalisation). With
the interval multiplicative entries are \(s^L_{ij} = 1000^{d^L_{ij}/q}\) and \(s^U_{ij} = 1000^{d^U_{ij}/q}\), the hesitancy factor is \(h_{ij} = 1 - ((\mu^U_{ij})^q - (\mu^L_{ij})^q) - ((\nu^U_{ij})^q - (\nu^L_{ij})^q)\), and
method="possibility" is defined for IVIFN (\(q = 1\)) only and is the default there
(interval weights, possibility degree and \(w = \sum p + n/2 - 1\) as in Cebi and Ilbahar 2018 and,
for neutrosophic numbers, Bolturk and Kahraman 2018; both use powers of 10 where this function
uses \(e\), which changes the weights). The
interval exponential matrix is \(a^-_{ij} = e^{\mu^L_{ij} - \nu^U_{ij}}\),
\(a^+_{ij} = e^{\mu^U_{ij} - \nu^L_{ij}}\), the interval weights come from the row sums,
and the possibility degree that \(\tilde w_j \ge \tilde w_i\) is
Which one?
| You have | Use | Why |
|---|---|---|
| A rung of 2 or more | "multiplicative" |
The only one of the two defined there. |
IVIFN judgements, and you want clear separation between criteria |
"multiplicative" |
The factor \(1000^{d/q}\) spreads the weights widely. |
IVIFN judgements, and you want interval weights or a flatter result |
"possibility" |
extras["interval_weights"] reports the intervals, and the weights stay closer together. |
| Any other number kind | ahp_fuzzy_numbers |
Works for every kind through its score. |
The consistency ratio is Saaty's. With consistency_matrix it is that matrix's ratio;
otherwise, if every entry's default score is positive, it is computed on the matrix of
entry scores; otherwise it is None. extras holds scored_matrix and
consistency_ratio, and for the multiplicative method d_lower, d_upper, s_lower,
s_upper, h and t, for the possibility method interval_weights and possibility.
from bulanik import IVIFN, IVPFN
from bulanik.mcdm import ahp_interval_valued
names = ["cost", "quality", "speed"]
e, a, b = IVPFN(.45, .55, .45, .55), IVPFN(.65, .80, .20, .35), IVPFN(.20, .35, .65, .80)
r = ahp_interval_valued([[e, a, a], [b, e, a], [b, b, e]], names) # q = 2: multiplicative
print({k: round(v, 3) for k, v in r.weights.items()}, r.operators)
e, a, b = IVIFN(.50, .50, .50, .50), IVIFN(.55, .65, .20, .35), IVIFN(.20, .35, .55, .65)
m = [[e, a, a], [b, e, a], [b, b, e]]
r = ahp_interval_valued(m, names) # q = 1: possibility
print({k: round(v, 3) for k, v in r.weights.items()}, r.operators)
print([(round(lo, 3), round(hi, 3)) for lo, hi in r.extras["interval_weights"]])
r = ahp_interval_valued(m, names, method="multiplicative")
print({k: round(v, 3) for k, v in r.weights.items()}, r.operators)
{'cost': 0.584, 'quality': 0.333, 'speed': 0.083} {'method': 'multiplicative', 'q': '2'}
{'cost': 0.464, 'quality': 0.348, 'speed': 0.189} {'method': 'possibility', 'q': '1'}
[(0.339, 0.482), (0.281, 0.395), (0.224, 0.308)]
{'cost': 0.63, 'quality': 0.333, 'speed': 0.037} {'method': 'multiplicative', 'q': '1'}
Example 23 compares the methods on one set of judgements.
DEMATEL¶
DEMATEL (Gabus and Fontela 1972) does not weigh criteria by preference. It asks how strongly each factor influences every other, and from the network of influences finds which factors are causes (they push others) and which are effects (they are pushed). Take a direct-relation matrix \(A\), where \(a_{ij}\) says how strongly factor \(i\) influences factor \(j\). The normalised matrix and the total-relation matrix are
with \(s = \max(\max_i \sum_j a_{ij},\ \max_j \sum_i a_{ij})\) (normalization="max_row_col",
the default) or \(s = \max_i \sum_j a_{ij}\) ("max_row"). The diagonal of \(A\) is used as
given. The row sums \(D\) and column sums \(R\) of \(T\) give each factor's
- prominence \(D + R\): how involved the factor is overall, and
- relation \(D - R\): its net influence.
A factor is a cause when \(D_i - R_i > 10^{-12} \max_k (D_k + R_k)\) and an effect
otherwise, so rounding noise around an exact zero net relation counts as an effect, as an
exact zero does. The result lists relations, the off-diagonal \(t_{ij}\) above a
threshold (the mean of all \(n^2\) entries of \(T\) by default), sorted row-major.
Weights. weighting="sqrt" (the default) gives
\(w_i \propto \sqrt{(D_i + R_i)^2 + (D_i - R_i)^2}\), the length of the factor's vector in the
cause-effect plane; "prominence" gives \(w_i \propto D_i + R_i\). The square-root form is
a common convention in DEMATEL-based weighting, not a formula of the original method;
if you need the plain prominence, ask for it.
DEMATELResult.as_weights() returns the
weights as a WeightingResult, with prominence and relation in its extras, usable
as the criteria weights of every ranking method.
The example is the 5 by 5 matrix of the vignette of the R package dematel, which the
test suite also uses as a cross-check against the printed values.
from bulanik.mcdm import dematel
A = [[0, 2, 4, 3, 4],
[3, 0, 2, 0, 0],
[3, 3, 0, 0, 0],
[3, 0, 4, 0, 2],
[4, 0, 2, 0, 0]]
r = dematel(A)
print(r.causes, r.effects)
print({k: round(v, 3) for k, v in r.prominence.items()})
print({k: round(v, 3) for k, v in r.relation.items()})
print({k: round(v, 3) for k, v in r.weights.items()}, r.ranking)
print(round(r.threshold, 3), len(r.relations), r.relations[0][:2])
print(r.operators)
p = dematel(A, weighting="prominence")
print({k: round(v, 3) for k, v in p.weights.items()})
w = r.as_weights()
print(w.method, w.ranking == r.ranking, sorted(w.extras))
('F1', 'F4', 'F5') ('F2', 'F3')
{'F1': 4.861, 'F2': 2.437, 'F3': 3.603, 'F4': 2.658, 'F5': 2.739}
{'F1': 0.014, 'F2': -0.146, 'F3': -1.027, 'F4': 1.078, 'F5': 0.081}
{'F1': 0.292, 'F2': 0.147, 'F3': 0.225, 'F4': 0.172, 'F5': 0.164} ('F1', 'F3', 'F4', 'F5', 'F2')
0.326 13 ('F1', 'F2')
{'normalization': 'max_row_col', 'defuzzification': 'crisp', 'threshold': 'mean', 'weights': 'sqrt'}
{'F1': 0.298, 'F2': 0.15, 'F3': 0.221, 'F4': 0.163, 'F5': 0.168}
dematel True ['prominence', 'relation']
plot.dematel:
each factor sits at its prominence \(D + R\) and relation \(D - R\) (above the line, a net
giver of influence), and the arrows are the total influences above 0.45 (the default
threshold, the mean of \(T\) at 0.33, would draw 13).Fuzzy and crisp input¶
The matrix may hold fuzzy numbers of one kind; they are defuzzified first
(defuzzification=). For triangular numbers the default is CFCS (converting fuzzy
data into crisp scores) of Opricovic and Tzeng (2003), also available as
cfcs. For cell \((i, j)\) with expert ratings
\((l^k, m^k, r^k)\), \(k = 1..K\), let \(\min = \min_k l^k\), \(\Delta = \max_k r^k - \min\) and,
for each expert, \(x_l = (l^k - \min)/\Delta\) (likewise \(x_m\), \(x_r\)),
\(x^{ls} = x_m/(1 + x_m - x_l)\), \(x^{rs} = x_r/(1 + x_r - x_m)\),
and the cell value is the mean of \(z^k\).
Scope of CFCS
As in Opricovic and Tzeng (2003), the minimum and maximum are taken per cell across the experts, not over the whole matrix. Each expert's crisp value is computed first, and the experts are averaged after the CFCS step. With a single expert the cell's own \(l\) and \(r\) are used; if \(\Delta = 0\) then \(z = \min\).
Any other kind is defuzzified with a score of the kind (the kind's default unless you name
one). Crisp input accepts only defuzzification=None or "crisp".
from bulanik import TFN
from bulanik.mcdm import dematel
from bulanik.mcdm.dematel import cfcs
z = TFN(0, 0, 0)
expert1 = [[z, TFN(1, 2, 4)], [z, z]]
expert2 = [[z, TFN(2, 3, 4)], [z, z]]
print(round(cfcs([expert1])[0][1], 4)) # one expert: the cell's own l and r
print(round(cfcs([expert1, expert2])[0][1], 4)) # two experts: min and max per cell, then mean
fuzzy = [[z, TFN(1, 2, 4), TFN(2, 3, 4)], [TFN(0, 1, 2), z, TFN(1, 2, 3)], [TFN(3, 4, 4), TFN(0, 1, 2), z]]
r = dematel(fuzzy)
print(r.operators["defuzzification"], r.causes, {k: round(v, 3) for k, v in r.weights.items()})
print(dematel(fuzzy, defuzzification="centroid").operators["defuzzification"])
2.2167
2.5833
cfcs ('F1', 'F3') {'F1': 0.374, 'F2': 0.255, 'F3': 0.371}
centroid
Pitfalls¶
DEMATEL needs I - N to be invertible. If the normalised matrix has spectral radius
1, which happens when every row sum equals the normalising maximum (for example
[[0, 1], [1, 0]]), the total relation is undefined and the call raises ValueError
saying so, never a meaningless huge \(T\). An all-zero matrix, a negative entry, a non-square
matrix or fewer than 2 factors also raise.
Fuzzy scores can be negative. After defuzzification every entry must be \(\ge 0\).
Orthopair kinds default to a signed score, so pass defuzzification="normalized"; a kind
without that score gets the hint "use a positive-valued score".
Influence is not preference. DEMATEL weights say how central a factor is in the
network. Whether that is the right notion of importance for your decision is your call,
and the "sqrt" weighting is a convention.
CRITIC needs variation and conflict. At least two alternatives are required. If every
column is constant there is nothing to weigh, and if the informative columns are all
perfectly positively correlated (for example 2 alternatives and no conflict), every \(C_j\)
is 0; both raise ValueError.
PIPRECIA judgements are \(n - 1\) ratios. The count must match, \(s_j \ge 2\) is
rejected, and crisp and TFN judgements cannot be mixed, nor can the forward and inverse
sets.
ahp_fuzzy_numbers needs positive row scores, so give an orthopair kind
score="normalized".
The possibility method needs \(q = 1\). On any other rung it raises ValueError; the
multiplicative method takes any rung. The default also follows the rung, so state method
when you compare runs.
The two interval-valued methods are on different scales of spread. The weights of one are not interchangeable with those of the other: the factor \(1000^{d/q}\) of the multiplicative method separates criteria far more than the possibility degrees do, and the order can be the same while the weights are not.
ahp_interval_valued takes the matrix as given. It does not fill the lower triangle
and does not force a diagonal, so write the whole matrix. The ratio on the scored matrix
is indicative only when the judgements are not reciprocal; pass the crisp Saaty matrix as
consistency_matrix for the usual one. The order is limited to 2 to 10.
from bulanik import IFN, TFN
from bulanik.mcdm import critic, dematel, piprecia
def show(make):
try:
print(make())
except Exception as error:
print(f"{type(error).__name__}: {error}")
show(lambda: dematel([[0, 1], [1, 0]])) # I - N is singular
show(lambda: dematel([[0, 0], [0, 0]]))
show(lambda: dematel([[0, -1], [1, 0]]))
show(lambda: dematel([[0, 1, 2], [1, 0, 1]]))
show(lambda: dematel([[0, 2], [1, 0]], weighting="sum"))
show(lambda: dematel([[0, 2], [1, 0]], defuzzification="cfcs")) # crisp input: no defuzzification
ifn = [[IFN(0.5, 0.4), IFN(0.5, 0.4)], [IFN(0.1, 0.4), IFN(0.5, 0.4)]]
show(lambda: dematel(ifn)) # signed default score
show(lambda: dematel(ifn, defuzzification="normalized").causes)
show(lambda: critic([[1, 2], [1, 2]])) # every column constant
show(lambda: critic([[1, 2], [2, 4]])) # perfectly correlated
show(lambda: piprecia([2.0], ["a", "b"])) # k = 2 - s must be positive
show(lambda: piprecia([1.1], ["a", "b", "c"])) # needs n - 1 = 2 judgements
show(lambda: piprecia([1.1, TFN(0.8, 0.9, 1.0)], ["a", "b", "c"]))
ValueError: I - N is singular: the normalised matrix has spectral radius 1 (e.g. equal row and column sums), so the total relation is undefined
ValueError: dematel matrix is all zero (normalising maximum is zero)
ValueError: dematel entries must be >= 0 (negative after defuzzification)
ValueError: dematel needs a square matrix
ValueError: unknown weighting 'sum' for dematel; valid: sqrt, prominence
ValueError: unknown defuzzification 'cfcs' for dematel; valid: crisp
ValueError: dematel entries must be >= 0 (negative after defuzzification); try defuzzification="normalized"
('F1',)
ValueError: no criterion discriminates between the alternatives (all columns constant)
ValueError: the informative criteria are perfectly correlated, so CRITIC's conflict term is zero for every criterion
ValueError: PIPRECIA needs every k_j = 2 - s_j to be positive, got s_2 = 2.0 (k_2 = 0.0)
ValueError: expected 2 relative importances for 3 criteria, got 1
ValueError: PIPRECIA relative importances must be all crisp or all TFN, not a mix
See also¶
- Weighting for AHP, fuzzy AHP, SWARA and entropy, and Ranking and More ranking methods for what to do with the weights.
- Choosing a method for when to use which.
- Interval-valued numbers and
Interval type-2 trapezoids for the kinds
ahp_fuzzy_numbersanddematelaccept; Aggregation. - API:
bulanik.mcdm.weighting,bulanik.mcdm.dematel,DEMATELResult,plot.dematel. - Diakoulaki, Mavrotas and Papayannakis (1995), Computers & Operations Research 22(7), 763-770 (CRITIC); Stanujkic, Zavadskas, Karabasevic, Smarandache and Turskis (2017), Romanian Journal of Economic Forecasting 20(4), 116-133, Stevic, Stjepanovic, Bozickovic, Das and Stanujkic (2018), Symmetry 10(11), 586, and Dalic, Stevic, Karamasa and Puska (2020), Decision Making: Applications in Management and Engineering 3(1), 80-95 (PIPRECIA); Saaty (1980), The Analytic Hierarchy Process, McGraw-Hill, and Kahraman, Oztaysi, Ucal Sari and Turanoglu (2014), Knowledge-Based Systems 59, 48-57 (generic and interval type-2 AHP); Karasan, Ilbahar and Kahraman (2019), Soft Computing 23(21), 10953-10968, Alkan and Kahraman (2023), Informatica 34(1), 1-33, Cebi and Ilbahar (2018), International Journal of the Analytic Hierarchy Process 10(2), and Bolturk and Kahraman (2018), the same journal, 10(3) (interval-valued AHP); Gabus and Fontela (1972), World Problems, an Invitation to Further Thought within the Framework of DEMATEL, Battelle Geneva Research Centre, Opricovic and Tzeng (2003), International Journal of Uncertainty, Fuzziness and Knowledge-Based Systems 11(5), 635-652, and Wu and Lee (2007), Expert Systems with Applications 32(2), 499-507 (fuzzy DEMATEL with CFCS).