///|
pub(all) struct PrometheeResult {
  ranking : Ranking
  preference_matrix : Array[Array[Double]]
  positive_flow : Array[Double]
  negative_flow : Array[Double]
} derive(@debug.Debug)

///|
fn preference_specs(
  m : DecisionMatrix,
  specs : Array[Preference],
) -> Unit raise ChoiceError {
  if specs.length() != m.criteria.length() {
    raise Invalid("preference specification count mismatch")
  }
  for spec in specs {
    valid_preference(spec)
  }
}

///|
/// Thresholds are in raw criterion units, not normalized units.
pub fn promethee(
  m : DecisionMatrix,
  weights : Array[Double],
  preferences : Array[Preference],
  tolerance~ : Double = 1.0e-10,
) -> PrometheeResult raise ChoiceError {
  let w = matrix_weights(m, weights)
  preference_specs(m, preferences)
  let (n, p) = m.shape()
  let pi = zeros(n, n)
  for i in 0.. 1 {
    let denominator = (n - 1).to_double()
    for i in 0.. pi[k][i] ]) / denominator
      net[i] = positive_flow[i] - negative_flow[i]
    }
  }
  {
    ranking: rank_scores(m.names, net, tolerance~),
    preference_matrix: pi,
    positive_flow,
    negative_flow,
  }
}

///|
pub extend PrometheeResult with @debug.Debug::{to_repr}