From 5a50196a1319e64245b47f3e48e1760dcf18d688 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Fri, 11 Nov 2022 11:35:53 +0100 Subject: [PATCH] drop Topsis prefix of all the types in topsis:: Signed-off-by: Wolfgang Bumiller --- src/pve_static.rs | 4 +- src/topsis.rs | 50 +++++++-------- tests/topsis.rs | 154 ++++++++++++++++++++++------------------------ 3 files changed, 102 insertions(+), 106 deletions(-) diff --git a/src/pve_static.rs b/src/pve_static.rs index f8757f3..345c0a2 100644 --- a/src/pve_static.rs +++ b/src/pve_static.rs @@ -1,7 +1,7 @@ use anyhow::Error; use serde::{Deserialize, Serialize}; -use crate::topsis::TopsisMatrix; +use crate::topsis; #[derive(Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] @@ -115,7 +115,7 @@ pub fn score_nodes_to_start_service( .collect::>(); let scores = - crate::topsis::score_alternatives(&TopsisMatrix::new(matrix)?, &PVE_HA_TOPSIS_CRITERIA)?; + topsis::score_alternatives(&topsis::Matrix::new(matrix)?, &PVE_HA_TOPSIS_CRITERIA)?; Ok(scores .into_iter() diff --git a/src/topsis.rs b/src/topsis.rs index 437f41f..90145fa 100644 --- a/src/topsis.rs +++ b/src/topsis.rs @@ -17,7 +17,7 @@ fn l2_norm(values: &[f64]) -> f64 { } /// A criterion that can be used when scoring with the TOPSIS algorithm. -pub struct TopsisCriterion { +pub struct Criterion { /// Name of the criterion. name: String, /// The relative weight of the criterion. Is non-negative. @@ -26,8 +26,8 @@ pub struct TopsisCriterion { maximize: bool, } -impl TopsisCriterion { - /// Construct a new `TopsisCriterion`. Use a negative weight if the value for the criterion +impl Criterion { + /// Construct a new `Criterion`. Use a negative weight if the value for the criterion /// should be minimized rather than maximized. /// /// Assumes that `weight` is finite. @@ -38,7 +38,7 @@ impl TopsisCriterion { (false, -weight) }; - TopsisCriterion { + Criterion { name, weight, maximize, @@ -46,14 +46,14 @@ impl TopsisCriterion { } } -/// A normalized array of `TopsisCriterion`. -pub struct TopsisCriteria([TopsisCriterion; N_CRITERIA]); +/// A normalized array of `Criterion`. +pub struct Criteria([Criterion; N_CRITERIA]); -impl TopsisCriteria { +impl Criteria { /// Create a new instance of normalized TOPSIS criteria. /// /// Assumes that the sum of weights can be calculated to a finite, non-zero value. - pub fn new(mut criteria: [TopsisCriterion; N]) -> Result { + pub fn new(mut criteria: [Criterion; N]) -> Result { let divisor = criteria .iter() .fold(0.0, |sum, criterion| sum + criterion.weight); @@ -73,7 +73,7 @@ impl TopsisCriteria { } } - Ok(TopsisCriteria(criteria)) + Ok(Criteria(criteria)) } /// Weigh each value according to the weight of its corresponding criterion. @@ -86,9 +86,9 @@ impl TopsisCriteria { } /// A normalized matrix used for scoring with the TOPSIS algorithm. -pub struct TopsisMatrix(Vec<[f64; N_CRITERIA]>); +pub struct Matrix(Vec<[f64; N_CRITERIA]>); -impl TopsisMatrix { +impl Matrix { /// Values of the matrix for the fixed critierion with index `index`. fn fixed_criterion(&self, index: usize) -> Vec { self.0 @@ -105,12 +105,12 @@ impl TopsisMatrix { .collect::>() } - /// Create a normalized `TopsisMatrix` based on the given values. + /// Create a normalized `Matrix` based on the given values. /// /// Assumes that the sum of squares for each fixed criterion in `matrix` can be calculated to a /// finite value. pub fn new(matrix: Vec<[f64; N]>) -> Result { - let mut matrix = TopsisMatrix(matrix); + let mut matrix = Matrix(matrix); for n in 0..N { let divisor = l2_norm(&matrix.fixed_criterion(n)); @@ -129,17 +129,17 @@ impl TopsisMatrix { } } -/// Idealized alternatives from a `TopsisMatrix`. That is, the alternative consisting of the best +/// Idealized alternatives from a `Matrix`. That is, the alternative consisting of the best /// (respectively worst) value among the alternatives in the matrix for each single criterion. -struct TopsisIdealAlternatives { +struct IdealAlternatives { best: [f64; N_CRITERIA], worst: [f64; N_CRITERIA], } -impl TopsisIdealAlternatives { +impl IdealAlternatives { /// Compute the idealized alternatives from the given `matrix`. The `criteria` are required to know /// if a critierion should be maximized or minimized. - fn compute(matrix: &TopsisMatrix, criteria: &TopsisCriteria) -> Self { + fn compute(matrix: &Matrix, criteria: &Criteria) -> Self { let criteria = &criteria.0; let mut best = [0.0; N]; @@ -170,10 +170,10 @@ impl TopsisIdealAlternatives { /// alternative. Scores range from 0.0 to 1.0 and a low score indicates closness to the ideal worst /// and/or distance to the ideal best alternatives. pub fn score_alternatives( - matrix: &TopsisMatrix, - criteria: &TopsisCriteria, + matrix: &Matrix, + criteria: &Criteria, ) -> Result, Error> { - let ideal_alternatives = TopsisIdealAlternatives::compute(matrix, criteria); + let ideal_alternatives = IdealAlternatives::compute(matrix, criteria); let ideal_best = &ideal_alternatives.best; let ideal_worst = &ideal_alternatives.worst; @@ -201,8 +201,8 @@ pub fn score_alternatives( /// Similar to `score_alternatives`, but returns the list of indices decreasing by score. pub fn rank_alternatives( - matrix: &TopsisMatrix, - criteria: &TopsisCriteria, + matrix: &Matrix, + criteria: &Criteria, ) -> Result, Error> { let scores = score_alternatives(matrix, criteria)?; @@ -243,10 +243,10 @@ macro_rules! criteria_struct { } ::lazy_static::lazy_static! { - static ref $criteria_name: $crate::topsis::TopsisCriteria<$count_name> = - $crate::topsis::TopsisCriteria::new([ + static ref $criteria_name: $crate::topsis::Criteria<$count_name> = + $crate::topsis::Criteria::new([ $( - $crate::topsis::TopsisCriterion::new($crit_name.to_string(), $crit_weight), + $crate::topsis::Criterion::new($crit_name.to_string(), $crit_weight), )* ]) .unwrap(); diff --git a/tests/topsis.rs b/tests/topsis.rs index bfb8624..601522f 100644 --- a/tests/topsis.rs +++ b/tests/topsis.rs @@ -1,64 +1,60 @@ use anyhow::Error; -use proxmox_resource_scheduling::topsis::{ - rank_alternatives, TopsisCriteria, TopsisCriterion, TopsisMatrix, -}; +use proxmox_resource_scheduling::topsis::{rank_alternatives, Criteria, Criterion, Matrix}; #[test] fn test_topsis_single_criterion() -> Result<(), Error> { - let criteria_pos = - TopsisCriteria::new([TopsisCriterion::new("the one and only".to_string(), 1.0)])?; + let criteria_pos = Criteria::new([Criterion::new("the one and only".to_string(), 1.0)])?; - let criteria_neg = - TopsisCriteria::new([TopsisCriterion::new("the one and only".to_string(), -1.0)])?; + let criteria_neg = Criteria::new([Criterion::new("the one and only".to_string(), -1.0)])?; let matrix = vec![[0.0]]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?, vec![0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?, vec![0], ); let matrix = vec![[0.0], [2.0]]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?, vec![1, 0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?, vec![0, 1], ); let matrix = vec![[1.0], [2.0]]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?, vec![1, 0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?, vec![0, 1], ); let matrix = vec![[1.0], [2.0], [5.0], [3.0], [4.0]]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?, vec![2, 4, 3, 1, 0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?, vec![0, 1, 3, 4, 2], ); let matrix = vec![[-2.0], [-5.0], [-4.0], [1.0], [-3.0]]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?, vec![3, 0, 4, 2, 1], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?, vec![1, 2, 4, 0, 3], ); @@ -67,38 +63,38 @@ fn test_topsis_single_criterion() -> Result<(), Error> { #[test] fn test_topsis_two_criteria() -> Result<(), Error> { - let criteria_max_min = TopsisCriteria::new([ - TopsisCriterion::new("max".to_string(), 1.0), - TopsisCriterion::new("min".to_string(), -1.0), + let criteria_max_min = Criteria::new([ + Criterion::new("max".to_string(), 1.0), + Criterion::new("min".to_string(), -1.0), ])?; - let criteria_min_max = TopsisCriteria::new([ - TopsisCriterion::new("min".to_string(), -1.0), - TopsisCriterion::new("max".to_string(), 1.0), + let criteria_min_max = Criteria::new([ + Criterion::new("min".to_string(), -1.0), + Criterion::new("max".to_string(), 1.0), ])?; - let criteria_min_min = TopsisCriteria::new([ - TopsisCriterion::new("min1".to_string(), -1.0), - TopsisCriterion::new("min2".to_string(), -1.0), + let criteria_min_min = Criteria::new([ + Criterion::new("min1".to_string(), -1.0), + Criterion::new("min2".to_string(), -1.0), ])?; - let criteria_max_max = TopsisCriteria::new([ - TopsisCriterion::new("max1".to_string(), 1.0), - TopsisCriterion::new("max2".to_string(), 1.0), + let criteria_max_max = Criteria::new([ + Criterion::new("max1".to_string(), 1.0), + Criterion::new("max2".to_string(), 1.0), ])?; let matrix = vec![[0.0, 0.0]]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_max_min)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_max_min)?, vec![0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_max)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_max)?, vec![0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_min)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_min)?, vec![0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_max_max)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?, vec![0], ); @@ -111,19 +107,19 @@ fn test_topsis_two_criteria() -> Result<(), Error> { [0.0, 0.0], ]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_max_min)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_max_min)?, vec![2, 1, 4, 3, 0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_max)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_max)?, vec![0, 3, 4, 1, 2], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_min)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_min)?, vec![2, 4, 1, 0, 3], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_max_max)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?, vec![3, 0, 1, 4, 2], ); @@ -137,19 +133,19 @@ fn test_topsis_two_criteria() -> Result<(), Error> { [4.0, 7.0], ]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_max_min)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_max_min)?, vec![0, 1, 4, 2, 3], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_max)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_max)?, vec![3, 2, 4, 1, 0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_min)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_min)?, vec![2, 3, 1, 0, 4], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_max_max)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?, vec![4, 0, 1, 3, 2], ); @@ -158,25 +154,25 @@ fn test_topsis_two_criteria() -> Result<(), Error> { #[test] fn test_topsis_three_criteria() -> Result<(), Error> { - let criteria_first = TopsisCriteria::new([ - TopsisCriterion::new("more".to_string(), 10.0), - TopsisCriterion::new("less".to_string(), 0.2), - TopsisCriterion::new("least".to_string(), 0.1), + let criteria_first = Criteria::new([ + Criterion::new("more".to_string(), 10.0), + Criterion::new("less".to_string(), 0.2), + Criterion::new("least".to_string(), 0.1), ])?; - let criteria_second = TopsisCriteria::new([ - TopsisCriterion::new("less".to_string(), 0.2), - TopsisCriterion::new("more".to_string(), 10.0), - TopsisCriterion::new("least".to_string(), 0.1), + let criteria_second = Criteria::new([ + Criterion::new("less".to_string(), 0.2), + Criterion::new("more".to_string(), 10.0), + Criterion::new("least".to_string(), 0.1), ])?; - let criteria_third = TopsisCriteria::new([ - TopsisCriterion::new("less".to_string(), 0.2), - TopsisCriterion::new("least".to_string(), 0.1), - TopsisCriterion::new("more".to_string(), 10.0), + let criteria_third = Criteria::new([ + Criterion::new("less".to_string(), 0.2), + Criterion::new("least".to_string(), 0.1), + Criterion::new("more".to_string(), 10.0), ])?; - let criteria_min = TopsisCriteria::new([ - TopsisCriterion::new("most".to_string(), -10.0), - TopsisCriterion::new("more".to_string(), -5.0), - TopsisCriterion::new("less".to_string(), 0.1), + let criteria_min = Criteria::new([ + Criterion::new("most".to_string(), -10.0), + Criterion::new("more".to_string(), -5.0), + Criterion::new("less".to_string(), 0.1), ])?; #[rustfmt::skip] @@ -186,19 +182,19 @@ fn test_topsis_three_criteria() -> Result<(), Error> { [0.0, 0.0, 1.0], ]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_first)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?, vec![0, 1, 2], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_second)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?, vec![1, 0, 2], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_third)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?, vec![2, 0, 1], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_min)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?, vec![2, 1, 0], ); @@ -210,19 +206,19 @@ fn test_topsis_three_criteria() -> Result<(), Error> { ]; // normalization ensures that it's still the same as above assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_first)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?, vec![0, 1, 2], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_second)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?, vec![1, 0, 2], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_third)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?, vec![2, 0, 1], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_min)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?, vec![2, 1, 0], ); @@ -233,19 +229,19 @@ fn test_topsis_three_criteria() -> Result<(), Error> { [0.0, 0.0, 1.0], ]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_first)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?, vec![2, 1, 0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_second)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?, vec![2, 0, 1], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_third)?, + rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?, vec![2, 1, 0], ); assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_min)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?, vec![0, 1, 2], ); @@ -260,22 +256,22 @@ fn test_nan() { [0.0, -1.0, 0.0], [0.0, f64::NAN, 1.0], ]; - assert!(TopsisMatrix::new(matrix).is_err()); + assert!(Matrix::new(matrix).is_err()); } #[test] fn test_zero() -> Result<(), Error> { - let criteria_zero = TopsisCriteria::new([ - TopsisCriterion::new("z".to_string(), 0.0), - TopsisCriterion::new("e".to_string(), 0.0), - TopsisCriterion::new("ro".to_string(), 0.0), + let criteria_zero = Criteria::new([ + Criterion::new("z".to_string(), 0.0), + Criterion::new("e".to_string(), 0.0), + Criterion::new("ro".to_string(), 0.0), ]); assert!(criteria_zero.is_err()); - let criteria_first = TopsisCriteria::new([ - TopsisCriterion::new("more".to_string(), 10.0), - TopsisCriterion::new("less".to_string(), 0.2), - TopsisCriterion::new("least".to_string(), 0.1), + let criteria_first = Criteria::new([ + Criterion::new("more".to_string(), 10.0), + Criterion::new("less".to_string(), 0.2), + Criterion::new("least".to_string(), 0.1), ])?; #[rustfmt::skip] @@ -285,7 +281,7 @@ fn test_zero() -> Result<(), Error> { [0.0, 0.0, 1.0], ]; assert_eq!( - rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_first)?, + rank_alternatives(&Matrix::new(matrix)?, &criteria_first)?, vec![1, 2, 0], );