///|
pub(all) struct VikorResult {
ranking : Ranking
utility : Array[Double]
regret : Array[Double]
criterion_regrets : Array[Array[Double]]
compromise : Array[String]
acceptable_advantage : Bool
acceptable_stability : Bool
} derive(@debug.Debug)
///|
pub fn vikor(
m : DecisionMatrix,
weights : Array[Double],
v~ : Double = 0.5,
tolerance~ : Double = 1.0e-10,
) -> VikorResult raise ChoiceError {
probability(v)
let w = matrix_weights(m, weights)
let x = m.normalize(MinMax)
let (n, p) = m.shape()
let losses = zeros(n, p)
let utility = Array::make(n, 0.0)
let regret = Array::make(n, 0.0)
for j in 0.. {
let s = if shi == slo { 0.0 } else { (utility[i] - slo) / (shi - slo) }
let r = if rhi == rlo { 0.0 } else { (regret[i] - rlo) / (rhi - rlo) }
v * s + (1.0 - v) * r
}
]
let ranking = rank_scores(m.names, scores, higher_is_better=false, tolerance~)
let best = ranking.order[0]
let acceptable_stability = utility[best] <= slo + tolerance ||
regret[best] <= rlo + tolerance
let threshold = if n <= 1 { 0.0 } else { 1.0 / (n - 1).to_double() }
let acceptable_advantage = n <= 1 ||
scores[ranking.order[1]] - scores[best] + tolerance >= threshold
let compromise : Array[String] = []
if acceptable_advantage && acceptable_stability {
compromise.push(m.names[best])
} else if acceptable_advantage {
compromise.push(m.names[best])
if n > 1 {
compromise.push(m.names[ranking.order[1]])
}
} else {
for i in ranking.order {
if scores[i] - scores[best] < threshold || ranking.ranks[i] == 1 {
compromise.push(m.names[i])
}
}
}
{
ranking,
utility,
regret,
criterion_regrets: losses,
compromise,
acceptable_advantage,
acceptable_stability,
}
}
///|
pub extend VikorResult with @debug.Debug::{to_repr}